blob: 041fbe2226bf9914caf45d6b22dab409508ee040 [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>
46#include <signal.h>
47#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020048#ifdef __ia64__
49int __clone2(int (*fn)(void *), void *child_stack_base,
50 size_t stack_size, int flags, void *arg, ...);
51#endif
bellard31e31b82003-02-18 22:55:36 +000052#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000053#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000054#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000055#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000056#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000057#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000058#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000059#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000060#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000061#include <sys/sysinfo.h>
aurel323b3f24a2009-04-15 16:12:13 +000062#include <sys/utsname.h>
bellard72f03902003-02-18 23:33:18 +000063//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000064#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000065#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020066#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000067#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020068#include "qemu-common.h"
Juan Quintela9788c9c2009-07-27 16:13:02 +020069#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000070#include <sys/gmon.h>
71#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030072#ifdef CONFIG_EVENTFD
73#include <sys/eventfd.h>
74#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000075#ifdef CONFIG_EPOLL
76#include <sys/epoll.h>
77#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070078#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010079#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070080#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000081#ifdef CONFIG_SENDFILE
82#include <sys/sendfile.h>
83#endif
bellard31e31b82003-02-18 22:55:36 +000084
85#define termios host_termios
86#define winsize host_winsize
87#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000088#define sgttyb host_sgttyb /* same as target */
89#define tchars host_tchars /* same as target */
90#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000091
92#include <linux/termios.h>
93#include <linux/unistd.h>
94#include <linux/utsname.h>
95#include <linux/cdrom.h>
96#include <linux/hdreg.h>
97#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000098#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000099#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +0300100#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000101#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +0000102#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000103#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200104#include <linux/fb.h>
105#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100106#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000107#include <linux/reboot.h>
pbrookd7e40362008-05-23 16:06:43 +0000108#include "linux_loop.h"
Loïc Minierda790302009-12-29 22:06:13 +0100109#include "cpu-uname.h"
bellard31e31b82003-02-18 22:55:36 +0000110
bellard3ef693a2003-03-23 20:17:16 +0000111#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000112
pbrookd865bab2008-06-07 22:12:17 +0000113#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
114 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000115
bellard72f03902003-02-18 23:33:18 +0000116//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000117
bellard1a9353d2003-03-16 20:28:50 +0000118//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000119#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
120#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000121
bellard70a194b2003-08-11 22:20:16 +0000122
bellard70a194b2003-08-11 22:20:16 +0000123#undef _syscall0
124#undef _syscall1
125#undef _syscall2
126#undef _syscall3
127#undef _syscall4
128#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000129#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000130
bellard83fcb512006-06-14 13:37:16 +0000131#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000132static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000133{ \
134 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000135}
136
bellard83fcb512006-06-14 13:37:16 +0000137#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000138static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000139{ \
140 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000141}
142
bellard83fcb512006-06-14 13:37:16 +0000143#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000144static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000145{ \
146 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000147}
148
bellard83fcb512006-06-14 13:37:16 +0000149#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000150static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000151{ \
152 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000153}
154
bellard83fcb512006-06-14 13:37:16 +0000155#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000156static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000157{ \
158 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000159}
160
bellard83fcb512006-06-14 13:37:16 +0000161#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
162 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000163static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000164{ \
165 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000166}
bellard83fcb512006-06-14 13:37:16 +0000167
168
169#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
170 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000171static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
172 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000173{ \
174 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
175}
176
bellard70a194b2003-08-11 22:20:16 +0000177
bellard31e31b82003-02-18 22:55:36 +0000178#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000179#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000180#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000181#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000182#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000183#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000184#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000185#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000186#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000187#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000188#define __NR_sys_inotify_init __NR_inotify_init
189#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
190#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000191
Alexander Graf42a39fb2011-04-15 17:32:45 +0200192#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
193 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000194#define __NR__llseek __NR_lseek
195#endif
196
bellard72f03902003-02-18 23:33:18 +0000197#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000198_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000199#else
ths0da46a62007-10-20 20:23:07 +0000200/* This is a replacement for the host gettid() and must return a host
201 errno. */
bellard72f03902003-02-18 23:33:18 +0000202static int gettid(void) {
203 return -ENOSYS;
204}
205#endif
Peter Maydell3307e232013-06-12 16:20:21 +0100206#ifdef __NR_getdents
aurel323b3f24a2009-04-15 16:12:13 +0000207_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100208#endif
209#if !defined(__NR_getdents) || \
210 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000211_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
212#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700213#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000214_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
215 loff_t *, res, uint, wh);
216#endif
217_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
218_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
219#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
220_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
221#endif
222#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
223_syscall2(int,sys_tkill,int,tid,int,sig)
224#endif
225#ifdef __NR_exit_group
226_syscall1(int,exit_group,int,error_code)
227#endif
228#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
229_syscall1(int,set_tid_address,int *,tidptr)
230#endif
aurel323b3f24a2009-04-15 16:12:13 +0000231#if defined(TARGET_NR_futex) && defined(__NR_futex)
232_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
233 const struct timespec *,timeout,int *,uaddr2,int,val3)
234#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500235#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
236_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
237 unsigned long *, user_mask_ptr);
238#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
239_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
240 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200241_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
242 void *, arg);
aurel323b3f24a2009-04-15 16:12:13 +0000243
244static bitmask_transtbl fcntl_flags_tbl[] = {
245 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
246 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
247 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
248 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
249 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
250 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
251 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
252 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700253 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000254 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
255 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
256 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
257 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000258#if defined(O_DIRECT)
259 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
260#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700261#if defined(O_NOATIME)
262 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
263#endif
264#if defined(O_CLOEXEC)
265 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
266#endif
267#if defined(O_PATH)
268 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
269#endif
270 /* Don't terminate the list prematurely on 64-bit host+guest. */
271#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
272 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
273#endif
aurel323b3f24a2009-04-15 16:12:13 +0000274 { 0, 0, 0, 0 }
275};
276
277#define COPY_UTSNAME_FIELD(dest, src) \
278 do { \
279 /* __NEW_UTS_LEN doesn't include terminating null */ \
280 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
281 (dest)[__NEW_UTS_LEN] = '\0'; \
282 } while (0)
283
284static int sys_uname(struct new_utsname *buf)
285{
286 struct utsname uts_buf;
287
288 if (uname(&uts_buf) < 0)
289 return (-1);
290
291 /*
292 * Just in case these have some differences, we
293 * translate utsname to new_utsname (which is the
294 * struct linux kernel uses).
295 */
296
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200297 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000298 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
299 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
300 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
301 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
302 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
303#ifdef _GNU_SOURCE
304 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
305#endif
306 return (0);
307
308#undef COPY_UTSNAME_FIELD
309}
310
311static int sys_getcwd1(char *buf, size_t size)
312{
313 if (getcwd(buf, size) == NULL) {
314 /* getcwd() sets errno */
315 return (-1);
316 }
aurel32aaf4ad32009-04-16 14:17:14 +0000317 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000318}
319
aurel323b3f24a2009-04-15 16:12:13 +0000320#ifdef TARGET_NR_openat
Alexander Graff4c69012011-09-25 06:25:35 +0200321static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000322{
323 /*
324 * open(2) has extra parameter 'mode' when called with
325 * flag O_CREAT.
326 */
327 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000328 return (openat(dirfd, pathname, flags, mode));
329 }
330 return (openat(dirfd, pathname, flags));
331}
332#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300333
334#ifdef CONFIG_UTIMENSAT
335static int sys_utimensat(int dirfd, const char *pathname,
336 const struct timespec times[2], int flags)
337{
338 if (pathname == NULL)
339 return futimens(dirfd, times);
340 else
341 return utimensat(dirfd, pathname, times, flags);
342}
343#else
ths9007f0e2007-09-25 17:50:37 +0000344#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
345_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
346 const struct timespec *,tsp,int,flags)
347#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300348#endif /* CONFIG_UTIMENSAT */
aurel323b3f24a2009-04-15 16:12:13 +0000349
350#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000351#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000352
aurel3239b59762008-10-01 21:46:50 +0000353#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000354static int sys_inotify_init(void)
355{
356 return (inotify_init());
357}
aurel3239b59762008-10-01 21:46:50 +0000358#endif
359#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000360static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
361{
362 return (inotify_add_watch(fd, pathname, mask));
363}
aurel3239b59762008-10-01 21:46:50 +0000364#endif
365#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000366static int sys_inotify_rm_watch(int fd, int32_t wd)
367{
aurel328690e422009-04-17 13:50:32 +0000368 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000369}
aurel3239b59762008-10-01 21:46:50 +0000370#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000371#ifdef CONFIG_INOTIFY1
372#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
373static int sys_inotify_init1(int flags)
374{
375 return (inotify_init1(flags));
376}
377#endif
378#endif
aurel323b3f24a2009-04-15 16:12:13 +0000379#else
380/* Userspace can usually survive runtime without inotify */
381#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000382#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000383#undef TARGET_NR_inotify_add_watch
384#undef TARGET_NR_inotify_rm_watch
385#endif /* CONFIG_INOTIFY */
386
Mike Frysingerd8035d42011-02-07 01:05:51 -0500387#if defined(TARGET_NR_ppoll)
388#ifndef __NR_ppoll
389# define __NR_ppoll -1
390#endif
391#define __NR_sys_ppoll __NR_ppoll
392_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
393 struct timespec *, timeout, const __sigset_t *, sigmask,
394 size_t, sigsetsize)
395#endif
bellard66fb9762003-03-23 01:06:05 +0000396
Mike Frysinger055e0902011-06-03 17:01:49 -0400397#if defined(TARGET_NR_pselect6)
398#ifndef __NR_pselect6
399# define __NR_pselect6 -1
400#endif
401#define __NR_sys_pselect6 __NR_pselect6
402_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
403 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
404#endif
405
Peter Maydell163a05a2011-06-27 17:44:52 +0100406#if defined(TARGET_NR_prlimit64)
407#ifndef __NR_prlimit64
408# define __NR_prlimit64 -1
409#endif
410#define __NR_sys_prlimit64 __NR_prlimit64
411/* The glibc rlimit structure may not be that used by the underlying syscall */
412struct host_rlimit64 {
413 uint64_t rlim_cur;
414 uint64_t rlim_max;
415};
416_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
417 const struct host_rlimit64 *, new_limit,
418 struct host_rlimit64 *, old_limit)
419#endif
420
Riku Voipio48e515d2011-07-12 15:40:51 +0300421/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000422#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300423static inline int regpairs_aligned(void *cpu_env) {
424 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
425}
426#elif defined(TARGET_MIPS)
427static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000428#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
429/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
430 * of registers which translates to the same as ARM/MIPS, because we start with
431 * r3 as arg1 */
432static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300433#else
434static inline int regpairs_aligned(void *cpu_env) { return 0; }
435#endif
436
thsb92c47c2007-11-01 00:07:38 +0000437#define ERRNO_TABLE_SIZE 1200
438
439/* target_to_host_errno_table[] is initialized from
440 * host_to_target_errno_table[] in syscall_init(). */
441static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
442};
443
ths637947f2007-06-01 12:09:19 +0000444/*
thsfe8f0962007-07-12 10:59:21 +0000445 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000446 * minus the errnos that are not actually generic to all archs.
447 */
thsb92c47c2007-11-01 00:07:38 +0000448static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000449 [EIDRM] = TARGET_EIDRM,
450 [ECHRNG] = TARGET_ECHRNG,
451 [EL2NSYNC] = TARGET_EL2NSYNC,
452 [EL3HLT] = TARGET_EL3HLT,
453 [EL3RST] = TARGET_EL3RST,
454 [ELNRNG] = TARGET_ELNRNG,
455 [EUNATCH] = TARGET_EUNATCH,
456 [ENOCSI] = TARGET_ENOCSI,
457 [EL2HLT] = TARGET_EL2HLT,
458 [EDEADLK] = TARGET_EDEADLK,
459 [ENOLCK] = TARGET_ENOLCK,
460 [EBADE] = TARGET_EBADE,
461 [EBADR] = TARGET_EBADR,
462 [EXFULL] = TARGET_EXFULL,
463 [ENOANO] = TARGET_ENOANO,
464 [EBADRQC] = TARGET_EBADRQC,
465 [EBADSLT] = TARGET_EBADSLT,
466 [EBFONT] = TARGET_EBFONT,
467 [ENOSTR] = TARGET_ENOSTR,
468 [ENODATA] = TARGET_ENODATA,
469 [ETIME] = TARGET_ETIME,
470 [ENOSR] = TARGET_ENOSR,
471 [ENONET] = TARGET_ENONET,
472 [ENOPKG] = TARGET_ENOPKG,
473 [EREMOTE] = TARGET_EREMOTE,
474 [ENOLINK] = TARGET_ENOLINK,
475 [EADV] = TARGET_EADV,
476 [ESRMNT] = TARGET_ESRMNT,
477 [ECOMM] = TARGET_ECOMM,
478 [EPROTO] = TARGET_EPROTO,
479 [EDOTDOT] = TARGET_EDOTDOT,
480 [EMULTIHOP] = TARGET_EMULTIHOP,
481 [EBADMSG] = TARGET_EBADMSG,
482 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
483 [EOVERFLOW] = TARGET_EOVERFLOW,
484 [ENOTUNIQ] = TARGET_ENOTUNIQ,
485 [EBADFD] = TARGET_EBADFD,
486 [EREMCHG] = TARGET_EREMCHG,
487 [ELIBACC] = TARGET_ELIBACC,
488 [ELIBBAD] = TARGET_ELIBBAD,
489 [ELIBSCN] = TARGET_ELIBSCN,
490 [ELIBMAX] = TARGET_ELIBMAX,
491 [ELIBEXEC] = TARGET_ELIBEXEC,
492 [EILSEQ] = TARGET_EILSEQ,
493 [ENOSYS] = TARGET_ENOSYS,
494 [ELOOP] = TARGET_ELOOP,
495 [ERESTART] = TARGET_ERESTART,
496 [ESTRPIPE] = TARGET_ESTRPIPE,
497 [ENOTEMPTY] = TARGET_ENOTEMPTY,
498 [EUSERS] = TARGET_EUSERS,
499 [ENOTSOCK] = TARGET_ENOTSOCK,
500 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
501 [EMSGSIZE] = TARGET_EMSGSIZE,
502 [EPROTOTYPE] = TARGET_EPROTOTYPE,
503 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
504 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
505 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
506 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
507 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
508 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
509 [EADDRINUSE] = TARGET_EADDRINUSE,
510 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
511 [ENETDOWN] = TARGET_ENETDOWN,
512 [ENETUNREACH] = TARGET_ENETUNREACH,
513 [ENETRESET] = TARGET_ENETRESET,
514 [ECONNABORTED] = TARGET_ECONNABORTED,
515 [ECONNRESET] = TARGET_ECONNRESET,
516 [ENOBUFS] = TARGET_ENOBUFS,
517 [EISCONN] = TARGET_EISCONN,
518 [ENOTCONN] = TARGET_ENOTCONN,
519 [EUCLEAN] = TARGET_EUCLEAN,
520 [ENOTNAM] = TARGET_ENOTNAM,
521 [ENAVAIL] = TARGET_ENAVAIL,
522 [EISNAM] = TARGET_EISNAM,
523 [EREMOTEIO] = TARGET_EREMOTEIO,
524 [ESHUTDOWN] = TARGET_ESHUTDOWN,
525 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
526 [ETIMEDOUT] = TARGET_ETIMEDOUT,
527 [ECONNREFUSED] = TARGET_ECONNREFUSED,
528 [EHOSTDOWN] = TARGET_EHOSTDOWN,
529 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
530 [EALREADY] = TARGET_EALREADY,
531 [EINPROGRESS] = TARGET_EINPROGRESS,
532 [ESTALE] = TARGET_ESTALE,
533 [ECANCELED] = TARGET_ECANCELED,
534 [ENOMEDIUM] = TARGET_ENOMEDIUM,
535 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000536#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000537 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000538#endif
539#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000540 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000541#endif
542#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000543 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000544#endif
545#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000546 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000547#endif
548#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000549 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000550#endif
551#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000552 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000553#endif
thsb92c47c2007-11-01 00:07:38 +0000554};
ths637947f2007-06-01 12:09:19 +0000555
556static inline int host_to_target_errno(int err)
557{
558 if(host_to_target_errno_table[err])
559 return host_to_target_errno_table[err];
560 return err;
561}
562
thsb92c47c2007-11-01 00:07:38 +0000563static inline int target_to_host_errno(int err)
564{
565 if (target_to_host_errno_table[err])
566 return target_to_host_errno_table[err];
567 return err;
568}
569
blueswir1992f48a2007-10-14 16:27:31 +0000570static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000571{
572 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000573 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000574 else
575 return ret;
576}
577
blueswir1992f48a2007-10-14 16:27:31 +0000578static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000579{
blueswir1992f48a2007-10-14 16:27:31 +0000580 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000581}
582
thsb92c47c2007-11-01 00:07:38 +0000583char *target_strerror(int err)
584{
Alexander Graf962b2892011-11-21 12:04:07 +0100585 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
586 return NULL;
587 }
thsb92c47c2007-11-01 00:07:38 +0000588 return strerror(target_to_host_errno(err));
589}
590
blueswir1992f48a2007-10-14 16:27:31 +0000591static abi_ulong target_brk;
592static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000593static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000594
blueswir1992f48a2007-10-14 16:27:31 +0000595void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000596{
blueswir14c1de732007-07-07 20:45:44 +0000597 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000598 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000599}
600
vincent4d1de872011-06-14 21:56:33 +0000601//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
602#define DEBUGF_BRK(message, args...)
603
ths0da46a62007-10-20 20:23:07 +0000604/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000605abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000606{
blueswir1992f48a2007-10-14 16:27:31 +0000607 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000608 int new_alloc_size;
609
Paul Brook3a0c6c42012-02-09 19:04:27 +0000610 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000611
vincent4d1de872011-06-14 21:56:33 +0000612 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000613 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000614 return target_brk;
615 }
616 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000617 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
618 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000619 return target_brk;
620 }
bellard31e31b82003-02-18 22:55:36 +0000621
vincent4d1de872011-06-14 21:56:33 +0000622 /* If the new brk is less than the highest page reserved to the
623 * target heap allocation, set it and we're almost done... */
624 if (new_brk <= brk_page) {
625 /* Heap contents are initialized to zero, as for anonymous
626 * mapped pages. */
627 if (new_brk > target_brk) {
628 memset(g2h(target_brk), 0, new_brk - target_brk);
629 }
bellard31e31b82003-02-18 22:55:36 +0000630 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000631 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000632 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000633 }
634
Peter Maydell00faf082011-04-18 16:34:24 +0100635 /* We need to allocate more memory after the brk... Note that
636 * we don't use MAP_FIXED because that will map over the top of
637 * any existing mapping (like the one with the host libc or qemu
638 * itself); instead we treat "mapped but at wrong address" as
639 * a failure and unmap again.
640 */
vincent4d1de872011-06-14 21:56:33 +0000641 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000642 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000643 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100644 MAP_ANON|MAP_PRIVATE, 0, 0));
645
646 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200647 /* Heap contents are initialized to zero, as for anonymous
648 * mapped pages. Technically the new pages are already
649 * initialized to zero since they *are* anonymous mapped
650 * pages, however we have to take care with the contents that
651 * come from the remaining part of the previous page: it may
652 * contains garbage data due to a previous heap usage (grown
653 * then shrunken). */
654 memset(g2h(target_brk), 0, brk_page - target_brk);
655
Peter Maydell00faf082011-04-18 16:34:24 +0100656 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000657 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000658 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
659 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100660 return target_brk;
661 } else if (mapped_addr != -1) {
662 /* Mapped but at wrong address, meaning there wasn't actually
663 * enough space for this brk.
664 */
665 target_munmap(mapped_addr, new_alloc_size);
666 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000667 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000668 }
669 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000670 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100671 }
balrog7ab240a2008-04-26 12:17:34 +0000672
Richard Henderson7dd46c02010-05-03 10:07:49 -0700673#if defined(TARGET_ALPHA)
674 /* We (partially) emulate OSF/1 on Alpha, which requires we
675 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100676 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700677#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100678 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000679 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000680}
681
ths26edcf42007-12-09 02:25:24 +0000682static inline abi_long copy_from_user_fdset(fd_set *fds,
683 abi_ulong target_fds_addr,
684 int n)
bellard31e31b82003-02-18 22:55:36 +0000685{
ths26edcf42007-12-09 02:25:24 +0000686 int i, nw, j, k;
687 abi_ulong b, *target_fds;
688
689 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
690 if (!(target_fds = lock_user(VERIFY_READ,
691 target_fds_addr,
692 sizeof(abi_ulong) * nw,
693 1)))
694 return -TARGET_EFAULT;
695
696 FD_ZERO(fds);
697 k = 0;
698 for (i = 0; i < nw; i++) {
699 /* grab the abi_ulong */
700 __get_user(b, &target_fds[i]);
701 for (j = 0; j < TARGET_ABI_BITS; j++) {
702 /* check the bit inside the abi_ulong */
703 if ((b >> j) & 1)
704 FD_SET(k, fds);
705 k++;
bellard31e31b82003-02-18 22:55:36 +0000706 }
bellard31e31b82003-02-18 22:55:36 +0000707 }
ths26edcf42007-12-09 02:25:24 +0000708
709 unlock_user(target_fds, target_fds_addr, 0);
710
711 return 0;
bellard31e31b82003-02-18 22:55:36 +0000712}
713
Mike Frysinger055e0902011-06-03 17:01:49 -0400714static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
715 abi_ulong target_fds_addr,
716 int n)
717{
718 if (target_fds_addr) {
719 if (copy_from_user_fdset(fds, target_fds_addr, n))
720 return -TARGET_EFAULT;
721 *fds_ptr = fds;
722 } else {
723 *fds_ptr = NULL;
724 }
725 return 0;
726}
727
ths26edcf42007-12-09 02:25:24 +0000728static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
729 const fd_set *fds,
730 int n)
bellard31e31b82003-02-18 22:55:36 +0000731{
bellard31e31b82003-02-18 22:55:36 +0000732 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000733 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000734 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000735
ths26edcf42007-12-09 02:25:24 +0000736 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
737 if (!(target_fds = lock_user(VERIFY_WRITE,
738 target_fds_addr,
739 sizeof(abi_ulong) * nw,
740 0)))
741 return -TARGET_EFAULT;
742
743 k = 0;
744 for (i = 0; i < nw; i++) {
745 v = 0;
746 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000747 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000748 k++;
bellard31e31b82003-02-18 22:55:36 +0000749 }
ths26edcf42007-12-09 02:25:24 +0000750 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000751 }
ths26edcf42007-12-09 02:25:24 +0000752
753 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
754
755 return 0;
bellard31e31b82003-02-18 22:55:36 +0000756}
757
bellardc596ed12003-07-13 17:32:31 +0000758#if defined(__alpha__)
759#define HOST_HZ 1024
760#else
761#define HOST_HZ 100
762#endif
763
blueswir1992f48a2007-10-14 16:27:31 +0000764static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000765{
766#if HOST_HZ == TARGET_HZ
767 return ticks;
768#else
769 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
770#endif
771}
772
bellard579a97f2007-11-11 14:26:47 +0000773static inline abi_long host_to_target_rusage(abi_ulong target_addr,
774 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000775{
pbrook53a59602006-03-25 19:31:22 +0000776 struct target_rusage *target_rusage;
777
bellard579a97f2007-11-11 14:26:47 +0000778 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
779 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200780 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
781 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
782 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
783 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
784 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
785 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
786 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
787 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
788 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
789 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
790 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
791 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
792 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
793 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
794 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
795 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
796 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
797 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000798 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000799
800 return 0;
bellardb4091862003-05-16 15:39:34 +0000801}
802
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200803static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900804{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200805 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300806 rlim_t result;
807
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200808 target_rlim_swap = tswapal(target_rlim);
809 if (target_rlim_swap == TARGET_RLIM_INFINITY)
810 return RLIM_INFINITY;
811
812 result = target_rlim_swap;
813 if (target_rlim_swap != (rlim_t)result)
814 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300815
816 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900817}
818
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200819static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900820{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200821 abi_ulong target_rlim_swap;
822 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300823
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200824 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300825 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900826 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300827 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200828 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300829
830 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900831}
832
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300833static inline int target_to_host_resource(int code)
834{
835 switch (code) {
836 case TARGET_RLIMIT_AS:
837 return RLIMIT_AS;
838 case TARGET_RLIMIT_CORE:
839 return RLIMIT_CORE;
840 case TARGET_RLIMIT_CPU:
841 return RLIMIT_CPU;
842 case TARGET_RLIMIT_DATA:
843 return RLIMIT_DATA;
844 case TARGET_RLIMIT_FSIZE:
845 return RLIMIT_FSIZE;
846 case TARGET_RLIMIT_LOCKS:
847 return RLIMIT_LOCKS;
848 case TARGET_RLIMIT_MEMLOCK:
849 return RLIMIT_MEMLOCK;
850 case TARGET_RLIMIT_MSGQUEUE:
851 return RLIMIT_MSGQUEUE;
852 case TARGET_RLIMIT_NICE:
853 return RLIMIT_NICE;
854 case TARGET_RLIMIT_NOFILE:
855 return RLIMIT_NOFILE;
856 case TARGET_RLIMIT_NPROC:
857 return RLIMIT_NPROC;
858 case TARGET_RLIMIT_RSS:
859 return RLIMIT_RSS;
860 case TARGET_RLIMIT_RTPRIO:
861 return RLIMIT_RTPRIO;
862 case TARGET_RLIMIT_SIGPENDING:
863 return RLIMIT_SIGPENDING;
864 case TARGET_RLIMIT_STACK:
865 return RLIMIT_STACK;
866 default:
867 return code;
868 }
869}
870
ths788f5ec2007-12-09 02:37:05 +0000871static inline abi_long copy_from_user_timeval(struct timeval *tv,
872 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000873{
pbrook53a59602006-03-25 19:31:22 +0000874 struct target_timeval *target_tv;
875
ths788f5ec2007-12-09 02:37:05 +0000876 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000877 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000878
879 __get_user(tv->tv_sec, &target_tv->tv_sec);
880 __get_user(tv->tv_usec, &target_tv->tv_usec);
881
882 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000883
884 return 0;
bellard31e31b82003-02-18 22:55:36 +0000885}
886
ths788f5ec2007-12-09 02:37:05 +0000887static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
888 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000889{
pbrook53a59602006-03-25 19:31:22 +0000890 struct target_timeval *target_tv;
891
ths788f5ec2007-12-09 02:37:05 +0000892 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000893 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000894
895 __put_user(tv->tv_sec, &target_tv->tv_sec);
896 __put_user(tv->tv_usec, &target_tv->tv_usec);
897
898 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000899
900 return 0;
bellard31e31b82003-02-18 22:55:36 +0000901}
902
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700903#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
904#include <mqueue.h>
905
aurel3224e10032009-04-15 16:11:43 +0000906static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
907 abi_ulong target_mq_attr_addr)
908{
909 struct target_mq_attr *target_mq_attr;
910
911 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
912 target_mq_attr_addr, 1))
913 return -TARGET_EFAULT;
914
915 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
916 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
917 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
918 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
919
920 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
921
922 return 0;
923}
924
925static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
926 const struct mq_attr *attr)
927{
928 struct target_mq_attr *target_mq_attr;
929
930 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
931 target_mq_attr_addr, 0))
932 return -TARGET_EFAULT;
933
934 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
935 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
936 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
937 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
938
939 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
940
941 return 0;
942}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700943#endif
bellard31e31b82003-02-18 22:55:36 +0000944
Mike Frysinger055e0902011-06-03 17:01:49 -0400945#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +0000946/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000947static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +0000948 abi_ulong rfd_addr, abi_ulong wfd_addr,
949 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000950{
951 fd_set rfds, wfds, efds;
952 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
953 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +0000954 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +0000955
Mike Frysinger055e0902011-06-03 17:01:49 -0400956 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
957 if (ret) {
958 return ret;
pbrook53a59602006-03-25 19:31:22 +0000959 }
Mike Frysinger055e0902011-06-03 17:01:49 -0400960 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
961 if (ret) {
962 return ret;
pbrook53a59602006-03-25 19:31:22 +0000963 }
Mike Frysinger055e0902011-06-03 17:01:49 -0400964 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
965 if (ret) {
966 return ret;
pbrook53a59602006-03-25 19:31:22 +0000967 }
ths3b46e622007-09-17 08:09:54 +0000968
ths26edcf42007-12-09 02:25:24 +0000969 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +0000970 if (copy_from_user_timeval(&tv, target_tv_addr))
971 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +0000972 tv_ptr = &tv;
973 } else {
974 tv_ptr = NULL;
975 }
ths26edcf42007-12-09 02:25:24 +0000976
bellard31e31b82003-02-18 22:55:36 +0000977 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +0000978
ths26edcf42007-12-09 02:25:24 +0000979 if (!is_error(ret)) {
980 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
981 return -TARGET_EFAULT;
982 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
983 return -TARGET_EFAULT;
984 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
985 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +0000986
ths788f5ec2007-12-09 02:37:05 +0000987 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
988 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +0000989 }
bellard579a97f2007-11-11 14:26:47 +0000990
bellard31e31b82003-02-18 22:55:36 +0000991 return ret;
992}
Mike Frysinger055e0902011-06-03 17:01:49 -0400993#endif
bellard31e31b82003-02-18 22:55:36 +0000994
Riku Voipio099d6b02009-05-05 12:10:04 +0300995static abi_long do_pipe2(int host_pipe[], int flags)
996{
997#ifdef CONFIG_PIPE2
998 return pipe2(host_pipe, flags);
999#else
1000 return -ENOSYS;
1001#endif
1002}
1003
Richard Hendersonfb41a662010-05-03 10:07:52 -07001004static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1005 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001006{
1007 int host_pipe[2];
1008 abi_long ret;
1009 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1010
1011 if (is_error(ret))
1012 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001013
1014 /* Several targets have special calling conventions for the original
1015 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1016 if (!is_pipe2) {
1017#if defined(TARGET_ALPHA)
1018 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1019 return host_pipe[0];
1020#elif defined(TARGET_MIPS)
1021 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1022 return host_pipe[0];
1023#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001024 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001025 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001026#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001027 }
1028
Riku Voipio099d6b02009-05-05 12:10:04 +03001029 if (put_user_s32(host_pipe[0], pipedes)
1030 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1031 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001032 return get_errno(ret);
1033}
1034
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001035static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1036 abi_ulong target_addr,
1037 socklen_t len)
1038{
1039 struct target_ip_mreqn *target_smreqn;
1040
1041 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1042 if (!target_smreqn)
1043 return -TARGET_EFAULT;
1044 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1045 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1046 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001047 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001048 unlock_user(target_smreqn, target_addr, 0);
1049
1050 return 0;
1051}
1052
bellard579a97f2007-11-11 14:26:47 +00001053static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1054 abi_ulong target_addr,
1055 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001056{
aurel32607175e2009-04-15 16:11:59 +00001057 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1058 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001059 struct target_sockaddr *target_saddr;
1060
bellard579a97f2007-11-11 14:26:47 +00001061 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1062 if (!target_saddr)
1063 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001064
1065 sa_family = tswap16(target_saddr->sa_family);
1066
1067 /* Oops. The caller might send a incomplete sun_path; sun_path
1068 * must be terminated by \0 (see the manual page), but
1069 * unfortunately it is quite common to specify sockaddr_un
1070 * length as "strlen(x->sun_path)" while it should be
1071 * "strlen(...) + 1". We'll fix that here if needed.
1072 * Linux kernel has a similar feature.
1073 */
1074
1075 if (sa_family == AF_UNIX) {
1076 if (len < unix_maxlen && len > 0) {
1077 char *cp = (char*)target_saddr;
1078
1079 if ( cp[len-1] && !cp[len] )
1080 len++;
1081 }
1082 if (len > unix_maxlen)
1083 len = unix_maxlen;
1084 }
1085
pbrook53a59602006-03-25 19:31:22 +00001086 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001087 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001088 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001089
1090 return 0;
bellard7854b052003-03-29 17:22:23 +00001091}
1092
bellard579a97f2007-11-11 14:26:47 +00001093static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1094 struct sockaddr *addr,
1095 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001096{
pbrook53a59602006-03-25 19:31:22 +00001097 struct target_sockaddr *target_saddr;
1098
bellard579a97f2007-11-11 14:26:47 +00001099 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1100 if (!target_saddr)
1101 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001102 memcpy(target_saddr, addr, len);
1103 target_saddr->sa_family = tswap16(addr->sa_family);
1104 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001105
1106 return 0;
bellard7854b052003-03-29 17:22:23 +00001107}
1108
bellard5a4a8982007-11-11 17:39:18 +00001109static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1110 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001111{
1112 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001113 abi_long msg_controllen;
1114 abi_ulong target_cmsg_addr;
1115 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001116 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001117
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001118 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001119 if (msg_controllen < sizeof (struct target_cmsghdr))
1120 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001121 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001122 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1123 if (!target_cmsg)
1124 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001125
1126 while (cmsg && target_cmsg) {
1127 void *data = CMSG_DATA(cmsg);
1128 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1129
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001130 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001131 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1132
1133 space += CMSG_SPACE(len);
1134 if (space > msgh->msg_controllen) {
1135 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001136 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001137 break;
1138 }
1139
1140 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1141 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1142 cmsg->cmsg_len = CMSG_LEN(len);
1143
bellard3532fa72006-06-24 15:06:03 +00001144 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001145 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1146 memcpy(data, target_data, len);
1147 } else {
1148 int *fd = (int *)data;
1149 int *target_fd = (int *)target_data;
1150 int i, numfds = len / sizeof(int);
1151
1152 for (i = 0; i < numfds; i++)
1153 fd[i] = tswap32(target_fd[i]);
1154 }
1155
1156 cmsg = CMSG_NXTHDR(msgh, cmsg);
1157 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1158 }
bellard5a4a8982007-11-11 17:39:18 +00001159 unlock_user(target_cmsg, target_cmsg_addr, 0);
1160 the_end:
bellard7854b052003-03-29 17:22:23 +00001161 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001162 return 0;
bellard7854b052003-03-29 17:22:23 +00001163}
1164
bellard5a4a8982007-11-11 17:39:18 +00001165static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1166 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001167{
1168 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001169 abi_long msg_controllen;
1170 abi_ulong target_cmsg_addr;
1171 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001172 socklen_t space = 0;
1173
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001174 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001175 if (msg_controllen < sizeof (struct target_cmsghdr))
1176 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001177 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001178 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1179 if (!target_cmsg)
1180 return -TARGET_EFAULT;
1181
bellard7854b052003-03-29 17:22:23 +00001182 while (cmsg && target_cmsg) {
1183 void *data = CMSG_DATA(cmsg);
1184 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1185
1186 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1187
1188 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001189 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001190 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001191 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001192 break;
1193 }
1194
1195 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1196 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001197 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001198
Jing Huangaebf5bc2012-07-24 14:01:42 +00001199 if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
1200 (cmsg->cmsg_type == SCM_RIGHTS)) {
bellard7854b052003-03-29 17:22:23 +00001201 int *fd = (int *)data;
1202 int *target_fd = (int *)target_data;
1203 int i, numfds = len / sizeof(int);
1204
1205 for (i = 0; i < numfds; i++)
1206 target_fd[i] = tswap32(fd[i]);
Jing Huangaebf5bc2012-07-24 14:01:42 +00001207 } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
1208 (cmsg->cmsg_type == SO_TIMESTAMP) &&
1209 (len == sizeof(struct timeval))) {
1210 /* copy struct timeval to target */
1211 struct timeval *tv = (struct timeval *)data;
1212 struct target_timeval *target_tv =
1213 (struct target_timeval *)target_data;
1214
1215 target_tv->tv_sec = tswapal(tv->tv_sec);
1216 target_tv->tv_usec = tswapal(tv->tv_usec);
1217 } else {
1218 gemu_log("Unsupported ancillary data: %d/%d\n",
1219 cmsg->cmsg_level, cmsg->cmsg_type);
1220 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001221 }
1222
1223 cmsg = CMSG_NXTHDR(msgh, cmsg);
1224 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1225 }
bellard5a4a8982007-11-11 17:39:18 +00001226 unlock_user(target_cmsg, target_cmsg_addr, space);
1227 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001228 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001229 return 0;
bellard7854b052003-03-29 17:22:23 +00001230}
1231
ths0da46a62007-10-20 20:23:07 +00001232/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001233static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001234 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001235{
blueswir1992f48a2007-10-14 16:27:31 +00001236 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001237 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001238 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001239 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001240
bellard8853f862004-02-22 14:57:26 +00001241 switch(level) {
1242 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001243 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001244 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001245 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001246
bellard2f619692007-11-16 10:46:05 +00001247 if (get_user_u32(val, optval_addr))
1248 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001249 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1250 break;
1251 case SOL_IP:
1252 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001253 case IP_TOS:
1254 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001255 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001256 case IP_ROUTER_ALERT:
1257 case IP_RECVOPTS:
1258 case IP_RETOPTS:
1259 case IP_PKTINFO:
1260 case IP_MTU_DISCOVER:
1261 case IP_RECVERR:
1262 case IP_RECVTOS:
1263#ifdef IP_FREEBIND
1264 case IP_FREEBIND:
1265#endif
1266 case IP_MULTICAST_TTL:
1267 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001268 val = 0;
1269 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001270 if (get_user_u32(val, optval_addr))
1271 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001272 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001273 if (get_user_u8(val, optval_addr))
1274 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001275 }
1276 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1277 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001278 case IP_ADD_MEMBERSHIP:
1279 case IP_DROP_MEMBERSHIP:
1280 if (optlen < sizeof (struct target_ip_mreq) ||
1281 optlen > sizeof (struct target_ip_mreqn))
1282 return -TARGET_EINVAL;
1283
1284 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1285 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1286 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1287 break;
1288
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001289 case IP_BLOCK_SOURCE:
1290 case IP_UNBLOCK_SOURCE:
1291 case IP_ADD_SOURCE_MEMBERSHIP:
1292 case IP_DROP_SOURCE_MEMBERSHIP:
1293 if (optlen != sizeof (struct target_ip_mreq_source))
1294 return -TARGET_EINVAL;
1295
1296 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1297 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1298 unlock_user (ip_mreq_source, optval_addr, 0);
1299 break;
1300
bellard8853f862004-02-22 14:57:26 +00001301 default:
1302 goto unimplemented;
1303 }
1304 break;
Jing Huang920394d2012-07-24 13:59:23 +00001305 case SOL_RAW:
1306 switch (optname) {
1307 case ICMP_FILTER:
1308 /* struct icmp_filter takes an u32 value */
1309 if (optlen < sizeof(uint32_t)) {
1310 return -TARGET_EINVAL;
1311 }
1312
1313 if (get_user_u32(val, optval_addr)) {
1314 return -TARGET_EFAULT;
1315 }
1316 ret = get_errno(setsockopt(sockfd, level, optname,
1317 &val, sizeof(val)));
1318 break;
1319
1320 default:
1321 goto unimplemented;
1322 }
1323 break;
bellard3532fa72006-06-24 15:06:03 +00001324 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001325 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001326 case TARGET_SO_RCVTIMEO:
1327 {
1328 struct timeval tv;
1329
1330 optname = SO_RCVTIMEO;
1331
1332set_timeout:
1333 if (optlen != sizeof(struct target_timeval)) {
1334 return -TARGET_EINVAL;
1335 }
1336
1337 if (copy_from_user_timeval(&tv, optval_addr)) {
1338 return -TARGET_EFAULT;
1339 }
1340
1341 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1342 &tv, sizeof(tv)));
1343 return ret;
1344 }
1345 case TARGET_SO_SNDTIMEO:
1346 optname = SO_SNDTIMEO;
1347 goto set_timeout;
bellard8853f862004-02-22 14:57:26 +00001348 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001349 case TARGET_SO_DEBUG:
1350 optname = SO_DEBUG;
1351 break;
1352 case TARGET_SO_REUSEADDR:
1353 optname = SO_REUSEADDR;
1354 break;
1355 case TARGET_SO_TYPE:
1356 optname = SO_TYPE;
1357 break;
1358 case TARGET_SO_ERROR:
1359 optname = SO_ERROR;
1360 break;
1361 case TARGET_SO_DONTROUTE:
1362 optname = SO_DONTROUTE;
1363 break;
1364 case TARGET_SO_BROADCAST:
1365 optname = SO_BROADCAST;
1366 break;
1367 case TARGET_SO_SNDBUF:
1368 optname = SO_SNDBUF;
1369 break;
1370 case TARGET_SO_RCVBUF:
1371 optname = SO_RCVBUF;
1372 break;
1373 case TARGET_SO_KEEPALIVE:
1374 optname = SO_KEEPALIVE;
1375 break;
1376 case TARGET_SO_OOBINLINE:
1377 optname = SO_OOBINLINE;
1378 break;
1379 case TARGET_SO_NO_CHECK:
1380 optname = SO_NO_CHECK;
1381 break;
1382 case TARGET_SO_PRIORITY:
1383 optname = SO_PRIORITY;
1384 break;
bellard5e83e8e2005-03-01 22:32:06 +00001385#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001386 case TARGET_SO_BSDCOMPAT:
1387 optname = SO_BSDCOMPAT;
1388 break;
bellard5e83e8e2005-03-01 22:32:06 +00001389#endif
bellard3532fa72006-06-24 15:06:03 +00001390 case TARGET_SO_PASSCRED:
1391 optname = SO_PASSCRED;
1392 break;
1393 case TARGET_SO_TIMESTAMP:
1394 optname = SO_TIMESTAMP;
1395 break;
1396 case TARGET_SO_RCVLOWAT:
1397 optname = SO_RCVLOWAT;
1398 break;
bellard8853f862004-02-22 14:57:26 +00001399 break;
1400 default:
1401 goto unimplemented;
1402 }
bellard3532fa72006-06-24 15:06:03 +00001403 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001404 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001405
bellard2f619692007-11-16 10:46:05 +00001406 if (get_user_u32(val, optval_addr))
1407 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001408 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001409 break;
bellard7854b052003-03-29 17:22:23 +00001410 default:
bellard8853f862004-02-22 14:57:26 +00001411 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001412 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001413 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001414 }
bellard8853f862004-02-22 14:57:26 +00001415 return ret;
bellard7854b052003-03-29 17:22:23 +00001416}
1417
ths0da46a62007-10-20 20:23:07 +00001418/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001419static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001420 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001421{
blueswir1992f48a2007-10-14 16:27:31 +00001422 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001423 int len, val;
1424 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001425
1426 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001427 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001428 level = SOL_SOCKET;
1429 switch (optname) {
1430 /* These don't just return a single integer */
1431 case TARGET_SO_LINGER:
1432 case TARGET_SO_RCVTIMEO:
1433 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001434 case TARGET_SO_PEERNAME:
1435 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001436 case TARGET_SO_PEERCRED: {
1437 struct ucred cr;
1438 socklen_t crlen;
1439 struct target_ucred *tcr;
1440
1441 if (get_user_u32(len, optlen)) {
1442 return -TARGET_EFAULT;
1443 }
1444 if (len < 0) {
1445 return -TARGET_EINVAL;
1446 }
1447
1448 crlen = sizeof(cr);
1449 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1450 &cr, &crlen));
1451 if (ret < 0) {
1452 return ret;
1453 }
1454 if (len > crlen) {
1455 len = crlen;
1456 }
1457 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1458 return -TARGET_EFAULT;
1459 }
1460 __put_user(cr.pid, &tcr->pid);
1461 __put_user(cr.uid, &tcr->uid);
1462 __put_user(cr.gid, &tcr->gid);
1463 unlock_user_struct(tcr, optval_addr, 1);
1464 if (put_user_u32(len, optlen)) {
1465 return -TARGET_EFAULT;
1466 }
1467 break;
1468 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001469 /* Options with 'int' argument. */
1470 case TARGET_SO_DEBUG:
1471 optname = SO_DEBUG;
1472 goto int_case;
1473 case TARGET_SO_REUSEADDR:
1474 optname = SO_REUSEADDR;
1475 goto int_case;
1476 case TARGET_SO_TYPE:
1477 optname = SO_TYPE;
1478 goto int_case;
1479 case TARGET_SO_ERROR:
1480 optname = SO_ERROR;
1481 goto int_case;
1482 case TARGET_SO_DONTROUTE:
1483 optname = SO_DONTROUTE;
1484 goto int_case;
1485 case TARGET_SO_BROADCAST:
1486 optname = SO_BROADCAST;
1487 goto int_case;
1488 case TARGET_SO_SNDBUF:
1489 optname = SO_SNDBUF;
1490 goto int_case;
1491 case TARGET_SO_RCVBUF:
1492 optname = SO_RCVBUF;
1493 goto int_case;
1494 case TARGET_SO_KEEPALIVE:
1495 optname = SO_KEEPALIVE;
1496 goto int_case;
1497 case TARGET_SO_OOBINLINE:
1498 optname = SO_OOBINLINE;
1499 goto int_case;
1500 case TARGET_SO_NO_CHECK:
1501 optname = SO_NO_CHECK;
1502 goto int_case;
1503 case TARGET_SO_PRIORITY:
1504 optname = SO_PRIORITY;
1505 goto int_case;
1506#ifdef SO_BSDCOMPAT
1507 case TARGET_SO_BSDCOMPAT:
1508 optname = SO_BSDCOMPAT;
1509 goto int_case;
1510#endif
1511 case TARGET_SO_PASSCRED:
1512 optname = SO_PASSCRED;
1513 goto int_case;
1514 case TARGET_SO_TIMESTAMP:
1515 optname = SO_TIMESTAMP;
1516 goto int_case;
1517 case TARGET_SO_RCVLOWAT:
1518 optname = SO_RCVLOWAT;
1519 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001520 default:
bellard2efbe912005-07-23 15:10:20 +00001521 goto int_case;
1522 }
1523 break;
1524 case SOL_TCP:
1525 /* TCP options all take an 'int' value. */
1526 int_case:
bellard2f619692007-11-16 10:46:05 +00001527 if (get_user_u32(len, optlen))
1528 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001529 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001530 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001531 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001532 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1533 if (ret < 0)
1534 return ret;
bellard2efbe912005-07-23 15:10:20 +00001535 if (len > lv)
1536 len = lv;
bellard2f619692007-11-16 10:46:05 +00001537 if (len == 4) {
1538 if (put_user_u32(val, optval_addr))
1539 return -TARGET_EFAULT;
1540 } else {
1541 if (put_user_u8(val, optval_addr))
1542 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001543 }
bellard2f619692007-11-16 10:46:05 +00001544 if (put_user_u32(len, optlen))
1545 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001546 break;
1547 case SOL_IP:
1548 switch(optname) {
1549 case IP_TOS:
1550 case IP_TTL:
1551 case IP_HDRINCL:
1552 case IP_ROUTER_ALERT:
1553 case IP_RECVOPTS:
1554 case IP_RETOPTS:
1555 case IP_PKTINFO:
1556 case IP_MTU_DISCOVER:
1557 case IP_RECVERR:
1558 case IP_RECVTOS:
1559#ifdef IP_FREEBIND
1560 case IP_FREEBIND:
1561#endif
1562 case IP_MULTICAST_TTL:
1563 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001564 if (get_user_u32(len, optlen))
1565 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001566 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001567 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001568 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001569 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1570 if (ret < 0)
1571 return ret;
bellard2efbe912005-07-23 15:10:20 +00001572 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001573 len = 1;
bellard2f619692007-11-16 10:46:05 +00001574 if (put_user_u32(len, optlen)
1575 || put_user_u8(val, optval_addr))
1576 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001577 } else {
bellard2efbe912005-07-23 15:10:20 +00001578 if (len > sizeof(int))
1579 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001580 if (put_user_u32(len, optlen)
1581 || put_user_u32(val, optval_addr))
1582 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001583 }
bellard8853f862004-02-22 14:57:26 +00001584 break;
bellard2efbe912005-07-23 15:10:20 +00001585 default:
thsc02f4992007-12-18 02:39:59 +00001586 ret = -TARGET_ENOPROTOOPT;
1587 break;
bellard8853f862004-02-22 14:57:26 +00001588 }
1589 break;
1590 default:
1591 unimplemented:
1592 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1593 level, optname);
thsc02f4992007-12-18 02:39:59 +00001594 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001595 break;
1596 }
1597 return ret;
bellard7854b052003-03-29 17:22:23 +00001598}
1599
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001600static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1601 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001602{
1603 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001604 struct iovec *vec;
1605 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001606 int i;
pbrook53a59602006-03-25 19:31:22 +00001607
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001608 if (count == 0) {
1609 errno = 0;
1610 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001611 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001612 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001613 errno = EINVAL;
1614 return NULL;
1615 }
1616
1617 vec = calloc(count, sizeof(struct iovec));
1618 if (vec == NULL) {
1619 errno = ENOMEM;
1620 return NULL;
1621 }
1622
1623 target_vec = lock_user(VERIFY_READ, target_addr,
1624 count * sizeof(struct target_iovec), 1);
1625 if (target_vec == NULL) {
1626 errno = EFAULT;
1627 goto fail2;
1628 }
1629
1630 /* ??? If host page size > target page size, this will result in a
1631 value larger than what we can actually support. */
1632 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1633 total_len = 0;
1634
1635 for (i = 0; i < count; i++) {
1636 abi_ulong base = tswapal(target_vec[i].iov_base);
1637 abi_long len = tswapal(target_vec[i].iov_len);
1638
1639 if (len < 0) {
1640 errno = EINVAL;
1641 goto fail;
1642 } else if (len == 0) {
1643 /* Zero length pointer is ignored. */
1644 vec[i].iov_base = 0;
1645 } else {
1646 vec[i].iov_base = lock_user(type, base, len, copy);
1647 if (!vec[i].iov_base) {
1648 errno = EFAULT;
1649 goto fail;
1650 }
1651 if (len > max_len - total_len) {
1652 len = max_len - total_len;
1653 }
1654 }
1655 vec[i].iov_len = len;
1656 total_len += len;
1657 }
1658
1659 unlock_user(target_vec, target_addr, 0);
1660 return vec;
1661
1662 fail:
1663 free(vec);
1664 fail2:
1665 unlock_user(target_vec, target_addr, 0);
1666 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001667}
1668
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001669static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1670 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001671{
1672 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00001673 int i;
1674
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001675 target_vec = lock_user(VERIFY_READ, target_addr,
1676 count * sizeof(struct target_iovec), 1);
1677 if (target_vec) {
1678 for (i = 0; i < count; i++) {
1679 abi_ulong base = tswapal(target_vec[i].iov_base);
1680 abi_long len = tswapal(target_vec[i].iov_base);
1681 if (len < 0) {
1682 break;
1683 }
balrogd732dcb2008-10-28 10:21:03 +00001684 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1685 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001686 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00001687 }
bellard579a97f2007-11-11 14:26:47 +00001688
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001689 free(vec);
pbrook53a59602006-03-25 19:31:22 +00001690}
1691
ths0da46a62007-10-20 20:23:07 +00001692/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001693static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001694{
1695#if defined(TARGET_MIPS)
1696 switch(type) {
1697 case TARGET_SOCK_DGRAM:
1698 type = SOCK_DGRAM;
1699 break;
1700 case TARGET_SOCK_STREAM:
1701 type = SOCK_STREAM;
1702 break;
1703 case TARGET_SOCK_RAW:
1704 type = SOCK_RAW;
1705 break;
1706 case TARGET_SOCK_RDM:
1707 type = SOCK_RDM;
1708 break;
1709 case TARGET_SOCK_SEQPACKET:
1710 type = SOCK_SEQPACKET;
1711 break;
1712 case TARGET_SOCK_PACKET:
1713 type = SOCK_PACKET;
1714 break;
1715 }
1716#endif
balrog12bc92a2007-10-30 21:06:14 +00001717 if (domain == PF_NETLINK)
1718 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
bellard3532fa72006-06-24 15:06:03 +00001719 return get_errno(socket(domain, type, protocol));
1720}
1721
ths0da46a62007-10-20 20:23:07 +00001722/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001723static abi_long do_bind(int sockfd, abi_ulong target_addr,
1724 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001725{
aurel328f7aeaf2009-01-30 19:47:57 +00001726 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001727 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001728
Blue Swirl38724252010-09-18 05:53:14 +00001729 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001730 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001731 }
aurel328f7aeaf2009-01-30 19:47:57 +00001732
aurel32607175e2009-04-15 16:11:59 +00001733 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001734
Arnaud Patard917507b2009-06-19 10:44:45 +03001735 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1736 if (ret)
1737 return ret;
1738
bellard3532fa72006-06-24 15:06:03 +00001739 return get_errno(bind(sockfd, addr, addrlen));
1740}
1741
ths0da46a62007-10-20 20:23:07 +00001742/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001743static abi_long do_connect(int sockfd, abi_ulong target_addr,
1744 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001745{
aurel328f7aeaf2009-01-30 19:47:57 +00001746 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001747 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001748
Blue Swirl38724252010-09-18 05:53:14 +00001749 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001750 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001751 }
aurel328f7aeaf2009-01-30 19:47:57 +00001752
1753 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001754
Arnaud Patard917507b2009-06-19 10:44:45 +03001755 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1756 if (ret)
1757 return ret;
1758
bellard3532fa72006-06-24 15:06:03 +00001759 return get_errno(connect(sockfd, addr, addrlen));
1760}
1761
ths0da46a62007-10-20 20:23:07 +00001762/* do_sendrecvmsg() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001763static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1764 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001765{
balrog6de645c2008-10-28 10:26:29 +00001766 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001767 struct target_msghdr *msgp;
1768 struct msghdr msg;
1769 int count;
1770 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001771 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001772
bellard579a97f2007-11-11 14:26:47 +00001773 /* FIXME */
1774 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1775 msgp,
1776 target_msg,
1777 send ? 1 : 0))
1778 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001779 if (msgp->msg_name) {
1780 msg.msg_namelen = tswap32(msgp->msg_namelen);
1781 msg.msg_name = alloca(msg.msg_namelen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001782 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001783 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001784 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001785 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03001786 }
bellard3532fa72006-06-24 15:06:03 +00001787 } else {
1788 msg.msg_name = NULL;
1789 msg.msg_namelen = 0;
1790 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001791 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00001792 msg.msg_control = alloca(msg.msg_controllen);
1793 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001794
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001795 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001796 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001797 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
1798 target_vec, count, send);
1799 if (vec == NULL) {
1800 ret = -host_to_target_errno(errno);
1801 goto out2;
1802 }
bellard3532fa72006-06-24 15:06:03 +00001803 msg.msg_iovlen = count;
1804 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001805
bellard3532fa72006-06-24 15:06:03 +00001806 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001807 ret = target_to_host_cmsg(&msg, msgp);
1808 if (ret == 0)
1809 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001810 } else {
1811 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001812 if (!is_error(ret)) {
1813 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001814 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00001815 if (!is_error(ret)) {
1816 msgp->msg_namelen = tswap32(msg.msg_namelen);
1817 if (msg.msg_name != NULL) {
1818 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
1819 msg.msg_name, msg.msg_namelen);
1820 if (ret) {
1821 goto out;
1822 }
1823 }
1824
balrog6de645c2008-10-28 10:26:29 +00001825 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00001826 }
balrog6de645c2008-10-28 10:26:29 +00001827 }
bellard3532fa72006-06-24 15:06:03 +00001828 }
Jing Huangca619062012-07-24 13:58:02 +00001829
1830out:
bellard3532fa72006-06-24 15:06:03 +00001831 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001832out2:
bellard579a97f2007-11-11 14:26:47 +00001833 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001834 return ret;
1835}
1836
Peter Maydella94b4982013-02-08 04:35:04 +00001837/* If we don't have a system accept4() then just call accept.
1838 * The callsites to do_accept4() will ensure that they don't
1839 * pass a non-zero flags argument in this config.
1840 */
1841#ifndef CONFIG_ACCEPT4
1842static inline int accept4(int sockfd, struct sockaddr *addr,
1843 socklen_t *addrlen, int flags)
1844{
1845 assert(flags == 0);
1846 return accept(sockfd, addr, addrlen);
1847}
1848#endif
1849
1850/* do_accept4() Must return target values and target errnos. */
1851static abi_long do_accept4(int fd, abi_ulong target_addr,
1852 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00001853{
bellard2f619692007-11-16 10:46:05 +00001854 socklen_t addrlen;
1855 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001856 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001857
Peter Maydella94b4982013-02-08 04:35:04 +00001858 if (target_addr == 0) {
1859 return get_errno(accept4(fd, NULL, NULL, flags));
1860 }
Arnaud Patard917507b2009-06-19 10:44:45 +03001861
1862 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00001863 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03001864 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00001865
Blue Swirl38724252010-09-18 05:53:14 +00001866 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001867 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001868 }
aurel328f7aeaf2009-01-30 19:47:57 +00001869
Arnaud Patard917507b2009-06-19 10:44:45 +03001870 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1871 return -TARGET_EINVAL;
1872
bellard2f619692007-11-16 10:46:05 +00001873 addr = alloca(addrlen);
1874
Peter Maydella94b4982013-02-08 04:35:04 +00001875 ret = get_errno(accept4(fd, addr, &addrlen, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00001876 if (!is_error(ret)) {
1877 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001878 if (put_user_u32(addrlen, target_addrlen_addr))
1879 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001880 }
1881 return ret;
1882}
1883
ths0da46a62007-10-20 20:23:07 +00001884/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001885static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001886 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001887{
bellard2f619692007-11-16 10:46:05 +00001888 socklen_t addrlen;
1889 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001890 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001891
bellard2f619692007-11-16 10:46:05 +00001892 if (get_user_u32(addrlen, target_addrlen_addr))
1893 return -TARGET_EFAULT;
1894
Blue Swirl38724252010-09-18 05:53:14 +00001895 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001896 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001897 }
aurel328f7aeaf2009-01-30 19:47:57 +00001898
Arnaud Patard917507b2009-06-19 10:44:45 +03001899 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1900 return -TARGET_EFAULT;
1901
bellard2f619692007-11-16 10:46:05 +00001902 addr = alloca(addrlen);
1903
pbrook1be9e1d2006-11-19 15:26:04 +00001904 ret = get_errno(getpeername(fd, addr, &addrlen));
1905 if (!is_error(ret)) {
1906 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001907 if (put_user_u32(addrlen, target_addrlen_addr))
1908 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001909 }
1910 return ret;
1911}
1912
ths0da46a62007-10-20 20:23:07 +00001913/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001914static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001915 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001916{
bellard2f619692007-11-16 10:46:05 +00001917 socklen_t addrlen;
1918 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001919 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001920
bellard2f619692007-11-16 10:46:05 +00001921 if (get_user_u32(addrlen, target_addrlen_addr))
1922 return -TARGET_EFAULT;
1923
Blue Swirl38724252010-09-18 05:53:14 +00001924 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001925 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001926 }
aurel328f7aeaf2009-01-30 19:47:57 +00001927
Arnaud Patard917507b2009-06-19 10:44:45 +03001928 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1929 return -TARGET_EFAULT;
1930
bellard2f619692007-11-16 10:46:05 +00001931 addr = alloca(addrlen);
1932
pbrook1be9e1d2006-11-19 15:26:04 +00001933 ret = get_errno(getsockname(fd, addr, &addrlen));
1934 if (!is_error(ret)) {
1935 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001936 if (put_user_u32(addrlen, target_addrlen_addr))
1937 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001938 }
1939 return ret;
1940}
1941
ths0da46a62007-10-20 20:23:07 +00001942/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001943static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00001944 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001945{
1946 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00001947 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001948
1949 ret = get_errno(socketpair(domain, type, protocol, tab));
1950 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00001951 if (put_user_s32(tab[0], target_tab_addr)
1952 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
1953 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001954 }
1955 return ret;
1956}
1957
ths0da46a62007-10-20 20:23:07 +00001958/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001959static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
1960 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001961{
1962 void *addr;
1963 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00001964 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001965
Blue Swirl38724252010-09-18 05:53:14 +00001966 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001967 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001968 }
aurel328f7aeaf2009-01-30 19:47:57 +00001969
bellard579a97f2007-11-11 14:26:47 +00001970 host_msg = lock_user(VERIFY_READ, msg, len, 1);
1971 if (!host_msg)
1972 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001973 if (target_addr) {
1974 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001975 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1976 if (ret) {
1977 unlock_user(host_msg, msg, 0);
1978 return ret;
1979 }
pbrook1be9e1d2006-11-19 15:26:04 +00001980 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
1981 } else {
1982 ret = get_errno(send(fd, host_msg, len, flags));
1983 }
1984 unlock_user(host_msg, msg, 0);
1985 return ret;
1986}
1987
ths0da46a62007-10-20 20:23:07 +00001988/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001989static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
1990 abi_ulong target_addr,
1991 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001992{
1993 socklen_t addrlen;
1994 void *addr;
1995 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00001996 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001997
bellard579a97f2007-11-11 14:26:47 +00001998 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
1999 if (!host_msg)
2000 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002001 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002002 if (get_user_u32(addrlen, target_addrlen)) {
2003 ret = -TARGET_EFAULT;
2004 goto fail;
2005 }
Blue Swirl38724252010-09-18 05:53:14 +00002006 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002007 ret = -TARGET_EINVAL;
2008 goto fail;
2009 }
pbrook1be9e1d2006-11-19 15:26:04 +00002010 addr = alloca(addrlen);
2011 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2012 } else {
2013 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002014 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002015 }
2016 if (!is_error(ret)) {
2017 if (target_addr) {
2018 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002019 if (put_user_u32(addrlen, target_addrlen)) {
2020 ret = -TARGET_EFAULT;
2021 goto fail;
2022 }
pbrook1be9e1d2006-11-19 15:26:04 +00002023 }
2024 unlock_user(host_msg, msg, len);
2025 } else {
bellard2f619692007-11-16 10:46:05 +00002026fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002027 unlock_user(host_msg, msg, 0);
2028 }
2029 return ret;
2030}
2031
j_mayer32407102007-09-26 23:01:49 +00002032#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002033/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002034static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002035{
blueswir1992f48a2007-10-14 16:27:31 +00002036 abi_long ret;
2037 const int n = sizeof(abi_ulong);
bellard31e31b82003-02-18 22:55:36 +00002038
2039 switch(num) {
2040 case SOCKOP_socket:
bellard7854b052003-03-29 17:22:23 +00002041 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002042 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002043
Ulrich Hecht98818182009-07-03 17:09:28 +02002044 if (get_user_ual(domain, vptr)
2045 || get_user_ual(type, vptr + n)
2046 || get_user_ual(protocol, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002047 return -TARGET_EFAULT;
2048
bellard3532fa72006-06-24 15:06:03 +00002049 ret = do_socket(domain, type, protocol);
bellard7854b052003-03-29 17:22:23 +00002050 }
bellard31e31b82003-02-18 22:55:36 +00002051 break;
2052 case SOCKOP_bind:
bellard7854b052003-03-29 17:22:23 +00002053 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002054 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002055 abi_ulong target_addr;
2056 socklen_t addrlen;
2057
Ulrich Hecht98818182009-07-03 17:09:28 +02002058 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002059 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002060 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002061 return -TARGET_EFAULT;
2062
bellard3532fa72006-06-24 15:06:03 +00002063 ret = do_bind(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002064 }
bellard31e31b82003-02-18 22:55:36 +00002065 break;
2066 case SOCKOP_connect:
bellard7854b052003-03-29 17:22:23 +00002067 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002068 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002069 abi_ulong target_addr;
2070 socklen_t addrlen;
2071
Ulrich Hecht98818182009-07-03 17:09:28 +02002072 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002073 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002074 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002075 return -TARGET_EFAULT;
2076
bellard3532fa72006-06-24 15:06:03 +00002077 ret = do_connect(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002078 }
bellard31e31b82003-02-18 22:55:36 +00002079 break;
2080 case SOCKOP_listen:
bellard7854b052003-03-29 17:22:23 +00002081 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002082 abi_ulong sockfd, backlog;
bellard2f619692007-11-16 10:46:05 +00002083
Ulrich Hecht98818182009-07-03 17:09:28 +02002084 if (get_user_ual(sockfd, vptr)
2085 || get_user_ual(backlog, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002086 return -TARGET_EFAULT;
2087
bellard7854b052003-03-29 17:22:23 +00002088 ret = get_errno(listen(sockfd, backlog));
2089 }
bellard31e31b82003-02-18 22:55:36 +00002090 break;
2091 case SOCKOP_accept:
2092 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002093 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002094 abi_ulong target_addr, target_addrlen;
2095
Ulrich Hecht98818182009-07-03 17:09:28 +02002096 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002097 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002098 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002099 return -TARGET_EFAULT;
2100
Peter Maydella94b4982013-02-08 04:35:04 +00002101 ret = do_accept4(sockfd, target_addr, target_addrlen, 0);
bellard31e31b82003-02-18 22:55:36 +00002102 }
2103 break;
2104 case SOCKOP_getsockname:
2105 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002106 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002107 abi_ulong target_addr, target_addrlen;
2108
Ulrich Hecht98818182009-07-03 17:09:28 +02002109 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002110 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002111 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002112 return -TARGET_EFAULT;
2113
pbrook1be9e1d2006-11-19 15:26:04 +00002114 ret = do_getsockname(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002115 }
2116 break;
2117 case SOCKOP_getpeername:
2118 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002119 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002120 abi_ulong target_addr, target_addrlen;
2121
Ulrich Hecht98818182009-07-03 17:09:28 +02002122 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002123 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002124 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002125 return -TARGET_EFAULT;
2126
pbrook1be9e1d2006-11-19 15:26:04 +00002127 ret = do_getpeername(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002128 }
2129 break;
2130 case SOCKOP_socketpair:
2131 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002132 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002133 abi_ulong tab;
2134
Ulrich Hecht98818182009-07-03 17:09:28 +02002135 if (get_user_ual(domain, vptr)
2136 || get_user_ual(type, vptr + n)
2137 || get_user_ual(protocol, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002138 || get_user_ual(tab, vptr + 3 * n))
2139 return -TARGET_EFAULT;
2140
pbrook1be9e1d2006-11-19 15:26:04 +00002141 ret = do_socketpair(domain, type, protocol, tab);
bellard31e31b82003-02-18 22:55:36 +00002142 }
2143 break;
2144 case SOCKOP_send:
bellard7854b052003-03-29 17:22:23 +00002145 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002146 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002147 abi_ulong msg;
2148 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002149 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002150
Ulrich Hecht98818182009-07-03 17:09:28 +02002151 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002152 || get_user_ual(msg, vptr + n)
2153 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002154 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002155 return -TARGET_EFAULT;
2156
pbrook1be9e1d2006-11-19 15:26:04 +00002157 ret = do_sendto(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002158 }
bellard31e31b82003-02-18 22:55:36 +00002159 break;
2160 case SOCKOP_recv:
bellard7854b052003-03-29 17:22:23 +00002161 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002162 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002163 abi_ulong msg;
2164 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002165 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002166
Ulrich Hecht98818182009-07-03 17:09:28 +02002167 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002168 || get_user_ual(msg, vptr + n)
2169 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002170 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002171 return -TARGET_EFAULT;
2172
pbrook1be9e1d2006-11-19 15:26:04 +00002173 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002174 }
bellard31e31b82003-02-18 22:55:36 +00002175 break;
2176 case SOCKOP_sendto:
bellard7854b052003-03-29 17:22:23 +00002177 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002178 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002179 abi_ulong msg;
2180 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002181 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002182 abi_ulong addr;
2183 socklen_t addrlen;
2184
Ulrich Hecht98818182009-07-03 17:09:28 +02002185 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002186 || get_user_ual(msg, vptr + n)
2187 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002188 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002189 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002190 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002191 return -TARGET_EFAULT;
2192
pbrook1be9e1d2006-11-19 15:26:04 +00002193 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002194 }
bellard31e31b82003-02-18 22:55:36 +00002195 break;
2196 case SOCKOP_recvfrom:
2197 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002198 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002199 abi_ulong msg;
2200 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002201 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002202 abi_ulong addr;
2203 socklen_t addrlen;
2204
Ulrich Hecht98818182009-07-03 17:09:28 +02002205 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002206 || get_user_ual(msg, vptr + n)
2207 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002208 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002209 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002210 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002211 return -TARGET_EFAULT;
2212
pbrook1be9e1d2006-11-19 15:26:04 +00002213 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
bellard31e31b82003-02-18 22:55:36 +00002214 }
2215 break;
2216 case SOCKOP_shutdown:
bellard7854b052003-03-29 17:22:23 +00002217 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002218 abi_ulong sockfd, how;
bellard2f619692007-11-16 10:46:05 +00002219
Ulrich Hecht98818182009-07-03 17:09:28 +02002220 if (get_user_ual(sockfd, vptr)
2221 || get_user_ual(how, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002222 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002223
2224 ret = get_errno(shutdown(sockfd, how));
2225 }
bellard31e31b82003-02-18 22:55:36 +00002226 break;
2227 case SOCKOP_sendmsg:
2228 case SOCKOP_recvmsg:
bellard1a9353d2003-03-16 20:28:50 +00002229 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002230 abi_ulong fd;
blueswir1992f48a2007-10-14 16:27:31 +00002231 abi_ulong target_msg;
Ulrich Hecht98818182009-07-03 17:09:28 +02002232 abi_ulong flags;
bellard1a9353d2003-03-16 20:28:50 +00002233
Ulrich Hecht98818182009-07-03 17:09:28 +02002234 if (get_user_ual(fd, vptr)
bellard2f619692007-11-16 10:46:05 +00002235 || get_user_ual(target_msg, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002236 || get_user_ual(flags, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002237 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002238
ths5fafdf22007-09-16 21:08:06 +00002239 ret = do_sendrecvmsg(fd, target_msg, flags,
bellard3532fa72006-06-24 15:06:03 +00002240 (num == SOCKOP_sendmsg));
bellard1a9353d2003-03-16 20:28:50 +00002241 }
2242 break;
bellard31e31b82003-02-18 22:55:36 +00002243 case SOCKOP_setsockopt:
bellard7854b052003-03-29 17:22:23 +00002244 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002245 abi_ulong sockfd;
2246 abi_ulong level;
2247 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002248 abi_ulong optval;
2249 socklen_t optlen;
2250
Ulrich Hecht98818182009-07-03 17:09:28 +02002251 if (get_user_ual(sockfd, vptr)
2252 || get_user_ual(level, vptr + n)
2253 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002254 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002255 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002256 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002257
2258 ret = do_setsockopt(sockfd, level, optname, optval, optlen);
2259 }
2260 break;
bellard31e31b82003-02-18 22:55:36 +00002261 case SOCKOP_getsockopt:
bellard7854b052003-03-29 17:22:23 +00002262 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002263 abi_ulong sockfd;
2264 abi_ulong level;
2265 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002266 abi_ulong optval;
2267 socklen_t optlen;
bellard7854b052003-03-29 17:22:23 +00002268
Ulrich Hecht98818182009-07-03 17:09:28 +02002269 if (get_user_ual(sockfd, vptr)
2270 || get_user_ual(level, vptr + n)
2271 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002272 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002273 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002274 return -TARGET_EFAULT;
2275
2276 ret = do_getsockopt(sockfd, level, optname, optval, optlen);
bellard7854b052003-03-29 17:22:23 +00002277 }
2278 break;
bellard31e31b82003-02-18 22:55:36 +00002279 default:
2280 gemu_log("Unsupported socketcall: %d\n", num);
ths0da46a62007-10-20 20:23:07 +00002281 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002282 break;
2283 }
2284 return ret;
2285}
j_mayer32407102007-09-26 23:01:49 +00002286#endif
bellard31e31b82003-02-18 22:55:36 +00002287
bellard8853f862004-02-22 14:57:26 +00002288#define N_SHM_REGIONS 32
2289
2290static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002291 abi_ulong start;
2292 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002293} shm_regions[N_SHM_REGIONS];
2294
ths3eb6b042007-06-03 14:26:27 +00002295struct target_ipc_perm
2296{
blueswir1992f48a2007-10-14 16:27:31 +00002297 abi_long __key;
2298 abi_ulong uid;
2299 abi_ulong gid;
2300 abi_ulong cuid;
2301 abi_ulong cgid;
ths3eb6b042007-06-03 14:26:27 +00002302 unsigned short int mode;
2303 unsigned short int __pad1;
2304 unsigned short int __seq;
2305 unsigned short int __pad2;
blueswir1992f48a2007-10-14 16:27:31 +00002306 abi_ulong __unused1;
2307 abi_ulong __unused2;
ths3eb6b042007-06-03 14:26:27 +00002308};
2309
2310struct target_semid_ds
2311{
2312 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002313 abi_ulong sem_otime;
2314 abi_ulong __unused1;
2315 abi_ulong sem_ctime;
2316 abi_ulong __unused2;
2317 abi_ulong sem_nsems;
2318 abi_ulong __unused3;
2319 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002320};
2321
bellard579a97f2007-11-11 14:26:47 +00002322static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2323 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002324{
2325 struct target_ipc_perm *target_ip;
2326 struct target_semid_ds *target_sd;
2327
bellard579a97f2007-11-11 14:26:47 +00002328 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2329 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002330 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002331 host_ip->__key = tswapal(target_ip->__key);
2332 host_ip->uid = tswapal(target_ip->uid);
2333 host_ip->gid = tswapal(target_ip->gid);
2334 host_ip->cuid = tswapal(target_ip->cuid);
2335 host_ip->cgid = tswapal(target_ip->cgid);
2336 host_ip->mode = tswap16(target_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002337 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002338 return 0;
ths3eb6b042007-06-03 14:26:27 +00002339}
2340
bellard579a97f2007-11-11 14:26:47 +00002341static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2342 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002343{
2344 struct target_ipc_perm *target_ip;
2345 struct target_semid_ds *target_sd;
2346
bellard579a97f2007-11-11 14:26:47 +00002347 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2348 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002349 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002350 target_ip->__key = tswapal(host_ip->__key);
2351 target_ip->uid = tswapal(host_ip->uid);
2352 target_ip->gid = tswapal(host_ip->gid);
2353 target_ip->cuid = tswapal(host_ip->cuid);
2354 target_ip->cgid = tswapal(host_ip->cgid);
2355 target_ip->mode = tswap16(host_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002356 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002357 return 0;
ths3eb6b042007-06-03 14:26:27 +00002358}
2359
bellard579a97f2007-11-11 14:26:47 +00002360static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2361 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002362{
2363 struct target_semid_ds *target_sd;
2364
bellard579a97f2007-11-11 14:26:47 +00002365 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2366 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002367 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2368 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002369 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2370 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2371 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002372 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002373 return 0;
ths3eb6b042007-06-03 14:26:27 +00002374}
2375
bellard579a97f2007-11-11 14:26:47 +00002376static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2377 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002378{
2379 struct target_semid_ds *target_sd;
2380
bellard579a97f2007-11-11 14:26:47 +00002381 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2382 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002383 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002384 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002385 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2386 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2387 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002388 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002389 return 0;
ths3eb6b042007-06-03 14:26:27 +00002390}
2391
aurel32e5289082009-04-18 16:16:12 +00002392struct target_seminfo {
2393 int semmap;
2394 int semmni;
2395 int semmns;
2396 int semmnu;
2397 int semmsl;
2398 int semopm;
2399 int semume;
2400 int semusz;
2401 int semvmx;
2402 int semaem;
2403};
2404
2405static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2406 struct seminfo *host_seminfo)
2407{
2408 struct target_seminfo *target_seminfo;
2409 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2410 return -TARGET_EFAULT;
2411 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2412 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2413 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2414 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2415 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2416 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2417 __put_user(host_seminfo->semume, &target_seminfo->semume);
2418 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2419 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2420 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2421 unlock_user_struct(target_seminfo, target_addr, 1);
2422 return 0;
2423}
2424
thsfa294812007-02-02 22:05:00 +00002425union semun {
2426 int val;
ths3eb6b042007-06-03 14:26:27 +00002427 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002428 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002429 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002430};
2431
ths3eb6b042007-06-03 14:26:27 +00002432union target_semun {
2433 int val;
aurel32e5289082009-04-18 16:16:12 +00002434 abi_ulong buf;
2435 abi_ulong array;
2436 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002437};
2438
aurel32e5289082009-04-18 16:16:12 +00002439static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2440 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002441{
aurel32e5289082009-04-18 16:16:12 +00002442 int nsems;
2443 unsigned short *array;
2444 union semun semun;
2445 struct semid_ds semid_ds;
2446 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002447
aurel32e5289082009-04-18 16:16:12 +00002448 semun.buf = &semid_ds;
2449
2450 ret = semctl(semid, 0, IPC_STAT, semun);
2451 if (ret == -1)
2452 return get_errno(ret);
2453
2454 nsems = semid_ds.sem_nsems;
2455
2456 *host_array = malloc(nsems*sizeof(unsigned short));
2457 array = lock_user(VERIFY_READ, target_addr,
2458 nsems*sizeof(unsigned short), 1);
2459 if (!array)
2460 return -TARGET_EFAULT;
2461
2462 for(i=0; i<nsems; i++) {
2463 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002464 }
aurel32e5289082009-04-18 16:16:12 +00002465 unlock_user(array, target_addr, 0);
2466
bellard579a97f2007-11-11 14:26:47 +00002467 return 0;
ths3eb6b042007-06-03 14:26:27 +00002468}
2469
aurel32e5289082009-04-18 16:16:12 +00002470static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2471 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002472{
aurel32e5289082009-04-18 16:16:12 +00002473 int nsems;
2474 unsigned short *array;
2475 union semun semun;
2476 struct semid_ds semid_ds;
2477 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002478
aurel32e5289082009-04-18 16:16:12 +00002479 semun.buf = &semid_ds;
2480
2481 ret = semctl(semid, 0, IPC_STAT, semun);
2482 if (ret == -1)
2483 return get_errno(ret);
2484
2485 nsems = semid_ds.sem_nsems;
2486
2487 array = lock_user(VERIFY_WRITE, target_addr,
2488 nsems*sizeof(unsigned short), 0);
2489 if (!array)
2490 return -TARGET_EFAULT;
2491
2492 for(i=0; i<nsems; i++) {
2493 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002494 }
aurel32e5289082009-04-18 16:16:12 +00002495 free(*host_array);
2496 unlock_user(array, target_addr, 1);
2497
bellard579a97f2007-11-11 14:26:47 +00002498 return 0;
ths3eb6b042007-06-03 14:26:27 +00002499}
2500
aurel32e5289082009-04-18 16:16:12 +00002501static inline abi_long do_semctl(int semid, int semnum, int cmd,
2502 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002503{
2504 union semun arg;
2505 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302506 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002507 struct seminfo seminfo;
2508 abi_long ret = -TARGET_EINVAL;
2509 abi_long err;
2510 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002511
2512 switch( cmd ) {
2513 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002514 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002515 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002516 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002517 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002518 break;
2519 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002520 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002521 err = target_to_host_semarray(semid, &array, target_su.array);
2522 if (err)
2523 return err;
2524 arg.array = array;
2525 ret = get_errno(semctl(semid, semnum, cmd, arg));
2526 err = host_to_target_semarray(semid, target_su.array, &array);
2527 if (err)
2528 return err;
ths3eb6b042007-06-03 14:26:27 +00002529 break;
2530 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002531 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002532 case SEM_STAT:
2533 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2534 if (err)
2535 return err;
2536 arg.buf = &dsarg;
2537 ret = get_errno(semctl(semid, semnum, cmd, arg));
2538 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2539 if (err)
2540 return err;
ths3eb6b042007-06-03 14:26:27 +00002541 break;
aurel32e5289082009-04-18 16:16:12 +00002542 case IPC_INFO:
2543 case SEM_INFO:
2544 arg.__buf = &seminfo;
2545 ret = get_errno(semctl(semid, semnum, cmd, arg));
2546 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2547 if (err)
2548 return err;
2549 break;
2550 case IPC_RMID:
2551 case GETPID:
2552 case GETNCNT:
2553 case GETZCNT:
2554 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2555 break;
ths3eb6b042007-06-03 14:26:27 +00002556 }
2557
2558 return ret;
2559}
2560
aurel32e5289082009-04-18 16:16:12 +00002561struct target_sembuf {
2562 unsigned short sem_num;
2563 short sem_op;
2564 short sem_flg;
2565};
2566
2567static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2568 abi_ulong target_addr,
2569 unsigned nsops)
2570{
2571 struct target_sembuf *target_sembuf;
2572 int i;
2573
2574 target_sembuf = lock_user(VERIFY_READ, target_addr,
2575 nsops*sizeof(struct target_sembuf), 1);
2576 if (!target_sembuf)
2577 return -TARGET_EFAULT;
2578
2579 for(i=0; i<nsops; i++) {
2580 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2581 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2582 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2583 }
2584
2585 unlock_user(target_sembuf, target_addr, 0);
2586
2587 return 0;
2588}
2589
2590static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2591{
2592 struct sembuf sops[nsops];
2593
2594 if (target_to_host_sembuf(sops, ptr, nsops))
2595 return -TARGET_EFAULT;
2596
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002597 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002598}
2599
ths1bc012f2007-06-03 14:27:49 +00002600struct target_msqid_ds
2601{
aurel321c54ff92008-10-13 21:08:44 +00002602 struct target_ipc_perm msg_perm;
2603 abi_ulong msg_stime;
2604#if TARGET_ABI_BITS == 32
2605 abi_ulong __unused1;
2606#endif
2607 abi_ulong msg_rtime;
2608#if TARGET_ABI_BITS == 32
2609 abi_ulong __unused2;
2610#endif
2611 abi_ulong msg_ctime;
2612#if TARGET_ABI_BITS == 32
2613 abi_ulong __unused3;
2614#endif
2615 abi_ulong __msg_cbytes;
2616 abi_ulong msg_qnum;
2617 abi_ulong msg_qbytes;
2618 abi_ulong msg_lspid;
2619 abi_ulong msg_lrpid;
2620 abi_ulong __unused4;
2621 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002622};
2623
bellard579a97f2007-11-11 14:26:47 +00002624static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2625 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002626{
2627 struct target_msqid_ds *target_md;
2628
bellard579a97f2007-11-11 14:26:47 +00002629 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2630 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002631 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2632 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002633 host_md->msg_stime = tswapal(target_md->msg_stime);
2634 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2635 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2636 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2637 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2638 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2639 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2640 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002641 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002642 return 0;
ths1bc012f2007-06-03 14:27:49 +00002643}
2644
bellard579a97f2007-11-11 14:26:47 +00002645static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2646 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002647{
2648 struct target_msqid_ds *target_md;
2649
bellard579a97f2007-11-11 14:26:47 +00002650 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2651 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002652 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2653 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002654 target_md->msg_stime = tswapal(host_md->msg_stime);
2655 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2656 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2657 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2658 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2659 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2660 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2661 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002662 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002663 return 0;
ths1bc012f2007-06-03 14:27:49 +00002664}
2665
aurel321c54ff92008-10-13 21:08:44 +00002666struct target_msginfo {
2667 int msgpool;
2668 int msgmap;
2669 int msgmax;
2670 int msgmnb;
2671 int msgmni;
2672 int msgssz;
2673 int msgtql;
2674 unsigned short int msgseg;
2675};
2676
2677static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2678 struct msginfo *host_msginfo)
2679{
2680 struct target_msginfo *target_msginfo;
2681 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2682 return -TARGET_EFAULT;
2683 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2684 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2685 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2686 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2687 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2688 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2689 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2690 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2691 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002692 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002693}
2694
2695static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002696{
2697 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002698 struct msginfo msginfo;
2699 abi_long ret = -TARGET_EINVAL;
2700
2701 cmd &= 0xff;
2702
2703 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002704 case IPC_STAT:
2705 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002706 case MSG_STAT:
2707 if (target_to_host_msqid_ds(&dsarg,ptr))
2708 return -TARGET_EFAULT;
2709 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2710 if (host_to_target_msqid_ds(ptr,&dsarg))
2711 return -TARGET_EFAULT;
2712 break;
2713 case IPC_RMID:
2714 ret = get_errno(msgctl(msgid, cmd, NULL));
2715 break;
2716 case IPC_INFO:
2717 case MSG_INFO:
2718 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2719 if (host_to_target_msginfo(ptr, &msginfo))
2720 return -TARGET_EFAULT;
2721 break;
ths1bc012f2007-06-03 14:27:49 +00002722 }
aurel321c54ff92008-10-13 21:08:44 +00002723
ths1bc012f2007-06-03 14:27:49 +00002724 return ret;
2725}
2726
2727struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002728 abi_long mtype;
2729 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002730};
2731
blueswir1992f48a2007-10-14 16:27:31 +00002732static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2733 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002734{
2735 struct target_msgbuf *target_mb;
2736 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002737 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002738
bellard579a97f2007-11-11 14:26:47 +00002739 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2740 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002741 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002742 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002743 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002744 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2745 free(host_mb);
2746 unlock_user_struct(target_mb, msgp, 0);
2747
2748 return ret;
2749}
2750
blueswir1992f48a2007-10-14 16:27:31 +00002751static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002752 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002753 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002754{
2755 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002756 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002757 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002758 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002759
bellard579a97f2007-11-11 14:26:47 +00002760 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2761 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002762
Jim Meyering0d07fe42012-08-22 13:55:53 +02002763 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00002764 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002765
bellard579a97f2007-11-11 14:26:47 +00002766 if (ret > 0) {
2767 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2768 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2769 if (!target_mtext) {
2770 ret = -TARGET_EFAULT;
2771 goto end;
2772 }
aurel321c54ff92008-10-13 21:08:44 +00002773 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002774 unlock_user(target_mtext, target_mtext_addr, ret);
2775 }
aurel321c54ff92008-10-13 21:08:44 +00002776
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002777 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002778
bellard579a97f2007-11-11 14:26:47 +00002779end:
2780 if (target_mb)
2781 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02002782 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002783 return ret;
2784}
2785
Riku Voipio88a8c982009-04-03 10:42:00 +03002786struct target_shmid_ds
2787{
2788 struct target_ipc_perm shm_perm;
2789 abi_ulong shm_segsz;
2790 abi_ulong shm_atime;
2791#if TARGET_ABI_BITS == 32
2792 abi_ulong __unused1;
2793#endif
2794 abi_ulong shm_dtime;
2795#if TARGET_ABI_BITS == 32
2796 abi_ulong __unused2;
2797#endif
2798 abi_ulong shm_ctime;
2799#if TARGET_ABI_BITS == 32
2800 abi_ulong __unused3;
2801#endif
2802 int shm_cpid;
2803 int shm_lpid;
2804 abi_ulong shm_nattch;
2805 unsigned long int __unused4;
2806 unsigned long int __unused5;
2807};
2808
2809static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2810 abi_ulong target_addr)
2811{
2812 struct target_shmid_ds *target_sd;
2813
2814 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2815 return -TARGET_EFAULT;
2816 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2817 return -TARGET_EFAULT;
2818 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2819 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2820 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2821 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2822 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2823 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2824 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2825 unlock_user_struct(target_sd, target_addr, 0);
2826 return 0;
2827}
2828
2829static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2830 struct shmid_ds *host_sd)
2831{
2832 struct target_shmid_ds *target_sd;
2833
2834 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2835 return -TARGET_EFAULT;
2836 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2837 return -TARGET_EFAULT;
2838 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2839 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2840 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2841 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2842 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2843 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2844 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2845 unlock_user_struct(target_sd, target_addr, 1);
2846 return 0;
2847}
2848
2849struct target_shminfo {
2850 abi_ulong shmmax;
2851 abi_ulong shmmin;
2852 abi_ulong shmmni;
2853 abi_ulong shmseg;
2854 abi_ulong shmall;
2855};
2856
2857static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2858 struct shminfo *host_shminfo)
2859{
2860 struct target_shminfo *target_shminfo;
2861 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2862 return -TARGET_EFAULT;
2863 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2864 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2865 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2866 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2867 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2868 unlock_user_struct(target_shminfo, target_addr, 1);
2869 return 0;
2870}
2871
2872struct target_shm_info {
2873 int used_ids;
2874 abi_ulong shm_tot;
2875 abi_ulong shm_rss;
2876 abi_ulong shm_swp;
2877 abi_ulong swap_attempts;
2878 abi_ulong swap_successes;
2879};
2880
2881static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2882 struct shm_info *host_shm_info)
2883{
2884 struct target_shm_info *target_shm_info;
2885 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2886 return -TARGET_EFAULT;
2887 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2888 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2889 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2890 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2891 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2892 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
2893 unlock_user_struct(target_shm_info, target_addr, 1);
2894 return 0;
2895}
2896
2897static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
2898{
2899 struct shmid_ds dsarg;
2900 struct shminfo shminfo;
2901 struct shm_info shm_info;
2902 abi_long ret = -TARGET_EINVAL;
2903
2904 cmd &= 0xff;
2905
2906 switch(cmd) {
2907 case IPC_STAT:
2908 case IPC_SET:
2909 case SHM_STAT:
2910 if (target_to_host_shmid_ds(&dsarg, buf))
2911 return -TARGET_EFAULT;
2912 ret = get_errno(shmctl(shmid, cmd, &dsarg));
2913 if (host_to_target_shmid_ds(buf, &dsarg))
2914 return -TARGET_EFAULT;
2915 break;
2916 case IPC_INFO:
2917 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
2918 if (host_to_target_shminfo(buf, &shminfo))
2919 return -TARGET_EFAULT;
2920 break;
2921 case SHM_INFO:
2922 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
2923 if (host_to_target_shm_info(buf, &shm_info))
2924 return -TARGET_EFAULT;
2925 break;
2926 case IPC_RMID:
2927 case SHM_LOCK:
2928 case SHM_UNLOCK:
2929 ret = get_errno(shmctl(shmid, cmd, NULL));
2930 break;
2931 }
2932
2933 return ret;
2934}
2935
2936static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
2937{
2938 abi_long raddr;
2939 void *host_raddr;
2940 struct shmid_ds shm_info;
2941 int i,ret;
2942
2943 /* find out the length of the shared memory segment */
2944 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
2945 if (is_error(ret)) {
2946 /* can't get length, bail out */
2947 return ret;
2948 }
2949
2950 mmap_lock();
2951
2952 if (shmaddr)
2953 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
2954 else {
2955 abi_ulong mmap_start;
2956
2957 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
2958
2959 if (mmap_start == -1) {
2960 errno = ENOMEM;
2961 host_raddr = (void *)-1;
2962 } else
2963 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
2964 }
2965
2966 if (host_raddr == (void *)-1) {
2967 mmap_unlock();
2968 return get_errno((long)host_raddr);
2969 }
2970 raddr=h2g((unsigned long)host_raddr);
2971
2972 page_set_flags(raddr, raddr + shm_info.shm_segsz,
2973 PAGE_VALID | PAGE_READ |
2974 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
2975
2976 for (i = 0; i < N_SHM_REGIONS; i++) {
2977 if (shm_regions[i].start == 0) {
2978 shm_regions[i].start = raddr;
2979 shm_regions[i].size = shm_info.shm_segsz;
2980 break;
2981 }
2982 }
2983
2984 mmap_unlock();
2985 return raddr;
2986
2987}
2988
2989static inline abi_long do_shmdt(abi_ulong shmaddr)
2990{
2991 int i;
2992
2993 for (i = 0; i < N_SHM_REGIONS; ++i) {
2994 if (shm_regions[i].start == shmaddr) {
2995 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09002996 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03002997 break;
2998 }
2999 }
3000
3001 return get_errno(shmdt(g2h(shmaddr)));
3002}
3003
aurel321c54ff92008-10-13 21:08:44 +00003004#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003005/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003006/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003007static abi_long do_ipc(unsigned int call, int first,
3008 int second, int third,
3009 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003010{
3011 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003012 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003013
3014 version = call >> 16;
3015 call &= 0xffff;
3016
3017 switch (call) {
thsfa294812007-02-02 22:05:00 +00003018 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003019 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003020 break;
3021
3022 case IPCOP_semget:
3023 ret = get_errno(semget(first, second, third));
3024 break;
3025
3026 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003027 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003028 break;
thsd96372e2007-02-02 22:05:44 +00003029
aurel321c54ff92008-10-13 21:08:44 +00003030 case IPCOP_msgget:
3031 ret = get_errno(msgget(first, second));
3032 break;
thsd96372e2007-02-02 22:05:44 +00003033
aurel321c54ff92008-10-13 21:08:44 +00003034 case IPCOP_msgsnd:
3035 ret = do_msgsnd(first, ptr, second, third);
3036 break;
thsd96372e2007-02-02 22:05:44 +00003037
aurel321c54ff92008-10-13 21:08:44 +00003038 case IPCOP_msgctl:
3039 ret = do_msgctl(first, second, ptr);
3040 break;
thsd96372e2007-02-02 22:05:44 +00003041
aurel321c54ff92008-10-13 21:08:44 +00003042 case IPCOP_msgrcv:
3043 switch (version) {
3044 case 0:
3045 {
3046 struct target_ipc_kludge {
3047 abi_long msgp;
3048 abi_long msgtyp;
3049 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003050
aurel321c54ff92008-10-13 21:08:44 +00003051 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3052 ret = -TARGET_EFAULT;
3053 break;
ths1bc012f2007-06-03 14:27:49 +00003054 }
aurel321c54ff92008-10-13 21:08:44 +00003055
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003056 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003057
3058 unlock_user_struct(tmp, ptr, 0);
3059 break;
3060 }
3061 default:
3062 ret = do_msgrcv(first, ptr, second, fifth, third);
3063 }
3064 break;
thsd96372e2007-02-02 22:05:44 +00003065
bellard8853f862004-02-22 14:57:26 +00003066 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003067 switch (version) {
3068 default:
bellard5a4a8982007-11-11 17:39:18 +00003069 {
3070 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003071 raddr = do_shmat(first, ptr, second);
3072 if (is_error(raddr))
3073 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003074 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003075 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003076 break;
3077 }
3078 case 1:
3079 ret = -TARGET_EINVAL;
3080 break;
bellard5a4a8982007-11-11 17:39:18 +00003081 }
bellard8853f862004-02-22 14:57:26 +00003082 break;
3083 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003084 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003085 break;
3086
3087 case IPCOP_shmget:
3088 /* IPC_* flag values are the same on all linux platforms */
3089 ret = get_errno(shmget(first, second, third));
3090 break;
3091
3092 /* IPC_* and SHM_* command values are the same on all linux platforms */
3093 case IPCOP_shmctl:
Riku Voipio88a8c982009-04-03 10:42:00 +03003094 ret = do_shmctl(first, second, third);
bellard8853f862004-02-22 14:57:26 +00003095 break;
3096 default:
j_mayer32407102007-09-26 23:01:49 +00003097 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003098 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003099 break;
3100 }
3101 return ret;
3102}
j_mayer32407102007-09-26 23:01:49 +00003103#endif
bellard8853f862004-02-22 14:57:26 +00003104
bellard31e31b82003-02-18 22:55:36 +00003105/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003106
Blue Swirl001faf32009-05-13 17:53:17 +00003107#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003108#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3109enum {
3110#include "syscall_types.h"
3111};
3112#undef STRUCT
3113#undef STRUCT_SPECIAL
3114
Blue Swirl001faf32009-05-13 17:53:17 +00003115#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003116#define STRUCT_SPECIAL(name)
3117#include "syscall_types.h"
3118#undef STRUCT
3119#undef STRUCT_SPECIAL
3120
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003121typedef struct IOCTLEntry IOCTLEntry;
3122
3123typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3124 int fd, abi_long cmd, abi_long arg);
3125
3126struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003127 unsigned int target_cmd;
3128 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003129 const char *name;
3130 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003131 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003132 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003133};
bellard31e31b82003-02-18 22:55:36 +00003134
3135#define IOC_R 0x0001
3136#define IOC_W 0x0002
3137#define IOC_RW (IOC_R | IOC_W)
3138
3139#define MAX_STRUCT_SIZE 4096
3140
Peter Maydelldace20d2011-01-10 13:11:24 +00003141#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003142/* So fiemap access checks don't overflow on 32 bit systems.
3143 * This is very slightly smaller than the limit imposed by
3144 * the underlying kernel.
3145 */
3146#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3147 / sizeof(struct fiemap_extent))
3148
3149static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3150 int fd, abi_long cmd, abi_long arg)
3151{
3152 /* The parameter for this ioctl is a struct fiemap followed
3153 * by an array of struct fiemap_extent whose size is set
3154 * in fiemap->fm_extent_count. The array is filled in by the
3155 * ioctl.
3156 */
3157 int target_size_in, target_size_out;
3158 struct fiemap *fm;
3159 const argtype *arg_type = ie->arg_type;
3160 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3161 void *argptr, *p;
3162 abi_long ret;
3163 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3164 uint32_t outbufsz;
3165 int free_fm = 0;
3166
3167 assert(arg_type[0] == TYPE_PTR);
3168 assert(ie->access == IOC_RW);
3169 arg_type++;
3170 target_size_in = thunk_type_size(arg_type, 0);
3171 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3172 if (!argptr) {
3173 return -TARGET_EFAULT;
3174 }
3175 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3176 unlock_user(argptr, arg, 0);
3177 fm = (struct fiemap *)buf_temp;
3178 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3179 return -TARGET_EINVAL;
3180 }
3181
3182 outbufsz = sizeof (*fm) +
3183 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3184
3185 if (outbufsz > MAX_STRUCT_SIZE) {
3186 /* We can't fit all the extents into the fixed size buffer.
3187 * Allocate one that is large enough and use it instead.
3188 */
3189 fm = malloc(outbufsz);
3190 if (!fm) {
3191 return -TARGET_ENOMEM;
3192 }
3193 memcpy(fm, buf_temp, sizeof(struct fiemap));
3194 free_fm = 1;
3195 }
3196 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3197 if (!is_error(ret)) {
3198 target_size_out = target_size_in;
3199 /* An extent_count of 0 means we were only counting the extents
3200 * so there are no structs to copy
3201 */
3202 if (fm->fm_extent_count != 0) {
3203 target_size_out += fm->fm_mapped_extents * extent_size;
3204 }
3205 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3206 if (!argptr) {
3207 ret = -TARGET_EFAULT;
3208 } else {
3209 /* Convert the struct fiemap */
3210 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3211 if (fm->fm_extent_count != 0) {
3212 p = argptr + target_size_in;
3213 /* ...and then all the struct fiemap_extents */
3214 for (i = 0; i < fm->fm_mapped_extents; i++) {
3215 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3216 THUNK_TARGET);
3217 p += extent_size;
3218 }
3219 }
3220 unlock_user(argptr, arg, target_size_out);
3221 }
3222 }
3223 if (free_fm) {
3224 free(fm);
3225 }
3226 return ret;
3227}
Peter Maydelldace20d2011-01-10 13:11:24 +00003228#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003229
Laurent Vivier059c2f22011-03-30 00:12:12 +02003230static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3231 int fd, abi_long cmd, abi_long arg)
3232{
3233 const argtype *arg_type = ie->arg_type;
3234 int target_size;
3235 void *argptr;
3236 int ret;
3237 struct ifconf *host_ifconf;
3238 uint32_t outbufsz;
3239 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3240 int target_ifreq_size;
3241 int nb_ifreq;
3242 int free_buf = 0;
3243 int i;
3244 int target_ifc_len;
3245 abi_long target_ifc_buf;
3246 int host_ifc_len;
3247 char *host_ifc_buf;
3248
3249 assert(arg_type[0] == TYPE_PTR);
3250 assert(ie->access == IOC_RW);
3251
3252 arg_type++;
3253 target_size = thunk_type_size(arg_type, 0);
3254
3255 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3256 if (!argptr)
3257 return -TARGET_EFAULT;
3258 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3259 unlock_user(argptr, arg, 0);
3260
3261 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3262 target_ifc_len = host_ifconf->ifc_len;
3263 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3264
3265 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3266 nb_ifreq = target_ifc_len / target_ifreq_size;
3267 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3268
3269 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3270 if (outbufsz > MAX_STRUCT_SIZE) {
3271 /* We can't fit all the extents into the fixed size buffer.
3272 * Allocate one that is large enough and use it instead.
3273 */
3274 host_ifconf = malloc(outbufsz);
3275 if (!host_ifconf) {
3276 return -TARGET_ENOMEM;
3277 }
3278 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3279 free_buf = 1;
3280 }
3281 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3282
3283 host_ifconf->ifc_len = host_ifc_len;
3284 host_ifconf->ifc_buf = host_ifc_buf;
3285
3286 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3287 if (!is_error(ret)) {
3288 /* convert host ifc_len to target ifc_len */
3289
3290 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3291 target_ifc_len = nb_ifreq * target_ifreq_size;
3292 host_ifconf->ifc_len = target_ifc_len;
3293
3294 /* restore target ifc_buf */
3295
3296 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3297
3298 /* copy struct ifconf to target user */
3299
3300 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3301 if (!argptr)
3302 return -TARGET_EFAULT;
3303 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3304 unlock_user(argptr, arg, target_size);
3305
3306 /* copy ifreq[] to target user */
3307
3308 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3309 for (i = 0; i < nb_ifreq ; i++) {
3310 thunk_convert(argptr + i * target_ifreq_size,
3311 host_ifc_buf + i * sizeof(struct ifreq),
3312 ifreq_arg_type, THUNK_TARGET);
3313 }
3314 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3315 }
3316
3317 if (free_buf) {
3318 free(host_ifconf);
3319 }
3320
3321 return ret;
3322}
3323
Alexander Graf56e904e2012-01-31 18:42:06 +01003324static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3325 abi_long cmd, abi_long arg)
3326{
3327 void *argptr;
3328 struct dm_ioctl *host_dm;
3329 abi_long guest_data;
3330 uint32_t guest_data_size;
3331 int target_size;
3332 const argtype *arg_type = ie->arg_type;
3333 abi_long ret;
3334 void *big_buf = NULL;
3335 char *host_data;
3336
3337 arg_type++;
3338 target_size = thunk_type_size(arg_type, 0);
3339 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3340 if (!argptr) {
3341 ret = -TARGET_EFAULT;
3342 goto out;
3343 }
3344 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3345 unlock_user(argptr, arg, 0);
3346
3347 /* buf_temp is too small, so fetch things into a bigger buffer */
3348 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3349 memcpy(big_buf, buf_temp, target_size);
3350 buf_temp = big_buf;
3351 host_dm = big_buf;
3352
3353 guest_data = arg + host_dm->data_start;
3354 if ((guest_data - arg) < 0) {
3355 ret = -EINVAL;
3356 goto out;
3357 }
3358 guest_data_size = host_dm->data_size - host_dm->data_start;
3359 host_data = (char*)host_dm + host_dm->data_start;
3360
3361 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3362 switch (ie->host_cmd) {
3363 case DM_REMOVE_ALL:
3364 case DM_LIST_DEVICES:
3365 case DM_DEV_CREATE:
3366 case DM_DEV_REMOVE:
3367 case DM_DEV_SUSPEND:
3368 case DM_DEV_STATUS:
3369 case DM_DEV_WAIT:
3370 case DM_TABLE_STATUS:
3371 case DM_TABLE_CLEAR:
3372 case DM_TABLE_DEPS:
3373 case DM_LIST_VERSIONS:
3374 /* no input data */
3375 break;
3376 case DM_DEV_RENAME:
3377 case DM_DEV_SET_GEOMETRY:
3378 /* data contains only strings */
3379 memcpy(host_data, argptr, guest_data_size);
3380 break;
3381 case DM_TARGET_MSG:
3382 memcpy(host_data, argptr, guest_data_size);
3383 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3384 break;
3385 case DM_TABLE_LOAD:
3386 {
3387 void *gspec = argptr;
3388 void *cur_data = host_data;
3389 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3390 int spec_size = thunk_type_size(arg_type, 0);
3391 int i;
3392
3393 for (i = 0; i < host_dm->target_count; i++) {
3394 struct dm_target_spec *spec = cur_data;
3395 uint32_t next;
3396 int slen;
3397
3398 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3399 slen = strlen((char*)gspec + spec_size) + 1;
3400 next = spec->next;
3401 spec->next = sizeof(*spec) + slen;
3402 strcpy((char*)&spec[1], gspec + spec_size);
3403 gspec += next;
3404 cur_data += spec->next;
3405 }
3406 break;
3407 }
3408 default:
3409 ret = -TARGET_EINVAL;
3410 goto out;
3411 }
3412 unlock_user(argptr, guest_data, 0);
3413
3414 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3415 if (!is_error(ret)) {
3416 guest_data = arg + host_dm->data_start;
3417 guest_data_size = host_dm->data_size - host_dm->data_start;
3418 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3419 switch (ie->host_cmd) {
3420 case DM_REMOVE_ALL:
3421 case DM_DEV_CREATE:
3422 case DM_DEV_REMOVE:
3423 case DM_DEV_RENAME:
3424 case DM_DEV_SUSPEND:
3425 case DM_DEV_STATUS:
3426 case DM_TABLE_LOAD:
3427 case DM_TABLE_CLEAR:
3428 case DM_TARGET_MSG:
3429 case DM_DEV_SET_GEOMETRY:
3430 /* no return data */
3431 break;
3432 case DM_LIST_DEVICES:
3433 {
3434 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3435 uint32_t remaining_data = guest_data_size;
3436 void *cur_data = argptr;
3437 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3438 int nl_size = 12; /* can't use thunk_size due to alignment */
3439
3440 while (1) {
3441 uint32_t next = nl->next;
3442 if (next) {
3443 nl->next = nl_size + (strlen(nl->name) + 1);
3444 }
3445 if (remaining_data < nl->next) {
3446 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3447 break;
3448 }
3449 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3450 strcpy(cur_data + nl_size, nl->name);
3451 cur_data += nl->next;
3452 remaining_data -= nl->next;
3453 if (!next) {
3454 break;
3455 }
3456 nl = (void*)nl + next;
3457 }
3458 break;
3459 }
3460 case DM_DEV_WAIT:
3461 case DM_TABLE_STATUS:
3462 {
3463 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3464 void *cur_data = argptr;
3465 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3466 int spec_size = thunk_type_size(arg_type, 0);
3467 int i;
3468
3469 for (i = 0; i < host_dm->target_count; i++) {
3470 uint32_t next = spec->next;
3471 int slen = strlen((char*)&spec[1]) + 1;
3472 spec->next = (cur_data - argptr) + spec_size + slen;
3473 if (guest_data_size < spec->next) {
3474 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3475 break;
3476 }
3477 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3478 strcpy(cur_data + spec_size, (char*)&spec[1]);
3479 cur_data = argptr + spec->next;
3480 spec = (void*)host_dm + host_dm->data_start + next;
3481 }
3482 break;
3483 }
3484 case DM_TABLE_DEPS:
3485 {
3486 void *hdata = (void*)host_dm + host_dm->data_start;
3487 int count = *(uint32_t*)hdata;
3488 uint64_t *hdev = hdata + 8;
3489 uint64_t *gdev = argptr + 8;
3490 int i;
3491
3492 *(uint32_t*)argptr = tswap32(count);
3493 for (i = 0; i < count; i++) {
3494 *gdev = tswap64(*hdev);
3495 gdev++;
3496 hdev++;
3497 }
3498 break;
3499 }
3500 case DM_LIST_VERSIONS:
3501 {
3502 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3503 uint32_t remaining_data = guest_data_size;
3504 void *cur_data = argptr;
3505 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3506 int vers_size = thunk_type_size(arg_type, 0);
3507
3508 while (1) {
3509 uint32_t next = vers->next;
3510 if (next) {
3511 vers->next = vers_size + (strlen(vers->name) + 1);
3512 }
3513 if (remaining_data < vers->next) {
3514 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3515 break;
3516 }
3517 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3518 strcpy(cur_data + vers_size, vers->name);
3519 cur_data += vers->next;
3520 remaining_data -= vers->next;
3521 if (!next) {
3522 break;
3523 }
3524 vers = (void*)vers + next;
3525 }
3526 break;
3527 }
3528 default:
3529 ret = -TARGET_EINVAL;
3530 goto out;
3531 }
3532 unlock_user(argptr, guest_data, guest_data_size);
3533
3534 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3535 if (!argptr) {
3536 ret = -TARGET_EFAULT;
3537 goto out;
3538 }
3539 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3540 unlock_user(argptr, arg, target_size);
3541 }
3542out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003543 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003544 return ret;
3545}
3546
blueswir19f106a72008-10-05 10:52:52 +00003547static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003548#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003549 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3550#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3551 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003552#include "ioctls.h"
3553 { 0, 0, },
3554};
3555
pbrook53a59602006-03-25 19:31:22 +00003556/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003557/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003558static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003559{
3560 const IOCTLEntry *ie;
3561 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003562 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003563 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003564 int target_size;
3565 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003566
3567 ie = ioctl_entries;
3568 for(;;) {
3569 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003570 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003571 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003572 }
3573 if (ie->target_cmd == cmd)
3574 break;
3575 ie++;
3576 }
3577 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003578#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003579 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003580#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003581 if (ie->do_ioctl) {
3582 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3583 }
3584
bellard31e31b82003-02-18 22:55:36 +00003585 switch(arg_type[0]) {
3586 case TYPE_NULL:
3587 /* no argument */
3588 ret = get_errno(ioctl(fd, ie->host_cmd));
3589 break;
3590 case TYPE_PTRVOID:
3591 case TYPE_INT:
3592 /* int argment */
3593 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3594 break;
3595 case TYPE_PTR:
3596 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003597 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003598 switch(ie->access) {
3599 case IOC_R:
3600 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3601 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003602 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3603 if (!argptr)
3604 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003605 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3606 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003607 }
3608 break;
3609 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003610 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3611 if (!argptr)
3612 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003613 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3614 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003615 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3616 break;
3617 default:
3618 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003619 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3620 if (!argptr)
3621 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003622 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3623 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003624 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3625 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003626 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3627 if (!argptr)
3628 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003629 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3630 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003631 }
3632 break;
3633 }
3634 break;
3635 default:
j_mayer32407102007-09-26 23:01:49 +00003636 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3637 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003638 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003639 break;
3640 }
3641 return ret;
3642}
3643
blueswir1b39bc502008-10-05 10:51:10 +00003644static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003645 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3646 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3647 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3648 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3649 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3650 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3651 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3652 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3653 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3654 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3655 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3656 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3657 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3658 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3659 { 0, 0, 0, 0 }
3660};
3661
blueswir1b39bc502008-10-05 10:51:10 +00003662static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003663 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3664 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3665 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3666 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3667 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3668 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3669 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3670 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3671 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3672 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3673 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3674 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3675 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3676 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3677 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3678 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3679 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3680 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3681 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3682 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3683 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3684 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3685 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3686 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3687 { 0, 0, 0, 0 }
3688};
3689
blueswir1b39bc502008-10-05 10:51:10 +00003690static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003691 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3692 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3693 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3694 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3695 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3696 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3697 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3698 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3699 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3700 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3701 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3702 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3703 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3704 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3705 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3706 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3707 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3708 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3709 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3710 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3711 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3712 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3713 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3714 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3715 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3716 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3717 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3718 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3719 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3720 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3721 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3722 { 0, 0, 0, 0 }
3723};
3724
blueswir1b39bc502008-10-05 10:51:10 +00003725static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003726 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3727 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3728 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3729 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3730 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3731 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3732 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3733 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3734 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3735 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3736 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3737 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3738 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3739 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3740 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3741 { 0, 0, 0, 0 }
3742};
3743
3744static void target_to_host_termios (void *dst, const void *src)
3745{
3746 struct host_termios *host = dst;
3747 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003748
ths5fafdf22007-09-16 21:08:06 +00003749 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003750 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003751 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003752 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003753 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003754 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003755 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003756 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3757 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003758
Arnaud Patard44607122009-04-21 17:39:08 +03003759 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003760 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3761 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003762 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003763 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003764 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003765 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003766 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003767 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003768 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003769 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3770 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003771 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3772 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3773 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3774 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3775 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003776 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003777}
ths3b46e622007-09-17 08:09:54 +00003778
bellard31e31b82003-02-18 22:55:36 +00003779static void host_to_target_termios (void *dst, const void *src)
3780{
3781 struct target_termios *target = dst;
3782 const struct host_termios *host = src;
3783
ths5fafdf22007-09-16 21:08:06 +00003784 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003785 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003786 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003787 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003788 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003789 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003790 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003791 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3792 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003793
Arnaud Patard44607122009-04-21 17:39:08 +03003794 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003795 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3796 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3797 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3798 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3799 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3800 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3801 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3802 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3803 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3804 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3805 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3806 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3807 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3808 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3809 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3810 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3811 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3812}
3813
blueswir18e853dc2008-10-05 10:49:32 +00003814static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003815 .convert = { host_to_target_termios, target_to_host_termios },
3816 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3817 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3818};
3819
bellard5286db72003-06-05 00:57:30 +00003820static bitmask_transtbl mmap_flags_tbl[] = {
3821 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3822 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3823 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3824 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3825 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3826 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3827 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3828 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3829 { 0, 0, 0, 0 }
3830};
3831
bellard2ab83ea2003-06-15 19:56:46 +00003832#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003833
3834/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003835static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003836
bellard03acab62007-11-11 14:57:14 +00003837static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003838{
3839 int size;
pbrook53a59602006-03-25 19:31:22 +00003840 void *p;
bellard6dbad632003-03-16 18:05:05 +00003841
3842 if (!ldt_table)
3843 return 0;
3844 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3845 if (size > bytecount)
3846 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003847 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3848 if (!p)
bellard03acab62007-11-11 14:57:14 +00003849 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003850 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003851 memcpy(p, ldt_table, size);
3852 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003853 return size;
3854}
3855
3856/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003857static abi_long write_ldt(CPUX86State *env,
3858 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003859{
3860 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003861 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003862 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003863 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003864 uint32_t *lp, entry_1, entry_2;
3865
3866 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003867 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003868 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003869 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003870 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003871 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00003872 ldt_info.limit = tswap32(target_ldt_info->limit);
3873 ldt_info.flags = tswap32(target_ldt_info->flags);
3874 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003875
bellard6dbad632003-03-16 18:05:05 +00003876 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003877 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003878 seg_32bit = ldt_info.flags & 1;
3879 contents = (ldt_info.flags >> 1) & 3;
3880 read_exec_only = (ldt_info.flags >> 3) & 1;
3881 limit_in_pages = (ldt_info.flags >> 4) & 1;
3882 seg_not_present = (ldt_info.flags >> 5) & 1;
3883 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00003884#ifdef TARGET_ABI32
3885 lm = 0;
3886#else
3887 lm = (ldt_info.flags >> 7) & 1;
3888#endif
bellard6dbad632003-03-16 18:05:05 +00003889 if (contents == 3) {
3890 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00003891 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003892 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00003893 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003894 }
3895 /* allocate the LDT */
3896 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00003897 env->ldt.base = target_mmap(0,
3898 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
3899 PROT_READ|PROT_WRITE,
3900 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3901 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00003902 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00003903 memset(g2h(env->ldt.base), 0,
3904 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00003905 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00003906 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00003907 }
3908
3909 /* NOTE: same code as Linux kernel */
3910 /* Allow LDTs to be cleared by the user. */
3911 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3912 if (oldmode ||
3913 (contents == 0 &&
3914 read_exec_only == 1 &&
3915 seg_32bit == 0 &&
3916 limit_in_pages == 0 &&
3917 seg_not_present == 1 &&
3918 useable == 0 )) {
3919 entry_1 = 0;
3920 entry_2 = 0;
3921 goto install;
3922 }
3923 }
ths3b46e622007-09-17 08:09:54 +00003924
bellard6dbad632003-03-16 18:05:05 +00003925 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3926 (ldt_info.limit & 0x0ffff);
3927 entry_2 = (ldt_info.base_addr & 0xff000000) |
3928 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3929 (ldt_info.limit & 0xf0000) |
3930 ((read_exec_only ^ 1) << 9) |
3931 (contents << 10) |
3932 ((seg_not_present ^ 1) << 15) |
3933 (seg_32bit << 22) |
3934 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00003935 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00003936 0x7000;
3937 if (!oldmode)
3938 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00003939
bellard6dbad632003-03-16 18:05:05 +00003940 /* Install the new entry ... */
3941install:
3942 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
3943 lp[0] = tswap32(entry_1);
3944 lp[1] = tswap32(entry_2);
3945 return 0;
3946}
3947
3948/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00003949static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
3950 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003951{
bellard03acab62007-11-11 14:57:14 +00003952 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00003953
bellard6dbad632003-03-16 18:05:05 +00003954 switch (func) {
3955 case 0:
3956 ret = read_ldt(ptr, bytecount);
3957 break;
3958 case 1:
3959 ret = write_ldt(env, ptr, bytecount, 1);
3960 break;
3961 case 0x11:
3962 ret = write_ldt(env, ptr, bytecount, 0);
3963 break;
bellard03acab62007-11-11 14:57:14 +00003964 default:
3965 ret = -TARGET_ENOSYS;
3966 break;
bellard6dbad632003-03-16 18:05:05 +00003967 }
3968 return ret;
3969}
bellard1b6b0292003-03-22 17:31:38 +00003970
blueswir14583f582008-08-24 10:35:55 +00003971#if defined(TARGET_I386) && defined(TARGET_ABI32)
blueswir18fcd3692008-08-17 20:26:25 +00003972static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00003973{
3974 uint64_t *gdt_table = g2h(env->gdt.base);
3975 struct target_modify_ldt_ldt_s ldt_info;
3976 struct target_modify_ldt_ldt_s *target_ldt_info;
3977 int seg_32bit, contents, read_exec_only, limit_in_pages;
3978 int seg_not_present, useable, lm;
3979 uint32_t *lp, entry_1, entry_2;
3980 int i;
3981
3982 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
3983 if (!target_ldt_info)
3984 return -TARGET_EFAULT;
3985 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003986 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00003987 ldt_info.limit = tswap32(target_ldt_info->limit);
3988 ldt_info.flags = tswap32(target_ldt_info->flags);
3989 if (ldt_info.entry_number == -1) {
3990 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
3991 if (gdt_table[i] == 0) {
3992 ldt_info.entry_number = i;
3993 target_ldt_info->entry_number = tswap32(i);
3994 break;
3995 }
3996 }
3997 }
3998 unlock_user_struct(target_ldt_info, ptr, 1);
3999
4000 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4001 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4002 return -TARGET_EINVAL;
4003 seg_32bit = ldt_info.flags & 1;
4004 contents = (ldt_info.flags >> 1) & 3;
4005 read_exec_only = (ldt_info.flags >> 3) & 1;
4006 limit_in_pages = (ldt_info.flags >> 4) & 1;
4007 seg_not_present = (ldt_info.flags >> 5) & 1;
4008 useable = (ldt_info.flags >> 6) & 1;
4009#ifdef TARGET_ABI32
4010 lm = 0;
4011#else
4012 lm = (ldt_info.flags >> 7) & 1;
4013#endif
4014
4015 if (contents == 3) {
4016 if (seg_not_present == 0)
4017 return -TARGET_EINVAL;
4018 }
4019
4020 /* NOTE: same code as Linux kernel */
4021 /* Allow LDTs to be cleared by the user. */
4022 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4023 if ((contents == 0 &&
4024 read_exec_only == 1 &&
4025 seg_32bit == 0 &&
4026 limit_in_pages == 0 &&
4027 seg_not_present == 1 &&
4028 useable == 0 )) {
4029 entry_1 = 0;
4030 entry_2 = 0;
4031 goto install;
4032 }
4033 }
4034
4035 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4036 (ldt_info.limit & 0x0ffff);
4037 entry_2 = (ldt_info.base_addr & 0xff000000) |
4038 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4039 (ldt_info.limit & 0xf0000) |
4040 ((read_exec_only ^ 1) << 9) |
4041 (contents << 10) |
4042 ((seg_not_present ^ 1) << 15) |
4043 (seg_32bit << 22) |
4044 (limit_in_pages << 23) |
4045 (useable << 20) |
4046 (lm << 21) |
4047 0x7000;
4048
4049 /* Install the new entry ... */
4050install:
4051 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4052 lp[0] = tswap32(entry_1);
4053 lp[1] = tswap32(entry_2);
4054 return 0;
4055}
4056
blueswir18fcd3692008-08-17 20:26:25 +00004057static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004058{
4059 struct target_modify_ldt_ldt_s *target_ldt_info;
4060 uint64_t *gdt_table = g2h(env->gdt.base);
4061 uint32_t base_addr, limit, flags;
4062 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4063 int seg_not_present, useable, lm;
4064 uint32_t *lp, entry_1, entry_2;
4065
4066 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4067 if (!target_ldt_info)
4068 return -TARGET_EFAULT;
4069 idx = tswap32(target_ldt_info->entry_number);
4070 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4071 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4072 unlock_user_struct(target_ldt_info, ptr, 1);
4073 return -TARGET_EINVAL;
4074 }
4075 lp = (uint32_t *)(gdt_table + idx);
4076 entry_1 = tswap32(lp[0]);
4077 entry_2 = tswap32(lp[1]);
4078
4079 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4080 contents = (entry_2 >> 10) & 3;
4081 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4082 seg_32bit = (entry_2 >> 22) & 1;
4083 limit_in_pages = (entry_2 >> 23) & 1;
4084 useable = (entry_2 >> 20) & 1;
4085#ifdef TARGET_ABI32
4086 lm = 0;
4087#else
4088 lm = (entry_2 >> 21) & 1;
4089#endif
4090 flags = (seg_32bit << 0) | (contents << 1) |
4091 (read_exec_only << 3) | (limit_in_pages << 4) |
4092 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4093 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4094 base_addr = (entry_1 >> 16) |
4095 (entry_2 & 0xff000000) |
4096 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004097 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004098 target_ldt_info->limit = tswap32(limit);
4099 target_ldt_info->flags = tswap32(flags);
4100 unlock_user_struct(target_ldt_info, ptr, 1);
4101 return 0;
4102}
blueswir14583f582008-08-24 10:35:55 +00004103#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004104
bellardd2fd1af2007-11-14 18:08:56 +00004105#ifndef TARGET_ABI32
blueswir18fcd3692008-08-17 20:26:25 +00004106static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004107{
Juan Quintela1add8692011-06-16 17:37:09 +01004108 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004109 abi_ulong val;
4110 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004111
bellardd2fd1af2007-11-14 18:08:56 +00004112 switch(code) {
4113 case TARGET_ARCH_SET_GS:
4114 case TARGET_ARCH_SET_FS:
4115 if (code == TARGET_ARCH_SET_GS)
4116 idx = R_GS;
4117 else
4118 idx = R_FS;
4119 cpu_x86_load_seg(env, idx, 0);
4120 env->segs[idx].base = addr;
4121 break;
4122 case TARGET_ARCH_GET_GS:
4123 case TARGET_ARCH_GET_FS:
4124 if (code == TARGET_ARCH_GET_GS)
4125 idx = R_GS;
4126 else
4127 idx = R_FS;
4128 val = env->segs[idx].base;
4129 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004130 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004131 break;
4132 default:
4133 ret = -TARGET_EINVAL;
4134 break;
4135 }
Juan Quintela1add8692011-06-16 17:37:09 +01004136 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004137}
4138#endif
4139
bellard2ab83ea2003-06-15 19:56:46 +00004140#endif /* defined(TARGET_I386) */
4141
Riku Voipio05098a92011-03-04 15:27:29 +02004142#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004143
pbrookd865bab2008-06-07 22:12:17 +00004144
4145static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4146typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004147 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004148 pthread_mutex_t mutex;
4149 pthread_cond_t cond;
4150 pthread_t thread;
4151 uint32_t tid;
4152 abi_ulong child_tidptr;
4153 abi_ulong parent_tidptr;
4154 sigset_t sigmask;
4155} new_thread_info;
4156
4157static void *clone_func(void *arg)
4158{
4159 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004160 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004161 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004162 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004163
4164 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004165 cpu = ENV_GET_CPU(env);
pbrookd865bab2008-06-07 22:12:17 +00004166 thread_env = env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004167 ts = (TaskState *)thread_env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004168 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004169 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004170 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004171 if (info->child_tidptr)
4172 put_user_u32(info->tid, info->child_tidptr);
4173 if (info->parent_tidptr)
4174 put_user_u32(info->tid, info->parent_tidptr);
4175 /* Enable signals. */
4176 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4177 /* Signal to the parent that we're ready. */
4178 pthread_mutex_lock(&info->mutex);
4179 pthread_cond_broadcast(&info->cond);
4180 pthread_mutex_unlock(&info->mutex);
4181 /* Wait until the parent has finshed initializing the tls state. */
4182 pthread_mutex_lock(&clone_lock);
4183 pthread_mutex_unlock(&clone_lock);
4184 cpu_loop(env);
4185 /* never exits */
4186 return NULL;
4187}
bellard1b6b0292003-03-22 17:31:38 +00004188
ths0da46a62007-10-20 20:23:07 +00004189/* do_fork() Must return host values and target errnos (unlike most
4190 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004191static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004192 abi_ulong parent_tidptr, target_ulong newtls,
4193 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004194{
4195 int ret;
bellard5cd43932003-03-29 16:54:36 +00004196 TaskState *ts;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004197 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004198 unsigned int nptl_flags;
4199 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004200
balrog436d1242008-09-21 02:39:45 +00004201 /* Emulate vfork() with fork() */
4202 if (flags & CLONE_VFORK)
4203 flags &= ~(CLONE_VFORK | CLONE_VM);
4204
bellard1b6b0292003-03-22 17:31:38 +00004205 if (flags & CLONE_VM) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004206 TaskState *parent_ts = (TaskState *)env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004207 new_thread_info info;
4208 pthread_attr_t attr;
Peter Maydell4132e122013-07-05 16:37:04 +01004209
Anthony Liguori7267c092011-08-20 22:09:37 -05004210 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004211 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004212 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004213 new_env = cpu_copy(env);
Blue Swirlb4558d72009-11-07 16:34:12 +00004214#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
Andreas Färberff18b762012-05-05 14:47:34 +02004215 cpu_reset(ENV_GET_CPU(new_env));
Blue Swirlb4558d72009-11-07 16:34:12 +00004216#endif
pbrook6e68e072008-05-30 17:22:15 +00004217 /* Init regs that differ from the parent. */
4218 cpu_clone_regs(new_env, newsp);
bellard5cd43932003-03-29 16:54:36 +00004219 new_env->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004220 ts->bprm = parent_ts->bprm;
4221 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004222 nptl_flags = flags;
4223 flags &= ~CLONE_NPTL_FLAGS2;
4224
pbrookc2764712009-03-07 15:24:59 +00004225 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4226 ts->child_tidptr = child_tidptr;
4227 }
4228
pbrookd865bab2008-06-07 22:12:17 +00004229 if (nptl_flags & CLONE_SETTLS)
4230 cpu_set_tls (new_env, newtls);
4231
4232 /* Grab a mutex so that thread setup appears atomic. */
4233 pthread_mutex_lock(&clone_lock);
4234
4235 memset(&info, 0, sizeof(info));
4236 pthread_mutex_init(&info.mutex, NULL);
4237 pthread_mutex_lock(&info.mutex);
4238 pthread_cond_init(&info.cond, NULL);
4239 info.env = new_env;
4240 if (nptl_flags & CLONE_CHILD_SETTID)
4241 info.child_tidptr = child_tidptr;
4242 if (nptl_flags & CLONE_PARENT_SETTID)
4243 info.parent_tidptr = parent_tidptr;
4244
4245 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004246 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4247 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004248 /* It is not safe to deliver signals until the child has finished
4249 initializing, so temporarily block all signals. */
4250 sigfillset(&sigmask);
4251 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4252
4253 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004254 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004255
4256 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4257 pthread_attr_destroy(&attr);
4258 if (ret == 0) {
4259 /* Wait for the child to initialize. */
4260 pthread_cond_wait(&info.cond, &info.mutex);
4261 ret = info.tid;
4262 if (flags & CLONE_PARENT_SETTID)
4263 put_user_u32(ret, parent_tidptr);
4264 } else {
4265 ret = -1;
4266 }
4267 pthread_mutex_unlock(&info.mutex);
4268 pthread_cond_destroy(&info.cond);
4269 pthread_mutex_destroy(&info.mutex);
4270 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004271 } else {
4272 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004273 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004274 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004275 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004276 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004277 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004278 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004279 cpu_clone_regs(env, newsp);
4280 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004281 /* There is a race condition here. The parent process could
4282 theoretically read the TID in the child process before the child
4283 tid is set. This would require using either ptrace
4284 (not implemented) or having *_tidptr to point at a shared memory
4285 mapping. We can't repeat the spinlock hack used above because
4286 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004287 if (flags & CLONE_CHILD_SETTID)
4288 put_user_u32(gettid(), child_tidptr);
4289 if (flags & CLONE_PARENT_SETTID)
4290 put_user_u32(gettid(), parent_tidptr);
4291 ts = (TaskState *)env->opaque;
4292 if (flags & CLONE_SETTLS)
4293 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004294 if (flags & CLONE_CHILD_CLEARTID)
4295 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004296 } else {
4297 fork_end(0);
4298 }
bellard1b6b0292003-03-22 17:31:38 +00004299 }
4300 return ret;
4301}
4302
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004303/* warning : doesn't handle linux specific flags... */
4304static int target_to_host_fcntl_cmd(int cmd)
4305{
4306 switch(cmd) {
4307 case TARGET_F_DUPFD:
4308 case TARGET_F_GETFD:
4309 case TARGET_F_SETFD:
4310 case TARGET_F_GETFL:
4311 case TARGET_F_SETFL:
4312 return cmd;
4313 case TARGET_F_GETLK:
4314 return F_GETLK;
4315 case TARGET_F_SETLK:
4316 return F_SETLK;
4317 case TARGET_F_SETLKW:
4318 return F_SETLKW;
4319 case TARGET_F_GETOWN:
4320 return F_GETOWN;
4321 case TARGET_F_SETOWN:
4322 return F_SETOWN;
4323 case TARGET_F_GETSIG:
4324 return F_GETSIG;
4325 case TARGET_F_SETSIG:
4326 return F_SETSIG;
4327#if TARGET_ABI_BITS == 32
4328 case TARGET_F_GETLK64:
4329 return F_GETLK64;
4330 case TARGET_F_SETLK64:
4331 return F_SETLK64;
4332 case TARGET_F_SETLKW64:
4333 return F_SETLKW64;
4334#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004335 case TARGET_F_SETLEASE:
4336 return F_SETLEASE;
4337 case TARGET_F_GETLEASE:
4338 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004339#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004340 case TARGET_F_DUPFD_CLOEXEC:
4341 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004342#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004343 case TARGET_F_NOTIFY:
4344 return F_NOTIFY;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004345 default:
4346 return -TARGET_EINVAL;
4347 }
4348 return -TARGET_EINVAL;
4349}
4350
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004351#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4352static const bitmask_transtbl flock_tbl[] = {
4353 TRANSTBL_CONVERT(F_RDLCK),
4354 TRANSTBL_CONVERT(F_WRLCK),
4355 TRANSTBL_CONVERT(F_UNLCK),
4356 TRANSTBL_CONVERT(F_EXLCK),
4357 TRANSTBL_CONVERT(F_SHLCK),
4358 { 0, 0, 0, 0 }
4359};
4360
blueswir1992f48a2007-10-14 16:27:31 +00004361static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004362{
4363 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004364 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004365 struct flock64 fl64;
4366 struct target_flock64 *target_fl64;
blueswir1992f48a2007-10-14 16:27:31 +00004367 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004368 int host_cmd = target_to_host_fcntl_cmd(cmd);
4369
4370 if (host_cmd == -TARGET_EINVAL)
4371 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004372
bellard7775e9e2003-05-14 22:46:48 +00004373 switch(cmd) {
4374 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004375 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4376 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004377 fl.l_type =
4378 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004379 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004380 fl.l_start = tswapal(target_fl->l_start);
4381 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004382 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004383 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004384 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004385 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004386 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4387 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004388 target_fl->l_type =
4389 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004390 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004391 target_fl->l_start = tswapal(fl.l_start);
4392 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004393 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004394 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004395 }
4396 break;
ths3b46e622007-09-17 08:09:54 +00004397
bellard7775e9e2003-05-14 22:46:48 +00004398 case TARGET_F_SETLK:
4399 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004400 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4401 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004402 fl.l_type =
4403 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004404 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004405 fl.l_start = tswapal(target_fl->l_start);
4406 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004407 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004408 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004409 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004410 break;
ths3b46e622007-09-17 08:09:54 +00004411
bellard7775e9e2003-05-14 22:46:48 +00004412 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004413 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4414 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004415 fl64.l_type =
4416 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004417 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004418 fl64.l_start = tswap64(target_fl64->l_start);
4419 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004420 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004421 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004422 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004423 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004424 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4425 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004426 target_fl64->l_type =
4427 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004428 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004429 target_fl64->l_start = tswap64(fl64.l_start);
4430 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004431 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004432 unlock_user_struct(target_fl64, arg, 1);
4433 }
bellard9ee1fa22007-11-11 15:11:19 +00004434 break;
bellard7775e9e2003-05-14 22:46:48 +00004435 case TARGET_F_SETLK64:
4436 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004437 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4438 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004439 fl64.l_type =
4440 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004441 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004442 fl64.l_start = tswap64(target_fl64->l_start);
4443 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004444 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004445 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004446 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004447 break;
4448
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004449 case TARGET_F_GETFL:
4450 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004451 if (ret >= 0) {
4452 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4453 }
bellardffa65c32004-01-04 23:57:22 +00004454 break;
4455
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004456 case TARGET_F_SETFL:
4457 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4458 break;
4459
4460 case TARGET_F_SETOWN:
4461 case TARGET_F_GETOWN:
4462 case TARGET_F_SETSIG:
4463 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004464 case TARGET_F_SETLEASE:
4465 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004466 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004467 break;
4468
bellard7775e9e2003-05-14 22:46:48 +00004469 default:
bellard9ee1fa22007-11-11 15:11:19 +00004470 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004471 break;
4472 }
4473 return ret;
4474}
4475
bellard67867302003-11-23 17:05:30 +00004476#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004477
bellard67867302003-11-23 17:05:30 +00004478static inline int high2lowuid(int uid)
4479{
4480 if (uid > 65535)
4481 return 65534;
4482 else
4483 return uid;
4484}
4485
4486static inline int high2lowgid(int gid)
4487{
4488 if (gid > 65535)
4489 return 65534;
4490 else
4491 return gid;
4492}
4493
4494static inline int low2highuid(int uid)
4495{
4496 if ((int16_t)uid == -1)
4497 return -1;
4498 else
4499 return uid;
4500}
4501
4502static inline int low2highgid(int gid)
4503{
4504 if ((int16_t)gid == -1)
4505 return -1;
4506 else
4507 return gid;
4508}
Riku Voipio0c866a72011-04-18 15:23:06 +03004509static inline int tswapid(int id)
4510{
4511 return tswap16(id);
4512}
4513#else /* !USE_UID16 */
4514static inline int high2lowuid(int uid)
4515{
4516 return uid;
4517}
4518static inline int high2lowgid(int gid)
4519{
4520 return gid;
4521}
4522static inline int low2highuid(int uid)
4523{
4524 return uid;
4525}
4526static inline int low2highgid(int gid)
4527{
4528 return gid;
4529}
4530static inline int tswapid(int id)
4531{
4532 return tswap32(id);
4533}
bellard67867302003-11-23 17:05:30 +00004534#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004535
bellard31e31b82003-02-18 22:55:36 +00004536void syscall_init(void)
4537{
bellard2ab83ea2003-06-15 19:56:46 +00004538 IOCTLEntry *ie;
4539 const argtype *arg_type;
4540 int size;
thsb92c47c2007-11-01 00:07:38 +00004541 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004542
Blue Swirl001faf32009-05-13 17:53:17 +00004543#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004544#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004545#include "syscall_types.h"
4546#undef STRUCT
4547#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004548
Peter Maydelldd6e9572012-07-23 08:07:22 +00004549 /* Build target_to_host_errno_table[] table from
4550 * host_to_target_errno_table[]. */
4551 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4552 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4553 }
4554
bellard2ab83ea2003-06-15 19:56:46 +00004555 /* we patch the ioctl size if necessary. We rely on the fact that
4556 no ioctl has all the bits at '1' in the size field */
4557 ie = ioctl_entries;
4558 while (ie->target_cmd != 0) {
4559 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4560 TARGET_IOC_SIZEMASK) {
4561 arg_type = ie->arg_type;
4562 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004563 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004564 ie->target_cmd);
4565 exit(1);
4566 }
4567 arg_type++;
4568 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004569 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004570 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4571 (size << TARGET_IOC_SIZESHIFT);
4572 }
thsb92c47c2007-11-01 00:07:38 +00004573
bellard2ab83ea2003-06-15 19:56:46 +00004574 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004575#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4576 (defined(__x86_64__) && defined(TARGET_X86_64))
4577 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4578 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4579 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004580 }
4581#endif
4582 ie++;
4583 }
bellard31e31b82003-02-18 22:55:36 +00004584}
bellardc573ff62004-01-04 15:51:36 +00004585
blueswir1992f48a2007-10-14 16:27:31 +00004586#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004587static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4588{
thsaf325d32008-06-10 15:29:15 +00004589#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004590 return ((uint64_t)word0 << 32) | word1;
4591#else
4592 return ((uint64_t)word1 << 32) | word0;
4593#endif
4594}
blueswir1992f48a2007-10-14 16:27:31 +00004595#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004596static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4597{
4598 return word0;
4599}
blueswir1992f48a2007-10-14 16:27:31 +00004600#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004601
4602#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004603static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4604 abi_long arg2,
4605 abi_long arg3,
4606 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004607{
Riku Voipio48e515d2011-07-12 15:40:51 +03004608 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004609 arg2 = arg3;
4610 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004611 }
pbrookce4defa2006-02-09 16:49:55 +00004612 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4613}
4614#endif
4615
4616#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004617static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4618 abi_long arg2,
4619 abi_long arg3,
4620 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004621{
Riku Voipio48e515d2011-07-12 15:40:51 +03004622 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004623 arg2 = arg3;
4624 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004625 }
pbrookce4defa2006-02-09 16:49:55 +00004626 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4627}
4628#endif
4629
bellard579a97f2007-11-11 14:26:47 +00004630static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4631 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004632{
4633 struct target_timespec *target_ts;
4634
bellard579a97f2007-11-11 14:26:47 +00004635 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4636 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004637 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4638 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004639 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004640 return 0;
pbrook53a59602006-03-25 19:31:22 +00004641}
4642
bellard579a97f2007-11-11 14:26:47 +00004643static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4644 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004645{
4646 struct target_timespec *target_ts;
4647
bellard579a97f2007-11-11 14:26:47 +00004648 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4649 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004650 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4651 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004652 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004653 return 0;
pbrook53a59602006-03-25 19:31:22 +00004654}
4655
aurel329d33b762009-04-08 23:07:05 +00004656#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004657static inline abi_long host_to_target_stat64(void *cpu_env,
4658 abi_ulong target_addr,
4659 struct stat *host_st)
4660{
4661#ifdef TARGET_ARM
4662 if (((CPUARMState *)cpu_env)->eabi) {
4663 struct target_eabi_stat64 *target_st;
4664
4665 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4666 return -TARGET_EFAULT;
4667 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4668 __put_user(host_st->st_dev, &target_st->st_dev);
4669 __put_user(host_st->st_ino, &target_st->st_ino);
4670#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4671 __put_user(host_st->st_ino, &target_st->__st_ino);
4672#endif
4673 __put_user(host_st->st_mode, &target_st->st_mode);
4674 __put_user(host_st->st_nlink, &target_st->st_nlink);
4675 __put_user(host_st->st_uid, &target_st->st_uid);
4676 __put_user(host_st->st_gid, &target_st->st_gid);
4677 __put_user(host_st->st_rdev, &target_st->st_rdev);
4678 __put_user(host_st->st_size, &target_st->st_size);
4679 __put_user(host_st->st_blksize, &target_st->st_blksize);
4680 __put_user(host_st->st_blocks, &target_st->st_blocks);
4681 __put_user(host_st->st_atime, &target_st->target_st_atime);
4682 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4683 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4684 unlock_user_struct(target_st, target_addr, 1);
4685 } else
4686#endif
4687 {
Richard Hendersoned18c5c2010-04-26 10:27:22 -07004688#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
aurel329d33b762009-04-08 23:07:05 +00004689 struct target_stat *target_st;
4690#else
balrog6a24a772008-09-20 02:23:36 +00004691 struct target_stat64 *target_st;
aurel329d33b762009-04-08 23:07:05 +00004692#endif
balrog6a24a772008-09-20 02:23:36 +00004693
4694 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4695 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004696 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004697 __put_user(host_st->st_dev, &target_st->st_dev);
4698 __put_user(host_st->st_ino, &target_st->st_ino);
4699#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4700 __put_user(host_st->st_ino, &target_st->__st_ino);
4701#endif
4702 __put_user(host_st->st_mode, &target_st->st_mode);
4703 __put_user(host_st->st_nlink, &target_st->st_nlink);
4704 __put_user(host_st->st_uid, &target_st->st_uid);
4705 __put_user(host_st->st_gid, &target_st->st_gid);
4706 __put_user(host_st->st_rdev, &target_st->st_rdev);
4707 /* XXX: better use of kernel struct */
4708 __put_user(host_st->st_size, &target_st->st_size);
4709 __put_user(host_st->st_blksize, &target_st->st_blksize);
4710 __put_user(host_st->st_blocks, &target_st->st_blocks);
4711 __put_user(host_st->st_atime, &target_st->target_st_atime);
4712 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4713 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4714 unlock_user_struct(target_st, target_addr, 1);
4715 }
4716
4717 return 0;
4718}
4719#endif
4720
pbrookbd0c5662008-05-29 14:34:11 +00004721/* ??? Using host futex calls even when target atomic operations
4722 are not really atomic probably breaks things. However implementing
4723 futexes locally would make futexes shared between multiple processes
4724 tricky. However they're probably useless because guest atomic
4725 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004726static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4727 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004728{
4729 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004730 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004731
4732 /* ??? We assume FUTEX_* constants are the same on both host
4733 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004734#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004735 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004736#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004737 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004738#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004739 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004740 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07004741 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00004742 if (timeout) {
4743 pts = &ts;
4744 target_to_host_timespec(pts, timeout);
4745 } else {
4746 pts = NULL;
4747 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004748 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07004749 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00004750 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004751 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004752 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004753 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004754 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004755 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004756 case FUTEX_WAKE_OP:
4757 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4758 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4759 But the prototype takes a `struct timespec *'; insert casts
4760 to satisfy the compiler. We do not need to tswap TIMEOUT
4761 since it's not compared to guest memory. */
4762 pts = (struct timespec *)(uintptr_t) timeout;
4763 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4764 g2h(uaddr2),
4765 (base_op == FUTEX_CMP_REQUEUE
4766 ? tswap32(val3)
4767 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004768 default:
4769 return -TARGET_ENOSYS;
4770 }
4771}
pbrookbd0c5662008-05-29 14:34:11 +00004772
pbrook1d9d8b52009-04-16 15:17:02 +00004773/* Map host to target signal numbers for the wait family of syscalls.
4774 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07004775int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00004776{
4777 if (WIFSIGNALED(status)) {
4778 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4779 }
4780 if (WIFSTOPPED(status)) {
4781 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4782 | (status & 0xff);
4783 }
4784 return status;
4785}
4786
pbrooka745ec62008-05-06 15:36:17 +00004787int get_osversion(void)
4788{
4789 static int osversion;
4790 struct new_utsname buf;
4791 const char *s;
4792 int i, n, tmp;
4793 if (osversion)
4794 return osversion;
4795 if (qemu_uname_release && *qemu_uname_release) {
4796 s = qemu_uname_release;
4797 } else {
4798 if (sys_uname(&buf))
4799 return 0;
4800 s = buf.release;
4801 }
4802 tmp = 0;
4803 for (i = 0; i < 3; i++) {
4804 n = 0;
4805 while (*s >= '0' && *s <= '9') {
4806 n *= 10;
4807 n += *s - '0';
4808 s++;
4809 }
4810 tmp = (tmp << 8) + n;
4811 if (*s == '.')
4812 s++;
4813 }
4814 osversion = tmp;
4815 return osversion;
4816}
4817
Alexander Graf36c08d42011-11-02 20:23:24 +01004818
4819static int open_self_maps(void *cpu_env, int fd)
4820{
Alexander Graf1a49ef22012-05-01 16:30:28 +01004821#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Andreas Färber9349b4f2012-03-14 01:38:32 +01004822 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01004823#endif
4824 FILE *fp;
4825 char *line = NULL;
4826 size_t len = 0;
4827 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01004828
Alexander Graf1a49ef22012-05-01 16:30:28 +01004829 fp = fopen("/proc/self/maps", "r");
4830 if (fp == NULL) {
4831 return -EACCES;
4832 }
4833
4834 while ((read = getline(&line, &len, fp)) != -1) {
4835 int fields, dev_maj, dev_min, inode;
4836 uint64_t min, max, offset;
4837 char flag_r, flag_w, flag_x, flag_p;
4838 char path[512] = "";
4839 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
4840 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
4841 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
4842
4843 if ((fields < 10) || (fields > 11)) {
4844 continue;
4845 }
4846 if (!strncmp(path, "[stack]", 7)) {
4847 continue;
4848 }
4849 if (h2g_valid(min) && h2g_valid(max)) {
4850 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02004851 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Alexander Graf1a49ef22012-05-01 16:30:28 +01004852 h2g(min), h2g(max), flag_r, flag_w,
4853 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02004854 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01004855 }
4856 }
4857
4858 free(line);
4859 fclose(fp);
4860
4861#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Alexander Graf36c08d42011-11-02 20:23:24 +01004862 dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
4863 (unsigned long long)ts->info->stack_limit,
Alexander Graf1bdd7c72012-05-30 14:45:21 +02004864 (unsigned long long)(ts->info->start_stack +
4865 (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK,
Alexander Graf1a49ef22012-05-01 16:30:28 +01004866 (unsigned long long)0);
4867#endif
Alexander Graf36c08d42011-11-02 20:23:24 +01004868
4869 return 0;
4870}
4871
Alexander Graf480b8e72011-11-02 20:23:25 +01004872static int open_self_stat(void *cpu_env, int fd)
4873{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004874 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01004875 abi_ulong start_stack = ts->info->start_stack;
4876 int i;
4877
4878 for (i = 0; i < 44; i++) {
4879 char buf[128];
4880 int len;
4881 uint64_t val = 0;
4882
Fabio Erculianie0e65be2012-01-03 09:38:34 +00004883 if (i == 0) {
4884 /* pid */
4885 val = getpid();
4886 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
4887 } else if (i == 1) {
4888 /* app name */
4889 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
4890 } else if (i == 27) {
4891 /* stack bottom */
4892 val = start_stack;
4893 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
4894 } else {
4895 /* for the rest, there is MasterCard */
4896 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01004897 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00004898
Alexander Graf480b8e72011-11-02 20:23:25 +01004899 len = strlen(buf);
4900 if (write(fd, buf, len) != len) {
4901 return -1;
4902 }
4903 }
4904
4905 return 0;
4906}
4907
Alexander Graf257450e2011-11-02 20:23:26 +01004908static int open_self_auxv(void *cpu_env, int fd)
4909{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004910 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01004911 abi_ulong auxv = ts->info->saved_auxv;
4912 abi_ulong len = ts->info->auxv_len;
4913 char *ptr;
4914
4915 /*
4916 * Auxiliary vector is stored in target process stack.
4917 * read in whole auxv vector and copy it to file
4918 */
4919 ptr = lock_user(VERIFY_READ, auxv, len, 0);
4920 if (ptr != NULL) {
4921 while (len > 0) {
4922 ssize_t r;
4923 r = write(fd, ptr, len);
4924 if (r <= 0) {
4925 break;
4926 }
4927 len -= r;
4928 ptr += r;
4929 }
4930 lseek(fd, 0, SEEK_SET);
4931 unlock_user(ptr, auxv, len);
4932 }
4933
4934 return 0;
4935}
4936
Alexander Graf3be14d02011-11-02 20:23:23 +01004937static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
4938{
4939 struct fake_open {
4940 const char *filename;
4941 int (*fill)(void *cpu_env, int fd);
4942 };
4943 const struct fake_open *fake_open;
4944 static const struct fake_open fakes[] = {
Alexander Graf36c08d42011-11-02 20:23:24 +01004945 { "/proc/self/maps", open_self_maps },
Alexander Graf480b8e72011-11-02 20:23:25 +01004946 { "/proc/self/stat", open_self_stat },
Alexander Graf257450e2011-11-02 20:23:26 +01004947 { "/proc/self/auxv", open_self_auxv },
Alexander Graf3be14d02011-11-02 20:23:23 +01004948 { NULL, NULL }
4949 };
4950
4951 for (fake_open = fakes; fake_open->filename; fake_open++) {
4952 if (!strncmp(pathname, fake_open->filename,
4953 strlen(fake_open->filename))) {
4954 break;
4955 }
4956 }
4957
4958 if (fake_open->filename) {
4959 const char *tmpdir;
4960 char filename[PATH_MAX];
4961 int fd, r;
4962
4963 /* create temporary file to map stat to */
4964 tmpdir = getenv("TMPDIR");
4965 if (!tmpdir)
4966 tmpdir = "/tmp";
4967 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
4968 fd = mkstemp(filename);
4969 if (fd < 0) {
4970 return fd;
4971 }
4972 unlink(filename);
4973
4974 if ((r = fake_open->fill(cpu_env, fd))) {
4975 close(fd);
4976 return r;
4977 }
4978 lseek(fd, 0, SEEK_SET);
4979
4980 return fd;
4981 }
4982
4983 return get_errno(open(path(pathname), flags, mode));
4984}
4985
ths0da46a62007-10-20 20:23:07 +00004986/* do_syscall() should always have a single exit point at the end so
4987 that actions, such as logging of syscall results, can be performed.
4988 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00004989abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
4990 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01004991 abi_long arg5, abi_long arg6, abi_long arg7,
4992 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00004993{
blueswir1992f48a2007-10-14 16:27:31 +00004994 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004995 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00004996 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00004997 void *p;
ths3b46e622007-09-17 08:09:54 +00004998
bellard72f03902003-02-18 23:33:18 +00004999#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005000 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005001#endif
thsb92c47c2007-11-01 00:07:38 +00005002 if(do_strace)
5003 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5004
bellard31e31b82003-02-18 22:55:36 +00005005 switch(num) {
5006 case TARGET_NR_exit:
pbrookc2764712009-03-07 15:24:59 +00005007 /* In old applications this may be used to implement _exit(2).
5008 However in threaded applictions it is used for thread termination,
5009 and _exit_group is used for application termination.
5010 Do thread termination if we have more then one thread. */
5011 /* FIXME: This probably breaks if a signal arrives. We should probably
5012 be disabling signals. */
5013 if (first_cpu->next_cpu) {
Nathan Froyd1e9fa732009-06-03 11:33:08 -07005014 TaskState *ts;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005015 CPUArchState **lastp;
5016 CPUArchState *p;
pbrookc2764712009-03-07 15:24:59 +00005017
5018 cpu_list_lock();
5019 lastp = &first_cpu;
5020 p = first_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005021 while (p && p != (CPUArchState *)cpu_env) {
pbrookc2764712009-03-07 15:24:59 +00005022 lastp = &p->next_cpu;
5023 p = p->next_cpu;
5024 }
5025 /* If we didn't find the CPU for this thread then something is
5026 horribly wrong. */
5027 if (!p)
5028 abort();
5029 /* Remove the CPU from the list. */
5030 *lastp = p->next_cpu;
5031 cpu_list_unlock();
Andreas Färber9349b4f2012-03-14 01:38:32 +01005032 ts = ((CPUArchState *)cpu_env)->opaque;
pbrookc2764712009-03-07 15:24:59 +00005033 if (ts->child_tidptr) {
5034 put_user_u32(0, ts->child_tidptr);
5035 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5036 NULL, NULL, 0);
5037 }
Nathan Froyd48e15fc2010-10-29 07:48:57 -07005038 thread_env = NULL;
Paolo Bonzini5c099532013-01-25 14:12:38 +01005039 object_unref(OBJECT(ENV_GET_CPU(cpu_env)));
Anthony Liguori7267c092011-08-20 22:09:37 -05005040 g_free(ts);
pbrookc2764712009-03-07 15:24:59 +00005041 pthread_exit(NULL);
5042 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005043#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005044 _mcleanup();
5045#endif
bellarde9009672005-04-26 20:42:36 +00005046 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005047 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005048 ret = 0; /* avoid warning */
5049 break;
5050 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005051 if (arg3 == 0)
5052 ret = 0;
5053 else {
5054 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5055 goto efault;
5056 ret = get_errno(read(arg1, p, arg3));
5057 unlock_user(p, arg2, ret);
5058 }
bellard31e31b82003-02-18 22:55:36 +00005059 break;
5060 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005061 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5062 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005063 ret = get_errno(write(arg1, p, arg3));
5064 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005065 break;
5066 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005067 if (!(p = lock_user_string(arg1)))
5068 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005069 ret = get_errno(do_open(cpu_env, p,
5070 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5071 arg3));
pbrook53a59602006-03-25 19:31:22 +00005072 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005073 break;
ths82424832007-09-24 09:21:55 +00005074#if defined(TARGET_NR_openat) && defined(__NR_openat)
5075 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005076 if (!(p = lock_user_string(arg2)))
5077 goto efault;
5078 ret = get_errno(sys_openat(arg1,
5079 path(p),
5080 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5081 arg4));
5082 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005083 break;
5084#endif
bellard31e31b82003-02-18 22:55:36 +00005085 case TARGET_NR_close:
5086 ret = get_errno(close(arg1));
5087 break;
5088 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005089 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005090 break;
5091 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005092 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005093 break;
thse5febef2007-04-01 18:31:35 +00005094#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005095 case TARGET_NR_waitpid:
5096 {
pbrook53a59602006-03-25 19:31:22 +00005097 int status;
5098 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005099 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005100 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005101 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005102 }
5103 break;
thse5febef2007-04-01 18:31:35 +00005104#endif
pbrookf0cbb612008-05-30 18:20:05 +00005105#ifdef TARGET_NR_waitid
5106 case TARGET_NR_waitid:
5107 {
5108 siginfo_t info;
5109 info.si_pid = 0;
5110 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5111 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005112 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005113 goto efault;
5114 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005115 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005116 }
5117 }
5118 break;
5119#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005120#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005121 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005122 if (!(p = lock_user_string(arg1)))
5123 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005124 ret = get_errno(creat(p, arg2));
5125 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005126 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005127#endif
bellard31e31b82003-02-18 22:55:36 +00005128 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005129 {
5130 void * p2;
5131 p = lock_user_string(arg1);
5132 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005133 if (!p || !p2)
5134 ret = -TARGET_EFAULT;
5135 else
5136 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005137 unlock_user(p2, arg2, 0);
5138 unlock_user(p, arg1, 0);
5139 }
bellard31e31b82003-02-18 22:55:36 +00005140 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005141#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00005142 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005143 {
5144 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005145 if (!arg2 || !arg4)
5146 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005147 p = lock_user_string(arg2);
5148 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005149 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005150 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005151 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005152 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005153 unlock_user(p, arg2, 0);
5154 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005155 }
5156 break;
5157#endif
bellard31e31b82003-02-18 22:55:36 +00005158 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005159 if (!(p = lock_user_string(arg1)))
5160 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005161 ret = get_errno(unlink(p));
5162 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005163 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005164#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00005165 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005166 if (!(p = lock_user_string(arg2)))
5167 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005168 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005169 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005170 break;
balrogb7d35e62007-12-12 00:40:24 +00005171#endif
bellard31e31b82003-02-18 22:55:36 +00005172 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005173 {
5174 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005175 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005176 abi_ulong gp;
5177 abi_ulong guest_argp;
5178 abi_ulong guest_envp;
5179 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005180 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005181 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005182
bellardf7341ff2003-03-30 21:00:25 +00005183 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005184 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005185 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005186 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005187 goto efault;
ths03aa1972007-12-02 06:28:08 +00005188 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005189 break;
bellard7854b052003-03-29 17:22:23 +00005190 argc++;
bellard2f619692007-11-16 10:46:05 +00005191 }
bellardf7341ff2003-03-30 21:00:25 +00005192 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005193 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005194 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005195 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005196 goto efault;
ths03aa1972007-12-02 06:28:08 +00005197 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005198 break;
bellard7854b052003-03-29 17:22:23 +00005199 envc++;
bellard2f619692007-11-16 10:46:05 +00005200 }
bellard7854b052003-03-29 17:22:23 +00005201
bellardf7341ff2003-03-30 21:00:25 +00005202 argp = alloca((argc + 1) * sizeof(void *));
5203 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005204
pbrookda94d262008-05-30 18:24:00 +00005205 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005206 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005207 if (get_user_ual(addr, gp))
5208 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005209 if (!addr)
5210 break;
bellard2f619692007-11-16 10:46:05 +00005211 if (!(*q = lock_user_string(addr)))
5212 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005213 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005214 }
bellardf7341ff2003-03-30 21:00:25 +00005215 *q = NULL;
5216
pbrookda94d262008-05-30 18:24:00 +00005217 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005218 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005219 if (get_user_ual(addr, gp))
5220 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005221 if (!addr)
5222 break;
bellard2f619692007-11-16 10:46:05 +00005223 if (!(*q = lock_user_string(addr)))
5224 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005225 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005226 }
bellardf7341ff2003-03-30 21:00:25 +00005227 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005228
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005229 /* This case will not be caught by the host's execve() if its
5230 page size is bigger than the target's. */
5231 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5232 ret = -TARGET_E2BIG;
5233 goto execve_end;
5234 }
bellard2f619692007-11-16 10:46:05 +00005235 if (!(p = lock_user_string(arg1)))
5236 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005237 ret = get_errno(execve(p, argp, envp));
5238 unlock_user(p, arg1, 0);
5239
bellard2f619692007-11-16 10:46:05 +00005240 goto execve_end;
5241
5242 execve_efault:
5243 ret = -TARGET_EFAULT;
5244
5245 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005246 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005247 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005248 if (get_user_ual(addr, gp)
5249 || !addr)
5250 break;
pbrook53a59602006-03-25 19:31:22 +00005251 unlock_user(*q, addr, 0);
5252 }
5253 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005254 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005255 if (get_user_ual(addr, gp)
5256 || !addr)
5257 break;
pbrook53a59602006-03-25 19:31:22 +00005258 unlock_user(*q, addr, 0);
5259 }
bellard7854b052003-03-29 17:22:23 +00005260 }
bellard31e31b82003-02-18 22:55:36 +00005261 break;
5262 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005263 if (!(p = lock_user_string(arg1)))
5264 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005265 ret = get_errno(chdir(p));
5266 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005267 break;
bellarda315a142005-01-30 22:59:18 +00005268#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005269 case TARGET_NR_time:
5270 {
pbrook53a59602006-03-25 19:31:22 +00005271 time_t host_time;
5272 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005273 if (!is_error(ret)
5274 && arg1
5275 && put_user_sal(host_time, arg1))
5276 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005277 }
5278 break;
bellarda315a142005-01-30 22:59:18 +00005279#endif
bellard31e31b82003-02-18 22:55:36 +00005280 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005281 if (!(p = lock_user_string(arg1)))
5282 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005283 ret = get_errno(mknod(p, arg2, arg3));
5284 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005285 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005286#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00005287 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005288 if (!(p = lock_user_string(arg2)))
5289 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005290 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00005291 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005292 break;
5293#endif
bellard31e31b82003-02-18 22:55:36 +00005294 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005295 if (!(p = lock_user_string(arg1)))
5296 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005297 ret = get_errno(chmod(p, arg2));
5298 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005299 break;
bellardebc05482003-09-30 21:08:41 +00005300#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005301 case TARGET_NR_break:
5302 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005303#endif
5304#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005305 case TARGET_NR_oldstat:
5306 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005307#endif
bellard31e31b82003-02-18 22:55:36 +00005308 case TARGET_NR_lseek:
5309 ret = get_errno(lseek(arg1, arg2, arg3));
5310 break;
Richard Henderson92317332010-05-03 10:07:53 -07005311#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5312 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005313 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005314 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005315 ret = get_errno(getpid());
5316 break;
Richard Henderson92317332010-05-03 10:07:53 -07005317#endif
5318#ifdef TARGET_NR_getpid
5319 case TARGET_NR_getpid:
5320 ret = get_errno(getpid());
5321 break;
5322#endif
bellard31e31b82003-02-18 22:55:36 +00005323 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00005324 {
5325 /* need to look at the data field */
5326 void *p2, *p3;
5327 p = lock_user_string(arg1);
5328 p2 = lock_user_string(arg2);
5329 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005330 if (!p || !p2 || !p3)
5331 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005332 else {
bellard579a97f2007-11-11 14:26:47 +00005333 /* FIXME - arg5 should be locked, but it isn't clear how to
5334 * do that since it's not guaranteed to be a NULL-terminated
5335 * string.
5336 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005337 if ( ! arg5 )
5338 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
5339 else
5340 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
5341 }
bellard579a97f2007-11-11 14:26:47 +00005342 unlock_user(p, arg1, 0);
5343 unlock_user(p2, arg2, 0);
5344 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00005345 break;
5346 }
thse5febef2007-04-01 18:31:35 +00005347#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005348 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005349 if (!(p = lock_user_string(arg1)))
5350 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005351 ret = get_errno(umount(p));
5352 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005353 break;
thse5febef2007-04-01 18:31:35 +00005354#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005355#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005356 case TARGET_NR_stime:
5357 {
pbrook53a59602006-03-25 19:31:22 +00005358 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005359 if (get_user_sal(host_time, arg1))
5360 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005361 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005362 }
5363 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005364#endif
bellard31e31b82003-02-18 22:55:36 +00005365 case TARGET_NR_ptrace:
5366 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005367#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005368 case TARGET_NR_alarm:
5369 ret = alarm(arg1);
5370 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005371#endif
bellardebc05482003-09-30 21:08:41 +00005372#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005373 case TARGET_NR_oldfstat:
5374 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005375#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005376#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005377 case TARGET_NR_pause:
5378 ret = get_errno(pause());
5379 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005380#endif
thse5febef2007-04-01 18:31:35 +00005381#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005382 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005383 {
pbrook53a59602006-03-25 19:31:22 +00005384 struct utimbuf tbuf, *host_tbuf;
5385 struct target_utimbuf *target_tbuf;
5386 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005387 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5388 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005389 tbuf.actime = tswapal(target_tbuf->actime);
5390 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005391 unlock_user_struct(target_tbuf, arg2, 0);
5392 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005393 } else {
pbrook53a59602006-03-25 19:31:22 +00005394 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005395 }
bellard579a97f2007-11-11 14:26:47 +00005396 if (!(p = lock_user_string(arg1)))
5397 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005398 ret = get_errno(utime(p, host_tbuf));
5399 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005400 }
5401 break;
thse5febef2007-04-01 18:31:35 +00005402#endif
bellard978a66f2004-12-06 22:58:05 +00005403 case TARGET_NR_utimes:
5404 {
bellard978a66f2004-12-06 22:58:05 +00005405 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005406 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005407 if (copy_from_user_timeval(&tv[0], arg2)
5408 || copy_from_user_timeval(&tv[1],
5409 arg2 + sizeof(struct target_timeval)))
5410 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005411 tvp = tv;
5412 } else {
5413 tvp = NULL;
5414 }
bellard579a97f2007-11-11 14:26:47 +00005415 if (!(p = lock_user_string(arg1)))
5416 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005417 ret = get_errno(utimes(p, tvp));
5418 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005419 }
5420 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005421#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00005422 case TARGET_NR_futimesat:
5423 {
5424 struct timeval *tvp, tv[2];
5425 if (arg3) {
5426 if (copy_from_user_timeval(&tv[0], arg3)
5427 || copy_from_user_timeval(&tv[1],
5428 arg3 + sizeof(struct target_timeval)))
5429 goto efault;
5430 tvp = tv;
5431 } else {
5432 tvp = NULL;
5433 }
5434 if (!(p = lock_user_string(arg2)))
5435 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005436 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00005437 unlock_user(p, arg2, 0);
5438 }
5439 break;
5440#endif
bellardebc05482003-09-30 21:08:41 +00005441#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005442 case TARGET_NR_stty:
5443 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005444#endif
5445#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005446 case TARGET_NR_gtty:
5447 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005448#endif
bellard31e31b82003-02-18 22:55:36 +00005449 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005450 if (!(p = lock_user_string(arg1)))
5451 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005452 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005453 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005454 break;
ths92a34c12007-09-24 09:27:49 +00005455#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5456 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005457 if (!(p = lock_user_string(arg2)))
5458 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005459 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00005460 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005461 break;
5462#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005463#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005464 case TARGET_NR_nice:
5465 ret = get_errno(nice(arg1));
5466 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005467#endif
bellardebc05482003-09-30 21:08:41 +00005468#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005469 case TARGET_NR_ftime:
5470 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005471#endif
bellard31e31b82003-02-18 22:55:36 +00005472 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005473 sync();
5474 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005475 break;
5476 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005477 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005478 break;
5479 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005480 {
5481 void *p2;
5482 p = lock_user_string(arg1);
5483 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005484 if (!p || !p2)
5485 ret = -TARGET_EFAULT;
5486 else
5487 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005488 unlock_user(p2, arg2, 0);
5489 unlock_user(p, arg1, 0);
5490 }
bellard31e31b82003-02-18 22:55:36 +00005491 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005492#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00005493 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005494 {
bellard579a97f2007-11-11 14:26:47 +00005495 void *p2;
ths722183f2007-09-24 09:24:37 +00005496 p = lock_user_string(arg2);
5497 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005498 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005499 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005500 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005501 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005502 unlock_user(p2, arg4, 0);
5503 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005504 }
5505 break;
5506#endif
bellard31e31b82003-02-18 22:55:36 +00005507 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005508 if (!(p = lock_user_string(arg1)))
5509 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005510 ret = get_errno(mkdir(p, arg2));
5511 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005512 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005513#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00005514 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005515 if (!(p = lock_user_string(arg2)))
5516 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005517 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005518 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005519 break;
5520#endif
bellard31e31b82003-02-18 22:55:36 +00005521 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005522 if (!(p = lock_user_string(arg1)))
5523 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005524 ret = get_errno(rmdir(p));
5525 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005526 break;
5527 case TARGET_NR_dup:
5528 ret = get_errno(dup(arg1));
5529 break;
5530 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005531 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005532 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005533#ifdef TARGET_NR_pipe2
5534 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07005535 ret = do_pipe(cpu_env, arg1,
5536 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005537 break;
5538#endif
bellard31e31b82003-02-18 22:55:36 +00005539 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005540 {
pbrook53a59602006-03-25 19:31:22 +00005541 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005542 struct tms tms;
5543 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005544 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005545 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5546 if (!tmsp)
5547 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005548 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5549 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5550 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5551 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005552 }
bellardc596ed12003-07-13 17:32:31 +00005553 if (!is_error(ret))
5554 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005555 }
5556 break;
bellardebc05482003-09-30 21:08:41 +00005557#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005558 case TARGET_NR_prof:
5559 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005560#endif
thse5febef2007-04-01 18:31:35 +00005561#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005562 case TARGET_NR_signal:
5563 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005564#endif
bellard31e31b82003-02-18 22:55:36 +00005565 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005566 if (arg1 == 0) {
5567 ret = get_errno(acct(NULL));
5568 } else {
5569 if (!(p = lock_user_string(arg1)))
5570 goto efault;
5571 ret = get_errno(acct(path(p)));
5572 unlock_user(p, arg1, 0);
5573 }
pbrook24836682006-04-16 14:14:53 +00005574 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005575#ifdef TARGET_NR_umount2 /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005576 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005577 if (!(p = lock_user_string(arg1)))
5578 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005579 ret = get_errno(umount2(p, arg2));
5580 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005581 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005582#endif
bellardebc05482003-09-30 21:08:41 +00005583#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005584 case TARGET_NR_lock:
5585 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005586#endif
bellard31e31b82003-02-18 22:55:36 +00005587 case TARGET_NR_ioctl:
5588 ret = do_ioctl(arg1, arg2, arg3);
5589 break;
5590 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005591 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005592 break;
bellardebc05482003-09-30 21:08:41 +00005593#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005594 case TARGET_NR_mpx:
5595 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005596#endif
bellard31e31b82003-02-18 22:55:36 +00005597 case TARGET_NR_setpgid:
5598 ret = get_errno(setpgid(arg1, arg2));
5599 break;
bellardebc05482003-09-30 21:08:41 +00005600#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005601 case TARGET_NR_ulimit:
5602 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005603#endif
5604#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005605 case TARGET_NR_oldolduname:
5606 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005607#endif
bellard31e31b82003-02-18 22:55:36 +00005608 case TARGET_NR_umask:
5609 ret = get_errno(umask(arg1));
5610 break;
5611 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005612 if (!(p = lock_user_string(arg1)))
5613 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005614 ret = get_errno(chroot(p));
5615 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005616 break;
5617 case TARGET_NR_ustat:
5618 goto unimplemented;
5619 case TARGET_NR_dup2:
5620 ret = get_errno(dup2(arg1, arg2));
5621 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005622#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5623 case TARGET_NR_dup3:
5624 ret = get_errno(dup3(arg1, arg2, arg3));
5625 break;
5626#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005627#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005628 case TARGET_NR_getppid:
5629 ret = get_errno(getppid());
5630 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005631#endif
bellard31e31b82003-02-18 22:55:36 +00005632 case TARGET_NR_getpgrp:
5633 ret = get_errno(getpgrp());
5634 break;
5635 case TARGET_NR_setsid:
5636 ret = get_errno(setsid());
5637 break;
thse5febef2007-04-01 18:31:35 +00005638#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005639 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005640 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005641#if defined(TARGET_ALPHA)
5642 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005643 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005644 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005645 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5646 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005647 act._sa_handler = old_act->_sa_handler;
5648 target_siginitset(&act.sa_mask, old_act->sa_mask);
5649 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005650 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005651 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005652 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005653 }
5654 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005655 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005656 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5657 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005658 old_act->_sa_handler = oact._sa_handler;
5659 old_act->sa_mask = oact.sa_mask.sig[0];
5660 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005661 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005662 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005663#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005664 struct target_sigaction act, oact, *pact, *old_act;
5665
5666 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005667 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5668 goto efault;
bellard106ec872006-06-27 21:08:10 +00005669 act._sa_handler = old_act->_sa_handler;
5670 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5671 act.sa_flags = old_act->sa_flags;
5672 unlock_user_struct(old_act, arg2, 0);
5673 pact = &act;
5674 } else {
5675 pact = NULL;
5676 }
5677
5678 ret = get_errno(do_sigaction(arg1, pact, &oact));
5679
5680 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005681 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5682 goto efault;
bellard106ec872006-06-27 21:08:10 +00005683 old_act->_sa_handler = oact._sa_handler;
5684 old_act->sa_flags = oact.sa_flags;
5685 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5686 old_act->sa_mask.sig[1] = 0;
5687 old_act->sa_mask.sig[2] = 0;
5688 old_act->sa_mask.sig[3] = 0;
5689 unlock_user_struct(old_act, arg3, 1);
5690 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005691#else
5692 struct target_old_sigaction *old_act;
5693 struct target_sigaction act, oact, *pact;
5694 if (arg2) {
5695 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5696 goto efault;
5697 act._sa_handler = old_act->_sa_handler;
5698 target_siginitset(&act.sa_mask, old_act->sa_mask);
5699 act.sa_flags = old_act->sa_flags;
5700 act.sa_restorer = old_act->sa_restorer;
5701 unlock_user_struct(old_act, arg2, 0);
5702 pact = &act;
5703 } else {
5704 pact = NULL;
5705 }
5706 ret = get_errno(do_sigaction(arg1, pact, &oact));
5707 if (!is_error(ret) && arg3) {
5708 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5709 goto efault;
5710 old_act->_sa_handler = oact._sa_handler;
5711 old_act->sa_mask = oact.sa_mask.sig[0];
5712 old_act->sa_flags = oact.sa_flags;
5713 old_act->sa_restorer = oact.sa_restorer;
5714 unlock_user_struct(old_act, arg3, 1);
5715 }
ths388bb212007-05-13 13:58:00 +00005716#endif
bellard31e31b82003-02-18 22:55:36 +00005717 }
5718 break;
thse5febef2007-04-01 18:31:35 +00005719#endif
bellard66fb9762003-03-23 01:06:05 +00005720 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005721 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005722#if defined(TARGET_ALPHA)
5723 struct target_sigaction act, oact, *pact = 0;
5724 struct target_rt_sigaction *rt_act;
5725 /* ??? arg4 == sizeof(sigset_t). */
5726 if (arg2) {
5727 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5728 goto efault;
5729 act._sa_handler = rt_act->_sa_handler;
5730 act.sa_mask = rt_act->sa_mask;
5731 act.sa_flags = rt_act->sa_flags;
5732 act.sa_restorer = arg5;
5733 unlock_user_struct(rt_act, arg2, 0);
5734 pact = &act;
5735 }
5736 ret = get_errno(do_sigaction(arg1, pact, &oact));
5737 if (!is_error(ret) && arg3) {
5738 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5739 goto efault;
5740 rt_act->_sa_handler = oact._sa_handler;
5741 rt_act->sa_mask = oact.sa_mask;
5742 rt_act->sa_flags = oact.sa_flags;
5743 unlock_user_struct(rt_act, arg3, 1);
5744 }
5745#else
pbrook53a59602006-03-25 19:31:22 +00005746 struct target_sigaction *act;
5747 struct target_sigaction *oact;
5748
bellard579a97f2007-11-11 14:26:47 +00005749 if (arg2) {
5750 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5751 goto efault;
5752 } else
pbrook53a59602006-03-25 19:31:22 +00005753 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005754 if (arg3) {
5755 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5756 ret = -TARGET_EFAULT;
5757 goto rt_sigaction_fail;
5758 }
5759 } else
pbrook53a59602006-03-25 19:31:22 +00005760 oact = NULL;
5761 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005762 rt_sigaction_fail:
5763 if (act)
pbrook53a59602006-03-25 19:31:22 +00005764 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005765 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005766 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005767#endif
pbrook53a59602006-03-25 19:31:22 +00005768 }
bellard66fb9762003-03-23 01:06:05 +00005769 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005770#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005771 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005772 {
5773 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005774 abi_ulong target_set;
bellard66fb9762003-03-23 01:06:05 +00005775 sigprocmask(0, NULL, &cur_set);
5776 host_to_target_old_sigset(&target_set, &cur_set);
5777 ret = target_set;
5778 }
5779 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005780#endif
5781#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005782 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005783 {
5784 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005785 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00005786 sigprocmask(0, NULL, &cur_set);
5787 target_to_host_old_sigset(&set, &target_set);
5788 sigorset(&set, &set, &cur_set);
5789 sigprocmask(SIG_SETMASK, &set, &oset);
5790 host_to_target_old_sigset(&target_set, &oset);
5791 ret = target_set;
5792 }
5793 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005794#endif
thse5febef2007-04-01 18:31:35 +00005795#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00005796 case TARGET_NR_sigprocmask:
5797 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005798#if defined(TARGET_ALPHA)
5799 sigset_t set, oldset;
5800 abi_ulong mask;
5801 int how;
5802
5803 switch (arg1) {
5804 case TARGET_SIG_BLOCK:
5805 how = SIG_BLOCK;
5806 break;
5807 case TARGET_SIG_UNBLOCK:
5808 how = SIG_UNBLOCK;
5809 break;
5810 case TARGET_SIG_SETMASK:
5811 how = SIG_SETMASK;
5812 break;
5813 default:
5814 ret = -TARGET_EINVAL;
5815 goto fail;
5816 }
5817 mask = arg2;
5818 target_to_host_old_sigset(&set, &mask);
5819
5820 ret = get_errno(sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07005821 if (!is_error(ret)) {
5822 host_to_target_old_sigset(&mask, &oldset);
5823 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07005824 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07005825 }
5826#else
bellard66fb9762003-03-23 01:06:05 +00005827 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07005828 int how;
ths3b46e622007-09-17 08:09:54 +00005829
pbrook53a59602006-03-25 19:31:22 +00005830 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005831 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00005832 case TARGET_SIG_BLOCK:
5833 how = SIG_BLOCK;
5834 break;
5835 case TARGET_SIG_UNBLOCK:
5836 how = SIG_UNBLOCK;
5837 break;
5838 case TARGET_SIG_SETMASK:
5839 how = SIG_SETMASK;
5840 break;
5841 default:
ths0da46a62007-10-20 20:23:07 +00005842 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005843 goto fail;
5844 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005845 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005846 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005847 target_to_host_old_sigset(&set, p);
5848 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005849 set_ptr = &set;
5850 } else {
5851 how = 0;
5852 set_ptr = NULL;
5853 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005854 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005855 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005856 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005857 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005858 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005859 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005860 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005861#endif
bellard66fb9762003-03-23 01:06:05 +00005862 }
5863 break;
thse5febef2007-04-01 18:31:35 +00005864#endif
bellard66fb9762003-03-23 01:06:05 +00005865 case TARGET_NR_rt_sigprocmask:
5866 {
5867 int how = arg1;
5868 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00005869
pbrook53a59602006-03-25 19:31:22 +00005870 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00005871 switch(how) {
5872 case TARGET_SIG_BLOCK:
5873 how = SIG_BLOCK;
5874 break;
5875 case TARGET_SIG_UNBLOCK:
5876 how = SIG_UNBLOCK;
5877 break;
5878 case TARGET_SIG_SETMASK:
5879 how = SIG_SETMASK;
5880 break;
5881 default:
ths0da46a62007-10-20 20:23:07 +00005882 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005883 goto fail;
5884 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005885 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005886 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005887 target_to_host_sigset(&set, p);
5888 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005889 set_ptr = &set;
5890 } else {
5891 how = 0;
5892 set_ptr = NULL;
5893 }
5894 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005895 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005896 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005897 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005898 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005899 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005900 }
5901 }
5902 break;
thse5febef2007-04-01 18:31:35 +00005903#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00005904 case TARGET_NR_sigpending:
5905 {
5906 sigset_t set;
5907 ret = get_errno(sigpending(&set));
5908 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005909 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005910 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005911 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005912 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005913 }
5914 }
5915 break;
thse5febef2007-04-01 18:31:35 +00005916#endif
bellard66fb9762003-03-23 01:06:05 +00005917 case TARGET_NR_rt_sigpending:
5918 {
5919 sigset_t set;
5920 ret = get_errno(sigpending(&set));
5921 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005922 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005923 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005924 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005925 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005926 }
5927 }
5928 break;
thse5febef2007-04-01 18:31:35 +00005929#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00005930 case TARGET_NR_sigsuspend:
5931 {
5932 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07005933#if defined(TARGET_ALPHA)
5934 abi_ulong mask = arg1;
5935 target_to_host_old_sigset(&set, &mask);
5936#else
Anthony Liguoric227f092009-10-01 16:12:16 -05005937 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005938 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005939 target_to_host_old_sigset(&set, p);
5940 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07005941#endif
bellard66fb9762003-03-23 01:06:05 +00005942 ret = get_errno(sigsuspend(&set));
5943 }
5944 break;
thse5febef2007-04-01 18:31:35 +00005945#endif
bellard66fb9762003-03-23 01:06:05 +00005946 case TARGET_NR_rt_sigsuspend:
5947 {
5948 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005949 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005950 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005951 target_to_host_sigset(&set, p);
5952 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005953 ret = get_errno(sigsuspend(&set));
5954 }
5955 break;
5956 case TARGET_NR_rt_sigtimedwait:
5957 {
bellard66fb9762003-03-23 01:06:05 +00005958 sigset_t set;
5959 struct timespec uts, *puts;
5960 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00005961
Anthony Liguoric227f092009-10-01 16:12:16 -05005962 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005963 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005964 target_to_host_sigset(&set, p);
5965 unlock_user(p, arg1, 0);
5966 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00005967 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00005968 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00005969 } else {
5970 puts = NULL;
5971 }
5972 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
pbrook53a59602006-03-25 19:31:22 +00005973 if (!is_error(ret) && arg2) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005974 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005975 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005976 host_to_target_siginfo(p, &uinfo);
Anthony Liguoric227f092009-10-01 16:12:16 -05005977 unlock_user(p, arg2, sizeof(target_siginfo_t));
bellard66fb9762003-03-23 01:06:05 +00005978 }
5979 }
5980 break;
5981 case TARGET_NR_rt_sigqueueinfo:
5982 {
5983 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05005984 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005985 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005986 target_to_host_siginfo(&uinfo, p);
5987 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005988 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
5989 }
5990 break;
thse5febef2007-04-01 18:31:35 +00005991#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00005992 case TARGET_NR_sigreturn:
5993 /* NOTE: ret is eax, so not transcoding must be done */
5994 ret = do_sigreturn(cpu_env);
5995 break;
thse5febef2007-04-01 18:31:35 +00005996#endif
bellard66fb9762003-03-23 01:06:05 +00005997 case TARGET_NR_rt_sigreturn:
5998 /* NOTE: ret is eax, so not transcoding must be done */
5999 ret = do_rt_sigreturn(cpu_env);
6000 break;
bellard31e31b82003-02-18 22:55:36 +00006001 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006002 if (!(p = lock_user_string(arg1)))
6003 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006004 ret = get_errno(sethostname(p, arg2));
6005 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006006 break;
6007 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006008 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006009 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006010 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006011 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006012 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6013 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006014 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6015 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006016 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006017 ret = get_errno(setrlimit(resource, &rlim));
6018 }
6019 break;
bellard31e31b82003-02-18 22:55:36 +00006020 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006021 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006022 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006023 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006024 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006025
bellard9de5e442003-03-23 16:49:39 +00006026 ret = get_errno(getrlimit(resource, &rlim));
6027 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006028 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6029 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006030 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6031 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006032 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006033 }
6034 }
6035 break;
bellard31e31b82003-02-18 22:55:36 +00006036 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006037 {
6038 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006039 ret = get_errno(getrusage(arg1, &rusage));
6040 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006041 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006042 }
6043 }
6044 break;
bellard31e31b82003-02-18 22:55:36 +00006045 case TARGET_NR_gettimeofday:
6046 {
bellard31e31b82003-02-18 22:55:36 +00006047 struct timeval tv;
6048 ret = get_errno(gettimeofday(&tv, NULL));
6049 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006050 if (copy_to_user_timeval(arg1, &tv))
6051 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006052 }
6053 }
6054 break;
6055 case TARGET_NR_settimeofday:
6056 {
bellard31e31b82003-02-18 22:55:36 +00006057 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00006058 if (copy_from_user_timeval(&tv, arg1))
6059 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006060 ret = get_errno(settimeofday(&tv, NULL));
6061 }
6062 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006063#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006064 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006065#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6066 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6067#else
bellardf2674e32003-07-09 12:26:09 +00006068 {
pbrook53a59602006-03-25 19:31:22 +00006069 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006070 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006071 long nsel;
6072
bellard579a97f2007-11-11 14:26:47 +00006073 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6074 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006075 nsel = tswapal(sel->n);
6076 inp = tswapal(sel->inp);
6077 outp = tswapal(sel->outp);
6078 exp = tswapal(sel->exp);
6079 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006080 unlock_user_struct(sel, arg1, 0);
6081 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006082 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006083#endif
bellardf2674e32003-07-09 12:26:09 +00006084 break;
bellard048f6b42005-11-26 18:47:20 +00006085#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006086#ifdef TARGET_NR_pselect6
6087 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006088 {
6089 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6090 fd_set rfds, wfds, efds;
6091 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6092 struct timespec ts, *ts_ptr;
6093
6094 /*
6095 * The 6th arg is actually two args smashed together,
6096 * so we cannot use the C library.
6097 */
6098 sigset_t set;
6099 struct {
6100 sigset_t *set;
6101 size_t size;
6102 } sig, *sig_ptr;
6103
6104 abi_ulong arg_sigset, arg_sigsize, *arg7;
6105 target_sigset_t *target_sigset;
6106
6107 n = arg1;
6108 rfd_addr = arg2;
6109 wfd_addr = arg3;
6110 efd_addr = arg4;
6111 ts_addr = arg5;
6112
6113 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6114 if (ret) {
6115 goto fail;
6116 }
6117 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6118 if (ret) {
6119 goto fail;
6120 }
6121 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6122 if (ret) {
6123 goto fail;
6124 }
6125
6126 /*
6127 * This takes a timespec, and not a timeval, so we cannot
6128 * use the do_select() helper ...
6129 */
6130 if (ts_addr) {
6131 if (target_to_host_timespec(&ts, ts_addr)) {
6132 goto efault;
6133 }
6134 ts_ptr = &ts;
6135 } else {
6136 ts_ptr = NULL;
6137 }
6138
6139 /* Extract the two packed args for the sigset */
6140 if (arg6) {
6141 sig_ptr = &sig;
6142 sig.size = _NSIG / 8;
6143
6144 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6145 if (!arg7) {
6146 goto efault;
6147 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006148 arg_sigset = tswapal(arg7[0]);
6149 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006150 unlock_user(arg7, arg6, 0);
6151
6152 if (arg_sigset) {
6153 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006154 if (arg_sigsize != sizeof(*target_sigset)) {
6155 /* Like the kernel, we enforce correct size sigsets */
6156 ret = -TARGET_EINVAL;
6157 goto fail;
6158 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006159 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6160 sizeof(*target_sigset), 1);
6161 if (!target_sigset) {
6162 goto efault;
6163 }
6164 target_to_host_sigset(&set, target_sigset);
6165 unlock_user(target_sigset, arg_sigset, 0);
6166 } else {
6167 sig.set = NULL;
6168 }
6169 } else {
6170 sig_ptr = NULL;
6171 }
6172
6173 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6174 ts_ptr, sig_ptr));
6175
6176 if (!is_error(ret)) {
6177 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6178 goto efault;
6179 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6180 goto efault;
6181 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6182 goto efault;
6183
6184 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6185 goto efault;
6186 }
6187 }
6188 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006189#endif
bellard31e31b82003-02-18 22:55:36 +00006190 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006191 {
6192 void *p2;
6193 p = lock_user_string(arg1);
6194 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006195 if (!p || !p2)
6196 ret = -TARGET_EFAULT;
6197 else
6198 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006199 unlock_user(p2, arg2, 0);
6200 unlock_user(p, arg1, 0);
6201 }
bellard31e31b82003-02-18 22:55:36 +00006202 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006203#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00006204 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006205 {
bellard579a97f2007-11-11 14:26:47 +00006206 void *p2;
thsf0b62432007-09-24 09:25:40 +00006207 p = lock_user_string(arg1);
6208 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006209 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006210 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006211 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006212 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006213 unlock_user(p2, arg3, 0);
6214 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006215 }
6216 break;
6217#endif
bellardebc05482003-09-30 21:08:41 +00006218#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006219 case TARGET_NR_oldlstat:
6220 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006221#endif
bellard31e31b82003-02-18 22:55:36 +00006222 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006223 {
aurel32d088d662009-01-30 20:09:01 +00006224 void *p2, *temp;
pbrook53a59602006-03-25 19:31:22 +00006225 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006226 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
6227 if (!p || !p2)
6228 ret = -TARGET_EFAULT;
aurel32d088d662009-01-30 20:09:01 +00006229 else {
6230 if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
6231 char real[PATH_MAX];
6232 temp = realpath(exec_path,real);
6233 ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
6234 snprintf((char *)p2, arg3, "%s", real);
6235 }
6236 else
6237 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006238 }
pbrook53a59602006-03-25 19:31:22 +00006239 unlock_user(p2, arg2, ret);
6240 unlock_user(p, arg1, 0);
6241 }
bellard31e31b82003-02-18 22:55:36 +00006242 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006243#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00006244 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006245 {
bellard579a97f2007-11-11 14:26:47 +00006246 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006247 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006248 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
6249 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006250 ret = -TARGET_EFAULT;
ths5e0ccb12007-09-24 09:26:10 +00006251 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006252 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
bellard579a97f2007-11-11 14:26:47 +00006253 unlock_user(p2, arg3, ret);
6254 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006255 }
6256 break;
6257#endif
thse5febef2007-04-01 18:31:35 +00006258#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006259 case TARGET_NR_uselib:
6260 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006261#endif
6262#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006263 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006264 if (!(p = lock_user_string(arg1)))
6265 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006266 ret = get_errno(swapon(p, arg2));
6267 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006268 break;
thse5febef2007-04-01 18:31:35 +00006269#endif
bellard31e31b82003-02-18 22:55:36 +00006270 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006271 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6272 /* arg4 must be ignored in all other cases */
6273 p = lock_user_string(arg4);
6274 if (!p) {
6275 goto efault;
6276 }
6277 ret = get_errno(reboot(arg1, arg2, arg3, p));
6278 unlock_user(p, arg4, 0);
6279 } else {
6280 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6281 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006282 break;
thse5febef2007-04-01 18:31:35 +00006283#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006284 case TARGET_NR_readdir:
6285 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006286#endif
6287#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006288 case TARGET_NR_mmap:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006289#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
6290 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6291 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006292 {
blueswir1992f48a2007-10-14 16:27:31 +00006293 abi_ulong *v;
6294 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006295 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6296 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006297 v1 = tswapal(v[0]);
6298 v2 = tswapal(v[1]);
6299 v3 = tswapal(v[2]);
6300 v4 = tswapal(v[3]);
6301 v5 = tswapal(v[4]);
6302 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006303 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006304 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006305 target_to_host_bitmask(v4, mmap_flags_tbl),
6306 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006307 }
bellard31e31b82003-02-18 22:55:36 +00006308#else
ths5fafdf22007-09-16 21:08:06 +00006309 ret = get_errno(target_mmap(arg1, arg2, arg3,
6310 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006311 arg5,
6312 arg6));
bellard31e31b82003-02-18 22:55:36 +00006313#endif
bellard6fb883e2003-07-09 17:12:39 +00006314 break;
thse5febef2007-04-01 18:31:35 +00006315#endif
bellarda315a142005-01-30 22:59:18 +00006316#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006317 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006318#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006319#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006320#endif
ths5fafdf22007-09-16 21:08:06 +00006321 ret = get_errno(target_mmap(arg1, arg2, arg3,
6322 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006323 arg5,
bellardc573ff62004-01-04 15:51:36 +00006324 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006325 break;
bellarda315a142005-01-30 22:59:18 +00006326#endif
bellard31e31b82003-02-18 22:55:36 +00006327 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006328 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006329 break;
bellard9de5e442003-03-23 16:49:39 +00006330 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006331 {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006332 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006333 /* Special hack to detect libc making the stack executable. */
6334 if ((arg3 & PROT_GROWSDOWN)
6335 && arg1 >= ts->info->stack_limit
6336 && arg1 <= ts->info->start_stack) {
6337 arg3 &= ~PROT_GROWSDOWN;
6338 arg2 = arg2 + arg1 - ts->info->stack_limit;
6339 arg1 = ts->info->stack_limit;
6340 }
6341 }
bellard54936002003-05-13 00:25:15 +00006342 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006343 break;
thse5febef2007-04-01 18:31:35 +00006344#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006345 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006346 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006347 break;
thse5febef2007-04-01 18:31:35 +00006348#endif
pbrook53a59602006-03-25 19:31:22 +00006349 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006350#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006351 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006352 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006353 break;
thse5febef2007-04-01 18:31:35 +00006354#endif
6355#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006356 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006357 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006358 break;
thse5febef2007-04-01 18:31:35 +00006359#endif
6360#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006361 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006362 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006363 break;
thse5febef2007-04-01 18:31:35 +00006364#endif
6365#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006366 case TARGET_NR_mlockall:
6367 ret = get_errno(mlockall(arg1));
6368 break;
thse5febef2007-04-01 18:31:35 +00006369#endif
6370#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006371 case TARGET_NR_munlockall:
6372 ret = get_errno(munlockall());
6373 break;
thse5febef2007-04-01 18:31:35 +00006374#endif
bellard31e31b82003-02-18 22:55:36 +00006375 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006376 if (!(p = lock_user_string(arg1)))
6377 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006378 ret = get_errno(truncate(p, arg2));
6379 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006380 break;
6381 case TARGET_NR_ftruncate:
6382 ret = get_errno(ftruncate(arg1, arg2));
6383 break;
6384 case TARGET_NR_fchmod:
6385 ret = get_errno(fchmod(arg1, arg2));
6386 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006387#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00006388 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006389 if (!(p = lock_user_string(arg2)))
6390 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006391 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006392 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006393 break;
6394#endif
bellard31e31b82003-02-18 22:55:36 +00006395 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006396 /* Note that negative values are valid for getpriority, so we must
6397 differentiate based on errno settings. */
6398 errno = 0;
6399 ret = getpriority(arg1, arg2);
6400 if (ret == -1 && errno != 0) {
6401 ret = -host_to_target_errno(errno);
6402 break;
6403 }
6404#ifdef TARGET_ALPHA
6405 /* Return value is the unbiased priority. Signal no error. */
6406 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6407#else
6408 /* Return value is a biased priority to avoid negative numbers. */
6409 ret = 20 - ret;
6410#endif
bellard31e31b82003-02-18 22:55:36 +00006411 break;
6412 case TARGET_NR_setpriority:
6413 ret = get_errno(setpriority(arg1, arg2, arg3));
6414 break;
bellardebc05482003-09-30 21:08:41 +00006415#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006416 case TARGET_NR_profil:
6417 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006418#endif
bellard31e31b82003-02-18 22:55:36 +00006419 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006420 if (!(p = lock_user_string(arg1)))
6421 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006422 ret = get_errno(statfs(path(p), &stfs));
6423 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006424 convert_statfs:
6425 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006426 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006427
bellard579a97f2007-11-11 14:26:47 +00006428 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6429 goto efault;
6430 __put_user(stfs.f_type, &target_stfs->f_type);
6431 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6432 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6433 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6434 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6435 __put_user(stfs.f_files, &target_stfs->f_files);
6436 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6437 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6438 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6439 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006440 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6441 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006442 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006443 }
6444 break;
6445 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006446 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006447 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006448#ifdef TARGET_NR_statfs64
6449 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006450 if (!(p = lock_user_string(arg1)))
6451 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006452 ret = get_errno(statfs(path(p), &stfs));
6453 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006454 convert_statfs64:
6455 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006456 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006457
bellard579a97f2007-11-11 14:26:47 +00006458 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6459 goto efault;
6460 __put_user(stfs.f_type, &target_stfs->f_type);
6461 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6462 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6463 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6464 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6465 __put_user(stfs.f_files, &target_stfs->f_files);
6466 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6467 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6468 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6469 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006470 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6471 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00006472 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006473 }
6474 break;
6475 case TARGET_NR_fstatfs64:
6476 ret = get_errno(fstatfs(arg1, &stfs));
6477 goto convert_statfs64;
6478#endif
bellardebc05482003-09-30 21:08:41 +00006479#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006480 case TARGET_NR_ioperm:
6481 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006482#endif
thse5febef2007-04-01 18:31:35 +00006483#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006484 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006485 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006486 break;
thse5febef2007-04-01 18:31:35 +00006487#endif
bellard3532fa72006-06-24 15:06:03 +00006488#ifdef TARGET_NR_accept
6489 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00006490 ret = do_accept4(arg1, arg2, arg3, 0);
6491 break;
6492#endif
6493#ifdef TARGET_NR_accept4
6494 case TARGET_NR_accept4:
6495#ifdef CONFIG_ACCEPT4
6496 ret = do_accept4(arg1, arg2, arg3, arg4);
6497#else
6498 goto unimplemented;
6499#endif
bellard3532fa72006-06-24 15:06:03 +00006500 break;
6501#endif
6502#ifdef TARGET_NR_bind
6503 case TARGET_NR_bind:
6504 ret = do_bind(arg1, arg2, arg3);
6505 break;
6506#endif
6507#ifdef TARGET_NR_connect
6508 case TARGET_NR_connect:
6509 ret = do_connect(arg1, arg2, arg3);
6510 break;
6511#endif
6512#ifdef TARGET_NR_getpeername
6513 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006514 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006515 break;
6516#endif
6517#ifdef TARGET_NR_getsockname
6518 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006519 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006520 break;
6521#endif
6522#ifdef TARGET_NR_getsockopt
6523 case TARGET_NR_getsockopt:
6524 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6525 break;
6526#endif
6527#ifdef TARGET_NR_listen
6528 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006529 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006530 break;
6531#endif
6532#ifdef TARGET_NR_recv
6533 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006534 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006535 break;
6536#endif
6537#ifdef TARGET_NR_recvfrom
6538 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006539 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006540 break;
6541#endif
6542#ifdef TARGET_NR_recvmsg
6543 case TARGET_NR_recvmsg:
6544 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6545 break;
6546#endif
6547#ifdef TARGET_NR_send
6548 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006549 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006550 break;
6551#endif
6552#ifdef TARGET_NR_sendmsg
6553 case TARGET_NR_sendmsg:
6554 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6555 break;
6556#endif
6557#ifdef TARGET_NR_sendto
6558 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006559 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006560 break;
6561#endif
6562#ifdef TARGET_NR_shutdown
6563 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006564 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006565 break;
6566#endif
6567#ifdef TARGET_NR_socket
6568 case TARGET_NR_socket:
6569 ret = do_socket(arg1, arg2, arg3);
6570 break;
6571#endif
6572#ifdef TARGET_NR_socketpair
6573 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006574 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006575 break;
6576#endif
6577#ifdef TARGET_NR_setsockopt
6578 case TARGET_NR_setsockopt:
6579 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6580 break;
6581#endif
ths7494b0f2007-02-11 18:26:53 +00006582
bellard31e31b82003-02-18 22:55:36 +00006583 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006584 if (!(p = lock_user_string(arg2)))
6585 goto efault;
thse5574482007-02-11 20:03:13 +00006586 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6587 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006588 break;
6589
bellard31e31b82003-02-18 22:55:36 +00006590 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006591 {
bellard66fb9762003-03-23 01:06:05 +00006592 struct itimerval value, ovalue, *pvalue;
6593
pbrook53a59602006-03-25 19:31:22 +00006594 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006595 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006596 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6597 || copy_from_user_timeval(&pvalue->it_value,
6598 arg2 + sizeof(struct target_timeval)))
6599 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006600 } else {
6601 pvalue = NULL;
6602 }
6603 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006604 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006605 if (copy_to_user_timeval(arg3,
6606 &ovalue.it_interval)
6607 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6608 &ovalue.it_value))
6609 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006610 }
6611 }
6612 break;
bellard31e31b82003-02-18 22:55:36 +00006613 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006614 {
bellard66fb9762003-03-23 01:06:05 +00006615 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006616
bellard66fb9762003-03-23 01:06:05 +00006617 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006618 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006619 if (copy_to_user_timeval(arg2,
6620 &value.it_interval)
6621 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6622 &value.it_value))
6623 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006624 }
6625 }
6626 break;
bellard31e31b82003-02-18 22:55:36 +00006627 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006628 if (!(p = lock_user_string(arg1)))
6629 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006630 ret = get_errno(stat(path(p), &st));
6631 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006632 goto do_stat;
6633 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006634 if (!(p = lock_user_string(arg1)))
6635 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006636 ret = get_errno(lstat(path(p), &st));
6637 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006638 goto do_stat;
6639 case TARGET_NR_fstat:
6640 {
6641 ret = get_errno(fstat(arg1, &st));
6642 do_stat:
6643 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006644 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006645
bellard579a97f2007-11-11 14:26:47 +00006646 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6647 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006648 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006649 __put_user(st.st_dev, &target_st->st_dev);
6650 __put_user(st.st_ino, &target_st->st_ino);
6651 __put_user(st.st_mode, &target_st->st_mode);
6652 __put_user(st.st_uid, &target_st->st_uid);
6653 __put_user(st.st_gid, &target_st->st_gid);
6654 __put_user(st.st_nlink, &target_st->st_nlink);
6655 __put_user(st.st_rdev, &target_st->st_rdev);
6656 __put_user(st.st_size, &target_st->st_size);
6657 __put_user(st.st_blksize, &target_st->st_blksize);
6658 __put_user(st.st_blocks, &target_st->st_blocks);
6659 __put_user(st.st_atime, &target_st->target_st_atime);
6660 __put_user(st.st_mtime, &target_st->target_st_mtime);
6661 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006662 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006663 }
6664 }
6665 break;
bellardebc05482003-09-30 21:08:41 +00006666#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006667 case TARGET_NR_olduname:
6668 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006669#endif
6670#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006671 case TARGET_NR_iopl:
6672 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006673#endif
bellard31e31b82003-02-18 22:55:36 +00006674 case TARGET_NR_vhangup:
6675 ret = get_errno(vhangup());
6676 break;
bellardebc05482003-09-30 21:08:41 +00006677#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006678 case TARGET_NR_idle:
6679 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006680#endif
bellard42ad6ae2005-01-03 22:48:11 +00006681#ifdef TARGET_NR_syscall
6682 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006683 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6684 arg6, arg7, arg8, 0);
6685 break;
bellard42ad6ae2005-01-03 22:48:11 +00006686#endif
bellard31e31b82003-02-18 22:55:36 +00006687 case TARGET_NR_wait4:
6688 {
6689 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006690 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006691 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006692 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00006693 if (target_rusage)
6694 rusage_ptr = &rusage;
6695 else
6696 rusage_ptr = NULL;
6697 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6698 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01006699 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00006700 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006701 if (put_user_s32(status, status_ptr))
6702 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006703 }
bellard2f619692007-11-16 10:46:05 +00006704 if (target_rusage)
6705 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00006706 }
6707 }
6708 break;
thse5febef2007-04-01 18:31:35 +00006709#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006710 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006711 if (!(p = lock_user_string(arg1)))
6712 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006713 ret = get_errno(swapoff(p));
6714 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006715 break;
thse5febef2007-04-01 18:31:35 +00006716#endif
bellard31e31b82003-02-18 22:55:36 +00006717 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006718 {
pbrook53a59602006-03-25 19:31:22 +00006719 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006720 struct sysinfo value;
6721 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006722 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006723 {
bellard579a97f2007-11-11 14:26:47 +00006724 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6725 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006726 __put_user(value.uptime, &target_value->uptime);
6727 __put_user(value.loads[0], &target_value->loads[0]);
6728 __put_user(value.loads[1], &target_value->loads[1]);
6729 __put_user(value.loads[2], &target_value->loads[2]);
6730 __put_user(value.totalram, &target_value->totalram);
6731 __put_user(value.freeram, &target_value->freeram);
6732 __put_user(value.sharedram, &target_value->sharedram);
6733 __put_user(value.bufferram, &target_value->bufferram);
6734 __put_user(value.totalswap, &target_value->totalswap);
6735 __put_user(value.freeswap, &target_value->freeswap);
6736 __put_user(value.procs, &target_value->procs);
6737 __put_user(value.totalhigh, &target_value->totalhigh);
6738 __put_user(value.freehigh, &target_value->freehigh);
6739 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006740 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006741 }
6742 }
6743 break;
thse5febef2007-04-01 18:31:35 +00006744#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006745 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006746 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6747 break;
thse5febef2007-04-01 18:31:35 +00006748#endif
aurel32e5289082009-04-18 16:16:12 +00006749#ifdef TARGET_NR_semget
6750 case TARGET_NR_semget:
6751 ret = get_errno(semget(arg1, arg2, arg3));
6752 break;
6753#endif
6754#ifdef TARGET_NR_semop
6755 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00006756 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00006757 break;
6758#endif
6759#ifdef TARGET_NR_semctl
6760 case TARGET_NR_semctl:
6761 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6762 break;
6763#endif
aurel32eeb438c2008-10-13 21:08:55 +00006764#ifdef TARGET_NR_msgctl
6765 case TARGET_NR_msgctl:
6766 ret = do_msgctl(arg1, arg2, arg3);
6767 break;
6768#endif
6769#ifdef TARGET_NR_msgget
6770 case TARGET_NR_msgget:
6771 ret = get_errno(msgget(arg1, arg2));
6772 break;
6773#endif
6774#ifdef TARGET_NR_msgrcv
6775 case TARGET_NR_msgrcv:
6776 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
6777 break;
6778#endif
6779#ifdef TARGET_NR_msgsnd
6780 case TARGET_NR_msgsnd:
6781 ret = do_msgsnd(arg1, arg2, arg3, arg4);
6782 break;
6783#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03006784#ifdef TARGET_NR_shmget
6785 case TARGET_NR_shmget:
6786 ret = get_errno(shmget(arg1, arg2, arg3));
6787 break;
6788#endif
6789#ifdef TARGET_NR_shmctl
6790 case TARGET_NR_shmctl:
6791 ret = do_shmctl(arg1, arg2, arg3);
6792 break;
6793#endif
6794#ifdef TARGET_NR_shmat
6795 case TARGET_NR_shmat:
6796 ret = do_shmat(arg1, arg2, arg3);
6797 break;
6798#endif
6799#ifdef TARGET_NR_shmdt
6800 case TARGET_NR_shmdt:
6801 ret = do_shmdt(arg1);
6802 break;
6803#endif
bellard31e31b82003-02-18 22:55:36 +00006804 case TARGET_NR_fsync:
6805 ret = get_errno(fsync(arg1));
6806 break;
bellard31e31b82003-02-18 22:55:36 +00006807 case TARGET_NR_clone:
Richard Hendersona4b388f2010-04-12 16:17:22 -07006808#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
aurel320b6d3ae2008-09-15 07:43:43 +00006809 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
edgar_iglb15ad612009-01-07 19:43:47 +00006810#elif defined(TARGET_CRIS)
6811 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02006812#elif defined(TARGET_MICROBLAZE)
6813 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006814#elif defined(TARGET_S390X)
6815 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00006816#else
pbrookd865bab2008-06-07 22:12:17 +00006817 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
aurel320b6d3ae2008-09-15 07:43:43 +00006818#endif
bellard1b6b0292003-03-22 17:31:38 +00006819 break;
bellardec86b0f2003-04-11 00:15:04 +00006820#ifdef __NR_exit_group
6821 /* new thread calls */
6822 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02006823#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00006824 _mcleanup();
6825#endif
bellarde9009672005-04-26 20:42:36 +00006826 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00006827 ret = get_errno(exit_group(arg1));
6828 break;
6829#endif
bellard31e31b82003-02-18 22:55:36 +00006830 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00006831 if (!(p = lock_user_string(arg1)))
6832 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006833 ret = get_errno(setdomainname(p, arg2));
6834 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006835 break;
6836 case TARGET_NR_uname:
6837 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00006838 {
6839 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00006840
bellard579a97f2007-11-11 14:26:47 +00006841 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
6842 goto efault;
bellard29e619b2004-09-13 21:41:04 +00006843 ret = get_errno(sys_uname(buf));
6844 if (!is_error(ret)) {
6845 /* Overrite the native machine name with whatever is being
6846 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01006847 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00006848 /* Allow the user to override the reported release. */
6849 if (qemu_uname_release && *qemu_uname_release)
6850 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00006851 }
pbrook53a59602006-03-25 19:31:22 +00006852 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00006853 }
bellard31e31b82003-02-18 22:55:36 +00006854 break;
bellard6dbad632003-03-16 18:05:05 +00006855#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00006856 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00006857 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00006858 break;
j_mayer84409dd2007-04-06 08:56:50 +00006859#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00006860 case TARGET_NR_vm86old:
6861 goto unimplemented;
6862 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00006863 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00006864 break;
6865#endif
j_mayer84409dd2007-04-06 08:56:50 +00006866#endif
bellard31e31b82003-02-18 22:55:36 +00006867 case TARGET_NR_adjtimex:
6868 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006869#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00006870 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00006871#endif
bellard31e31b82003-02-18 22:55:36 +00006872 case TARGET_NR_init_module:
6873 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00006874#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00006875 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00006876#endif
bellard31e31b82003-02-18 22:55:36 +00006877 goto unimplemented;
6878 case TARGET_NR_quotactl:
6879 goto unimplemented;
6880 case TARGET_NR_getpgid:
6881 ret = get_errno(getpgid(arg1));
6882 break;
6883 case TARGET_NR_fchdir:
6884 ret = get_errno(fchdir(arg1));
6885 break;
j_mayer84409dd2007-04-06 08:56:50 +00006886#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00006887 case TARGET_NR_bdflush:
6888 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00006889#endif
thse5febef2007-04-01 18:31:35 +00006890#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00006891 case TARGET_NR_sysfs:
6892 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006893#endif
bellard31e31b82003-02-18 22:55:36 +00006894 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00006895 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00006896 break;
thse5febef2007-04-01 18:31:35 +00006897#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00006898 case TARGET_NR_afs_syscall:
6899 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006900#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006901#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006902 case TARGET_NR__llseek:
6903 {
6904 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00006905#if !defined(__NR_llseek)
6906 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
6907 if (res == -1) {
6908 ret = get_errno(res);
6909 } else {
6910 ret = 0;
6911 }
6912#else
bellard31e31b82003-02-18 22:55:36 +00006913 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00006914#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00006915 if ((ret == 0) && put_user_s64(res, arg4)) {
6916 goto efault;
6917 }
bellard31e31b82003-02-18 22:55:36 +00006918 }
6919 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006920#endif
bellard31e31b82003-02-18 22:55:36 +00006921 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01006922#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02006923#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00006924 {
pbrook53a59602006-03-25 19:31:22 +00006925 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00006926 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006927 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00006928
6929 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00006930 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00006931 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00006932 goto fail;
6933 }
ths3b46e622007-09-17 08:09:54 +00006934
bellard4add45b2003-06-05 01:52:59 +00006935 ret = get_errno(sys_getdents(arg1, dirp, count));
6936 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006937 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00006938 struct target_dirent *tde;
6939 int len = ret;
6940 int reclen, treclen;
6941 int count1, tnamelen;
6942
6943 count1 = 0;
6944 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00006945 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6946 goto efault;
bellard4add45b2003-06-05 01:52:59 +00006947 tde = target_dirp;
6948 while (len > 0) {
6949 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04006950 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
6951 assert(tnamelen >= 0);
6952 treclen = tnamelen + offsetof(struct target_dirent, d_name);
6953 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00006954 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006955 tde->d_ino = tswapal(de->d_ino);
6956 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04006957 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00006958 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00006959 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00006960 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00006961 count1 += treclen;
6962 }
6963 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00006964 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00006965 }
6966 free(dirp);
6967 }
6968#else
bellard31e31b82003-02-18 22:55:36 +00006969 {
aurel326556a832008-10-13 21:08:17 +00006970 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006971 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00006972
bellard579a97f2007-11-11 14:26:47 +00006973 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6974 goto efault;
bellard72f03902003-02-18 23:33:18 +00006975 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00006976 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006977 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00006978 int len = ret;
6979 int reclen;
6980 de = dirp;
6981 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006982 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00006983 if (reclen > len)
6984 break;
bellard8083a3e2003-03-24 23:12:16 +00006985 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00006986 tswapls(&de->d_ino);
6987 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006988 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00006989 len -= reclen;
6990 }
6991 }
pbrook53a59602006-03-25 19:31:22 +00006992 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00006993 }
bellard4add45b2003-06-05 01:52:59 +00006994#endif
Peter Maydell3307e232013-06-12 16:20:21 +01006995#else
6996 /* Implement getdents in terms of getdents64 */
6997 {
6998 struct linux_dirent64 *dirp;
6999 abi_long count = arg3;
7000
7001 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7002 if (!dirp) {
7003 goto efault;
7004 }
7005 ret = get_errno(sys_getdents64(arg1, dirp, count));
7006 if (!is_error(ret)) {
7007 /* Convert the dirent64 structs to target dirent. We do this
7008 * in-place, since we can guarantee that a target_dirent is no
7009 * larger than a dirent64; however this means we have to be
7010 * careful to read everything before writing in the new format.
7011 */
7012 struct linux_dirent64 *de;
7013 struct target_dirent *tde;
7014 int len = ret;
7015 int tlen = 0;
7016
7017 de = dirp;
7018 tde = (struct target_dirent *)dirp;
7019 while (len > 0) {
7020 int namelen, treclen;
7021 int reclen = de->d_reclen;
7022 uint64_t ino = de->d_ino;
7023 int64_t off = de->d_off;
7024 uint8_t type = de->d_type;
7025
7026 namelen = strlen(de->d_name);
7027 treclen = offsetof(struct target_dirent, d_name)
7028 + namelen + 2;
7029 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
7030
7031 memmove(tde->d_name, de->d_name, namelen + 1);
7032 tde->d_ino = tswapal(ino);
7033 tde->d_off = tswapal(off);
7034 tde->d_reclen = tswap16(treclen);
7035 /* The target_dirent type is in what was formerly a padding
7036 * byte at the end of the structure:
7037 */
7038 *(((char *)tde) + treclen - 1) = type;
7039
7040 de = (struct linux_dirent64 *)((char *)de + reclen);
7041 tde = (struct target_dirent *)((char *)tde + treclen);
7042 len -= reclen;
7043 tlen += treclen;
7044 }
7045 ret = tlen;
7046 }
7047 unlock_user(dirp, arg2, ret);
7048 }
7049#endif
bellard31e31b82003-02-18 22:55:36 +00007050 break;
ths3ae43202007-09-16 21:39:48 +00007051#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007052 case TARGET_NR_getdents64:
7053 {
aurel326556a832008-10-13 21:08:17 +00007054 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007055 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007056 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7057 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007058 ret = get_errno(sys_getdents64(arg1, dirp, count));
7059 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007060 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007061 int len = ret;
7062 int reclen;
7063 de = dirp;
7064 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007065 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007066 if (reclen > len)
7067 break;
bellard8083a3e2003-03-24 23:12:16 +00007068 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007069 tswap64s((uint64_t *)&de->d_ino);
7070 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007071 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007072 len -= reclen;
7073 }
7074 }
pbrook53a59602006-03-25 19:31:22 +00007075 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007076 }
7077 break;
bellarda541f292004-04-12 20:39:29 +00007078#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007079#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007080 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007081 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007082 break;
thse5febef2007-04-01 18:31:35 +00007083#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007084#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7085# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007086 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007087# endif
7088# ifdef TARGET_NR_ppoll
7089 case TARGET_NR_ppoll:
7090# endif
bellard9de5e442003-03-23 16:49:39 +00007091 {
pbrook53a59602006-03-25 19:31:22 +00007092 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007093 unsigned int nfds = arg2;
7094 int timeout = arg3;
7095 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007096 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007097
bellard579a97f2007-11-11 14:26:47 +00007098 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7099 if (!target_pfd)
7100 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007101
bellard9de5e442003-03-23 16:49:39 +00007102 pfd = alloca(sizeof(struct pollfd) * nfds);
7103 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007104 pfd[i].fd = tswap32(target_pfd[i].fd);
7105 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007106 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007107
7108# ifdef TARGET_NR_ppoll
7109 if (num == TARGET_NR_ppoll) {
7110 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7111 target_sigset_t *target_set;
7112 sigset_t _set, *set = &_set;
7113
7114 if (arg3) {
7115 if (target_to_host_timespec(timeout_ts, arg3)) {
7116 unlock_user(target_pfd, arg1, 0);
7117 goto efault;
7118 }
7119 } else {
7120 timeout_ts = NULL;
7121 }
7122
7123 if (arg4) {
7124 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7125 if (!target_set) {
7126 unlock_user(target_pfd, arg1, 0);
7127 goto efault;
7128 }
7129 target_to_host_sigset(set, target_set);
7130 } else {
7131 set = NULL;
7132 }
7133
7134 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7135
7136 if (!is_error(ret) && arg3) {
7137 host_to_target_timespec(arg3, timeout_ts);
7138 }
7139 if (arg4) {
7140 unlock_user(target_set, arg4, 0);
7141 }
7142 } else
7143# endif
7144 ret = get_errno(poll(pfd, nfds, timeout));
7145
bellard9de5e442003-03-23 16:49:39 +00007146 if (!is_error(ret)) {
7147 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007148 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007149 }
7150 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007151 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007152 }
7153 break;
thse5febef2007-04-01 18:31:35 +00007154#endif
bellard31e31b82003-02-18 22:55:36 +00007155 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007156 /* NOTE: the flock constant seems to be the same for every
7157 Linux platform */
7158 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007159 break;
7160 case TARGET_NR_readv:
7161 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007162 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7163 if (vec != NULL) {
7164 ret = get_errno(readv(arg1, vec, arg3));
7165 unlock_iovec(vec, arg2, arg3, 1);
7166 } else {
7167 ret = -host_to_target_errno(errno);
7168 }
bellard31e31b82003-02-18 22:55:36 +00007169 }
7170 break;
7171 case TARGET_NR_writev:
7172 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007173 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7174 if (vec != NULL) {
7175 ret = get_errno(writev(arg1, vec, arg3));
7176 unlock_iovec(vec, arg2, arg3, 0);
7177 } else {
7178 ret = -host_to_target_errno(errno);
7179 }
bellard31e31b82003-02-18 22:55:36 +00007180 }
7181 break;
7182 case TARGET_NR_getsid:
7183 ret = get_errno(getsid(arg1));
7184 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007185#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007186 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007187 ret = get_errno(fdatasync(arg1));
7188 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007189#endif
bellard31e31b82003-02-18 22:55:36 +00007190 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007191 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007192 return value. */
ths0da46a62007-10-20 20:23:07 +00007193 ret = -TARGET_ENOTDIR;
7194 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007195 case TARGET_NR_sched_getaffinity:
7196 {
7197 unsigned int mask_size;
7198 unsigned long *mask;
7199
7200 /*
7201 * sched_getaffinity needs multiples of ulong, so need to take
7202 * care of mismatches between target ulong and host ulong sizes.
7203 */
7204 if (arg2 & (sizeof(abi_ulong) - 1)) {
7205 ret = -TARGET_EINVAL;
7206 break;
7207 }
7208 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7209
7210 mask = alloca(mask_size);
7211 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7212
7213 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09007214 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007215 goto efault;
7216 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007217 }
7218 }
7219 break;
7220 case TARGET_NR_sched_setaffinity:
7221 {
7222 unsigned int mask_size;
7223 unsigned long *mask;
7224
7225 /*
7226 * sched_setaffinity needs multiples of ulong, so need to take
7227 * care of mismatches between target ulong and host ulong sizes.
7228 */
7229 if (arg2 & (sizeof(abi_ulong) - 1)) {
7230 ret = -TARGET_EINVAL;
7231 break;
7232 }
7233 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7234
7235 mask = alloca(mask_size);
7236 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7237 goto efault;
7238 }
7239 memcpy(mask, p, arg2);
7240 unlock_user_struct(p, arg2, 0);
7241
7242 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7243 }
7244 break;
bellard31e31b82003-02-18 22:55:36 +00007245 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007246 {
pbrook53a59602006-03-25 19:31:22 +00007247 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007248 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007249
bellard579a97f2007-11-11 14:26:47 +00007250 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7251 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007252 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007253 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007254 ret = get_errno(sched_setparam(arg1, &schp));
7255 }
7256 break;
bellard31e31b82003-02-18 22:55:36 +00007257 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007258 {
pbrook53a59602006-03-25 19:31:22 +00007259 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007260 struct sched_param schp;
7261 ret = get_errno(sched_getparam(arg1, &schp));
7262 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007263 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7264 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007265 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007266 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007267 }
7268 }
7269 break;
bellard31e31b82003-02-18 22:55:36 +00007270 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007271 {
pbrook53a59602006-03-25 19:31:22 +00007272 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007273 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007274 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7275 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007276 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007277 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007278 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7279 }
7280 break;
bellard31e31b82003-02-18 22:55:36 +00007281 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007282 ret = get_errno(sched_getscheduler(arg1));
7283 break;
bellard31e31b82003-02-18 22:55:36 +00007284 case TARGET_NR_sched_yield:
7285 ret = get_errno(sched_yield());
7286 break;
7287 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007288 ret = get_errno(sched_get_priority_max(arg1));
7289 break;
bellard31e31b82003-02-18 22:55:36 +00007290 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007291 ret = get_errno(sched_get_priority_min(arg1));
7292 break;
bellard31e31b82003-02-18 22:55:36 +00007293 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007294 {
bellard5cd43932003-03-29 16:54:36 +00007295 struct timespec ts;
7296 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7297 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007298 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007299 }
7300 }
7301 break;
bellard31e31b82003-02-18 22:55:36 +00007302 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007303 {
bellard1b6b0292003-03-22 17:31:38 +00007304 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007305 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007306 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007307 if (is_error(ret) && arg2) {
7308 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007309 }
7310 }
7311 break;
thse5febef2007-04-01 18:31:35 +00007312#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007313 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007314 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007315#endif
7316#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007317 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007318 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007319#endif
bellard31e31b82003-02-18 22:55:36 +00007320 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007321 switch (arg1) {
7322 case PR_GET_PDEATHSIG:
7323 {
7324 int deathsig;
7325 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7326 if (!is_error(ret) && arg2
7327 && put_user_ual(deathsig, arg2)) {
7328 goto efault;
thse5574482007-02-11 20:03:13 +00007329 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007330 break;
7331 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007332#ifdef PR_GET_NAME
7333 case PR_GET_NAME:
7334 {
7335 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7336 if (!name) {
7337 goto efault;
7338 }
7339 ret = get_errno(prctl(arg1, (unsigned long)name,
7340 arg3, arg4, arg5));
7341 unlock_user(name, arg2, 16);
7342 break;
7343 }
7344 case PR_SET_NAME:
7345 {
7346 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7347 if (!name) {
7348 goto efault;
7349 }
7350 ret = get_errno(prctl(arg1, (unsigned long)name,
7351 arg3, arg4, arg5));
7352 unlock_user(name, arg2, 0);
7353 break;
7354 }
7355#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007356 default:
7357 /* Most prctl options have no pointer arguments */
7358 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7359 break;
7360 }
ths39b9aae2007-02-11 18:36:44 +00007361 break;
bellardd2fd1af2007-11-14 18:08:56 +00007362#ifdef TARGET_NR_arch_prctl
7363 case TARGET_NR_arch_prctl:
7364#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7365 ret = do_arch_prctl(cpu_env, arg1, arg2);
7366 break;
7367#else
7368 goto unimplemented;
7369#endif
7370#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007371#ifdef TARGET_NR_pread64
7372 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007373 if (regpairs_aligned(cpu_env)) {
7374 arg4 = arg5;
7375 arg5 = arg6;
7376 }
aurel32f2c7ba12008-03-28 22:32:06 +00007377 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7378 goto efault;
7379 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7380 unlock_user(p, arg2, ret);
7381 break;
7382 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00007383 if (regpairs_aligned(cpu_env)) {
7384 arg4 = arg5;
7385 arg5 = arg6;
7386 }
aurel32f2c7ba12008-03-28 22:32:06 +00007387 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7388 goto efault;
7389 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7390 unlock_user(p, arg2, 0);
7391 break;
7392#endif
bellard31e31b82003-02-18 22:55:36 +00007393 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007394 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7395 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007396 ret = get_errno(sys_getcwd1(p, arg2));
7397 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007398 break;
7399 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00007400 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007401 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00007402 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007403 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007404#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007405 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08007406 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007407 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007408 break;
7409#else
bellard5cd43932003-03-29 16:54:36 +00007410 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007411#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007412
7413#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00007414 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007415 {
7416 off_t *offp = NULL;
7417 off_t off;
7418 if (arg3) {
7419 ret = get_user_sal(off, arg3);
7420 if (is_error(ret)) {
7421 break;
7422 }
7423 offp = &off;
7424 }
7425 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7426 if (!is_error(ret) && arg3) {
7427 abi_long ret2 = put_user_sal(off, arg3);
7428 if (is_error(ret2)) {
7429 ret = ret2;
7430 }
7431 }
7432 break;
7433 }
7434#ifdef TARGET_NR_sendfile64
7435 case TARGET_NR_sendfile64:
7436 {
7437 off_t *offp = NULL;
7438 off_t off;
7439 if (arg3) {
7440 ret = get_user_s64(off, arg3);
7441 if (is_error(ret)) {
7442 break;
7443 }
7444 offp = &off;
7445 }
7446 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7447 if (!is_error(ret) && arg3) {
7448 abi_long ret2 = put_user_s64(off, arg3);
7449 if (is_error(ret2)) {
7450 ret = ret2;
7451 }
7452 }
7453 break;
7454 }
7455#endif
7456#else
7457 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01007458#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007459 case TARGET_NR_sendfile64:
7460#endif
bellard5cd43932003-03-29 16:54:36 +00007461 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007462#endif
7463
bellardebc05482003-09-30 21:08:41 +00007464#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007465 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007466 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007467#endif
7468#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007469 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007470 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007471#endif
bellard048f6b42005-11-26 18:47:20 +00007472#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007473 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007474 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7475 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007476 break;
bellard048f6b42005-11-26 18:47:20 +00007477#endif
bellardebc05482003-09-30 21:08:41 +00007478#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007479 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007480 {
7481 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007482 int resource = target_to_host_resource(arg1);
7483 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007484 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007485 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007486 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7487 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007488 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7489 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007490 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007491 }
7492 break;
7493 }
bellardebc05482003-09-30 21:08:41 +00007494#endif
bellarda315a142005-01-30 22:59:18 +00007495#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007496 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007497 if (!(p = lock_user_string(arg1)))
7498 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007499 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7500 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007501 break;
bellarda315a142005-01-30 22:59:18 +00007502#endif
7503#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00007504 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00007505 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00007506 break;
bellarda315a142005-01-30 22:59:18 +00007507#endif
7508#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00007509 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00007510 if (!(p = lock_user_string(arg1)))
7511 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007512 ret = get_errno(stat(path(p), &st));
7513 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007514 if (!is_error(ret))
7515 ret = host_to_target_stat64(cpu_env, arg2, &st);
7516 break;
bellarda315a142005-01-30 22:59:18 +00007517#endif
7518#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00007519 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00007520 if (!(p = lock_user_string(arg1)))
7521 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007522 ret = get_errno(lstat(path(p), &st));
7523 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007524 if (!is_error(ret))
7525 ret = host_to_target_stat64(cpu_env, arg2, &st);
7526 break;
bellarda315a142005-01-30 22:59:18 +00007527#endif
7528#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00007529 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00007530 ret = get_errno(fstat(arg1, &st));
7531 if (!is_error(ret))
7532 ret = host_to_target_stat64(cpu_env, arg2, &st);
7533 break;
bellardec86b0f2003-04-11 00:15:04 +00007534#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007535#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00007536#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007537 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007538#endif
7539#ifdef TARGET_NR_newfstatat
7540 case TARGET_NR_newfstatat:
7541#endif
balrog6a24a772008-09-20 02:23:36 +00007542 if (!(p = lock_user_string(arg2)))
7543 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007544 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00007545 if (!is_error(ret))
7546 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007547 break;
bellarda315a142005-01-30 22:59:18 +00007548#endif
bellard67867302003-11-23 17:05:30 +00007549 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007550 if (!(p = lock_user_string(arg1)))
7551 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007552 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7553 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007554 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007555#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007556 case TARGET_NR_getuid:
7557 ret = get_errno(high2lowuid(getuid()));
7558 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007559#endif
7560#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007561 case TARGET_NR_getgid:
7562 ret = get_errno(high2lowgid(getgid()));
7563 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007564#endif
7565#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007566 case TARGET_NR_geteuid:
7567 ret = get_errno(high2lowuid(geteuid()));
7568 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007569#endif
7570#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007571 case TARGET_NR_getegid:
7572 ret = get_errno(high2lowgid(getegid()));
7573 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007574#endif
bellard67867302003-11-23 17:05:30 +00007575 case TARGET_NR_setreuid:
7576 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7577 break;
7578 case TARGET_NR_setregid:
7579 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7580 break;
7581 case TARGET_NR_getgroups:
7582 {
7583 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007584 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007585 gid_t *grouplist;
7586 int i;
7587
7588 grouplist = alloca(gidsetsize * sizeof(gid_t));
7589 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007590 if (gidsetsize == 0)
7591 break;
bellard67867302003-11-23 17:05:30 +00007592 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00007593 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00007594 if (!target_grouplist)
7595 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007596 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007597 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007598 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00007599 }
7600 }
7601 break;
7602 case TARGET_NR_setgroups:
7603 {
7604 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007605 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007606 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00007607 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007608 if (gidsetsize) {
7609 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007610 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007611 if (!target_grouplist) {
7612 ret = -TARGET_EFAULT;
7613 goto fail;
7614 }
7615 for (i = 0; i < gidsetsize; i++) {
7616 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
7617 }
7618 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007619 }
bellard67867302003-11-23 17:05:30 +00007620 ret = get_errno(setgroups(gidsetsize, grouplist));
7621 }
7622 break;
7623 case TARGET_NR_fchown:
7624 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7625 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007626#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00007627 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007628 if (!(p = lock_user_string(arg2)))
7629 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007630 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
7631 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00007632 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007633 break;
7634#endif
bellard67867302003-11-23 17:05:30 +00007635#ifdef TARGET_NR_setresuid
7636 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007637 ret = get_errno(setresuid(low2highuid(arg1),
7638 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007639 low2highuid(arg3)));
7640 break;
7641#endif
7642#ifdef TARGET_NR_getresuid
7643 case TARGET_NR_getresuid:
7644 {
pbrook53a59602006-03-25 19:31:22 +00007645 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007646 ret = get_errno(getresuid(&ruid, &euid, &suid));
7647 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007648 if (put_user_u16(high2lowuid(ruid), arg1)
7649 || put_user_u16(high2lowuid(euid), arg2)
7650 || put_user_u16(high2lowuid(suid), arg3))
7651 goto efault;
bellard67867302003-11-23 17:05:30 +00007652 }
7653 }
7654 break;
7655#endif
7656#ifdef TARGET_NR_getresgid
7657 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007658 ret = get_errno(setresgid(low2highgid(arg1),
7659 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007660 low2highgid(arg3)));
7661 break;
7662#endif
7663#ifdef TARGET_NR_getresgid
7664 case TARGET_NR_getresgid:
7665 {
pbrook53a59602006-03-25 19:31:22 +00007666 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007667 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7668 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007669 if (put_user_u16(high2lowgid(rgid), arg1)
7670 || put_user_u16(high2lowgid(egid), arg2)
7671 || put_user_u16(high2lowgid(sgid), arg3))
7672 goto efault;
bellard67867302003-11-23 17:05:30 +00007673 }
7674 }
7675 break;
7676#endif
7677 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007678 if (!(p = lock_user_string(arg1)))
7679 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007680 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7681 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007682 break;
7683 case TARGET_NR_setuid:
7684 ret = get_errno(setuid(low2highuid(arg1)));
7685 break;
7686 case TARGET_NR_setgid:
7687 ret = get_errno(setgid(low2highgid(arg1)));
7688 break;
7689 case TARGET_NR_setfsuid:
7690 ret = get_errno(setfsuid(arg1));
7691 break;
7692 case TARGET_NR_setfsgid:
7693 ret = get_errno(setfsgid(arg1));
7694 break;
bellard67867302003-11-23 17:05:30 +00007695
bellarda315a142005-01-30 22:59:18 +00007696#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00007697 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00007698 if (!(p = lock_user_string(arg1)))
7699 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007700 ret = get_errno(lchown(p, arg2, arg3));
7701 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007702 break;
bellarda315a142005-01-30 22:59:18 +00007703#endif
7704#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00007705 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00007706 ret = get_errno(getuid());
7707 break;
bellarda315a142005-01-30 22:59:18 +00007708#endif
aurel3264b4d282008-11-14 17:20:15 +00007709
7710#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
7711 /* Alpha specific */
7712 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007713 {
7714 uid_t euid;
7715 euid=geteuid();
7716 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
7717 }
aurel3264b4d282008-11-14 17:20:15 +00007718 ret = get_errno(getuid());
7719 break;
7720#endif
7721#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
7722 /* Alpha specific */
7723 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007724 {
7725 uid_t egid;
7726 egid=getegid();
7727 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
7728 }
aurel3264b4d282008-11-14 17:20:15 +00007729 ret = get_errno(getgid());
7730 break;
7731#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08007732#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
7733 /* Alpha specific */
7734 case TARGET_NR_osf_getsysinfo:
7735 ret = -TARGET_EOPNOTSUPP;
7736 switch (arg1) {
7737 case TARGET_GSI_IEEE_FP_CONTROL:
7738 {
7739 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
7740
7741 /* Copied from linux ieee_fpcr_to_swcr. */
7742 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
7743 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
7744 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
7745 | SWCR_TRAP_ENABLE_DZE
7746 | SWCR_TRAP_ENABLE_OVF);
7747 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
7748 | SWCR_TRAP_ENABLE_INE);
7749 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
7750 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
7751
7752 if (put_user_u64 (swcr, arg2))
7753 goto efault;
7754 ret = 0;
7755 }
7756 break;
7757
7758 /* case GSI_IEEE_STATE_AT_SIGNAL:
7759 -- Not implemented in linux kernel.
7760 case GSI_UACPROC:
7761 -- Retrieves current unaligned access state; not much used.
7762 case GSI_PROC_TYPE:
7763 -- Retrieves implver information; surely not used.
7764 case GSI_GET_HWRPB:
7765 -- Grabs a copy of the HWRPB; surely not used.
7766 */
7767 }
7768 break;
7769#endif
7770#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
7771 /* Alpha specific */
7772 case TARGET_NR_osf_setsysinfo:
7773 ret = -TARGET_EOPNOTSUPP;
7774 switch (arg1) {
7775 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007776 {
7777 uint64_t swcr, fpcr, orig_fpcr;
7778
Richard Henderson6e06d512012-06-01 09:08:21 -07007779 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08007780 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07007781 }
7782 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007783 fpcr = orig_fpcr & FPCR_DYN_MASK;
7784
7785 /* Copied from linux ieee_swcr_to_fpcr. */
7786 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
7787 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
7788 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
7789 | SWCR_TRAP_ENABLE_DZE
7790 | SWCR_TRAP_ENABLE_OVF)) << 48;
7791 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
7792 | SWCR_TRAP_ENABLE_INE)) << 57;
7793 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
7794 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
7795
Richard Henderson6e06d512012-06-01 09:08:21 -07007796 cpu_alpha_store_fpcr(cpu_env, fpcr);
7797 ret = 0;
7798 }
7799 break;
7800
7801 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
7802 {
7803 uint64_t exc, fpcr, orig_fpcr;
7804 int si_code;
7805
7806 if (get_user_u64(exc, arg2)) {
7807 goto efault;
7808 }
7809
7810 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
7811
7812 /* We only add to the exception status here. */
7813 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
7814
7815 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007816 ret = 0;
7817
Richard Henderson6e06d512012-06-01 09:08:21 -07007818 /* Old exceptions are not signaled. */
7819 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007820
Richard Henderson6e06d512012-06-01 09:08:21 -07007821 /* If any exceptions set by this call,
7822 and are unmasked, send a signal. */
7823 si_code = 0;
7824 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
7825 si_code = TARGET_FPE_FLTRES;
7826 }
7827 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
7828 si_code = TARGET_FPE_FLTUND;
7829 }
7830 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
7831 si_code = TARGET_FPE_FLTOVF;
7832 }
7833 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
7834 si_code = TARGET_FPE_FLTDIV;
7835 }
7836 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
7837 si_code = TARGET_FPE_FLTINV;
7838 }
7839 if (si_code != 0) {
7840 target_siginfo_t info;
7841 info.si_signo = SIGFPE;
7842 info.si_errno = 0;
7843 info.si_code = si_code;
7844 info._sifields._sigfault._addr
7845 = ((CPUArchState *)cpu_env)->pc;
7846 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007847 }
7848 }
7849 break;
7850
7851 /* case SSI_NVPAIRS:
7852 -- Used with SSIN_UACPROC to enable unaligned accesses.
7853 case SSI_IEEE_STATE_AT_SIGNAL:
7854 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
7855 -- Not implemented in linux kernel
7856 */
7857 }
7858 break;
7859#endif
7860#ifdef TARGET_NR_osf_sigprocmask
7861 /* Alpha specific. */
7862 case TARGET_NR_osf_sigprocmask:
7863 {
7864 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01007865 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08007866 sigset_t set, oldset;
7867
7868 switch(arg1) {
7869 case TARGET_SIG_BLOCK:
7870 how = SIG_BLOCK;
7871 break;
7872 case TARGET_SIG_UNBLOCK:
7873 how = SIG_UNBLOCK;
7874 break;
7875 case TARGET_SIG_SETMASK:
7876 how = SIG_SETMASK;
7877 break;
7878 default:
7879 ret = -TARGET_EINVAL;
7880 goto fail;
7881 }
7882 mask = arg2;
7883 target_to_host_old_sigset(&set, &mask);
Juan Quintelabc088ba2011-06-16 17:37:10 +01007884 sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007885 host_to_target_old_sigset(&mask, &oldset);
7886 ret = mask;
7887 }
7888 break;
7889#endif
aurel3264b4d282008-11-14 17:20:15 +00007890
bellarda315a142005-01-30 22:59:18 +00007891#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00007892 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00007893 ret = get_errno(getgid());
7894 break;
bellarda315a142005-01-30 22:59:18 +00007895#endif
7896#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00007897 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00007898 ret = get_errno(geteuid());
7899 break;
bellarda315a142005-01-30 22:59:18 +00007900#endif
7901#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00007902 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00007903 ret = get_errno(getegid());
7904 break;
bellarda315a142005-01-30 22:59:18 +00007905#endif
7906#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00007907 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00007908 ret = get_errno(setreuid(arg1, arg2));
7909 break;
bellarda315a142005-01-30 22:59:18 +00007910#endif
7911#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00007912 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00007913 ret = get_errno(setregid(arg1, arg2));
7914 break;
bellarda315a142005-01-30 22:59:18 +00007915#endif
7916#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00007917 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00007918 {
7919 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007920 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007921 gid_t *grouplist;
7922 int i;
7923
7924 grouplist = alloca(gidsetsize * sizeof(gid_t));
7925 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007926 if (gidsetsize == 0)
7927 break;
bellard99c475a2005-01-31 20:45:13 +00007928 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007929 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
7930 if (!target_grouplist) {
7931 ret = -TARGET_EFAULT;
7932 goto fail;
7933 }
balroga2155fc2008-09-20 02:12:08 +00007934 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00007935 target_grouplist[i] = tswap32(grouplist[i]);
7936 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00007937 }
7938 }
7939 break;
bellarda315a142005-01-30 22:59:18 +00007940#endif
7941#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00007942 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00007943 {
7944 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007945 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007946 gid_t *grouplist;
7947 int i;
ths3b46e622007-09-17 08:09:54 +00007948
bellard99c475a2005-01-31 20:45:13 +00007949 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007950 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
7951 if (!target_grouplist) {
7952 ret = -TARGET_EFAULT;
7953 goto fail;
7954 }
bellard99c475a2005-01-31 20:45:13 +00007955 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00007956 grouplist[i] = tswap32(target_grouplist[i]);
7957 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00007958 ret = get_errno(setgroups(gidsetsize, grouplist));
7959 }
7960 break;
bellarda315a142005-01-30 22:59:18 +00007961#endif
7962#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00007963 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00007964 ret = get_errno(fchown(arg1, arg2, arg3));
7965 break;
bellarda315a142005-01-30 22:59:18 +00007966#endif
7967#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00007968 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007969 ret = get_errno(setresuid(arg1, arg2, arg3));
7970 break;
bellarda315a142005-01-30 22:59:18 +00007971#endif
7972#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00007973 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007974 {
pbrook53a59602006-03-25 19:31:22 +00007975 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00007976 ret = get_errno(getresuid(&ruid, &euid, &suid));
7977 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007978 if (put_user_u32(ruid, arg1)
7979 || put_user_u32(euid, arg2)
7980 || put_user_u32(suid, arg3))
7981 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007982 }
7983 }
7984 break;
bellarda315a142005-01-30 22:59:18 +00007985#endif
7986#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00007987 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007988 ret = get_errno(setresgid(arg1, arg2, arg3));
7989 break;
bellarda315a142005-01-30 22:59:18 +00007990#endif
7991#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00007992 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007993 {
pbrook53a59602006-03-25 19:31:22 +00007994 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00007995 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7996 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007997 if (put_user_u32(rgid, arg1)
7998 || put_user_u32(egid, arg2)
7999 || put_user_u32(sgid, arg3))
8000 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008001 }
8002 }
8003 break;
bellarda315a142005-01-30 22:59:18 +00008004#endif
8005#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008006 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008007 if (!(p = lock_user_string(arg1)))
8008 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008009 ret = get_errno(chown(p, arg2, arg3));
8010 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008011 break;
bellarda315a142005-01-30 22:59:18 +00008012#endif
8013#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008014 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008015 ret = get_errno(setuid(arg1));
8016 break;
bellarda315a142005-01-30 22:59:18 +00008017#endif
8018#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008019 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008020 ret = get_errno(setgid(arg1));
8021 break;
bellarda315a142005-01-30 22:59:18 +00008022#endif
8023#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008024 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008025 ret = get_errno(setfsuid(arg1));
8026 break;
bellarda315a142005-01-30 22:59:18 +00008027#endif
8028#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008029 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008030 ret = get_errno(setfsgid(arg1));
8031 break;
bellarda315a142005-01-30 22:59:18 +00008032#endif
bellard67867302003-11-23 17:05:30 +00008033
bellard31e31b82003-02-18 22:55:36 +00008034 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008035 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008036#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008037 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008038 {
8039 void *a;
8040 ret = -TARGET_EFAULT;
8041 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8042 goto efault;
8043 if (!(p = lock_user_string(arg3)))
8044 goto mincore_fail;
8045 ret = get_errno(mincore(a, arg2, p));
8046 unlock_user(p, arg3, ret);
8047 mincore_fail:
8048 unlock_user(a, arg1, 0);
8049 }
8050 break;
bellardffa65c32004-01-04 23:57:22 +00008051#endif
aurel32408321b2008-10-01 21:46:32 +00008052#ifdef TARGET_NR_arm_fadvise64_64
8053 case TARGET_NR_arm_fadvise64_64:
8054 {
8055 /*
8056 * arm_fadvise64_64 looks like fadvise64_64 but
8057 * with different argument order
8058 */
8059 abi_long temp;
8060 temp = arg3;
8061 arg3 = arg4;
8062 arg4 = temp;
8063 }
8064#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008065#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008066#ifdef TARGET_NR_fadvise64_64
8067 case TARGET_NR_fadvise64_64:
8068#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008069#ifdef TARGET_NR_fadvise64
8070 case TARGET_NR_fadvise64:
8071#endif
8072#ifdef TARGET_S390X
8073 switch (arg4) {
8074 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8075 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8076 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8077 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8078 default: break;
8079 }
8080#endif
8081 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008082 break;
8083#endif
bellardffa65c32004-01-04 23:57:22 +00008084#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008085 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008086 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08008087 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00008088 This will break MADV_DONTNEED.
8089 This is a hint, so ignoring and returning success is ok. */
8090 ret = get_errno(0);
8091 break;
bellardffa65c32004-01-04 23:57:22 +00008092#endif
blueswir1992f48a2007-10-14 16:27:31 +00008093#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008094 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008095 {
thsb1e341e2007-03-20 21:50:52 +00008096 int cmd;
bellard77e46722003-04-29 20:39:06 +00008097 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008098 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008099#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008100 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008101#endif
bellard77e46722003-04-29 20:39:06 +00008102
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008103 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008104 if (cmd == -TARGET_EINVAL) {
8105 ret = cmd;
8106 break;
8107 }
thsb1e341e2007-03-20 21:50:52 +00008108
bellard60cd49d2003-03-16 22:53:56 +00008109 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008110 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008111#ifdef TARGET_ARM
8112 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008113 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8114 goto efault;
ths58134272007-03-31 18:59:32 +00008115 fl.l_type = tswap16(target_efl->l_type);
8116 fl.l_whence = tswap16(target_efl->l_whence);
8117 fl.l_start = tswap64(target_efl->l_start);
8118 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008119 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008120 unlock_user_struct(target_efl, arg3, 0);
8121 } else
8122#endif
8123 {
bellard9ee1fa22007-11-11 15:11:19 +00008124 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8125 goto efault;
ths58134272007-03-31 18:59:32 +00008126 fl.l_type = tswap16(target_fl->l_type);
8127 fl.l_whence = tswap16(target_fl->l_whence);
8128 fl.l_start = tswap64(target_fl->l_start);
8129 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008130 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008131 unlock_user_struct(target_fl, arg3, 0);
8132 }
thsb1e341e2007-03-20 21:50:52 +00008133 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008134 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008135#ifdef TARGET_ARM
8136 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008137 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8138 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008139 target_efl->l_type = tswap16(fl.l_type);
8140 target_efl->l_whence = tswap16(fl.l_whence);
8141 target_efl->l_start = tswap64(fl.l_start);
8142 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008143 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008144 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008145 } else
8146#endif
8147 {
bellard9ee1fa22007-11-11 15:11:19 +00008148 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8149 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008150 target_fl->l_type = tswap16(fl.l_type);
8151 target_fl->l_whence = tswap16(fl.l_whence);
8152 target_fl->l_start = tswap64(fl.l_start);
8153 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008154 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008155 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008156 }
bellard77e46722003-04-29 20:39:06 +00008157 }
8158 break;
8159
thsb1e341e2007-03-20 21:50:52 +00008160 case TARGET_F_SETLK64:
8161 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008162#ifdef TARGET_ARM
8163 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008164 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8165 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008166 fl.l_type = tswap16(target_efl->l_type);
8167 fl.l_whence = tswap16(target_efl->l_whence);
8168 fl.l_start = tswap64(target_efl->l_start);
8169 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008170 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008171 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008172 } else
8173#endif
8174 {
bellard9ee1fa22007-11-11 15:11:19 +00008175 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8176 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008177 fl.l_type = tswap16(target_fl->l_type);
8178 fl.l_whence = tswap16(target_fl->l_whence);
8179 fl.l_start = tswap64(target_fl->l_start);
8180 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008181 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008182 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008183 }
thsb1e341e2007-03-20 21:50:52 +00008184 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008185 break;
bellard60cd49d2003-03-16 22:53:56 +00008186 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008187 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008188 break;
8189 }
bellard77e46722003-04-29 20:39:06 +00008190 break;
8191 }
bellard60cd49d2003-03-16 22:53:56 +00008192#endif
ths7d600c82006-12-08 01:32:58 +00008193#ifdef TARGET_NR_cacheflush
8194 case TARGET_NR_cacheflush:
8195 /* self-modifying code is handled automatically, so nothing needed */
8196 ret = 0;
8197 break;
8198#endif
bellardebc05482003-09-30 21:08:41 +00008199#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008200 case TARGET_NR_security:
8201 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008202#endif
bellardc573ff62004-01-04 15:51:36 +00008203#ifdef TARGET_NR_getpagesize
8204 case TARGET_NR_getpagesize:
8205 ret = TARGET_PAGE_SIZE;
8206 break;
8207#endif
bellard31e31b82003-02-18 22:55:36 +00008208 case TARGET_NR_gettid:
8209 ret = get_errno(gettid());
8210 break;
thse5febef2007-04-01 18:31:35 +00008211#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008212 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008213#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008214 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008215 arg2 = arg3;
8216 arg3 = arg4;
8217 arg4 = arg5;
8218 }
aurel322054ac92008-10-13 21:08:07 +00008219 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8220#else
8221 ret = get_errno(readahead(arg1, arg2, arg3));
8222#endif
8223 break;
thse5febef2007-04-01 18:31:35 +00008224#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008225#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008226#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008227 case TARGET_NR_listxattr:
8228 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008229 {
8230 void *p, *b = 0;
8231 if (arg2) {
8232 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8233 if (!b) {
8234 ret = -TARGET_EFAULT;
8235 break;
8236 }
8237 }
8238 p = lock_user_string(arg1);
8239 if (p) {
8240 if (num == TARGET_NR_listxattr) {
8241 ret = get_errno(listxattr(p, b, arg3));
8242 } else {
8243 ret = get_errno(llistxattr(p, b, arg3));
8244 }
8245 } else {
8246 ret = -TARGET_EFAULT;
8247 }
8248 unlock_user(p, arg1, 0);
8249 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008250 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008251 }
8252 case TARGET_NR_flistxattr:
8253 {
8254 void *b = 0;
8255 if (arg2) {
8256 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8257 if (!b) {
8258 ret = -TARGET_EFAULT;
8259 break;
8260 }
8261 }
8262 ret = get_errno(flistxattr(arg1, b, arg3));
8263 unlock_user(b, arg2, arg3);
8264 break;
8265 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008266 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008267 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008268 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008269 void *p, *n, *v = 0;
8270 if (arg3) {
8271 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8272 if (!v) {
8273 ret = -TARGET_EFAULT;
8274 break;
8275 }
8276 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008277 p = lock_user_string(arg1);
8278 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008279 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008280 if (num == TARGET_NR_setxattr) {
8281 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8282 } else {
8283 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8284 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008285 } else {
8286 ret = -TARGET_EFAULT;
8287 }
8288 unlock_user(p, arg1, 0);
8289 unlock_user(n, arg2, 0);
8290 unlock_user(v, arg3, 0);
8291 }
8292 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008293 case TARGET_NR_fsetxattr:
8294 {
8295 void *n, *v = 0;
8296 if (arg3) {
8297 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8298 if (!v) {
8299 ret = -TARGET_EFAULT;
8300 break;
8301 }
8302 }
8303 n = lock_user_string(arg2);
8304 if (n) {
8305 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8306 } else {
8307 ret = -TARGET_EFAULT;
8308 }
8309 unlock_user(n, arg2, 0);
8310 unlock_user(v, arg3, 0);
8311 }
8312 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008313 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008314 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008315 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008316 void *p, *n, *v = 0;
8317 if (arg3) {
8318 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8319 if (!v) {
8320 ret = -TARGET_EFAULT;
8321 break;
8322 }
8323 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008324 p = lock_user_string(arg1);
8325 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008326 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008327 if (num == TARGET_NR_getxattr) {
8328 ret = get_errno(getxattr(p, n, v, arg4));
8329 } else {
8330 ret = get_errno(lgetxattr(p, n, v, arg4));
8331 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008332 } else {
8333 ret = -TARGET_EFAULT;
8334 }
8335 unlock_user(p, arg1, 0);
8336 unlock_user(n, arg2, 0);
8337 unlock_user(v, arg3, arg4);
8338 }
8339 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008340 case TARGET_NR_fgetxattr:
8341 {
8342 void *n, *v = 0;
8343 if (arg3) {
8344 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8345 if (!v) {
8346 ret = -TARGET_EFAULT;
8347 break;
8348 }
8349 }
8350 n = lock_user_string(arg2);
8351 if (n) {
8352 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8353 } else {
8354 ret = -TARGET_EFAULT;
8355 }
8356 unlock_user(n, arg2, 0);
8357 unlock_user(v, arg3, arg4);
8358 }
8359 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008360 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008361 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008362 {
8363 void *p, *n;
8364 p = lock_user_string(arg1);
8365 n = lock_user_string(arg2);
8366 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008367 if (num == TARGET_NR_removexattr) {
8368 ret = get_errno(removexattr(p, n));
8369 } else {
8370 ret = get_errno(lremovexattr(p, n));
8371 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008372 } else {
8373 ret = -TARGET_EFAULT;
8374 }
8375 unlock_user(p, arg1, 0);
8376 unlock_user(n, arg2, 0);
8377 }
8378 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008379 case TARGET_NR_fremovexattr:
8380 {
8381 void *n;
8382 n = lock_user_string(arg2);
8383 if (n) {
8384 ret = get_errno(fremovexattr(arg1, n));
8385 } else {
8386 ret = -TARGET_EFAULT;
8387 }
8388 unlock_user(n, arg2, 0);
8389 }
8390 break;
bellardebc05482003-09-30 21:08:41 +00008391#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008392#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008393#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008394 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008395#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00008396 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
8397 ret = 0;
8398 break;
edgar_iglef967792009-01-07 14:19:38 +00008399#elif defined(TARGET_CRIS)
8400 if (arg1 & 0xff)
8401 ret = -TARGET_EINVAL;
8402 else {
8403 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8404 ret = 0;
8405 }
8406 break;
bellard8d18e892007-11-14 15:18:40 +00008407#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8408 ret = do_set_thread_area(cpu_env, arg1);
8409 break;
Peter Maydelld5bea012013-07-05 16:10:50 +01008410#elif defined(TARGET_M68K)
8411 {
8412 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
8413 ts->tp_value = arg1;
8414 }
ths6f5b89a2007-03-02 20:48:00 +00008415#else
8416 goto unimplemented_nowarn;
8417#endif
8418#endif
8419#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008420 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008421#if defined(TARGET_I386) && defined(TARGET_ABI32)
8422 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld5bea012013-07-05 16:10:50 +01008423#elif defined(TARGET_M68K)
8424 {
8425 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
8426 ts->tp_value = arg1;
8427 }
bellard8d18e892007-11-14 15:18:40 +00008428#else
bellard5cd43932003-03-29 16:54:36 +00008429 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008430#endif
bellard8d18e892007-11-14 15:18:40 +00008431#endif
bellard48dc41e2006-06-21 18:15:50 +00008432#ifdef TARGET_NR_getdomainname
8433 case TARGET_NR_getdomainname:
8434 goto unimplemented_nowarn;
8435#endif
ths6f5b89a2007-03-02 20:48:00 +00008436
thsb5906f92007-03-19 13:32:45 +00008437#ifdef TARGET_NR_clock_gettime
8438 case TARGET_NR_clock_gettime:
8439 {
8440 struct timespec ts;
8441 ret = get_errno(clock_gettime(arg1, &ts));
8442 if (!is_error(ret)) {
8443 host_to_target_timespec(arg2, &ts);
8444 }
8445 break;
8446 }
8447#endif
8448#ifdef TARGET_NR_clock_getres
8449 case TARGET_NR_clock_getres:
8450 {
8451 struct timespec ts;
8452 ret = get_errno(clock_getres(arg1, &ts));
8453 if (!is_error(ret)) {
8454 host_to_target_timespec(arg2, &ts);
8455 }
8456 break;
8457 }
8458#endif
pbrook63d76512008-05-29 13:43:29 +00008459#ifdef TARGET_NR_clock_nanosleep
8460 case TARGET_NR_clock_nanosleep:
8461 {
8462 struct timespec ts;
8463 target_to_host_timespec(&ts, arg3);
8464 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8465 if (arg4)
8466 host_to_target_timespec(arg4, &ts);
8467 break;
8468 }
8469#endif
thsb5906f92007-03-19 13:32:45 +00008470
ths6f5b89a2007-03-02 20:48:00 +00008471#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8472 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008473 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8474 break;
ths6f5b89a2007-03-02 20:48:00 +00008475#endif
8476
ths3ae43202007-09-16 21:39:48 +00008477#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008478 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008479 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008480 break;
8481#endif
8482
ths3ae43202007-09-16 21:39:48 +00008483#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008484 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008485 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8486 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008487 break;
8488#endif
8489
ths4f2b1fe2007-06-21 21:57:12 +00008490#ifdef TARGET_NR_set_robust_list
8491 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00008492 case TARGET_NR_get_robust_list:
8493 /* The ABI for supporting robust futexes has userspace pass
8494 * the kernel a pointer to a linked list which is updated by
8495 * userspace after the syscall; the list is walked by the kernel
8496 * when the thread exits. Since the linked list in QEMU guest
8497 * memory isn't a valid linked list for the host and we have
8498 * no way to reliably intercept the thread-death event, we can't
8499 * support these. Silently return ENOSYS so that guest userspace
8500 * falls back to a non-robust futex implementation (which should
8501 * be OK except in the corner case of the guest crashing while
8502 * holding a mutex that is shared with another process via
8503 * shared memory).
8504 */
8505 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00008506#endif
8507
ths9007f0e2007-09-25 17:50:37 +00008508#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
8509 case TARGET_NR_utimensat:
8510 {
Riku Voipioebc996f2009-04-21 15:01:51 +03008511 struct timespec *tsp, ts[2];
8512 if (!arg3) {
8513 tsp = NULL;
8514 } else {
8515 target_to_host_timespec(ts, arg3);
8516 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
8517 tsp = ts;
8518 }
ths9007f0e2007-09-25 17:50:37 +00008519 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03008520 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00008521 else {
bellard579a97f2007-11-11 14:26:47 +00008522 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00008523 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008524 goto fail;
8525 }
Riku Voipioebc996f2009-04-21 15:01:51 +03008526 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00008527 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00008528 }
8529 }
8530 break;
8531#endif
pbrookbd0c5662008-05-29 14:34:11 +00008532 case TARGET_NR_futex:
8533 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
8534 break;
aurel32dbfe4c32009-04-08 21:29:30 +00008535#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00008536 case TARGET_NR_inotify_init:
8537 ret = get_errno(sys_inotify_init());
8538 break;
8539#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008540#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00008541#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
8542 case TARGET_NR_inotify_init1:
8543 ret = get_errno(sys_inotify_init1(arg1));
8544 break;
8545#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008546#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008547#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00008548 case TARGET_NR_inotify_add_watch:
8549 p = lock_user_string(arg2);
8550 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
8551 unlock_user(p, arg2, 0);
8552 break;
8553#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008554#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00008555 case TARGET_NR_inotify_rm_watch:
8556 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
8557 break;
8558#endif
ths9007f0e2007-09-25 17:50:37 +00008559
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07008560#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00008561 case TARGET_NR_mq_open:
8562 {
8563 struct mq_attr posix_mq_attr;
8564
8565 p = lock_user_string(arg1 - 1);
8566 if (arg4 != 0)
8567 copy_from_user_mq_attr (&posix_mq_attr, arg4);
8568 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
8569 unlock_user (p, arg1, 0);
8570 }
8571 break;
8572
8573 case TARGET_NR_mq_unlink:
8574 p = lock_user_string(arg1 - 1);
8575 ret = get_errno(mq_unlink(p));
8576 unlock_user (p, arg1, 0);
8577 break;
8578
8579 case TARGET_NR_mq_timedsend:
8580 {
8581 struct timespec ts;
8582
8583 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8584 if (arg5 != 0) {
8585 target_to_host_timespec(&ts, arg5);
8586 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
8587 host_to_target_timespec(arg5, &ts);
8588 }
8589 else
8590 ret = get_errno(mq_send(arg1, p, arg3, arg4));
8591 unlock_user (p, arg2, arg3);
8592 }
8593 break;
8594
8595 case TARGET_NR_mq_timedreceive:
8596 {
8597 struct timespec ts;
8598 unsigned int prio;
8599
8600 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8601 if (arg5 != 0) {
8602 target_to_host_timespec(&ts, arg5);
8603 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
8604 host_to_target_timespec(arg5, &ts);
8605 }
8606 else
8607 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
8608 unlock_user (p, arg2, arg3);
8609 if (arg4 != 0)
8610 put_user_u32(prio, arg4);
8611 }
8612 break;
8613
8614 /* Not implemented for now... */
8615/* case TARGET_NR_mq_notify: */
8616/* break; */
8617
8618 case TARGET_NR_mq_getsetattr:
8619 {
8620 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
8621 ret = 0;
8622 if (arg3 != 0) {
8623 ret = mq_getattr(arg1, &posix_mq_attr_out);
8624 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
8625 }
8626 if (arg2 != 0) {
8627 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
8628 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
8629 }
8630
8631 }
8632 break;
8633#endif
8634
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308635#ifdef CONFIG_SPLICE
8636#ifdef TARGET_NR_tee
8637 case TARGET_NR_tee:
8638 {
8639 ret = get_errno(tee(arg1,arg2,arg3,arg4));
8640 }
8641 break;
8642#endif
8643#ifdef TARGET_NR_splice
8644 case TARGET_NR_splice:
8645 {
8646 loff_t loff_in, loff_out;
8647 loff_t *ploff_in = NULL, *ploff_out = NULL;
8648 if(arg2) {
8649 get_user_u64(loff_in, arg2);
8650 ploff_in = &loff_in;
8651 }
8652 if(arg4) {
8653 get_user_u64(loff_out, arg2);
8654 ploff_out = &loff_out;
8655 }
8656 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
8657 }
8658 break;
8659#endif
8660#ifdef TARGET_NR_vmsplice
8661 case TARGET_NR_vmsplice:
8662 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008663 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
8664 if (vec != NULL) {
8665 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
8666 unlock_iovec(vec, arg2, arg3, 0);
8667 } else {
8668 ret = -host_to_target_errno(errno);
8669 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308670 }
8671 break;
8672#endif
8673#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03008674#ifdef CONFIG_EVENTFD
8675#if defined(TARGET_NR_eventfd)
8676 case TARGET_NR_eventfd:
8677 ret = get_errno(eventfd(arg1, 0));
8678 break;
8679#endif
8680#if defined(TARGET_NR_eventfd2)
8681 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02008682 {
8683 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
8684 if (arg2 & TARGET_O_NONBLOCK) {
8685 host_flags |= O_NONBLOCK;
8686 }
8687 if (arg2 & TARGET_O_CLOEXEC) {
8688 host_flags |= O_CLOEXEC;
8689 }
8690 ret = get_errno(eventfd(arg1, host_flags));
Riku Voipioc2882b92009-08-12 15:08:24 +03008691 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02008692 }
Riku Voipioc2882b92009-08-12 15:08:24 +03008693#endif
8694#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03008695#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
8696 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01008697#if TARGET_ABI_BITS == 32
8698 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
8699 target_offset64(arg5, arg6)));
8700#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03008701 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01008702#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008703 break;
8704#endif
Peter Maydellc727f472011-01-06 11:05:10 +00008705#if defined(CONFIG_SYNC_FILE_RANGE)
8706#if defined(TARGET_NR_sync_file_range)
8707 case TARGET_NR_sync_file_range:
8708#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03008709#if defined(TARGET_MIPS)
8710 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8711 target_offset64(arg5, arg6), arg7));
8712#else
Peter Maydellc727f472011-01-06 11:05:10 +00008713 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
8714 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03008715#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00008716#else
8717 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
8718#endif
8719 break;
8720#endif
8721#if defined(TARGET_NR_sync_file_range2)
8722 case TARGET_NR_sync_file_range2:
8723 /* This is like sync_file_range but the arguments are reordered */
8724#if TARGET_ABI_BITS == 32
8725 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8726 target_offset64(arg5, arg6), arg2));
8727#else
8728 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
8729#endif
8730 break;
8731#endif
8732#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00008733#if defined(CONFIG_EPOLL)
8734#if defined(TARGET_NR_epoll_create)
8735 case TARGET_NR_epoll_create:
8736 ret = get_errno(epoll_create(arg1));
8737 break;
8738#endif
8739#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
8740 case TARGET_NR_epoll_create1:
8741 ret = get_errno(epoll_create1(arg1));
8742 break;
8743#endif
8744#if defined(TARGET_NR_epoll_ctl)
8745 case TARGET_NR_epoll_ctl:
8746 {
8747 struct epoll_event ep;
8748 struct epoll_event *epp = 0;
8749 if (arg4) {
8750 struct target_epoll_event *target_ep;
8751 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
8752 goto efault;
8753 }
8754 ep.events = tswap32(target_ep->events);
8755 /* The epoll_data_t union is just opaque data to the kernel,
8756 * so we transfer all 64 bits across and need not worry what
8757 * actual data type it is.
8758 */
8759 ep.data.u64 = tswap64(target_ep->data.u64);
8760 unlock_user_struct(target_ep, arg4, 0);
8761 epp = &ep;
8762 }
8763 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
8764 break;
8765 }
8766#endif
8767
8768#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
8769#define IMPLEMENT_EPOLL_PWAIT
8770#endif
8771#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
8772#if defined(TARGET_NR_epoll_wait)
8773 case TARGET_NR_epoll_wait:
8774#endif
8775#if defined(IMPLEMENT_EPOLL_PWAIT)
8776 case TARGET_NR_epoll_pwait:
8777#endif
8778 {
8779 struct target_epoll_event *target_ep;
8780 struct epoll_event *ep;
8781 int epfd = arg1;
8782 int maxevents = arg3;
8783 int timeout = arg4;
8784
8785 target_ep = lock_user(VERIFY_WRITE, arg2,
8786 maxevents * sizeof(struct target_epoll_event), 1);
8787 if (!target_ep) {
8788 goto efault;
8789 }
8790
8791 ep = alloca(maxevents * sizeof(struct epoll_event));
8792
8793 switch (num) {
8794#if defined(IMPLEMENT_EPOLL_PWAIT)
8795 case TARGET_NR_epoll_pwait:
8796 {
8797 target_sigset_t *target_set;
8798 sigset_t _set, *set = &_set;
8799
8800 if (arg5) {
8801 target_set = lock_user(VERIFY_READ, arg5,
8802 sizeof(target_sigset_t), 1);
8803 if (!target_set) {
8804 unlock_user(target_ep, arg2, 0);
8805 goto efault;
8806 }
8807 target_to_host_sigset(set, target_set);
8808 unlock_user(target_set, arg5, 0);
8809 } else {
8810 set = NULL;
8811 }
8812
8813 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
8814 break;
8815 }
8816#endif
8817#if defined(TARGET_NR_epoll_wait)
8818 case TARGET_NR_epoll_wait:
8819 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
8820 break;
8821#endif
8822 default:
8823 ret = -TARGET_ENOSYS;
8824 }
8825 if (!is_error(ret)) {
8826 int i;
8827 for (i = 0; i < ret; i++) {
8828 target_ep[i].events = tswap32(ep[i].events);
8829 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
8830 }
8831 }
8832 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
8833 break;
8834 }
8835#endif
8836#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01008837#ifdef TARGET_NR_prlimit64
8838 case TARGET_NR_prlimit64:
8839 {
8840 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
8841 struct target_rlimit64 *target_rnew, *target_rold;
8842 struct host_rlimit64 rnew, rold, *rnewp = 0;
8843 if (arg3) {
8844 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
8845 goto efault;
8846 }
8847 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
8848 rnew.rlim_max = tswap64(target_rnew->rlim_max);
8849 unlock_user_struct(target_rnew, arg3, 0);
8850 rnewp = &rnew;
8851 }
8852
8853 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
8854 if (!is_error(ret) && arg4) {
8855 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
8856 goto efault;
8857 }
8858 target_rold->rlim_cur = tswap64(rold.rlim_cur);
8859 target_rold->rlim_max = tswap64(rold.rlim_max);
8860 unlock_user_struct(target_rold, arg4, 1);
8861 }
8862 break;
8863 }
8864#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07008865#ifdef TARGET_NR_gethostname
8866 case TARGET_NR_gethostname:
8867 {
8868 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
8869 if (name) {
8870 ret = get_errno(gethostname(name, arg2));
8871 unlock_user(name, arg1, arg2);
8872 } else {
8873 ret = -TARGET_EFAULT;
8874 }
8875 break;
8876 }
8877#endif
bellard31e31b82003-02-18 22:55:36 +00008878 default:
8879 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00008880 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00008881#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 +00008882 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00008883#endif
ths0da46a62007-10-20 20:23:07 +00008884 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00008885 break;
8886 }
bellard579a97f2007-11-11 14:26:47 +00008887fail:
bellardc573ff62004-01-04 15:51:36 +00008888#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00008889 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00008890#endif
thsb92c47c2007-11-01 00:07:38 +00008891 if(do_strace)
8892 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00008893 return ret;
bellard579a97f2007-11-11 14:26:47 +00008894efault:
8895 ret = -TARGET_EFAULT;
8896 goto fail;
bellard31e31b82003-02-18 22:55:36 +00008897}