blob: 4c96f4fd8528d869a6f06d3921d47efde0624b02 [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
Juan Quintela2f7bb872009-07-27 16:13:24 +0200113#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +0000114#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
115 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
116#else
117/* XXX: Hardcode the above values. */
118#define CLONE_NPTL_FLAGS2 0
pbrook30813ce2008-06-02 15:45:44 +0000119#endif
120
bellard72f03902003-02-18 23:33:18 +0000121//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000122
bellard1a9353d2003-03-16 20:28:50 +0000123//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000124#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
125#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000126
bellard70a194b2003-08-11 22:20:16 +0000127
bellard70a194b2003-08-11 22:20:16 +0000128#undef _syscall0
129#undef _syscall1
130#undef _syscall2
131#undef _syscall3
132#undef _syscall4
133#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000134#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000135
bellard83fcb512006-06-14 13:37:16 +0000136#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000137static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000138{ \
139 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000140}
141
bellard83fcb512006-06-14 13:37:16 +0000142#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000143static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000144{ \
145 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000146}
147
bellard83fcb512006-06-14 13:37:16 +0000148#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000149static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000150{ \
151 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000152}
153
bellard83fcb512006-06-14 13:37:16 +0000154#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000155static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000156{ \
157 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000158}
159
bellard83fcb512006-06-14 13:37:16 +0000160#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000161static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000162{ \
163 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000164}
165
bellard83fcb512006-06-14 13:37:16 +0000166#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
167 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000168static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000169{ \
170 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000171}
bellard83fcb512006-06-14 13:37:16 +0000172
173
174#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
175 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000176static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
177 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000178{ \
179 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
180}
181
bellard70a194b2003-08-11 22:20:16 +0000182
bellard31e31b82003-02-18 22:55:36 +0000183#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000184#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000185#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000186#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000187#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000188#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000189#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000190#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000191#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000192#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000193#define __NR_sys_inotify_init __NR_inotify_init
194#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
195#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000196
Alexander Graf42a39fb2011-04-15 17:32:45 +0200197#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
198 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000199#define __NR__llseek __NR_lseek
200#endif
201
bellard72f03902003-02-18 23:33:18 +0000202#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000203_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000204#else
ths0da46a62007-10-20 20:23:07 +0000205/* This is a replacement for the host gettid() and must return a host
206 errno. */
bellard72f03902003-02-18 23:33:18 +0000207static int gettid(void) {
208 return -ENOSYS;
209}
210#endif
Peter Maydell3307e232013-06-12 16:20:21 +0100211#ifdef __NR_getdents
aurel323b3f24a2009-04-15 16:12:13 +0000212_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100213#endif
214#if !defined(__NR_getdents) || \
215 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000216_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
217#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700218#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000219_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
220 loff_t *, res, uint, wh);
221#endif
222_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
223_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
224#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
225_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
226#endif
227#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
228_syscall2(int,sys_tkill,int,tid,int,sig)
229#endif
230#ifdef __NR_exit_group
231_syscall1(int,exit_group,int,error_code)
232#endif
233#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
234_syscall1(int,set_tid_address,int *,tidptr)
235#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +0200236#if defined(CONFIG_USE_NPTL)
aurel323b3f24a2009-04-15 16:12:13 +0000237#if defined(TARGET_NR_futex) && defined(__NR_futex)
238_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
239 const struct timespec *,timeout,int *,uaddr2,int,val3)
240#endif
241#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500242#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
243_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
244 unsigned long *, user_mask_ptr);
245#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
246_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
247 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200248_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
249 void *, arg);
aurel323b3f24a2009-04-15 16:12:13 +0000250
251static bitmask_transtbl fcntl_flags_tbl[] = {
252 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
253 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
254 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
255 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
256 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
257 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
258 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
259 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700260 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000261 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
262 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
263 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
264 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000265#if defined(O_DIRECT)
266 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
267#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700268#if defined(O_NOATIME)
269 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
270#endif
271#if defined(O_CLOEXEC)
272 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
273#endif
274#if defined(O_PATH)
275 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
276#endif
277 /* Don't terminate the list prematurely on 64-bit host+guest. */
278#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
279 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
280#endif
aurel323b3f24a2009-04-15 16:12:13 +0000281 { 0, 0, 0, 0 }
282};
283
284#define COPY_UTSNAME_FIELD(dest, src) \
285 do { \
286 /* __NEW_UTS_LEN doesn't include terminating null */ \
287 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
288 (dest)[__NEW_UTS_LEN] = '\0'; \
289 } while (0)
290
291static int sys_uname(struct new_utsname *buf)
292{
293 struct utsname uts_buf;
294
295 if (uname(&uts_buf) < 0)
296 return (-1);
297
298 /*
299 * Just in case these have some differences, we
300 * translate utsname to new_utsname (which is the
301 * struct linux kernel uses).
302 */
303
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200304 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000305 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
306 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
307 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
308 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
309 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
310#ifdef _GNU_SOURCE
311 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
312#endif
313 return (0);
314
315#undef COPY_UTSNAME_FIELD
316}
317
318static int sys_getcwd1(char *buf, size_t size)
319{
320 if (getcwd(buf, size) == NULL) {
321 /* getcwd() sets errno */
322 return (-1);
323 }
aurel32aaf4ad32009-04-16 14:17:14 +0000324 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000325}
326
aurel323b3f24a2009-04-15 16:12:13 +0000327#ifdef TARGET_NR_openat
Alexander Graff4c69012011-09-25 06:25:35 +0200328static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000329{
330 /*
331 * open(2) has extra parameter 'mode' when called with
332 * flag O_CREAT.
333 */
334 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000335 return (openat(dirfd, pathname, flags, mode));
336 }
337 return (openat(dirfd, pathname, flags));
338}
339#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300340
341#ifdef CONFIG_UTIMENSAT
342static int sys_utimensat(int dirfd, const char *pathname,
343 const struct timespec times[2], int flags)
344{
345 if (pathname == NULL)
346 return futimens(dirfd, times);
347 else
348 return utimensat(dirfd, pathname, times, flags);
349}
350#else
ths9007f0e2007-09-25 17:50:37 +0000351#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
352_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
353 const struct timespec *,tsp,int,flags)
354#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300355#endif /* CONFIG_UTIMENSAT */
aurel323b3f24a2009-04-15 16:12:13 +0000356
357#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000358#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000359
aurel3239b59762008-10-01 21:46:50 +0000360#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000361static int sys_inotify_init(void)
362{
363 return (inotify_init());
364}
aurel3239b59762008-10-01 21:46:50 +0000365#endif
366#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000367static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
368{
369 return (inotify_add_watch(fd, pathname, mask));
370}
aurel3239b59762008-10-01 21:46:50 +0000371#endif
372#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000373static int sys_inotify_rm_watch(int fd, int32_t wd)
374{
aurel328690e422009-04-17 13:50:32 +0000375 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000376}
aurel3239b59762008-10-01 21:46:50 +0000377#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000378#ifdef CONFIG_INOTIFY1
379#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
380static int sys_inotify_init1(int flags)
381{
382 return (inotify_init1(flags));
383}
384#endif
385#endif
aurel323b3f24a2009-04-15 16:12:13 +0000386#else
387/* Userspace can usually survive runtime without inotify */
388#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000389#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000390#undef TARGET_NR_inotify_add_watch
391#undef TARGET_NR_inotify_rm_watch
392#endif /* CONFIG_INOTIFY */
393
Mike Frysingerd8035d42011-02-07 01:05:51 -0500394#if defined(TARGET_NR_ppoll)
395#ifndef __NR_ppoll
396# define __NR_ppoll -1
397#endif
398#define __NR_sys_ppoll __NR_ppoll
399_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
400 struct timespec *, timeout, const __sigset_t *, sigmask,
401 size_t, sigsetsize)
402#endif
bellard66fb9762003-03-23 01:06:05 +0000403
Mike Frysinger055e0902011-06-03 17:01:49 -0400404#if defined(TARGET_NR_pselect6)
405#ifndef __NR_pselect6
406# define __NR_pselect6 -1
407#endif
408#define __NR_sys_pselect6 __NR_pselect6
409_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
410 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
411#endif
412
Peter Maydell163a05a2011-06-27 17:44:52 +0100413#if defined(TARGET_NR_prlimit64)
414#ifndef __NR_prlimit64
415# define __NR_prlimit64 -1
416#endif
417#define __NR_sys_prlimit64 __NR_prlimit64
418/* The glibc rlimit structure may not be that used by the underlying syscall */
419struct host_rlimit64 {
420 uint64_t rlim_cur;
421 uint64_t rlim_max;
422};
423_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
424 const struct host_rlimit64 *, new_limit,
425 struct host_rlimit64 *, old_limit)
426#endif
427
Riku Voipio48e515d2011-07-12 15:40:51 +0300428/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000429#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300430static inline int regpairs_aligned(void *cpu_env) {
431 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
432}
433#elif defined(TARGET_MIPS)
434static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000435#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
436/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
437 * of registers which translates to the same as ARM/MIPS, because we start with
438 * r3 as arg1 */
439static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300440#else
441static inline int regpairs_aligned(void *cpu_env) { return 0; }
442#endif
443
thsb92c47c2007-11-01 00:07:38 +0000444#define ERRNO_TABLE_SIZE 1200
445
446/* target_to_host_errno_table[] is initialized from
447 * host_to_target_errno_table[] in syscall_init(). */
448static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
449};
450
ths637947f2007-06-01 12:09:19 +0000451/*
thsfe8f0962007-07-12 10:59:21 +0000452 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000453 * minus the errnos that are not actually generic to all archs.
454 */
thsb92c47c2007-11-01 00:07:38 +0000455static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000456 [EIDRM] = TARGET_EIDRM,
457 [ECHRNG] = TARGET_ECHRNG,
458 [EL2NSYNC] = TARGET_EL2NSYNC,
459 [EL3HLT] = TARGET_EL3HLT,
460 [EL3RST] = TARGET_EL3RST,
461 [ELNRNG] = TARGET_ELNRNG,
462 [EUNATCH] = TARGET_EUNATCH,
463 [ENOCSI] = TARGET_ENOCSI,
464 [EL2HLT] = TARGET_EL2HLT,
465 [EDEADLK] = TARGET_EDEADLK,
466 [ENOLCK] = TARGET_ENOLCK,
467 [EBADE] = TARGET_EBADE,
468 [EBADR] = TARGET_EBADR,
469 [EXFULL] = TARGET_EXFULL,
470 [ENOANO] = TARGET_ENOANO,
471 [EBADRQC] = TARGET_EBADRQC,
472 [EBADSLT] = TARGET_EBADSLT,
473 [EBFONT] = TARGET_EBFONT,
474 [ENOSTR] = TARGET_ENOSTR,
475 [ENODATA] = TARGET_ENODATA,
476 [ETIME] = TARGET_ETIME,
477 [ENOSR] = TARGET_ENOSR,
478 [ENONET] = TARGET_ENONET,
479 [ENOPKG] = TARGET_ENOPKG,
480 [EREMOTE] = TARGET_EREMOTE,
481 [ENOLINK] = TARGET_ENOLINK,
482 [EADV] = TARGET_EADV,
483 [ESRMNT] = TARGET_ESRMNT,
484 [ECOMM] = TARGET_ECOMM,
485 [EPROTO] = TARGET_EPROTO,
486 [EDOTDOT] = TARGET_EDOTDOT,
487 [EMULTIHOP] = TARGET_EMULTIHOP,
488 [EBADMSG] = TARGET_EBADMSG,
489 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
490 [EOVERFLOW] = TARGET_EOVERFLOW,
491 [ENOTUNIQ] = TARGET_ENOTUNIQ,
492 [EBADFD] = TARGET_EBADFD,
493 [EREMCHG] = TARGET_EREMCHG,
494 [ELIBACC] = TARGET_ELIBACC,
495 [ELIBBAD] = TARGET_ELIBBAD,
496 [ELIBSCN] = TARGET_ELIBSCN,
497 [ELIBMAX] = TARGET_ELIBMAX,
498 [ELIBEXEC] = TARGET_ELIBEXEC,
499 [EILSEQ] = TARGET_EILSEQ,
500 [ENOSYS] = TARGET_ENOSYS,
501 [ELOOP] = TARGET_ELOOP,
502 [ERESTART] = TARGET_ERESTART,
503 [ESTRPIPE] = TARGET_ESTRPIPE,
504 [ENOTEMPTY] = TARGET_ENOTEMPTY,
505 [EUSERS] = TARGET_EUSERS,
506 [ENOTSOCK] = TARGET_ENOTSOCK,
507 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
508 [EMSGSIZE] = TARGET_EMSGSIZE,
509 [EPROTOTYPE] = TARGET_EPROTOTYPE,
510 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
511 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
512 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
513 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
514 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
515 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
516 [EADDRINUSE] = TARGET_EADDRINUSE,
517 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
518 [ENETDOWN] = TARGET_ENETDOWN,
519 [ENETUNREACH] = TARGET_ENETUNREACH,
520 [ENETRESET] = TARGET_ENETRESET,
521 [ECONNABORTED] = TARGET_ECONNABORTED,
522 [ECONNRESET] = TARGET_ECONNRESET,
523 [ENOBUFS] = TARGET_ENOBUFS,
524 [EISCONN] = TARGET_EISCONN,
525 [ENOTCONN] = TARGET_ENOTCONN,
526 [EUCLEAN] = TARGET_EUCLEAN,
527 [ENOTNAM] = TARGET_ENOTNAM,
528 [ENAVAIL] = TARGET_ENAVAIL,
529 [EISNAM] = TARGET_EISNAM,
530 [EREMOTEIO] = TARGET_EREMOTEIO,
531 [ESHUTDOWN] = TARGET_ESHUTDOWN,
532 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
533 [ETIMEDOUT] = TARGET_ETIMEDOUT,
534 [ECONNREFUSED] = TARGET_ECONNREFUSED,
535 [EHOSTDOWN] = TARGET_EHOSTDOWN,
536 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
537 [EALREADY] = TARGET_EALREADY,
538 [EINPROGRESS] = TARGET_EINPROGRESS,
539 [ESTALE] = TARGET_ESTALE,
540 [ECANCELED] = TARGET_ECANCELED,
541 [ENOMEDIUM] = TARGET_ENOMEDIUM,
542 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000543#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000544 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000545#endif
546#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000547 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000548#endif
549#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000550 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000551#endif
552#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000553 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000554#endif
555#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000556 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000557#endif
558#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000559 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000560#endif
thsb92c47c2007-11-01 00:07:38 +0000561};
ths637947f2007-06-01 12:09:19 +0000562
563static inline int host_to_target_errno(int err)
564{
565 if(host_to_target_errno_table[err])
566 return host_to_target_errno_table[err];
567 return err;
568}
569
thsb92c47c2007-11-01 00:07:38 +0000570static inline int target_to_host_errno(int err)
571{
572 if (target_to_host_errno_table[err])
573 return target_to_host_errno_table[err];
574 return err;
575}
576
blueswir1992f48a2007-10-14 16:27:31 +0000577static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000578{
579 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000580 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000581 else
582 return ret;
583}
584
blueswir1992f48a2007-10-14 16:27:31 +0000585static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000586{
blueswir1992f48a2007-10-14 16:27:31 +0000587 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000588}
589
thsb92c47c2007-11-01 00:07:38 +0000590char *target_strerror(int err)
591{
Alexander Graf962b2892011-11-21 12:04:07 +0100592 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
593 return NULL;
594 }
thsb92c47c2007-11-01 00:07:38 +0000595 return strerror(target_to_host_errno(err));
596}
597
blueswir1992f48a2007-10-14 16:27:31 +0000598static abi_ulong target_brk;
599static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000600static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000601
blueswir1992f48a2007-10-14 16:27:31 +0000602void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000603{
blueswir14c1de732007-07-07 20:45:44 +0000604 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000605 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000606}
607
vincent4d1de872011-06-14 21:56:33 +0000608//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
609#define DEBUGF_BRK(message, args...)
610
ths0da46a62007-10-20 20:23:07 +0000611/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000612abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000613{
blueswir1992f48a2007-10-14 16:27:31 +0000614 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000615 int new_alloc_size;
616
Paul Brook3a0c6c42012-02-09 19:04:27 +0000617 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000618
vincent4d1de872011-06-14 21:56:33 +0000619 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000620 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000621 return target_brk;
622 }
623 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000624 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
625 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000626 return target_brk;
627 }
bellard31e31b82003-02-18 22:55:36 +0000628
vincent4d1de872011-06-14 21:56:33 +0000629 /* If the new brk is less than the highest page reserved to the
630 * target heap allocation, set it and we're almost done... */
631 if (new_brk <= brk_page) {
632 /* Heap contents are initialized to zero, as for anonymous
633 * mapped pages. */
634 if (new_brk > target_brk) {
635 memset(g2h(target_brk), 0, new_brk - target_brk);
636 }
bellard31e31b82003-02-18 22:55:36 +0000637 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000638 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000639 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000640 }
641
Peter Maydell00faf082011-04-18 16:34:24 +0100642 /* We need to allocate more memory after the brk... Note that
643 * we don't use MAP_FIXED because that will map over the top of
644 * any existing mapping (like the one with the host libc or qemu
645 * itself); instead we treat "mapped but at wrong address" as
646 * a failure and unmap again.
647 */
vincent4d1de872011-06-14 21:56:33 +0000648 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000649 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000650 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100651 MAP_ANON|MAP_PRIVATE, 0, 0));
652
653 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200654 /* Heap contents are initialized to zero, as for anonymous
655 * mapped pages. Technically the new pages are already
656 * initialized to zero since they *are* anonymous mapped
657 * pages, however we have to take care with the contents that
658 * come from the remaining part of the previous page: it may
659 * contains garbage data due to a previous heap usage (grown
660 * then shrunken). */
661 memset(g2h(target_brk), 0, brk_page - target_brk);
662
Peter Maydell00faf082011-04-18 16:34:24 +0100663 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000664 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000665 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
666 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100667 return target_brk;
668 } else if (mapped_addr != -1) {
669 /* Mapped but at wrong address, meaning there wasn't actually
670 * enough space for this brk.
671 */
672 target_munmap(mapped_addr, new_alloc_size);
673 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000674 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000675 }
676 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000677 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100678 }
balrog7ab240a2008-04-26 12:17:34 +0000679
Richard Henderson7dd46c02010-05-03 10:07:49 -0700680#if defined(TARGET_ALPHA)
681 /* We (partially) emulate OSF/1 on Alpha, which requires we
682 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100683 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700684#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100685 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000686 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000687}
688
ths26edcf42007-12-09 02:25:24 +0000689static inline abi_long copy_from_user_fdset(fd_set *fds,
690 abi_ulong target_fds_addr,
691 int n)
bellard31e31b82003-02-18 22:55:36 +0000692{
ths26edcf42007-12-09 02:25:24 +0000693 int i, nw, j, k;
694 abi_ulong b, *target_fds;
695
696 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
697 if (!(target_fds = lock_user(VERIFY_READ,
698 target_fds_addr,
699 sizeof(abi_ulong) * nw,
700 1)))
701 return -TARGET_EFAULT;
702
703 FD_ZERO(fds);
704 k = 0;
705 for (i = 0; i < nw; i++) {
706 /* grab the abi_ulong */
707 __get_user(b, &target_fds[i]);
708 for (j = 0; j < TARGET_ABI_BITS; j++) {
709 /* check the bit inside the abi_ulong */
710 if ((b >> j) & 1)
711 FD_SET(k, fds);
712 k++;
bellard31e31b82003-02-18 22:55:36 +0000713 }
bellard31e31b82003-02-18 22:55:36 +0000714 }
ths26edcf42007-12-09 02:25:24 +0000715
716 unlock_user(target_fds, target_fds_addr, 0);
717
718 return 0;
bellard31e31b82003-02-18 22:55:36 +0000719}
720
Mike Frysinger055e0902011-06-03 17:01:49 -0400721static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
722 abi_ulong target_fds_addr,
723 int n)
724{
725 if (target_fds_addr) {
726 if (copy_from_user_fdset(fds, target_fds_addr, n))
727 return -TARGET_EFAULT;
728 *fds_ptr = fds;
729 } else {
730 *fds_ptr = NULL;
731 }
732 return 0;
733}
734
ths26edcf42007-12-09 02:25:24 +0000735static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
736 const fd_set *fds,
737 int n)
bellard31e31b82003-02-18 22:55:36 +0000738{
bellard31e31b82003-02-18 22:55:36 +0000739 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000740 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000741 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000742
ths26edcf42007-12-09 02:25:24 +0000743 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
744 if (!(target_fds = lock_user(VERIFY_WRITE,
745 target_fds_addr,
746 sizeof(abi_ulong) * nw,
747 0)))
748 return -TARGET_EFAULT;
749
750 k = 0;
751 for (i = 0; i < nw; i++) {
752 v = 0;
753 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000754 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000755 k++;
bellard31e31b82003-02-18 22:55:36 +0000756 }
ths26edcf42007-12-09 02:25:24 +0000757 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000758 }
ths26edcf42007-12-09 02:25:24 +0000759
760 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
761
762 return 0;
bellard31e31b82003-02-18 22:55:36 +0000763}
764
bellardc596ed12003-07-13 17:32:31 +0000765#if defined(__alpha__)
766#define HOST_HZ 1024
767#else
768#define HOST_HZ 100
769#endif
770
blueswir1992f48a2007-10-14 16:27:31 +0000771static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000772{
773#if HOST_HZ == TARGET_HZ
774 return ticks;
775#else
776 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
777#endif
778}
779
bellard579a97f2007-11-11 14:26:47 +0000780static inline abi_long host_to_target_rusage(abi_ulong target_addr,
781 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000782{
pbrook53a59602006-03-25 19:31:22 +0000783 struct target_rusage *target_rusage;
784
bellard579a97f2007-11-11 14:26:47 +0000785 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
786 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200787 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
788 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
789 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
790 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
791 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
792 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
793 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
794 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
795 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
796 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
797 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
798 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
799 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
800 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
801 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
802 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
803 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
804 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000805 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000806
807 return 0;
bellardb4091862003-05-16 15:39:34 +0000808}
809
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200810static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900811{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200812 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300813 rlim_t result;
814
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200815 target_rlim_swap = tswapal(target_rlim);
816 if (target_rlim_swap == TARGET_RLIM_INFINITY)
817 return RLIM_INFINITY;
818
819 result = target_rlim_swap;
820 if (target_rlim_swap != (rlim_t)result)
821 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300822
823 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900824}
825
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200826static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900827{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200828 abi_ulong target_rlim_swap;
829 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300830
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200831 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300832 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900833 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300834 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200835 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300836
837 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900838}
839
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300840static inline int target_to_host_resource(int code)
841{
842 switch (code) {
843 case TARGET_RLIMIT_AS:
844 return RLIMIT_AS;
845 case TARGET_RLIMIT_CORE:
846 return RLIMIT_CORE;
847 case TARGET_RLIMIT_CPU:
848 return RLIMIT_CPU;
849 case TARGET_RLIMIT_DATA:
850 return RLIMIT_DATA;
851 case TARGET_RLIMIT_FSIZE:
852 return RLIMIT_FSIZE;
853 case TARGET_RLIMIT_LOCKS:
854 return RLIMIT_LOCKS;
855 case TARGET_RLIMIT_MEMLOCK:
856 return RLIMIT_MEMLOCK;
857 case TARGET_RLIMIT_MSGQUEUE:
858 return RLIMIT_MSGQUEUE;
859 case TARGET_RLIMIT_NICE:
860 return RLIMIT_NICE;
861 case TARGET_RLIMIT_NOFILE:
862 return RLIMIT_NOFILE;
863 case TARGET_RLIMIT_NPROC:
864 return RLIMIT_NPROC;
865 case TARGET_RLIMIT_RSS:
866 return RLIMIT_RSS;
867 case TARGET_RLIMIT_RTPRIO:
868 return RLIMIT_RTPRIO;
869 case TARGET_RLIMIT_SIGPENDING:
870 return RLIMIT_SIGPENDING;
871 case TARGET_RLIMIT_STACK:
872 return RLIMIT_STACK;
873 default:
874 return code;
875 }
876}
877
ths788f5ec2007-12-09 02:37:05 +0000878static inline abi_long copy_from_user_timeval(struct timeval *tv,
879 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000880{
pbrook53a59602006-03-25 19:31:22 +0000881 struct target_timeval *target_tv;
882
ths788f5ec2007-12-09 02:37:05 +0000883 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000884 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000885
886 __get_user(tv->tv_sec, &target_tv->tv_sec);
887 __get_user(tv->tv_usec, &target_tv->tv_usec);
888
889 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000890
891 return 0;
bellard31e31b82003-02-18 22:55:36 +0000892}
893
ths788f5ec2007-12-09 02:37:05 +0000894static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
895 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000896{
pbrook53a59602006-03-25 19:31:22 +0000897 struct target_timeval *target_tv;
898
ths788f5ec2007-12-09 02:37:05 +0000899 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000900 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000901
902 __put_user(tv->tv_sec, &target_tv->tv_sec);
903 __put_user(tv->tv_usec, &target_tv->tv_usec);
904
905 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000906
907 return 0;
bellard31e31b82003-02-18 22:55:36 +0000908}
909
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700910#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
911#include <mqueue.h>
912
aurel3224e10032009-04-15 16:11:43 +0000913static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
914 abi_ulong target_mq_attr_addr)
915{
916 struct target_mq_attr *target_mq_attr;
917
918 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
919 target_mq_attr_addr, 1))
920 return -TARGET_EFAULT;
921
922 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
923 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
924 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
925 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
926
927 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
928
929 return 0;
930}
931
932static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
933 const struct mq_attr *attr)
934{
935 struct target_mq_attr *target_mq_attr;
936
937 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
938 target_mq_attr_addr, 0))
939 return -TARGET_EFAULT;
940
941 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
942 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
943 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
944 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
945
946 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
947
948 return 0;
949}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700950#endif
bellard31e31b82003-02-18 22:55:36 +0000951
Mike Frysinger055e0902011-06-03 17:01:49 -0400952#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +0000953/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000954static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +0000955 abi_ulong rfd_addr, abi_ulong wfd_addr,
956 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000957{
958 fd_set rfds, wfds, efds;
959 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
960 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +0000961 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +0000962
Mike Frysinger055e0902011-06-03 17:01:49 -0400963 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
964 if (ret) {
965 return ret;
pbrook53a59602006-03-25 19:31:22 +0000966 }
Mike Frysinger055e0902011-06-03 17:01:49 -0400967 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
968 if (ret) {
969 return ret;
pbrook53a59602006-03-25 19:31:22 +0000970 }
Mike Frysinger055e0902011-06-03 17:01:49 -0400971 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
972 if (ret) {
973 return ret;
pbrook53a59602006-03-25 19:31:22 +0000974 }
ths3b46e622007-09-17 08:09:54 +0000975
ths26edcf42007-12-09 02:25:24 +0000976 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +0000977 if (copy_from_user_timeval(&tv, target_tv_addr))
978 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +0000979 tv_ptr = &tv;
980 } else {
981 tv_ptr = NULL;
982 }
ths26edcf42007-12-09 02:25:24 +0000983
bellard31e31b82003-02-18 22:55:36 +0000984 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +0000985
ths26edcf42007-12-09 02:25:24 +0000986 if (!is_error(ret)) {
987 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
988 return -TARGET_EFAULT;
989 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
990 return -TARGET_EFAULT;
991 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
992 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +0000993
ths788f5ec2007-12-09 02:37:05 +0000994 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
995 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +0000996 }
bellard579a97f2007-11-11 14:26:47 +0000997
bellard31e31b82003-02-18 22:55:36 +0000998 return ret;
999}
Mike Frysinger055e0902011-06-03 17:01:49 -04001000#endif
bellard31e31b82003-02-18 22:55:36 +00001001
Riku Voipio099d6b02009-05-05 12:10:04 +03001002static abi_long do_pipe2(int host_pipe[], int flags)
1003{
1004#ifdef CONFIG_PIPE2
1005 return pipe2(host_pipe, flags);
1006#else
1007 return -ENOSYS;
1008#endif
1009}
1010
Richard Hendersonfb41a662010-05-03 10:07:52 -07001011static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1012 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001013{
1014 int host_pipe[2];
1015 abi_long ret;
1016 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1017
1018 if (is_error(ret))
1019 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001020
1021 /* Several targets have special calling conventions for the original
1022 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1023 if (!is_pipe2) {
1024#if defined(TARGET_ALPHA)
1025 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1026 return host_pipe[0];
1027#elif defined(TARGET_MIPS)
1028 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1029 return host_pipe[0];
1030#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001031 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001032 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001033#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001034 }
1035
Riku Voipio099d6b02009-05-05 12:10:04 +03001036 if (put_user_s32(host_pipe[0], pipedes)
1037 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1038 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001039 return get_errno(ret);
1040}
1041
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001042static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1043 abi_ulong target_addr,
1044 socklen_t len)
1045{
1046 struct target_ip_mreqn *target_smreqn;
1047
1048 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1049 if (!target_smreqn)
1050 return -TARGET_EFAULT;
1051 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1052 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1053 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001054 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001055 unlock_user(target_smreqn, target_addr, 0);
1056
1057 return 0;
1058}
1059
bellard579a97f2007-11-11 14:26:47 +00001060static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1061 abi_ulong target_addr,
1062 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001063{
aurel32607175e2009-04-15 16:11:59 +00001064 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1065 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001066 struct target_sockaddr *target_saddr;
1067
bellard579a97f2007-11-11 14:26:47 +00001068 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1069 if (!target_saddr)
1070 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001071
1072 sa_family = tswap16(target_saddr->sa_family);
1073
1074 /* Oops. The caller might send a incomplete sun_path; sun_path
1075 * must be terminated by \0 (see the manual page), but
1076 * unfortunately it is quite common to specify sockaddr_un
1077 * length as "strlen(x->sun_path)" while it should be
1078 * "strlen(...) + 1". We'll fix that here if needed.
1079 * Linux kernel has a similar feature.
1080 */
1081
1082 if (sa_family == AF_UNIX) {
1083 if (len < unix_maxlen && len > 0) {
1084 char *cp = (char*)target_saddr;
1085
1086 if ( cp[len-1] && !cp[len] )
1087 len++;
1088 }
1089 if (len > unix_maxlen)
1090 len = unix_maxlen;
1091 }
1092
pbrook53a59602006-03-25 19:31:22 +00001093 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001094 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001095 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001096
1097 return 0;
bellard7854b052003-03-29 17:22:23 +00001098}
1099
bellard579a97f2007-11-11 14:26:47 +00001100static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1101 struct sockaddr *addr,
1102 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001103{
pbrook53a59602006-03-25 19:31:22 +00001104 struct target_sockaddr *target_saddr;
1105
bellard579a97f2007-11-11 14:26:47 +00001106 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1107 if (!target_saddr)
1108 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001109 memcpy(target_saddr, addr, len);
1110 target_saddr->sa_family = tswap16(addr->sa_family);
1111 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001112
1113 return 0;
bellard7854b052003-03-29 17:22:23 +00001114}
1115
bellard5a4a8982007-11-11 17:39:18 +00001116static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1117 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001118{
1119 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001120 abi_long msg_controllen;
1121 abi_ulong target_cmsg_addr;
1122 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001123 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001124
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001125 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001126 if (msg_controllen < sizeof (struct target_cmsghdr))
1127 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001128 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001129 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1130 if (!target_cmsg)
1131 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001132
1133 while (cmsg && target_cmsg) {
1134 void *data = CMSG_DATA(cmsg);
1135 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1136
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001137 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001138 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1139
1140 space += CMSG_SPACE(len);
1141 if (space > msgh->msg_controllen) {
1142 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001143 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001144 break;
1145 }
1146
1147 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1148 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1149 cmsg->cmsg_len = CMSG_LEN(len);
1150
bellard3532fa72006-06-24 15:06:03 +00001151 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001152 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1153 memcpy(data, target_data, len);
1154 } else {
1155 int *fd = (int *)data;
1156 int *target_fd = (int *)target_data;
1157 int i, numfds = len / sizeof(int);
1158
1159 for (i = 0; i < numfds; i++)
1160 fd[i] = tswap32(target_fd[i]);
1161 }
1162
1163 cmsg = CMSG_NXTHDR(msgh, cmsg);
1164 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1165 }
bellard5a4a8982007-11-11 17:39:18 +00001166 unlock_user(target_cmsg, target_cmsg_addr, 0);
1167 the_end:
bellard7854b052003-03-29 17:22:23 +00001168 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001169 return 0;
bellard7854b052003-03-29 17:22:23 +00001170}
1171
bellard5a4a8982007-11-11 17:39:18 +00001172static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1173 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001174{
1175 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001176 abi_long msg_controllen;
1177 abi_ulong target_cmsg_addr;
1178 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001179 socklen_t space = 0;
1180
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001181 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001182 if (msg_controllen < sizeof (struct target_cmsghdr))
1183 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001184 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001185 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1186 if (!target_cmsg)
1187 return -TARGET_EFAULT;
1188
bellard7854b052003-03-29 17:22:23 +00001189 while (cmsg && target_cmsg) {
1190 void *data = CMSG_DATA(cmsg);
1191 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1192
1193 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1194
1195 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001196 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001197 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001198 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001199 break;
1200 }
1201
1202 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1203 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001204 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001205
Jing Huangaebf5bc2012-07-24 14:01:42 +00001206 if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
1207 (cmsg->cmsg_type == SCM_RIGHTS)) {
bellard7854b052003-03-29 17:22:23 +00001208 int *fd = (int *)data;
1209 int *target_fd = (int *)target_data;
1210 int i, numfds = len / sizeof(int);
1211
1212 for (i = 0; i < numfds; i++)
1213 target_fd[i] = tswap32(fd[i]);
Jing Huangaebf5bc2012-07-24 14:01:42 +00001214 } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
1215 (cmsg->cmsg_type == SO_TIMESTAMP) &&
1216 (len == sizeof(struct timeval))) {
1217 /* copy struct timeval to target */
1218 struct timeval *tv = (struct timeval *)data;
1219 struct target_timeval *target_tv =
1220 (struct target_timeval *)target_data;
1221
1222 target_tv->tv_sec = tswapal(tv->tv_sec);
1223 target_tv->tv_usec = tswapal(tv->tv_usec);
1224 } else {
1225 gemu_log("Unsupported ancillary data: %d/%d\n",
1226 cmsg->cmsg_level, cmsg->cmsg_type);
1227 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001228 }
1229
1230 cmsg = CMSG_NXTHDR(msgh, cmsg);
1231 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1232 }
bellard5a4a8982007-11-11 17:39:18 +00001233 unlock_user(target_cmsg, target_cmsg_addr, space);
1234 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001235 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001236 return 0;
bellard7854b052003-03-29 17:22:23 +00001237}
1238
ths0da46a62007-10-20 20:23:07 +00001239/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001240static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001241 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001242{
blueswir1992f48a2007-10-14 16:27:31 +00001243 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001244 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001245 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001246 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001247
bellard8853f862004-02-22 14:57:26 +00001248 switch(level) {
1249 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001250 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001251 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001252 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001253
bellard2f619692007-11-16 10:46:05 +00001254 if (get_user_u32(val, optval_addr))
1255 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001256 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1257 break;
1258 case SOL_IP:
1259 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001260 case IP_TOS:
1261 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001262 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001263 case IP_ROUTER_ALERT:
1264 case IP_RECVOPTS:
1265 case IP_RETOPTS:
1266 case IP_PKTINFO:
1267 case IP_MTU_DISCOVER:
1268 case IP_RECVERR:
1269 case IP_RECVTOS:
1270#ifdef IP_FREEBIND
1271 case IP_FREEBIND:
1272#endif
1273 case IP_MULTICAST_TTL:
1274 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001275 val = 0;
1276 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001277 if (get_user_u32(val, optval_addr))
1278 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001279 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001280 if (get_user_u8(val, optval_addr))
1281 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001282 }
1283 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1284 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001285 case IP_ADD_MEMBERSHIP:
1286 case IP_DROP_MEMBERSHIP:
1287 if (optlen < sizeof (struct target_ip_mreq) ||
1288 optlen > sizeof (struct target_ip_mreqn))
1289 return -TARGET_EINVAL;
1290
1291 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1292 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1293 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1294 break;
1295
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001296 case IP_BLOCK_SOURCE:
1297 case IP_UNBLOCK_SOURCE:
1298 case IP_ADD_SOURCE_MEMBERSHIP:
1299 case IP_DROP_SOURCE_MEMBERSHIP:
1300 if (optlen != sizeof (struct target_ip_mreq_source))
1301 return -TARGET_EINVAL;
1302
1303 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1304 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1305 unlock_user (ip_mreq_source, optval_addr, 0);
1306 break;
1307
bellard8853f862004-02-22 14:57:26 +00001308 default:
1309 goto unimplemented;
1310 }
1311 break;
Jing Huang920394d2012-07-24 13:59:23 +00001312 case SOL_RAW:
1313 switch (optname) {
1314 case ICMP_FILTER:
1315 /* struct icmp_filter takes an u32 value */
1316 if (optlen < sizeof(uint32_t)) {
1317 return -TARGET_EINVAL;
1318 }
1319
1320 if (get_user_u32(val, optval_addr)) {
1321 return -TARGET_EFAULT;
1322 }
1323 ret = get_errno(setsockopt(sockfd, level, optname,
1324 &val, sizeof(val)));
1325 break;
1326
1327 default:
1328 goto unimplemented;
1329 }
1330 break;
bellard3532fa72006-06-24 15:06:03 +00001331 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001332 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001333 case TARGET_SO_RCVTIMEO:
1334 {
1335 struct timeval tv;
1336
1337 optname = SO_RCVTIMEO;
1338
1339set_timeout:
1340 if (optlen != sizeof(struct target_timeval)) {
1341 return -TARGET_EINVAL;
1342 }
1343
1344 if (copy_from_user_timeval(&tv, optval_addr)) {
1345 return -TARGET_EFAULT;
1346 }
1347
1348 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1349 &tv, sizeof(tv)));
1350 return ret;
1351 }
1352 case TARGET_SO_SNDTIMEO:
1353 optname = SO_SNDTIMEO;
1354 goto set_timeout;
bellard8853f862004-02-22 14:57:26 +00001355 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001356 case TARGET_SO_DEBUG:
1357 optname = SO_DEBUG;
1358 break;
1359 case TARGET_SO_REUSEADDR:
1360 optname = SO_REUSEADDR;
1361 break;
1362 case TARGET_SO_TYPE:
1363 optname = SO_TYPE;
1364 break;
1365 case TARGET_SO_ERROR:
1366 optname = SO_ERROR;
1367 break;
1368 case TARGET_SO_DONTROUTE:
1369 optname = SO_DONTROUTE;
1370 break;
1371 case TARGET_SO_BROADCAST:
1372 optname = SO_BROADCAST;
1373 break;
1374 case TARGET_SO_SNDBUF:
1375 optname = SO_SNDBUF;
1376 break;
1377 case TARGET_SO_RCVBUF:
1378 optname = SO_RCVBUF;
1379 break;
1380 case TARGET_SO_KEEPALIVE:
1381 optname = SO_KEEPALIVE;
1382 break;
1383 case TARGET_SO_OOBINLINE:
1384 optname = SO_OOBINLINE;
1385 break;
1386 case TARGET_SO_NO_CHECK:
1387 optname = SO_NO_CHECK;
1388 break;
1389 case TARGET_SO_PRIORITY:
1390 optname = SO_PRIORITY;
1391 break;
bellard5e83e8e2005-03-01 22:32:06 +00001392#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001393 case TARGET_SO_BSDCOMPAT:
1394 optname = SO_BSDCOMPAT;
1395 break;
bellard5e83e8e2005-03-01 22:32:06 +00001396#endif
bellard3532fa72006-06-24 15:06:03 +00001397 case TARGET_SO_PASSCRED:
1398 optname = SO_PASSCRED;
1399 break;
1400 case TARGET_SO_TIMESTAMP:
1401 optname = SO_TIMESTAMP;
1402 break;
1403 case TARGET_SO_RCVLOWAT:
1404 optname = SO_RCVLOWAT;
1405 break;
bellard8853f862004-02-22 14:57:26 +00001406 break;
1407 default:
1408 goto unimplemented;
1409 }
bellard3532fa72006-06-24 15:06:03 +00001410 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001411 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001412
bellard2f619692007-11-16 10:46:05 +00001413 if (get_user_u32(val, optval_addr))
1414 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001415 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001416 break;
bellard7854b052003-03-29 17:22:23 +00001417 default:
bellard8853f862004-02-22 14:57:26 +00001418 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001419 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001420 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001421 }
bellard8853f862004-02-22 14:57:26 +00001422 return ret;
bellard7854b052003-03-29 17:22:23 +00001423}
1424
ths0da46a62007-10-20 20:23:07 +00001425/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001426static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001427 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001428{
blueswir1992f48a2007-10-14 16:27:31 +00001429 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001430 int len, val;
1431 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001432
1433 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001434 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001435 level = SOL_SOCKET;
1436 switch (optname) {
1437 /* These don't just return a single integer */
1438 case TARGET_SO_LINGER:
1439 case TARGET_SO_RCVTIMEO:
1440 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001441 case TARGET_SO_PEERNAME:
1442 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001443 case TARGET_SO_PEERCRED: {
1444 struct ucred cr;
1445 socklen_t crlen;
1446 struct target_ucred *tcr;
1447
1448 if (get_user_u32(len, optlen)) {
1449 return -TARGET_EFAULT;
1450 }
1451 if (len < 0) {
1452 return -TARGET_EINVAL;
1453 }
1454
1455 crlen = sizeof(cr);
1456 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1457 &cr, &crlen));
1458 if (ret < 0) {
1459 return ret;
1460 }
1461 if (len > crlen) {
1462 len = crlen;
1463 }
1464 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1465 return -TARGET_EFAULT;
1466 }
1467 __put_user(cr.pid, &tcr->pid);
1468 __put_user(cr.uid, &tcr->uid);
1469 __put_user(cr.gid, &tcr->gid);
1470 unlock_user_struct(tcr, optval_addr, 1);
1471 if (put_user_u32(len, optlen)) {
1472 return -TARGET_EFAULT;
1473 }
1474 break;
1475 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001476 /* Options with 'int' argument. */
1477 case TARGET_SO_DEBUG:
1478 optname = SO_DEBUG;
1479 goto int_case;
1480 case TARGET_SO_REUSEADDR:
1481 optname = SO_REUSEADDR;
1482 goto int_case;
1483 case TARGET_SO_TYPE:
1484 optname = SO_TYPE;
1485 goto int_case;
1486 case TARGET_SO_ERROR:
1487 optname = SO_ERROR;
1488 goto int_case;
1489 case TARGET_SO_DONTROUTE:
1490 optname = SO_DONTROUTE;
1491 goto int_case;
1492 case TARGET_SO_BROADCAST:
1493 optname = SO_BROADCAST;
1494 goto int_case;
1495 case TARGET_SO_SNDBUF:
1496 optname = SO_SNDBUF;
1497 goto int_case;
1498 case TARGET_SO_RCVBUF:
1499 optname = SO_RCVBUF;
1500 goto int_case;
1501 case TARGET_SO_KEEPALIVE:
1502 optname = SO_KEEPALIVE;
1503 goto int_case;
1504 case TARGET_SO_OOBINLINE:
1505 optname = SO_OOBINLINE;
1506 goto int_case;
1507 case TARGET_SO_NO_CHECK:
1508 optname = SO_NO_CHECK;
1509 goto int_case;
1510 case TARGET_SO_PRIORITY:
1511 optname = SO_PRIORITY;
1512 goto int_case;
1513#ifdef SO_BSDCOMPAT
1514 case TARGET_SO_BSDCOMPAT:
1515 optname = SO_BSDCOMPAT;
1516 goto int_case;
1517#endif
1518 case TARGET_SO_PASSCRED:
1519 optname = SO_PASSCRED;
1520 goto int_case;
1521 case TARGET_SO_TIMESTAMP:
1522 optname = SO_TIMESTAMP;
1523 goto int_case;
1524 case TARGET_SO_RCVLOWAT:
1525 optname = SO_RCVLOWAT;
1526 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001527 default:
bellard2efbe912005-07-23 15:10:20 +00001528 goto int_case;
1529 }
1530 break;
1531 case SOL_TCP:
1532 /* TCP options all take an 'int' value. */
1533 int_case:
bellard2f619692007-11-16 10:46:05 +00001534 if (get_user_u32(len, optlen))
1535 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001536 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001537 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001538 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001539 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1540 if (ret < 0)
1541 return ret;
bellard2efbe912005-07-23 15:10:20 +00001542 if (len > lv)
1543 len = lv;
bellard2f619692007-11-16 10:46:05 +00001544 if (len == 4) {
1545 if (put_user_u32(val, optval_addr))
1546 return -TARGET_EFAULT;
1547 } else {
1548 if (put_user_u8(val, optval_addr))
1549 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001550 }
bellard2f619692007-11-16 10:46:05 +00001551 if (put_user_u32(len, optlen))
1552 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001553 break;
1554 case SOL_IP:
1555 switch(optname) {
1556 case IP_TOS:
1557 case IP_TTL:
1558 case IP_HDRINCL:
1559 case IP_ROUTER_ALERT:
1560 case IP_RECVOPTS:
1561 case IP_RETOPTS:
1562 case IP_PKTINFO:
1563 case IP_MTU_DISCOVER:
1564 case IP_RECVERR:
1565 case IP_RECVTOS:
1566#ifdef IP_FREEBIND
1567 case IP_FREEBIND:
1568#endif
1569 case IP_MULTICAST_TTL:
1570 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001571 if (get_user_u32(len, optlen))
1572 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001573 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001574 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001575 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001576 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1577 if (ret < 0)
1578 return ret;
bellard2efbe912005-07-23 15:10:20 +00001579 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001580 len = 1;
bellard2f619692007-11-16 10:46:05 +00001581 if (put_user_u32(len, optlen)
1582 || put_user_u8(val, optval_addr))
1583 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001584 } else {
bellard2efbe912005-07-23 15:10:20 +00001585 if (len > sizeof(int))
1586 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001587 if (put_user_u32(len, optlen)
1588 || put_user_u32(val, optval_addr))
1589 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001590 }
bellard8853f862004-02-22 14:57:26 +00001591 break;
bellard2efbe912005-07-23 15:10:20 +00001592 default:
thsc02f4992007-12-18 02:39:59 +00001593 ret = -TARGET_ENOPROTOOPT;
1594 break;
bellard8853f862004-02-22 14:57:26 +00001595 }
1596 break;
1597 default:
1598 unimplemented:
1599 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1600 level, optname);
thsc02f4992007-12-18 02:39:59 +00001601 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001602 break;
1603 }
1604 return ret;
bellard7854b052003-03-29 17:22:23 +00001605}
1606
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001607static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1608 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001609{
1610 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001611 struct iovec *vec;
1612 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001613 int i;
pbrook53a59602006-03-25 19:31:22 +00001614
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001615 if (count == 0) {
1616 errno = 0;
1617 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001618 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001619 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001620 errno = EINVAL;
1621 return NULL;
1622 }
1623
1624 vec = calloc(count, sizeof(struct iovec));
1625 if (vec == NULL) {
1626 errno = ENOMEM;
1627 return NULL;
1628 }
1629
1630 target_vec = lock_user(VERIFY_READ, target_addr,
1631 count * sizeof(struct target_iovec), 1);
1632 if (target_vec == NULL) {
1633 errno = EFAULT;
1634 goto fail2;
1635 }
1636
1637 /* ??? If host page size > target page size, this will result in a
1638 value larger than what we can actually support. */
1639 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1640 total_len = 0;
1641
1642 for (i = 0; i < count; i++) {
1643 abi_ulong base = tswapal(target_vec[i].iov_base);
1644 abi_long len = tswapal(target_vec[i].iov_len);
1645
1646 if (len < 0) {
1647 errno = EINVAL;
1648 goto fail;
1649 } else if (len == 0) {
1650 /* Zero length pointer is ignored. */
1651 vec[i].iov_base = 0;
1652 } else {
1653 vec[i].iov_base = lock_user(type, base, len, copy);
1654 if (!vec[i].iov_base) {
1655 errno = EFAULT;
1656 goto fail;
1657 }
1658 if (len > max_len - total_len) {
1659 len = max_len - total_len;
1660 }
1661 }
1662 vec[i].iov_len = len;
1663 total_len += len;
1664 }
1665
1666 unlock_user(target_vec, target_addr, 0);
1667 return vec;
1668
1669 fail:
1670 free(vec);
1671 fail2:
1672 unlock_user(target_vec, target_addr, 0);
1673 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001674}
1675
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001676static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1677 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001678{
1679 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00001680 int i;
1681
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001682 target_vec = lock_user(VERIFY_READ, target_addr,
1683 count * sizeof(struct target_iovec), 1);
1684 if (target_vec) {
1685 for (i = 0; i < count; i++) {
1686 abi_ulong base = tswapal(target_vec[i].iov_base);
1687 abi_long len = tswapal(target_vec[i].iov_base);
1688 if (len < 0) {
1689 break;
1690 }
balrogd732dcb2008-10-28 10:21:03 +00001691 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1692 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001693 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00001694 }
bellard579a97f2007-11-11 14:26:47 +00001695
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001696 free(vec);
pbrook53a59602006-03-25 19:31:22 +00001697}
1698
ths0da46a62007-10-20 20:23:07 +00001699/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001700static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001701{
1702#if defined(TARGET_MIPS)
1703 switch(type) {
1704 case TARGET_SOCK_DGRAM:
1705 type = SOCK_DGRAM;
1706 break;
1707 case TARGET_SOCK_STREAM:
1708 type = SOCK_STREAM;
1709 break;
1710 case TARGET_SOCK_RAW:
1711 type = SOCK_RAW;
1712 break;
1713 case TARGET_SOCK_RDM:
1714 type = SOCK_RDM;
1715 break;
1716 case TARGET_SOCK_SEQPACKET:
1717 type = SOCK_SEQPACKET;
1718 break;
1719 case TARGET_SOCK_PACKET:
1720 type = SOCK_PACKET;
1721 break;
1722 }
1723#endif
balrog12bc92a2007-10-30 21:06:14 +00001724 if (domain == PF_NETLINK)
1725 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
bellard3532fa72006-06-24 15:06:03 +00001726 return get_errno(socket(domain, type, protocol));
1727}
1728
ths0da46a62007-10-20 20:23:07 +00001729/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001730static abi_long do_bind(int sockfd, abi_ulong target_addr,
1731 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001732{
aurel328f7aeaf2009-01-30 19:47:57 +00001733 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001734 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001735
Blue Swirl38724252010-09-18 05:53:14 +00001736 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001737 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001738 }
aurel328f7aeaf2009-01-30 19:47:57 +00001739
aurel32607175e2009-04-15 16:11:59 +00001740 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001741
Arnaud Patard917507b2009-06-19 10:44:45 +03001742 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1743 if (ret)
1744 return ret;
1745
bellard3532fa72006-06-24 15:06:03 +00001746 return get_errno(bind(sockfd, addr, addrlen));
1747}
1748
ths0da46a62007-10-20 20:23:07 +00001749/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001750static abi_long do_connect(int sockfd, abi_ulong target_addr,
1751 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001752{
aurel328f7aeaf2009-01-30 19:47:57 +00001753 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001754 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001755
Blue Swirl38724252010-09-18 05:53:14 +00001756 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001757 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001758 }
aurel328f7aeaf2009-01-30 19:47:57 +00001759
1760 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001761
Arnaud Patard917507b2009-06-19 10:44:45 +03001762 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1763 if (ret)
1764 return ret;
1765
bellard3532fa72006-06-24 15:06:03 +00001766 return get_errno(connect(sockfd, addr, addrlen));
1767}
1768
ths0da46a62007-10-20 20:23:07 +00001769/* do_sendrecvmsg() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001770static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1771 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001772{
balrog6de645c2008-10-28 10:26:29 +00001773 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001774 struct target_msghdr *msgp;
1775 struct msghdr msg;
1776 int count;
1777 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001778 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001779
bellard579a97f2007-11-11 14:26:47 +00001780 /* FIXME */
1781 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1782 msgp,
1783 target_msg,
1784 send ? 1 : 0))
1785 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001786 if (msgp->msg_name) {
1787 msg.msg_namelen = tswap32(msgp->msg_namelen);
1788 msg.msg_name = alloca(msg.msg_namelen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001789 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001790 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001791 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001792 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03001793 }
bellard3532fa72006-06-24 15:06:03 +00001794 } else {
1795 msg.msg_name = NULL;
1796 msg.msg_namelen = 0;
1797 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001798 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00001799 msg.msg_control = alloca(msg.msg_controllen);
1800 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001801
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001802 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001803 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001804 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
1805 target_vec, count, send);
1806 if (vec == NULL) {
1807 ret = -host_to_target_errno(errno);
1808 goto out2;
1809 }
bellard3532fa72006-06-24 15:06:03 +00001810 msg.msg_iovlen = count;
1811 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001812
bellard3532fa72006-06-24 15:06:03 +00001813 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001814 ret = target_to_host_cmsg(&msg, msgp);
1815 if (ret == 0)
1816 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001817 } else {
1818 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001819 if (!is_error(ret)) {
1820 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001821 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00001822 if (!is_error(ret)) {
1823 msgp->msg_namelen = tswap32(msg.msg_namelen);
1824 if (msg.msg_name != NULL) {
1825 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
1826 msg.msg_name, msg.msg_namelen);
1827 if (ret) {
1828 goto out;
1829 }
1830 }
1831
balrog6de645c2008-10-28 10:26:29 +00001832 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00001833 }
balrog6de645c2008-10-28 10:26:29 +00001834 }
bellard3532fa72006-06-24 15:06:03 +00001835 }
Jing Huangca619062012-07-24 13:58:02 +00001836
1837out:
bellard3532fa72006-06-24 15:06:03 +00001838 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001839out2:
bellard579a97f2007-11-11 14:26:47 +00001840 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001841 return ret;
1842}
1843
Peter Maydella94b4982013-02-08 04:35:04 +00001844/* If we don't have a system accept4() then just call accept.
1845 * The callsites to do_accept4() will ensure that they don't
1846 * pass a non-zero flags argument in this config.
1847 */
1848#ifndef CONFIG_ACCEPT4
1849static inline int accept4(int sockfd, struct sockaddr *addr,
1850 socklen_t *addrlen, int flags)
1851{
1852 assert(flags == 0);
1853 return accept(sockfd, addr, addrlen);
1854}
1855#endif
1856
1857/* do_accept4() Must return target values and target errnos. */
1858static abi_long do_accept4(int fd, abi_ulong target_addr,
1859 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00001860{
bellard2f619692007-11-16 10:46:05 +00001861 socklen_t addrlen;
1862 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001863 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001864
Peter Maydella94b4982013-02-08 04:35:04 +00001865 if (target_addr == 0) {
1866 return get_errno(accept4(fd, NULL, NULL, flags));
1867 }
Arnaud Patard917507b2009-06-19 10:44:45 +03001868
1869 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00001870 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03001871 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00001872
Blue Swirl38724252010-09-18 05:53:14 +00001873 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001874 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001875 }
aurel328f7aeaf2009-01-30 19:47:57 +00001876
Arnaud Patard917507b2009-06-19 10:44:45 +03001877 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1878 return -TARGET_EINVAL;
1879
bellard2f619692007-11-16 10:46:05 +00001880 addr = alloca(addrlen);
1881
Peter Maydella94b4982013-02-08 04:35:04 +00001882 ret = get_errno(accept4(fd, addr, &addrlen, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00001883 if (!is_error(ret)) {
1884 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001885 if (put_user_u32(addrlen, target_addrlen_addr))
1886 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001887 }
1888 return ret;
1889}
1890
ths0da46a62007-10-20 20:23:07 +00001891/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001892static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001893 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001894{
bellard2f619692007-11-16 10:46:05 +00001895 socklen_t addrlen;
1896 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001897 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001898
bellard2f619692007-11-16 10:46:05 +00001899 if (get_user_u32(addrlen, target_addrlen_addr))
1900 return -TARGET_EFAULT;
1901
Blue Swirl38724252010-09-18 05:53:14 +00001902 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001903 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001904 }
aurel328f7aeaf2009-01-30 19:47:57 +00001905
Arnaud Patard917507b2009-06-19 10:44:45 +03001906 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1907 return -TARGET_EFAULT;
1908
bellard2f619692007-11-16 10:46:05 +00001909 addr = alloca(addrlen);
1910
pbrook1be9e1d2006-11-19 15:26:04 +00001911 ret = get_errno(getpeername(fd, addr, &addrlen));
1912 if (!is_error(ret)) {
1913 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001914 if (put_user_u32(addrlen, target_addrlen_addr))
1915 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001916 }
1917 return ret;
1918}
1919
ths0da46a62007-10-20 20:23:07 +00001920/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001921static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001922 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001923{
bellard2f619692007-11-16 10:46:05 +00001924 socklen_t addrlen;
1925 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001926 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001927
bellard2f619692007-11-16 10:46:05 +00001928 if (get_user_u32(addrlen, target_addrlen_addr))
1929 return -TARGET_EFAULT;
1930
Blue Swirl38724252010-09-18 05:53:14 +00001931 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001932 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001933 }
aurel328f7aeaf2009-01-30 19:47:57 +00001934
Arnaud Patard917507b2009-06-19 10:44:45 +03001935 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1936 return -TARGET_EFAULT;
1937
bellard2f619692007-11-16 10:46:05 +00001938 addr = alloca(addrlen);
1939
pbrook1be9e1d2006-11-19 15:26:04 +00001940 ret = get_errno(getsockname(fd, addr, &addrlen));
1941 if (!is_error(ret)) {
1942 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001943 if (put_user_u32(addrlen, target_addrlen_addr))
1944 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001945 }
1946 return ret;
1947}
1948
ths0da46a62007-10-20 20:23:07 +00001949/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001950static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00001951 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001952{
1953 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00001954 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001955
1956 ret = get_errno(socketpair(domain, type, protocol, tab));
1957 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00001958 if (put_user_s32(tab[0], target_tab_addr)
1959 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
1960 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001961 }
1962 return ret;
1963}
1964
ths0da46a62007-10-20 20:23:07 +00001965/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001966static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
1967 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001968{
1969 void *addr;
1970 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00001971 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001972
Blue Swirl38724252010-09-18 05:53:14 +00001973 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001974 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001975 }
aurel328f7aeaf2009-01-30 19:47:57 +00001976
bellard579a97f2007-11-11 14:26:47 +00001977 host_msg = lock_user(VERIFY_READ, msg, len, 1);
1978 if (!host_msg)
1979 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001980 if (target_addr) {
1981 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001982 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1983 if (ret) {
1984 unlock_user(host_msg, msg, 0);
1985 return ret;
1986 }
pbrook1be9e1d2006-11-19 15:26:04 +00001987 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
1988 } else {
1989 ret = get_errno(send(fd, host_msg, len, flags));
1990 }
1991 unlock_user(host_msg, msg, 0);
1992 return ret;
1993}
1994
ths0da46a62007-10-20 20:23:07 +00001995/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001996static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
1997 abi_ulong target_addr,
1998 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001999{
2000 socklen_t addrlen;
2001 void *addr;
2002 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002003 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002004
bellard579a97f2007-11-11 14:26:47 +00002005 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2006 if (!host_msg)
2007 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002008 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002009 if (get_user_u32(addrlen, target_addrlen)) {
2010 ret = -TARGET_EFAULT;
2011 goto fail;
2012 }
Blue Swirl38724252010-09-18 05:53:14 +00002013 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002014 ret = -TARGET_EINVAL;
2015 goto fail;
2016 }
pbrook1be9e1d2006-11-19 15:26:04 +00002017 addr = alloca(addrlen);
2018 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2019 } else {
2020 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002021 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002022 }
2023 if (!is_error(ret)) {
2024 if (target_addr) {
2025 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002026 if (put_user_u32(addrlen, target_addrlen)) {
2027 ret = -TARGET_EFAULT;
2028 goto fail;
2029 }
pbrook1be9e1d2006-11-19 15:26:04 +00002030 }
2031 unlock_user(host_msg, msg, len);
2032 } else {
bellard2f619692007-11-16 10:46:05 +00002033fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002034 unlock_user(host_msg, msg, 0);
2035 }
2036 return ret;
2037}
2038
j_mayer32407102007-09-26 23:01:49 +00002039#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002040/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002041static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002042{
blueswir1992f48a2007-10-14 16:27:31 +00002043 abi_long ret;
2044 const int n = sizeof(abi_ulong);
bellard31e31b82003-02-18 22:55:36 +00002045
2046 switch(num) {
2047 case SOCKOP_socket:
bellard7854b052003-03-29 17:22:23 +00002048 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002049 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002050
Ulrich Hecht98818182009-07-03 17:09:28 +02002051 if (get_user_ual(domain, vptr)
2052 || get_user_ual(type, vptr + n)
2053 || get_user_ual(protocol, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002054 return -TARGET_EFAULT;
2055
bellard3532fa72006-06-24 15:06:03 +00002056 ret = do_socket(domain, type, protocol);
bellard7854b052003-03-29 17:22:23 +00002057 }
bellard31e31b82003-02-18 22:55:36 +00002058 break;
2059 case SOCKOP_bind:
bellard7854b052003-03-29 17:22:23 +00002060 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002061 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002062 abi_ulong target_addr;
2063 socklen_t addrlen;
2064
Ulrich Hecht98818182009-07-03 17:09:28 +02002065 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002066 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002067 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002068 return -TARGET_EFAULT;
2069
bellard3532fa72006-06-24 15:06:03 +00002070 ret = do_bind(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002071 }
bellard31e31b82003-02-18 22:55:36 +00002072 break;
2073 case SOCKOP_connect:
bellard7854b052003-03-29 17:22:23 +00002074 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002075 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002076 abi_ulong target_addr;
2077 socklen_t addrlen;
2078
Ulrich Hecht98818182009-07-03 17:09:28 +02002079 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002080 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002081 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002082 return -TARGET_EFAULT;
2083
bellard3532fa72006-06-24 15:06:03 +00002084 ret = do_connect(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002085 }
bellard31e31b82003-02-18 22:55:36 +00002086 break;
2087 case SOCKOP_listen:
bellard7854b052003-03-29 17:22:23 +00002088 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002089 abi_ulong sockfd, backlog;
bellard2f619692007-11-16 10:46:05 +00002090
Ulrich Hecht98818182009-07-03 17:09:28 +02002091 if (get_user_ual(sockfd, vptr)
2092 || get_user_ual(backlog, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002093 return -TARGET_EFAULT;
2094
bellard7854b052003-03-29 17:22:23 +00002095 ret = get_errno(listen(sockfd, backlog));
2096 }
bellard31e31b82003-02-18 22:55:36 +00002097 break;
2098 case SOCKOP_accept:
2099 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002100 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002101 abi_ulong target_addr, target_addrlen;
2102
Ulrich Hecht98818182009-07-03 17:09:28 +02002103 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002104 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002105 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002106 return -TARGET_EFAULT;
2107
Peter Maydella94b4982013-02-08 04:35:04 +00002108 ret = do_accept4(sockfd, target_addr, target_addrlen, 0);
bellard31e31b82003-02-18 22:55:36 +00002109 }
2110 break;
2111 case SOCKOP_getsockname:
2112 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002113 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002114 abi_ulong target_addr, target_addrlen;
2115
Ulrich Hecht98818182009-07-03 17:09:28 +02002116 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002117 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002118 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002119 return -TARGET_EFAULT;
2120
pbrook1be9e1d2006-11-19 15:26:04 +00002121 ret = do_getsockname(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002122 }
2123 break;
2124 case SOCKOP_getpeername:
2125 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002126 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002127 abi_ulong target_addr, target_addrlen;
2128
Ulrich Hecht98818182009-07-03 17:09:28 +02002129 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002130 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002131 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002132 return -TARGET_EFAULT;
2133
pbrook1be9e1d2006-11-19 15:26:04 +00002134 ret = do_getpeername(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002135 }
2136 break;
2137 case SOCKOP_socketpair:
2138 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002139 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002140 abi_ulong tab;
2141
Ulrich Hecht98818182009-07-03 17:09:28 +02002142 if (get_user_ual(domain, vptr)
2143 || get_user_ual(type, vptr + n)
2144 || get_user_ual(protocol, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002145 || get_user_ual(tab, vptr + 3 * n))
2146 return -TARGET_EFAULT;
2147
pbrook1be9e1d2006-11-19 15:26:04 +00002148 ret = do_socketpair(domain, type, protocol, tab);
bellard31e31b82003-02-18 22:55:36 +00002149 }
2150 break;
2151 case SOCKOP_send:
bellard7854b052003-03-29 17:22:23 +00002152 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002153 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002154 abi_ulong msg;
2155 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002156 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002157
Ulrich Hecht98818182009-07-03 17:09:28 +02002158 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002159 || get_user_ual(msg, vptr + n)
2160 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002161 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002162 return -TARGET_EFAULT;
2163
pbrook1be9e1d2006-11-19 15:26:04 +00002164 ret = do_sendto(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002165 }
bellard31e31b82003-02-18 22:55:36 +00002166 break;
2167 case SOCKOP_recv:
bellard7854b052003-03-29 17:22:23 +00002168 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002169 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002170 abi_ulong msg;
2171 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002172 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002173
Ulrich Hecht98818182009-07-03 17:09:28 +02002174 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002175 || get_user_ual(msg, vptr + n)
2176 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002177 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002178 return -TARGET_EFAULT;
2179
pbrook1be9e1d2006-11-19 15:26:04 +00002180 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002181 }
bellard31e31b82003-02-18 22:55:36 +00002182 break;
2183 case SOCKOP_sendto:
bellard7854b052003-03-29 17:22:23 +00002184 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002185 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002186 abi_ulong msg;
2187 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002188 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002189 abi_ulong addr;
2190 socklen_t addrlen;
2191
Ulrich Hecht98818182009-07-03 17:09:28 +02002192 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002193 || get_user_ual(msg, vptr + n)
2194 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002195 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002196 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002197 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002198 return -TARGET_EFAULT;
2199
pbrook1be9e1d2006-11-19 15:26:04 +00002200 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002201 }
bellard31e31b82003-02-18 22:55:36 +00002202 break;
2203 case SOCKOP_recvfrom:
2204 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002205 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002206 abi_ulong msg;
2207 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002208 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002209 abi_ulong addr;
2210 socklen_t addrlen;
2211
Ulrich Hecht98818182009-07-03 17:09:28 +02002212 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002213 || get_user_ual(msg, vptr + n)
2214 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002215 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002216 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002217 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002218 return -TARGET_EFAULT;
2219
pbrook1be9e1d2006-11-19 15:26:04 +00002220 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
bellard31e31b82003-02-18 22:55:36 +00002221 }
2222 break;
2223 case SOCKOP_shutdown:
bellard7854b052003-03-29 17:22:23 +00002224 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002225 abi_ulong sockfd, how;
bellard2f619692007-11-16 10:46:05 +00002226
Ulrich Hecht98818182009-07-03 17:09:28 +02002227 if (get_user_ual(sockfd, vptr)
2228 || get_user_ual(how, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002229 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002230
2231 ret = get_errno(shutdown(sockfd, how));
2232 }
bellard31e31b82003-02-18 22:55:36 +00002233 break;
2234 case SOCKOP_sendmsg:
2235 case SOCKOP_recvmsg:
bellard1a9353d2003-03-16 20:28:50 +00002236 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002237 abi_ulong fd;
blueswir1992f48a2007-10-14 16:27:31 +00002238 abi_ulong target_msg;
Ulrich Hecht98818182009-07-03 17:09:28 +02002239 abi_ulong flags;
bellard1a9353d2003-03-16 20:28:50 +00002240
Ulrich Hecht98818182009-07-03 17:09:28 +02002241 if (get_user_ual(fd, vptr)
bellard2f619692007-11-16 10:46:05 +00002242 || get_user_ual(target_msg, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002243 || get_user_ual(flags, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002244 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002245
ths5fafdf22007-09-16 21:08:06 +00002246 ret = do_sendrecvmsg(fd, target_msg, flags,
bellard3532fa72006-06-24 15:06:03 +00002247 (num == SOCKOP_sendmsg));
bellard1a9353d2003-03-16 20:28:50 +00002248 }
2249 break;
bellard31e31b82003-02-18 22:55:36 +00002250 case SOCKOP_setsockopt:
bellard7854b052003-03-29 17:22:23 +00002251 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002252 abi_ulong sockfd;
2253 abi_ulong level;
2254 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002255 abi_ulong optval;
2256 socklen_t optlen;
2257
Ulrich Hecht98818182009-07-03 17:09:28 +02002258 if (get_user_ual(sockfd, vptr)
2259 || get_user_ual(level, vptr + n)
2260 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002261 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002262 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002263 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002264
2265 ret = do_setsockopt(sockfd, level, optname, optval, optlen);
2266 }
2267 break;
bellard31e31b82003-02-18 22:55:36 +00002268 case SOCKOP_getsockopt:
bellard7854b052003-03-29 17:22:23 +00002269 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002270 abi_ulong sockfd;
2271 abi_ulong level;
2272 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002273 abi_ulong optval;
2274 socklen_t optlen;
bellard7854b052003-03-29 17:22:23 +00002275
Ulrich Hecht98818182009-07-03 17:09:28 +02002276 if (get_user_ual(sockfd, vptr)
2277 || get_user_ual(level, vptr + n)
2278 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002279 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002280 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002281 return -TARGET_EFAULT;
2282
2283 ret = do_getsockopt(sockfd, level, optname, optval, optlen);
bellard7854b052003-03-29 17:22:23 +00002284 }
2285 break;
bellard31e31b82003-02-18 22:55:36 +00002286 default:
2287 gemu_log("Unsupported socketcall: %d\n", num);
ths0da46a62007-10-20 20:23:07 +00002288 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002289 break;
2290 }
2291 return ret;
2292}
j_mayer32407102007-09-26 23:01:49 +00002293#endif
bellard31e31b82003-02-18 22:55:36 +00002294
bellard8853f862004-02-22 14:57:26 +00002295#define N_SHM_REGIONS 32
2296
2297static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002298 abi_ulong start;
2299 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002300} shm_regions[N_SHM_REGIONS];
2301
ths3eb6b042007-06-03 14:26:27 +00002302struct target_ipc_perm
2303{
blueswir1992f48a2007-10-14 16:27:31 +00002304 abi_long __key;
2305 abi_ulong uid;
2306 abi_ulong gid;
2307 abi_ulong cuid;
2308 abi_ulong cgid;
ths3eb6b042007-06-03 14:26:27 +00002309 unsigned short int mode;
2310 unsigned short int __pad1;
2311 unsigned short int __seq;
2312 unsigned short int __pad2;
blueswir1992f48a2007-10-14 16:27:31 +00002313 abi_ulong __unused1;
2314 abi_ulong __unused2;
ths3eb6b042007-06-03 14:26:27 +00002315};
2316
2317struct target_semid_ds
2318{
2319 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002320 abi_ulong sem_otime;
2321 abi_ulong __unused1;
2322 abi_ulong sem_ctime;
2323 abi_ulong __unused2;
2324 abi_ulong sem_nsems;
2325 abi_ulong __unused3;
2326 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002327};
2328
bellard579a97f2007-11-11 14:26:47 +00002329static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2330 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002331{
2332 struct target_ipc_perm *target_ip;
2333 struct target_semid_ds *target_sd;
2334
bellard579a97f2007-11-11 14:26:47 +00002335 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2336 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002337 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002338 host_ip->__key = tswapal(target_ip->__key);
2339 host_ip->uid = tswapal(target_ip->uid);
2340 host_ip->gid = tswapal(target_ip->gid);
2341 host_ip->cuid = tswapal(target_ip->cuid);
2342 host_ip->cgid = tswapal(target_ip->cgid);
2343 host_ip->mode = tswap16(target_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002344 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002345 return 0;
ths3eb6b042007-06-03 14:26:27 +00002346}
2347
bellard579a97f2007-11-11 14:26:47 +00002348static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2349 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002350{
2351 struct target_ipc_perm *target_ip;
2352 struct target_semid_ds *target_sd;
2353
bellard579a97f2007-11-11 14:26:47 +00002354 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2355 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002356 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002357 target_ip->__key = tswapal(host_ip->__key);
2358 target_ip->uid = tswapal(host_ip->uid);
2359 target_ip->gid = tswapal(host_ip->gid);
2360 target_ip->cuid = tswapal(host_ip->cuid);
2361 target_ip->cgid = tswapal(host_ip->cgid);
2362 target_ip->mode = tswap16(host_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002363 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002364 return 0;
ths3eb6b042007-06-03 14:26:27 +00002365}
2366
bellard579a97f2007-11-11 14:26:47 +00002367static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2368 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002369{
2370 struct target_semid_ds *target_sd;
2371
bellard579a97f2007-11-11 14:26:47 +00002372 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2373 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002374 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2375 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002376 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2377 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2378 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002379 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002380 return 0;
ths3eb6b042007-06-03 14:26:27 +00002381}
2382
bellard579a97f2007-11-11 14:26:47 +00002383static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2384 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002385{
2386 struct target_semid_ds *target_sd;
2387
bellard579a97f2007-11-11 14:26:47 +00002388 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2389 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002390 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002391 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002392 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2393 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2394 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002395 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002396 return 0;
ths3eb6b042007-06-03 14:26:27 +00002397}
2398
aurel32e5289082009-04-18 16:16:12 +00002399struct target_seminfo {
2400 int semmap;
2401 int semmni;
2402 int semmns;
2403 int semmnu;
2404 int semmsl;
2405 int semopm;
2406 int semume;
2407 int semusz;
2408 int semvmx;
2409 int semaem;
2410};
2411
2412static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2413 struct seminfo *host_seminfo)
2414{
2415 struct target_seminfo *target_seminfo;
2416 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2417 return -TARGET_EFAULT;
2418 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2419 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2420 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2421 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2422 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2423 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2424 __put_user(host_seminfo->semume, &target_seminfo->semume);
2425 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2426 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2427 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2428 unlock_user_struct(target_seminfo, target_addr, 1);
2429 return 0;
2430}
2431
thsfa294812007-02-02 22:05:00 +00002432union semun {
2433 int val;
ths3eb6b042007-06-03 14:26:27 +00002434 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002435 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002436 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002437};
2438
ths3eb6b042007-06-03 14:26:27 +00002439union target_semun {
2440 int val;
aurel32e5289082009-04-18 16:16:12 +00002441 abi_ulong buf;
2442 abi_ulong array;
2443 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002444};
2445
aurel32e5289082009-04-18 16:16:12 +00002446static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2447 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002448{
aurel32e5289082009-04-18 16:16:12 +00002449 int nsems;
2450 unsigned short *array;
2451 union semun semun;
2452 struct semid_ds semid_ds;
2453 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002454
aurel32e5289082009-04-18 16:16:12 +00002455 semun.buf = &semid_ds;
2456
2457 ret = semctl(semid, 0, IPC_STAT, semun);
2458 if (ret == -1)
2459 return get_errno(ret);
2460
2461 nsems = semid_ds.sem_nsems;
2462
2463 *host_array = malloc(nsems*sizeof(unsigned short));
2464 array = lock_user(VERIFY_READ, target_addr,
2465 nsems*sizeof(unsigned short), 1);
2466 if (!array)
2467 return -TARGET_EFAULT;
2468
2469 for(i=0; i<nsems; i++) {
2470 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002471 }
aurel32e5289082009-04-18 16:16:12 +00002472 unlock_user(array, target_addr, 0);
2473
bellard579a97f2007-11-11 14:26:47 +00002474 return 0;
ths3eb6b042007-06-03 14:26:27 +00002475}
2476
aurel32e5289082009-04-18 16:16:12 +00002477static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2478 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002479{
aurel32e5289082009-04-18 16:16:12 +00002480 int nsems;
2481 unsigned short *array;
2482 union semun semun;
2483 struct semid_ds semid_ds;
2484 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002485
aurel32e5289082009-04-18 16:16:12 +00002486 semun.buf = &semid_ds;
2487
2488 ret = semctl(semid, 0, IPC_STAT, semun);
2489 if (ret == -1)
2490 return get_errno(ret);
2491
2492 nsems = semid_ds.sem_nsems;
2493
2494 array = lock_user(VERIFY_WRITE, target_addr,
2495 nsems*sizeof(unsigned short), 0);
2496 if (!array)
2497 return -TARGET_EFAULT;
2498
2499 for(i=0; i<nsems; i++) {
2500 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002501 }
aurel32e5289082009-04-18 16:16:12 +00002502 free(*host_array);
2503 unlock_user(array, target_addr, 1);
2504
bellard579a97f2007-11-11 14:26:47 +00002505 return 0;
ths3eb6b042007-06-03 14:26:27 +00002506}
2507
aurel32e5289082009-04-18 16:16:12 +00002508static inline abi_long do_semctl(int semid, int semnum, int cmd,
2509 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002510{
2511 union semun arg;
2512 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302513 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002514 struct seminfo seminfo;
2515 abi_long ret = -TARGET_EINVAL;
2516 abi_long err;
2517 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002518
2519 switch( cmd ) {
2520 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002521 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002522 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002523 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002524 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002525 break;
2526 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002527 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002528 err = target_to_host_semarray(semid, &array, target_su.array);
2529 if (err)
2530 return err;
2531 arg.array = array;
2532 ret = get_errno(semctl(semid, semnum, cmd, arg));
2533 err = host_to_target_semarray(semid, target_su.array, &array);
2534 if (err)
2535 return err;
ths3eb6b042007-06-03 14:26:27 +00002536 break;
2537 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002538 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002539 case SEM_STAT:
2540 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2541 if (err)
2542 return err;
2543 arg.buf = &dsarg;
2544 ret = get_errno(semctl(semid, semnum, cmd, arg));
2545 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2546 if (err)
2547 return err;
ths3eb6b042007-06-03 14:26:27 +00002548 break;
aurel32e5289082009-04-18 16:16:12 +00002549 case IPC_INFO:
2550 case SEM_INFO:
2551 arg.__buf = &seminfo;
2552 ret = get_errno(semctl(semid, semnum, cmd, arg));
2553 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2554 if (err)
2555 return err;
2556 break;
2557 case IPC_RMID:
2558 case GETPID:
2559 case GETNCNT:
2560 case GETZCNT:
2561 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2562 break;
ths3eb6b042007-06-03 14:26:27 +00002563 }
2564
2565 return ret;
2566}
2567
aurel32e5289082009-04-18 16:16:12 +00002568struct target_sembuf {
2569 unsigned short sem_num;
2570 short sem_op;
2571 short sem_flg;
2572};
2573
2574static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2575 abi_ulong target_addr,
2576 unsigned nsops)
2577{
2578 struct target_sembuf *target_sembuf;
2579 int i;
2580
2581 target_sembuf = lock_user(VERIFY_READ, target_addr,
2582 nsops*sizeof(struct target_sembuf), 1);
2583 if (!target_sembuf)
2584 return -TARGET_EFAULT;
2585
2586 for(i=0; i<nsops; i++) {
2587 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2588 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2589 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2590 }
2591
2592 unlock_user(target_sembuf, target_addr, 0);
2593
2594 return 0;
2595}
2596
2597static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2598{
2599 struct sembuf sops[nsops];
2600
2601 if (target_to_host_sembuf(sops, ptr, nsops))
2602 return -TARGET_EFAULT;
2603
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002604 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002605}
2606
ths1bc012f2007-06-03 14:27:49 +00002607struct target_msqid_ds
2608{
aurel321c54ff92008-10-13 21:08:44 +00002609 struct target_ipc_perm msg_perm;
2610 abi_ulong msg_stime;
2611#if TARGET_ABI_BITS == 32
2612 abi_ulong __unused1;
2613#endif
2614 abi_ulong msg_rtime;
2615#if TARGET_ABI_BITS == 32
2616 abi_ulong __unused2;
2617#endif
2618 abi_ulong msg_ctime;
2619#if TARGET_ABI_BITS == 32
2620 abi_ulong __unused3;
2621#endif
2622 abi_ulong __msg_cbytes;
2623 abi_ulong msg_qnum;
2624 abi_ulong msg_qbytes;
2625 abi_ulong msg_lspid;
2626 abi_ulong msg_lrpid;
2627 abi_ulong __unused4;
2628 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002629};
2630
bellard579a97f2007-11-11 14:26:47 +00002631static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2632 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002633{
2634 struct target_msqid_ds *target_md;
2635
bellard579a97f2007-11-11 14:26:47 +00002636 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2637 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002638 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2639 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002640 host_md->msg_stime = tswapal(target_md->msg_stime);
2641 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2642 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2643 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2644 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2645 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2646 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2647 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002648 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002649 return 0;
ths1bc012f2007-06-03 14:27:49 +00002650}
2651
bellard579a97f2007-11-11 14:26:47 +00002652static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2653 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002654{
2655 struct target_msqid_ds *target_md;
2656
bellard579a97f2007-11-11 14:26:47 +00002657 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2658 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002659 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2660 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002661 target_md->msg_stime = tswapal(host_md->msg_stime);
2662 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2663 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2664 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2665 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2666 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2667 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2668 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002669 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002670 return 0;
ths1bc012f2007-06-03 14:27:49 +00002671}
2672
aurel321c54ff92008-10-13 21:08:44 +00002673struct target_msginfo {
2674 int msgpool;
2675 int msgmap;
2676 int msgmax;
2677 int msgmnb;
2678 int msgmni;
2679 int msgssz;
2680 int msgtql;
2681 unsigned short int msgseg;
2682};
2683
2684static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2685 struct msginfo *host_msginfo)
2686{
2687 struct target_msginfo *target_msginfo;
2688 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2689 return -TARGET_EFAULT;
2690 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2691 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2692 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2693 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2694 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2695 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2696 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2697 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2698 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002699 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002700}
2701
2702static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002703{
2704 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002705 struct msginfo msginfo;
2706 abi_long ret = -TARGET_EINVAL;
2707
2708 cmd &= 0xff;
2709
2710 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002711 case IPC_STAT:
2712 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002713 case MSG_STAT:
2714 if (target_to_host_msqid_ds(&dsarg,ptr))
2715 return -TARGET_EFAULT;
2716 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2717 if (host_to_target_msqid_ds(ptr,&dsarg))
2718 return -TARGET_EFAULT;
2719 break;
2720 case IPC_RMID:
2721 ret = get_errno(msgctl(msgid, cmd, NULL));
2722 break;
2723 case IPC_INFO:
2724 case MSG_INFO:
2725 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2726 if (host_to_target_msginfo(ptr, &msginfo))
2727 return -TARGET_EFAULT;
2728 break;
ths1bc012f2007-06-03 14:27:49 +00002729 }
aurel321c54ff92008-10-13 21:08:44 +00002730
ths1bc012f2007-06-03 14:27:49 +00002731 return ret;
2732}
2733
2734struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002735 abi_long mtype;
2736 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002737};
2738
blueswir1992f48a2007-10-14 16:27:31 +00002739static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2740 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002741{
2742 struct target_msgbuf *target_mb;
2743 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002744 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002745
bellard579a97f2007-11-11 14:26:47 +00002746 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2747 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002748 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002749 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002750 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002751 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2752 free(host_mb);
2753 unlock_user_struct(target_mb, msgp, 0);
2754
2755 return ret;
2756}
2757
blueswir1992f48a2007-10-14 16:27:31 +00002758static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002759 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002760 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002761{
2762 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002763 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002764 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002765 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002766
bellard579a97f2007-11-11 14:26:47 +00002767 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2768 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002769
Jim Meyering0d07fe42012-08-22 13:55:53 +02002770 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00002771 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002772
bellard579a97f2007-11-11 14:26:47 +00002773 if (ret > 0) {
2774 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2775 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2776 if (!target_mtext) {
2777 ret = -TARGET_EFAULT;
2778 goto end;
2779 }
aurel321c54ff92008-10-13 21:08:44 +00002780 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002781 unlock_user(target_mtext, target_mtext_addr, ret);
2782 }
aurel321c54ff92008-10-13 21:08:44 +00002783
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002784 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002785
bellard579a97f2007-11-11 14:26:47 +00002786end:
2787 if (target_mb)
2788 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02002789 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002790 return ret;
2791}
2792
Riku Voipio88a8c982009-04-03 10:42:00 +03002793struct target_shmid_ds
2794{
2795 struct target_ipc_perm shm_perm;
2796 abi_ulong shm_segsz;
2797 abi_ulong shm_atime;
2798#if TARGET_ABI_BITS == 32
2799 abi_ulong __unused1;
2800#endif
2801 abi_ulong shm_dtime;
2802#if TARGET_ABI_BITS == 32
2803 abi_ulong __unused2;
2804#endif
2805 abi_ulong shm_ctime;
2806#if TARGET_ABI_BITS == 32
2807 abi_ulong __unused3;
2808#endif
2809 int shm_cpid;
2810 int shm_lpid;
2811 abi_ulong shm_nattch;
2812 unsigned long int __unused4;
2813 unsigned long int __unused5;
2814};
2815
2816static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2817 abi_ulong target_addr)
2818{
2819 struct target_shmid_ds *target_sd;
2820
2821 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2822 return -TARGET_EFAULT;
2823 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2824 return -TARGET_EFAULT;
2825 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2826 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2827 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2828 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2829 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2830 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2831 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2832 unlock_user_struct(target_sd, target_addr, 0);
2833 return 0;
2834}
2835
2836static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2837 struct shmid_ds *host_sd)
2838{
2839 struct target_shmid_ds *target_sd;
2840
2841 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2842 return -TARGET_EFAULT;
2843 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2844 return -TARGET_EFAULT;
2845 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2846 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2847 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2848 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2849 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2850 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2851 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2852 unlock_user_struct(target_sd, target_addr, 1);
2853 return 0;
2854}
2855
2856struct target_shminfo {
2857 abi_ulong shmmax;
2858 abi_ulong shmmin;
2859 abi_ulong shmmni;
2860 abi_ulong shmseg;
2861 abi_ulong shmall;
2862};
2863
2864static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2865 struct shminfo *host_shminfo)
2866{
2867 struct target_shminfo *target_shminfo;
2868 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2869 return -TARGET_EFAULT;
2870 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2871 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2872 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2873 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2874 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2875 unlock_user_struct(target_shminfo, target_addr, 1);
2876 return 0;
2877}
2878
2879struct target_shm_info {
2880 int used_ids;
2881 abi_ulong shm_tot;
2882 abi_ulong shm_rss;
2883 abi_ulong shm_swp;
2884 abi_ulong swap_attempts;
2885 abi_ulong swap_successes;
2886};
2887
2888static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2889 struct shm_info *host_shm_info)
2890{
2891 struct target_shm_info *target_shm_info;
2892 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2893 return -TARGET_EFAULT;
2894 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2895 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2896 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2897 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2898 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2899 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
2900 unlock_user_struct(target_shm_info, target_addr, 1);
2901 return 0;
2902}
2903
2904static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
2905{
2906 struct shmid_ds dsarg;
2907 struct shminfo shminfo;
2908 struct shm_info shm_info;
2909 abi_long ret = -TARGET_EINVAL;
2910
2911 cmd &= 0xff;
2912
2913 switch(cmd) {
2914 case IPC_STAT:
2915 case IPC_SET:
2916 case SHM_STAT:
2917 if (target_to_host_shmid_ds(&dsarg, buf))
2918 return -TARGET_EFAULT;
2919 ret = get_errno(shmctl(shmid, cmd, &dsarg));
2920 if (host_to_target_shmid_ds(buf, &dsarg))
2921 return -TARGET_EFAULT;
2922 break;
2923 case IPC_INFO:
2924 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
2925 if (host_to_target_shminfo(buf, &shminfo))
2926 return -TARGET_EFAULT;
2927 break;
2928 case SHM_INFO:
2929 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
2930 if (host_to_target_shm_info(buf, &shm_info))
2931 return -TARGET_EFAULT;
2932 break;
2933 case IPC_RMID:
2934 case SHM_LOCK:
2935 case SHM_UNLOCK:
2936 ret = get_errno(shmctl(shmid, cmd, NULL));
2937 break;
2938 }
2939
2940 return ret;
2941}
2942
2943static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
2944{
2945 abi_long raddr;
2946 void *host_raddr;
2947 struct shmid_ds shm_info;
2948 int i,ret;
2949
2950 /* find out the length of the shared memory segment */
2951 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
2952 if (is_error(ret)) {
2953 /* can't get length, bail out */
2954 return ret;
2955 }
2956
2957 mmap_lock();
2958
2959 if (shmaddr)
2960 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
2961 else {
2962 abi_ulong mmap_start;
2963
2964 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
2965
2966 if (mmap_start == -1) {
2967 errno = ENOMEM;
2968 host_raddr = (void *)-1;
2969 } else
2970 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
2971 }
2972
2973 if (host_raddr == (void *)-1) {
2974 mmap_unlock();
2975 return get_errno((long)host_raddr);
2976 }
2977 raddr=h2g((unsigned long)host_raddr);
2978
2979 page_set_flags(raddr, raddr + shm_info.shm_segsz,
2980 PAGE_VALID | PAGE_READ |
2981 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
2982
2983 for (i = 0; i < N_SHM_REGIONS; i++) {
2984 if (shm_regions[i].start == 0) {
2985 shm_regions[i].start = raddr;
2986 shm_regions[i].size = shm_info.shm_segsz;
2987 break;
2988 }
2989 }
2990
2991 mmap_unlock();
2992 return raddr;
2993
2994}
2995
2996static inline abi_long do_shmdt(abi_ulong shmaddr)
2997{
2998 int i;
2999
3000 for (i = 0; i < N_SHM_REGIONS; ++i) {
3001 if (shm_regions[i].start == shmaddr) {
3002 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003003 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003004 break;
3005 }
3006 }
3007
3008 return get_errno(shmdt(g2h(shmaddr)));
3009}
3010
aurel321c54ff92008-10-13 21:08:44 +00003011#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003012/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003013/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003014static abi_long do_ipc(unsigned int call, int first,
3015 int second, int third,
3016 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003017{
3018 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003019 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003020
3021 version = call >> 16;
3022 call &= 0xffff;
3023
3024 switch (call) {
thsfa294812007-02-02 22:05:00 +00003025 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003026 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003027 break;
3028
3029 case IPCOP_semget:
3030 ret = get_errno(semget(first, second, third));
3031 break;
3032
3033 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003034 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003035 break;
thsd96372e2007-02-02 22:05:44 +00003036
aurel321c54ff92008-10-13 21:08:44 +00003037 case IPCOP_msgget:
3038 ret = get_errno(msgget(first, second));
3039 break;
thsd96372e2007-02-02 22:05:44 +00003040
aurel321c54ff92008-10-13 21:08:44 +00003041 case IPCOP_msgsnd:
3042 ret = do_msgsnd(first, ptr, second, third);
3043 break;
thsd96372e2007-02-02 22:05:44 +00003044
aurel321c54ff92008-10-13 21:08:44 +00003045 case IPCOP_msgctl:
3046 ret = do_msgctl(first, second, ptr);
3047 break;
thsd96372e2007-02-02 22:05:44 +00003048
aurel321c54ff92008-10-13 21:08:44 +00003049 case IPCOP_msgrcv:
3050 switch (version) {
3051 case 0:
3052 {
3053 struct target_ipc_kludge {
3054 abi_long msgp;
3055 abi_long msgtyp;
3056 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003057
aurel321c54ff92008-10-13 21:08:44 +00003058 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3059 ret = -TARGET_EFAULT;
3060 break;
ths1bc012f2007-06-03 14:27:49 +00003061 }
aurel321c54ff92008-10-13 21:08:44 +00003062
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003063 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003064
3065 unlock_user_struct(tmp, ptr, 0);
3066 break;
3067 }
3068 default:
3069 ret = do_msgrcv(first, ptr, second, fifth, third);
3070 }
3071 break;
thsd96372e2007-02-02 22:05:44 +00003072
bellard8853f862004-02-22 14:57:26 +00003073 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003074 switch (version) {
3075 default:
bellard5a4a8982007-11-11 17:39:18 +00003076 {
3077 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003078 raddr = do_shmat(first, ptr, second);
3079 if (is_error(raddr))
3080 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003081 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003082 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003083 break;
3084 }
3085 case 1:
3086 ret = -TARGET_EINVAL;
3087 break;
bellard5a4a8982007-11-11 17:39:18 +00003088 }
bellard8853f862004-02-22 14:57:26 +00003089 break;
3090 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003091 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003092 break;
3093
3094 case IPCOP_shmget:
3095 /* IPC_* flag values are the same on all linux platforms */
3096 ret = get_errno(shmget(first, second, third));
3097 break;
3098
3099 /* IPC_* and SHM_* command values are the same on all linux platforms */
3100 case IPCOP_shmctl:
Riku Voipio88a8c982009-04-03 10:42:00 +03003101 ret = do_shmctl(first, second, third);
bellard8853f862004-02-22 14:57:26 +00003102 break;
3103 default:
j_mayer32407102007-09-26 23:01:49 +00003104 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003105 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003106 break;
3107 }
3108 return ret;
3109}
j_mayer32407102007-09-26 23:01:49 +00003110#endif
bellard8853f862004-02-22 14:57:26 +00003111
bellard31e31b82003-02-18 22:55:36 +00003112/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003113
Blue Swirl001faf32009-05-13 17:53:17 +00003114#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003115#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3116enum {
3117#include "syscall_types.h"
3118};
3119#undef STRUCT
3120#undef STRUCT_SPECIAL
3121
Blue Swirl001faf32009-05-13 17:53:17 +00003122#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003123#define STRUCT_SPECIAL(name)
3124#include "syscall_types.h"
3125#undef STRUCT
3126#undef STRUCT_SPECIAL
3127
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003128typedef struct IOCTLEntry IOCTLEntry;
3129
3130typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3131 int fd, abi_long cmd, abi_long arg);
3132
3133struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003134 unsigned int target_cmd;
3135 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003136 const char *name;
3137 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003138 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003139 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003140};
bellard31e31b82003-02-18 22:55:36 +00003141
3142#define IOC_R 0x0001
3143#define IOC_W 0x0002
3144#define IOC_RW (IOC_R | IOC_W)
3145
3146#define MAX_STRUCT_SIZE 4096
3147
Peter Maydelldace20d2011-01-10 13:11:24 +00003148#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003149/* So fiemap access checks don't overflow on 32 bit systems.
3150 * This is very slightly smaller than the limit imposed by
3151 * the underlying kernel.
3152 */
3153#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3154 / sizeof(struct fiemap_extent))
3155
3156static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3157 int fd, abi_long cmd, abi_long arg)
3158{
3159 /* The parameter for this ioctl is a struct fiemap followed
3160 * by an array of struct fiemap_extent whose size is set
3161 * in fiemap->fm_extent_count. The array is filled in by the
3162 * ioctl.
3163 */
3164 int target_size_in, target_size_out;
3165 struct fiemap *fm;
3166 const argtype *arg_type = ie->arg_type;
3167 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3168 void *argptr, *p;
3169 abi_long ret;
3170 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3171 uint32_t outbufsz;
3172 int free_fm = 0;
3173
3174 assert(arg_type[0] == TYPE_PTR);
3175 assert(ie->access == IOC_RW);
3176 arg_type++;
3177 target_size_in = thunk_type_size(arg_type, 0);
3178 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3179 if (!argptr) {
3180 return -TARGET_EFAULT;
3181 }
3182 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3183 unlock_user(argptr, arg, 0);
3184 fm = (struct fiemap *)buf_temp;
3185 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3186 return -TARGET_EINVAL;
3187 }
3188
3189 outbufsz = sizeof (*fm) +
3190 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3191
3192 if (outbufsz > MAX_STRUCT_SIZE) {
3193 /* We can't fit all the extents into the fixed size buffer.
3194 * Allocate one that is large enough and use it instead.
3195 */
3196 fm = malloc(outbufsz);
3197 if (!fm) {
3198 return -TARGET_ENOMEM;
3199 }
3200 memcpy(fm, buf_temp, sizeof(struct fiemap));
3201 free_fm = 1;
3202 }
3203 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3204 if (!is_error(ret)) {
3205 target_size_out = target_size_in;
3206 /* An extent_count of 0 means we were only counting the extents
3207 * so there are no structs to copy
3208 */
3209 if (fm->fm_extent_count != 0) {
3210 target_size_out += fm->fm_mapped_extents * extent_size;
3211 }
3212 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3213 if (!argptr) {
3214 ret = -TARGET_EFAULT;
3215 } else {
3216 /* Convert the struct fiemap */
3217 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3218 if (fm->fm_extent_count != 0) {
3219 p = argptr + target_size_in;
3220 /* ...and then all the struct fiemap_extents */
3221 for (i = 0; i < fm->fm_mapped_extents; i++) {
3222 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3223 THUNK_TARGET);
3224 p += extent_size;
3225 }
3226 }
3227 unlock_user(argptr, arg, target_size_out);
3228 }
3229 }
3230 if (free_fm) {
3231 free(fm);
3232 }
3233 return ret;
3234}
Peter Maydelldace20d2011-01-10 13:11:24 +00003235#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003236
Laurent Vivier059c2f22011-03-30 00:12:12 +02003237static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3238 int fd, abi_long cmd, abi_long arg)
3239{
3240 const argtype *arg_type = ie->arg_type;
3241 int target_size;
3242 void *argptr;
3243 int ret;
3244 struct ifconf *host_ifconf;
3245 uint32_t outbufsz;
3246 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3247 int target_ifreq_size;
3248 int nb_ifreq;
3249 int free_buf = 0;
3250 int i;
3251 int target_ifc_len;
3252 abi_long target_ifc_buf;
3253 int host_ifc_len;
3254 char *host_ifc_buf;
3255
3256 assert(arg_type[0] == TYPE_PTR);
3257 assert(ie->access == IOC_RW);
3258
3259 arg_type++;
3260 target_size = thunk_type_size(arg_type, 0);
3261
3262 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3263 if (!argptr)
3264 return -TARGET_EFAULT;
3265 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3266 unlock_user(argptr, arg, 0);
3267
3268 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3269 target_ifc_len = host_ifconf->ifc_len;
3270 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3271
3272 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3273 nb_ifreq = target_ifc_len / target_ifreq_size;
3274 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3275
3276 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3277 if (outbufsz > MAX_STRUCT_SIZE) {
3278 /* We can't fit all the extents into the fixed size buffer.
3279 * Allocate one that is large enough and use it instead.
3280 */
3281 host_ifconf = malloc(outbufsz);
3282 if (!host_ifconf) {
3283 return -TARGET_ENOMEM;
3284 }
3285 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3286 free_buf = 1;
3287 }
3288 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3289
3290 host_ifconf->ifc_len = host_ifc_len;
3291 host_ifconf->ifc_buf = host_ifc_buf;
3292
3293 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3294 if (!is_error(ret)) {
3295 /* convert host ifc_len to target ifc_len */
3296
3297 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3298 target_ifc_len = nb_ifreq * target_ifreq_size;
3299 host_ifconf->ifc_len = target_ifc_len;
3300
3301 /* restore target ifc_buf */
3302
3303 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3304
3305 /* copy struct ifconf to target user */
3306
3307 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3308 if (!argptr)
3309 return -TARGET_EFAULT;
3310 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3311 unlock_user(argptr, arg, target_size);
3312
3313 /* copy ifreq[] to target user */
3314
3315 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3316 for (i = 0; i < nb_ifreq ; i++) {
3317 thunk_convert(argptr + i * target_ifreq_size,
3318 host_ifc_buf + i * sizeof(struct ifreq),
3319 ifreq_arg_type, THUNK_TARGET);
3320 }
3321 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3322 }
3323
3324 if (free_buf) {
3325 free(host_ifconf);
3326 }
3327
3328 return ret;
3329}
3330
Alexander Graf56e904e2012-01-31 18:42:06 +01003331static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3332 abi_long cmd, abi_long arg)
3333{
3334 void *argptr;
3335 struct dm_ioctl *host_dm;
3336 abi_long guest_data;
3337 uint32_t guest_data_size;
3338 int target_size;
3339 const argtype *arg_type = ie->arg_type;
3340 abi_long ret;
3341 void *big_buf = NULL;
3342 char *host_data;
3343
3344 arg_type++;
3345 target_size = thunk_type_size(arg_type, 0);
3346 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3347 if (!argptr) {
3348 ret = -TARGET_EFAULT;
3349 goto out;
3350 }
3351 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3352 unlock_user(argptr, arg, 0);
3353
3354 /* buf_temp is too small, so fetch things into a bigger buffer */
3355 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3356 memcpy(big_buf, buf_temp, target_size);
3357 buf_temp = big_buf;
3358 host_dm = big_buf;
3359
3360 guest_data = arg + host_dm->data_start;
3361 if ((guest_data - arg) < 0) {
3362 ret = -EINVAL;
3363 goto out;
3364 }
3365 guest_data_size = host_dm->data_size - host_dm->data_start;
3366 host_data = (char*)host_dm + host_dm->data_start;
3367
3368 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3369 switch (ie->host_cmd) {
3370 case DM_REMOVE_ALL:
3371 case DM_LIST_DEVICES:
3372 case DM_DEV_CREATE:
3373 case DM_DEV_REMOVE:
3374 case DM_DEV_SUSPEND:
3375 case DM_DEV_STATUS:
3376 case DM_DEV_WAIT:
3377 case DM_TABLE_STATUS:
3378 case DM_TABLE_CLEAR:
3379 case DM_TABLE_DEPS:
3380 case DM_LIST_VERSIONS:
3381 /* no input data */
3382 break;
3383 case DM_DEV_RENAME:
3384 case DM_DEV_SET_GEOMETRY:
3385 /* data contains only strings */
3386 memcpy(host_data, argptr, guest_data_size);
3387 break;
3388 case DM_TARGET_MSG:
3389 memcpy(host_data, argptr, guest_data_size);
3390 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3391 break;
3392 case DM_TABLE_LOAD:
3393 {
3394 void *gspec = argptr;
3395 void *cur_data = host_data;
3396 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3397 int spec_size = thunk_type_size(arg_type, 0);
3398 int i;
3399
3400 for (i = 0; i < host_dm->target_count; i++) {
3401 struct dm_target_spec *spec = cur_data;
3402 uint32_t next;
3403 int slen;
3404
3405 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3406 slen = strlen((char*)gspec + spec_size) + 1;
3407 next = spec->next;
3408 spec->next = sizeof(*spec) + slen;
3409 strcpy((char*)&spec[1], gspec + spec_size);
3410 gspec += next;
3411 cur_data += spec->next;
3412 }
3413 break;
3414 }
3415 default:
3416 ret = -TARGET_EINVAL;
3417 goto out;
3418 }
3419 unlock_user(argptr, guest_data, 0);
3420
3421 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3422 if (!is_error(ret)) {
3423 guest_data = arg + host_dm->data_start;
3424 guest_data_size = host_dm->data_size - host_dm->data_start;
3425 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3426 switch (ie->host_cmd) {
3427 case DM_REMOVE_ALL:
3428 case DM_DEV_CREATE:
3429 case DM_DEV_REMOVE:
3430 case DM_DEV_RENAME:
3431 case DM_DEV_SUSPEND:
3432 case DM_DEV_STATUS:
3433 case DM_TABLE_LOAD:
3434 case DM_TABLE_CLEAR:
3435 case DM_TARGET_MSG:
3436 case DM_DEV_SET_GEOMETRY:
3437 /* no return data */
3438 break;
3439 case DM_LIST_DEVICES:
3440 {
3441 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3442 uint32_t remaining_data = guest_data_size;
3443 void *cur_data = argptr;
3444 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3445 int nl_size = 12; /* can't use thunk_size due to alignment */
3446
3447 while (1) {
3448 uint32_t next = nl->next;
3449 if (next) {
3450 nl->next = nl_size + (strlen(nl->name) + 1);
3451 }
3452 if (remaining_data < nl->next) {
3453 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3454 break;
3455 }
3456 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3457 strcpy(cur_data + nl_size, nl->name);
3458 cur_data += nl->next;
3459 remaining_data -= nl->next;
3460 if (!next) {
3461 break;
3462 }
3463 nl = (void*)nl + next;
3464 }
3465 break;
3466 }
3467 case DM_DEV_WAIT:
3468 case DM_TABLE_STATUS:
3469 {
3470 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3471 void *cur_data = argptr;
3472 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3473 int spec_size = thunk_type_size(arg_type, 0);
3474 int i;
3475
3476 for (i = 0; i < host_dm->target_count; i++) {
3477 uint32_t next = spec->next;
3478 int slen = strlen((char*)&spec[1]) + 1;
3479 spec->next = (cur_data - argptr) + spec_size + slen;
3480 if (guest_data_size < spec->next) {
3481 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3482 break;
3483 }
3484 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3485 strcpy(cur_data + spec_size, (char*)&spec[1]);
3486 cur_data = argptr + spec->next;
3487 spec = (void*)host_dm + host_dm->data_start + next;
3488 }
3489 break;
3490 }
3491 case DM_TABLE_DEPS:
3492 {
3493 void *hdata = (void*)host_dm + host_dm->data_start;
3494 int count = *(uint32_t*)hdata;
3495 uint64_t *hdev = hdata + 8;
3496 uint64_t *gdev = argptr + 8;
3497 int i;
3498
3499 *(uint32_t*)argptr = tswap32(count);
3500 for (i = 0; i < count; i++) {
3501 *gdev = tswap64(*hdev);
3502 gdev++;
3503 hdev++;
3504 }
3505 break;
3506 }
3507 case DM_LIST_VERSIONS:
3508 {
3509 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3510 uint32_t remaining_data = guest_data_size;
3511 void *cur_data = argptr;
3512 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3513 int vers_size = thunk_type_size(arg_type, 0);
3514
3515 while (1) {
3516 uint32_t next = vers->next;
3517 if (next) {
3518 vers->next = vers_size + (strlen(vers->name) + 1);
3519 }
3520 if (remaining_data < vers->next) {
3521 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3522 break;
3523 }
3524 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3525 strcpy(cur_data + vers_size, vers->name);
3526 cur_data += vers->next;
3527 remaining_data -= vers->next;
3528 if (!next) {
3529 break;
3530 }
3531 vers = (void*)vers + next;
3532 }
3533 break;
3534 }
3535 default:
3536 ret = -TARGET_EINVAL;
3537 goto out;
3538 }
3539 unlock_user(argptr, guest_data, guest_data_size);
3540
3541 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3542 if (!argptr) {
3543 ret = -TARGET_EFAULT;
3544 goto out;
3545 }
3546 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3547 unlock_user(argptr, arg, target_size);
3548 }
3549out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003550 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003551 return ret;
3552}
3553
blueswir19f106a72008-10-05 10:52:52 +00003554static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003555#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003556 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3557#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3558 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003559#include "ioctls.h"
3560 { 0, 0, },
3561};
3562
pbrook53a59602006-03-25 19:31:22 +00003563/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003564/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003565static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003566{
3567 const IOCTLEntry *ie;
3568 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003569 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003570 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003571 int target_size;
3572 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003573
3574 ie = ioctl_entries;
3575 for(;;) {
3576 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003577 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003578 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003579 }
3580 if (ie->target_cmd == cmd)
3581 break;
3582 ie++;
3583 }
3584 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003585#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003586 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003587#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003588 if (ie->do_ioctl) {
3589 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3590 }
3591
bellard31e31b82003-02-18 22:55:36 +00003592 switch(arg_type[0]) {
3593 case TYPE_NULL:
3594 /* no argument */
3595 ret = get_errno(ioctl(fd, ie->host_cmd));
3596 break;
3597 case TYPE_PTRVOID:
3598 case TYPE_INT:
3599 /* int argment */
3600 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3601 break;
3602 case TYPE_PTR:
3603 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003604 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003605 switch(ie->access) {
3606 case IOC_R:
3607 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3608 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003609 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3610 if (!argptr)
3611 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003612 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3613 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003614 }
3615 break;
3616 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003617 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3618 if (!argptr)
3619 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003620 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3621 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003622 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3623 break;
3624 default:
3625 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003626 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3627 if (!argptr)
3628 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003629 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3630 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003631 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3632 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003633 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3634 if (!argptr)
3635 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003636 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3637 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003638 }
3639 break;
3640 }
3641 break;
3642 default:
j_mayer32407102007-09-26 23:01:49 +00003643 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3644 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003645 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003646 break;
3647 }
3648 return ret;
3649}
3650
blueswir1b39bc502008-10-05 10:51:10 +00003651static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003652 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3653 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3654 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3655 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3656 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3657 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3658 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3659 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3660 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3661 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3662 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3663 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3664 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3665 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3666 { 0, 0, 0, 0 }
3667};
3668
blueswir1b39bc502008-10-05 10:51:10 +00003669static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003670 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3671 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3672 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3673 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3674 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3675 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3676 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3677 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3678 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3679 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3680 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3681 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3682 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3683 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3684 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3685 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3686 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3687 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3688 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3689 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3690 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3691 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3692 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3693 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3694 { 0, 0, 0, 0 }
3695};
3696
blueswir1b39bc502008-10-05 10:51:10 +00003697static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003698 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3699 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3700 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3701 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3702 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3703 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3704 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3705 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3706 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3707 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3708 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3709 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3710 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3711 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3712 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3713 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3714 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3715 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3716 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3717 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3718 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3719 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3720 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3721 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3722 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3723 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3724 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3725 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3726 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3727 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3728 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3729 { 0, 0, 0, 0 }
3730};
3731
blueswir1b39bc502008-10-05 10:51:10 +00003732static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003733 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3734 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3735 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3736 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3737 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3738 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3739 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3740 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3741 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3742 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3743 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3744 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3745 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3746 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3747 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3748 { 0, 0, 0, 0 }
3749};
3750
3751static void target_to_host_termios (void *dst, const void *src)
3752{
3753 struct host_termios *host = dst;
3754 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003755
ths5fafdf22007-09-16 21:08:06 +00003756 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003757 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003758 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003759 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003760 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003761 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003762 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003763 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3764 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003765
Arnaud Patard44607122009-04-21 17:39:08 +03003766 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003767 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3768 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003769 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003770 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003771 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003772 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003773 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003774 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003775 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003776 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3777 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003778 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3779 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3780 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3781 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3782 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003783 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003784}
ths3b46e622007-09-17 08:09:54 +00003785
bellard31e31b82003-02-18 22:55:36 +00003786static void host_to_target_termios (void *dst, const void *src)
3787{
3788 struct target_termios *target = dst;
3789 const struct host_termios *host = src;
3790
ths5fafdf22007-09-16 21:08:06 +00003791 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003792 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003793 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003794 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003795 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003796 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003797 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003798 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3799 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003800
Arnaud Patard44607122009-04-21 17:39:08 +03003801 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003802 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3803 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3804 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3805 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3806 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3807 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3808 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3809 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3810 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3811 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3812 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3813 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3814 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3815 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3816 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3817 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3818 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3819}
3820
blueswir18e853dc2008-10-05 10:49:32 +00003821static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003822 .convert = { host_to_target_termios, target_to_host_termios },
3823 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3824 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3825};
3826
bellard5286db72003-06-05 00:57:30 +00003827static bitmask_transtbl mmap_flags_tbl[] = {
3828 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3829 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3830 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3831 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3832 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3833 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3834 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3835 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3836 { 0, 0, 0, 0 }
3837};
3838
bellard2ab83ea2003-06-15 19:56:46 +00003839#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003840
3841/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003842static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003843
bellard03acab62007-11-11 14:57:14 +00003844static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003845{
3846 int size;
pbrook53a59602006-03-25 19:31:22 +00003847 void *p;
bellard6dbad632003-03-16 18:05:05 +00003848
3849 if (!ldt_table)
3850 return 0;
3851 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3852 if (size > bytecount)
3853 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003854 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3855 if (!p)
bellard03acab62007-11-11 14:57:14 +00003856 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003857 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003858 memcpy(p, ldt_table, size);
3859 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003860 return size;
3861}
3862
3863/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003864static abi_long write_ldt(CPUX86State *env,
3865 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003866{
3867 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003868 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003869 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003870 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003871 uint32_t *lp, entry_1, entry_2;
3872
3873 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003874 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003875 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003876 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003877 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003878 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00003879 ldt_info.limit = tswap32(target_ldt_info->limit);
3880 ldt_info.flags = tswap32(target_ldt_info->flags);
3881 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003882
bellard6dbad632003-03-16 18:05:05 +00003883 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003884 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003885 seg_32bit = ldt_info.flags & 1;
3886 contents = (ldt_info.flags >> 1) & 3;
3887 read_exec_only = (ldt_info.flags >> 3) & 1;
3888 limit_in_pages = (ldt_info.flags >> 4) & 1;
3889 seg_not_present = (ldt_info.flags >> 5) & 1;
3890 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00003891#ifdef TARGET_ABI32
3892 lm = 0;
3893#else
3894 lm = (ldt_info.flags >> 7) & 1;
3895#endif
bellard6dbad632003-03-16 18:05:05 +00003896 if (contents == 3) {
3897 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00003898 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003899 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00003900 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003901 }
3902 /* allocate the LDT */
3903 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00003904 env->ldt.base = target_mmap(0,
3905 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
3906 PROT_READ|PROT_WRITE,
3907 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3908 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00003909 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00003910 memset(g2h(env->ldt.base), 0,
3911 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00003912 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00003913 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00003914 }
3915
3916 /* NOTE: same code as Linux kernel */
3917 /* Allow LDTs to be cleared by the user. */
3918 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3919 if (oldmode ||
3920 (contents == 0 &&
3921 read_exec_only == 1 &&
3922 seg_32bit == 0 &&
3923 limit_in_pages == 0 &&
3924 seg_not_present == 1 &&
3925 useable == 0 )) {
3926 entry_1 = 0;
3927 entry_2 = 0;
3928 goto install;
3929 }
3930 }
ths3b46e622007-09-17 08:09:54 +00003931
bellard6dbad632003-03-16 18:05:05 +00003932 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3933 (ldt_info.limit & 0x0ffff);
3934 entry_2 = (ldt_info.base_addr & 0xff000000) |
3935 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3936 (ldt_info.limit & 0xf0000) |
3937 ((read_exec_only ^ 1) << 9) |
3938 (contents << 10) |
3939 ((seg_not_present ^ 1) << 15) |
3940 (seg_32bit << 22) |
3941 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00003942 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00003943 0x7000;
3944 if (!oldmode)
3945 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00003946
bellard6dbad632003-03-16 18:05:05 +00003947 /* Install the new entry ... */
3948install:
3949 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
3950 lp[0] = tswap32(entry_1);
3951 lp[1] = tswap32(entry_2);
3952 return 0;
3953}
3954
3955/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00003956static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
3957 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003958{
bellard03acab62007-11-11 14:57:14 +00003959 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00003960
bellard6dbad632003-03-16 18:05:05 +00003961 switch (func) {
3962 case 0:
3963 ret = read_ldt(ptr, bytecount);
3964 break;
3965 case 1:
3966 ret = write_ldt(env, ptr, bytecount, 1);
3967 break;
3968 case 0x11:
3969 ret = write_ldt(env, ptr, bytecount, 0);
3970 break;
bellard03acab62007-11-11 14:57:14 +00003971 default:
3972 ret = -TARGET_ENOSYS;
3973 break;
bellard6dbad632003-03-16 18:05:05 +00003974 }
3975 return ret;
3976}
bellard1b6b0292003-03-22 17:31:38 +00003977
blueswir14583f582008-08-24 10:35:55 +00003978#if defined(TARGET_I386) && defined(TARGET_ABI32)
blueswir18fcd3692008-08-17 20:26:25 +00003979static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00003980{
3981 uint64_t *gdt_table = g2h(env->gdt.base);
3982 struct target_modify_ldt_ldt_s ldt_info;
3983 struct target_modify_ldt_ldt_s *target_ldt_info;
3984 int seg_32bit, contents, read_exec_only, limit_in_pages;
3985 int seg_not_present, useable, lm;
3986 uint32_t *lp, entry_1, entry_2;
3987 int i;
3988
3989 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
3990 if (!target_ldt_info)
3991 return -TARGET_EFAULT;
3992 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003993 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00003994 ldt_info.limit = tswap32(target_ldt_info->limit);
3995 ldt_info.flags = tswap32(target_ldt_info->flags);
3996 if (ldt_info.entry_number == -1) {
3997 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
3998 if (gdt_table[i] == 0) {
3999 ldt_info.entry_number = i;
4000 target_ldt_info->entry_number = tswap32(i);
4001 break;
4002 }
4003 }
4004 }
4005 unlock_user_struct(target_ldt_info, ptr, 1);
4006
4007 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4008 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4009 return -TARGET_EINVAL;
4010 seg_32bit = ldt_info.flags & 1;
4011 contents = (ldt_info.flags >> 1) & 3;
4012 read_exec_only = (ldt_info.flags >> 3) & 1;
4013 limit_in_pages = (ldt_info.flags >> 4) & 1;
4014 seg_not_present = (ldt_info.flags >> 5) & 1;
4015 useable = (ldt_info.flags >> 6) & 1;
4016#ifdef TARGET_ABI32
4017 lm = 0;
4018#else
4019 lm = (ldt_info.flags >> 7) & 1;
4020#endif
4021
4022 if (contents == 3) {
4023 if (seg_not_present == 0)
4024 return -TARGET_EINVAL;
4025 }
4026
4027 /* NOTE: same code as Linux kernel */
4028 /* Allow LDTs to be cleared by the user. */
4029 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4030 if ((contents == 0 &&
4031 read_exec_only == 1 &&
4032 seg_32bit == 0 &&
4033 limit_in_pages == 0 &&
4034 seg_not_present == 1 &&
4035 useable == 0 )) {
4036 entry_1 = 0;
4037 entry_2 = 0;
4038 goto install;
4039 }
4040 }
4041
4042 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4043 (ldt_info.limit & 0x0ffff);
4044 entry_2 = (ldt_info.base_addr & 0xff000000) |
4045 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4046 (ldt_info.limit & 0xf0000) |
4047 ((read_exec_only ^ 1) << 9) |
4048 (contents << 10) |
4049 ((seg_not_present ^ 1) << 15) |
4050 (seg_32bit << 22) |
4051 (limit_in_pages << 23) |
4052 (useable << 20) |
4053 (lm << 21) |
4054 0x7000;
4055
4056 /* Install the new entry ... */
4057install:
4058 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4059 lp[0] = tswap32(entry_1);
4060 lp[1] = tswap32(entry_2);
4061 return 0;
4062}
4063
blueswir18fcd3692008-08-17 20:26:25 +00004064static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004065{
4066 struct target_modify_ldt_ldt_s *target_ldt_info;
4067 uint64_t *gdt_table = g2h(env->gdt.base);
4068 uint32_t base_addr, limit, flags;
4069 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4070 int seg_not_present, useable, lm;
4071 uint32_t *lp, entry_1, entry_2;
4072
4073 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4074 if (!target_ldt_info)
4075 return -TARGET_EFAULT;
4076 idx = tswap32(target_ldt_info->entry_number);
4077 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4078 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4079 unlock_user_struct(target_ldt_info, ptr, 1);
4080 return -TARGET_EINVAL;
4081 }
4082 lp = (uint32_t *)(gdt_table + idx);
4083 entry_1 = tswap32(lp[0]);
4084 entry_2 = tswap32(lp[1]);
4085
4086 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4087 contents = (entry_2 >> 10) & 3;
4088 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4089 seg_32bit = (entry_2 >> 22) & 1;
4090 limit_in_pages = (entry_2 >> 23) & 1;
4091 useable = (entry_2 >> 20) & 1;
4092#ifdef TARGET_ABI32
4093 lm = 0;
4094#else
4095 lm = (entry_2 >> 21) & 1;
4096#endif
4097 flags = (seg_32bit << 0) | (contents << 1) |
4098 (read_exec_only << 3) | (limit_in_pages << 4) |
4099 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4100 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4101 base_addr = (entry_1 >> 16) |
4102 (entry_2 & 0xff000000) |
4103 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004104 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004105 target_ldt_info->limit = tswap32(limit);
4106 target_ldt_info->flags = tswap32(flags);
4107 unlock_user_struct(target_ldt_info, ptr, 1);
4108 return 0;
4109}
blueswir14583f582008-08-24 10:35:55 +00004110#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004111
bellardd2fd1af2007-11-14 18:08:56 +00004112#ifndef TARGET_ABI32
blueswir18fcd3692008-08-17 20:26:25 +00004113static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004114{
Juan Quintela1add8692011-06-16 17:37:09 +01004115 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004116 abi_ulong val;
4117 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004118
bellardd2fd1af2007-11-14 18:08:56 +00004119 switch(code) {
4120 case TARGET_ARCH_SET_GS:
4121 case TARGET_ARCH_SET_FS:
4122 if (code == TARGET_ARCH_SET_GS)
4123 idx = R_GS;
4124 else
4125 idx = R_FS;
4126 cpu_x86_load_seg(env, idx, 0);
4127 env->segs[idx].base = addr;
4128 break;
4129 case TARGET_ARCH_GET_GS:
4130 case TARGET_ARCH_GET_FS:
4131 if (code == TARGET_ARCH_GET_GS)
4132 idx = R_GS;
4133 else
4134 idx = R_FS;
4135 val = env->segs[idx].base;
4136 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004137 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004138 break;
4139 default:
4140 ret = -TARGET_EINVAL;
4141 break;
4142 }
Juan Quintela1add8692011-06-16 17:37:09 +01004143 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004144}
4145#endif
4146
bellard2ab83ea2003-06-15 19:56:46 +00004147#endif /* defined(TARGET_I386) */
4148
Riku Voipio05098a92011-03-04 15:27:29 +02004149#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004150
Riku Voipio05098a92011-03-04 15:27:29 +02004151#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004152
4153static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4154typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004155 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004156 pthread_mutex_t mutex;
4157 pthread_cond_t cond;
4158 pthread_t thread;
4159 uint32_t tid;
4160 abi_ulong child_tidptr;
4161 abi_ulong parent_tidptr;
4162 sigset_t sigmask;
4163} new_thread_info;
4164
4165static void *clone_func(void *arg)
4166{
4167 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004168 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004169 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004170 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004171
4172 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004173 cpu = ENV_GET_CPU(env);
pbrookd865bab2008-06-07 22:12:17 +00004174 thread_env = env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004175 ts = (TaskState *)thread_env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004176 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004177 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004178 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004179 if (info->child_tidptr)
4180 put_user_u32(info->tid, info->child_tidptr);
4181 if (info->parent_tidptr)
4182 put_user_u32(info->tid, info->parent_tidptr);
4183 /* Enable signals. */
4184 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4185 /* Signal to the parent that we're ready. */
4186 pthread_mutex_lock(&info->mutex);
4187 pthread_cond_broadcast(&info->cond);
4188 pthread_mutex_unlock(&info->mutex);
4189 /* Wait until the parent has finshed initializing the tls state. */
4190 pthread_mutex_lock(&clone_lock);
4191 pthread_mutex_unlock(&clone_lock);
4192 cpu_loop(env);
4193 /* never exits */
4194 return NULL;
4195}
4196#else
bellard1b6b0292003-03-22 17:31:38 +00004197
4198static int clone_func(void *arg)
4199{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004200 CPUArchState *env = arg;
bellard1b6b0292003-03-22 17:31:38 +00004201 cpu_loop(env);
4202 /* never exits */
4203 return 0;
4204}
pbrookd865bab2008-06-07 22:12:17 +00004205#endif
bellard1b6b0292003-03-22 17:31:38 +00004206
ths0da46a62007-10-20 20:23:07 +00004207/* do_fork() Must return host values and target errnos (unlike most
4208 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004209static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004210 abi_ulong parent_tidptr, target_ulong newtls,
4211 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004212{
4213 int ret;
bellard5cd43932003-03-29 16:54:36 +00004214 TaskState *ts;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004215 CPUArchState *new_env;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004216#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004217 unsigned int nptl_flags;
4218 sigset_t sigmask;
Riku Voipio91907492010-11-26 16:21:34 +02004219#else
4220 uint8_t *new_stack;
pbrookd865bab2008-06-07 22:12:17 +00004221#endif
ths3b46e622007-09-17 08:09:54 +00004222
balrog436d1242008-09-21 02:39:45 +00004223 /* Emulate vfork() with fork() */
4224 if (flags & CLONE_VFORK)
4225 flags &= ~(CLONE_VFORK | CLONE_VM);
4226
bellard1b6b0292003-03-22 17:31:38 +00004227 if (flags & CLONE_VM) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004228 TaskState *parent_ts = (TaskState *)env->opaque;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004229#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004230 new_thread_info info;
4231 pthread_attr_t attr;
pbrookbd0c5662008-05-29 14:34:11 +00004232#endif
Anthony Liguori7267c092011-08-20 22:09:37 -05004233 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004234 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004235 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004236 new_env = cpu_copy(env);
Blue Swirlb4558d72009-11-07 16:34:12 +00004237#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
Andreas Färberff18b762012-05-05 14:47:34 +02004238 cpu_reset(ENV_GET_CPU(new_env));
Blue Swirlb4558d72009-11-07 16:34:12 +00004239#endif
pbrook6e68e072008-05-30 17:22:15 +00004240 /* Init regs that differ from the parent. */
4241 cpu_clone_regs(new_env, newsp);
bellard5cd43932003-03-29 16:54:36 +00004242 new_env->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004243 ts->bprm = parent_ts->bprm;
4244 ts->info = parent_ts->info;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004245#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004246 nptl_flags = flags;
4247 flags &= ~CLONE_NPTL_FLAGS2;
4248
pbrookc2764712009-03-07 15:24:59 +00004249 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4250 ts->child_tidptr = child_tidptr;
4251 }
4252
pbrookd865bab2008-06-07 22:12:17 +00004253 if (nptl_flags & CLONE_SETTLS)
4254 cpu_set_tls (new_env, newtls);
4255
4256 /* Grab a mutex so that thread setup appears atomic. */
4257 pthread_mutex_lock(&clone_lock);
4258
4259 memset(&info, 0, sizeof(info));
4260 pthread_mutex_init(&info.mutex, NULL);
4261 pthread_mutex_lock(&info.mutex);
4262 pthread_cond_init(&info.cond, NULL);
4263 info.env = new_env;
4264 if (nptl_flags & CLONE_CHILD_SETTID)
4265 info.child_tidptr = child_tidptr;
4266 if (nptl_flags & CLONE_PARENT_SETTID)
4267 info.parent_tidptr = parent_tidptr;
4268
4269 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004270 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4271 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004272 /* It is not safe to deliver signals until the child has finished
4273 initializing, so temporarily block all signals. */
4274 sigfillset(&sigmask);
4275 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4276
4277 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004278 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004279
4280 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4281 pthread_attr_destroy(&attr);
4282 if (ret == 0) {
4283 /* Wait for the child to initialize. */
4284 pthread_cond_wait(&info.cond, &info.mutex);
4285 ret = info.tid;
4286 if (flags & CLONE_PARENT_SETTID)
4287 put_user_u32(ret, parent_tidptr);
4288 } else {
4289 ret = -1;
4290 }
4291 pthread_mutex_unlock(&info.mutex);
4292 pthread_cond_destroy(&info.cond);
4293 pthread_mutex_destroy(&info.mutex);
4294 pthread_mutex_unlock(&clone_lock);
4295#else
4296 if (flags & CLONE_NPTL_FLAGS2)
4297 return -EINVAL;
4298 /* This is probably going to die very quickly, but do it anyway. */
Anthony Liguori7267c092011-08-20 22:09:37 -05004299 new_stack = g_malloc0 (NEW_STACK_SIZE);
bellard27725c12003-04-29 21:08:18 +00004300#ifdef __ia64__
Aurelien Jarno60e99242010-03-29 02:12:51 +02004301 ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
bellard27725c12003-04-29 21:08:18 +00004302#else
4303 ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
4304#endif
pbrookd865bab2008-06-07 22:12:17 +00004305#endif
bellard1b6b0292003-03-22 17:31:38 +00004306 } else {
4307 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004308 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004309 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004310 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004311 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004312 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004313 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004314 cpu_clone_regs(env, newsp);
4315 fork_end(1);
Juan Quintela2f7bb872009-07-27 16:13:24 +02004316#if defined(CONFIG_USE_NPTL)
aurel322b1319c2008-12-18 22:44:04 +00004317 /* There is a race condition here. The parent process could
4318 theoretically read the TID in the child process before the child
4319 tid is set. This would require using either ptrace
4320 (not implemented) or having *_tidptr to point at a shared memory
4321 mapping. We can't repeat the spinlock hack used above because
4322 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004323 if (flags & CLONE_CHILD_SETTID)
4324 put_user_u32(gettid(), child_tidptr);
4325 if (flags & CLONE_PARENT_SETTID)
4326 put_user_u32(gettid(), parent_tidptr);
4327 ts = (TaskState *)env->opaque;
4328 if (flags & CLONE_SETTLS)
4329 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004330 if (flags & CLONE_CHILD_CLEARTID)
4331 ts->child_tidptr = child_tidptr;
aurel322b1319c2008-12-18 22:44:04 +00004332#endif
pbrookd865bab2008-06-07 22:12:17 +00004333 } else {
4334 fork_end(0);
4335 }
bellard1b6b0292003-03-22 17:31:38 +00004336 }
4337 return ret;
4338}
4339
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004340/* warning : doesn't handle linux specific flags... */
4341static int target_to_host_fcntl_cmd(int cmd)
4342{
4343 switch(cmd) {
4344 case TARGET_F_DUPFD:
4345 case TARGET_F_GETFD:
4346 case TARGET_F_SETFD:
4347 case TARGET_F_GETFL:
4348 case TARGET_F_SETFL:
4349 return cmd;
4350 case TARGET_F_GETLK:
4351 return F_GETLK;
4352 case TARGET_F_SETLK:
4353 return F_SETLK;
4354 case TARGET_F_SETLKW:
4355 return F_SETLKW;
4356 case TARGET_F_GETOWN:
4357 return F_GETOWN;
4358 case TARGET_F_SETOWN:
4359 return F_SETOWN;
4360 case TARGET_F_GETSIG:
4361 return F_GETSIG;
4362 case TARGET_F_SETSIG:
4363 return F_SETSIG;
4364#if TARGET_ABI_BITS == 32
4365 case TARGET_F_GETLK64:
4366 return F_GETLK64;
4367 case TARGET_F_SETLK64:
4368 return F_SETLK64;
4369 case TARGET_F_SETLKW64:
4370 return F_SETLKW64;
4371#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004372 case TARGET_F_SETLEASE:
4373 return F_SETLEASE;
4374 case TARGET_F_GETLEASE:
4375 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004376#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004377 case TARGET_F_DUPFD_CLOEXEC:
4378 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004379#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004380 case TARGET_F_NOTIFY:
4381 return F_NOTIFY;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004382 default:
4383 return -TARGET_EINVAL;
4384 }
4385 return -TARGET_EINVAL;
4386}
4387
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004388#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4389static const bitmask_transtbl flock_tbl[] = {
4390 TRANSTBL_CONVERT(F_RDLCK),
4391 TRANSTBL_CONVERT(F_WRLCK),
4392 TRANSTBL_CONVERT(F_UNLCK),
4393 TRANSTBL_CONVERT(F_EXLCK),
4394 TRANSTBL_CONVERT(F_SHLCK),
4395 { 0, 0, 0, 0 }
4396};
4397
blueswir1992f48a2007-10-14 16:27:31 +00004398static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004399{
4400 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004401 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004402 struct flock64 fl64;
4403 struct target_flock64 *target_fl64;
blueswir1992f48a2007-10-14 16:27:31 +00004404 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004405 int host_cmd = target_to_host_fcntl_cmd(cmd);
4406
4407 if (host_cmd == -TARGET_EINVAL)
4408 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004409
bellard7775e9e2003-05-14 22:46:48 +00004410 switch(cmd) {
4411 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004412 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4413 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004414 fl.l_type =
4415 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004416 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004417 fl.l_start = tswapal(target_fl->l_start);
4418 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004419 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004420 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004421 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004422 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004423 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4424 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004425 target_fl->l_type =
4426 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004427 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004428 target_fl->l_start = tswapal(fl.l_start);
4429 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004430 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004431 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004432 }
4433 break;
ths3b46e622007-09-17 08:09:54 +00004434
bellard7775e9e2003-05-14 22:46:48 +00004435 case TARGET_F_SETLK:
4436 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004437 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4438 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004439 fl.l_type =
4440 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004441 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004442 fl.l_start = tswapal(target_fl->l_start);
4443 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004444 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004445 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004446 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004447 break;
ths3b46e622007-09-17 08:09:54 +00004448
bellard7775e9e2003-05-14 22:46:48 +00004449 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004450 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4451 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004452 fl64.l_type =
4453 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004454 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004455 fl64.l_start = tswap64(target_fl64->l_start);
4456 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004457 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004458 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004459 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004460 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004461 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4462 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004463 target_fl64->l_type =
4464 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004465 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004466 target_fl64->l_start = tswap64(fl64.l_start);
4467 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004468 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004469 unlock_user_struct(target_fl64, arg, 1);
4470 }
bellard9ee1fa22007-11-11 15:11:19 +00004471 break;
bellard7775e9e2003-05-14 22:46:48 +00004472 case TARGET_F_SETLK64:
4473 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004474 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4475 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004476 fl64.l_type =
4477 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004478 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004479 fl64.l_start = tswap64(target_fl64->l_start);
4480 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004481 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004482 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004483 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004484 break;
4485
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004486 case TARGET_F_GETFL:
4487 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004488 if (ret >= 0) {
4489 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4490 }
bellardffa65c32004-01-04 23:57:22 +00004491 break;
4492
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004493 case TARGET_F_SETFL:
4494 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4495 break;
4496
4497 case TARGET_F_SETOWN:
4498 case TARGET_F_GETOWN:
4499 case TARGET_F_SETSIG:
4500 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004501 case TARGET_F_SETLEASE:
4502 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004503 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004504 break;
4505
bellard7775e9e2003-05-14 22:46:48 +00004506 default:
bellard9ee1fa22007-11-11 15:11:19 +00004507 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004508 break;
4509 }
4510 return ret;
4511}
4512
bellard67867302003-11-23 17:05:30 +00004513#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004514
bellard67867302003-11-23 17:05:30 +00004515static inline int high2lowuid(int uid)
4516{
4517 if (uid > 65535)
4518 return 65534;
4519 else
4520 return uid;
4521}
4522
4523static inline int high2lowgid(int gid)
4524{
4525 if (gid > 65535)
4526 return 65534;
4527 else
4528 return gid;
4529}
4530
4531static inline int low2highuid(int uid)
4532{
4533 if ((int16_t)uid == -1)
4534 return -1;
4535 else
4536 return uid;
4537}
4538
4539static inline int low2highgid(int gid)
4540{
4541 if ((int16_t)gid == -1)
4542 return -1;
4543 else
4544 return gid;
4545}
Riku Voipio0c866a72011-04-18 15:23:06 +03004546static inline int tswapid(int id)
4547{
4548 return tswap16(id);
4549}
4550#else /* !USE_UID16 */
4551static inline int high2lowuid(int uid)
4552{
4553 return uid;
4554}
4555static inline int high2lowgid(int gid)
4556{
4557 return gid;
4558}
4559static inline int low2highuid(int uid)
4560{
4561 return uid;
4562}
4563static inline int low2highgid(int gid)
4564{
4565 return gid;
4566}
4567static inline int tswapid(int id)
4568{
4569 return tswap32(id);
4570}
bellard67867302003-11-23 17:05:30 +00004571#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004572
bellard31e31b82003-02-18 22:55:36 +00004573void syscall_init(void)
4574{
bellard2ab83ea2003-06-15 19:56:46 +00004575 IOCTLEntry *ie;
4576 const argtype *arg_type;
4577 int size;
thsb92c47c2007-11-01 00:07:38 +00004578 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004579
Blue Swirl001faf32009-05-13 17:53:17 +00004580#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004581#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004582#include "syscall_types.h"
4583#undef STRUCT
4584#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004585
Peter Maydelldd6e9572012-07-23 08:07:22 +00004586 /* Build target_to_host_errno_table[] table from
4587 * host_to_target_errno_table[]. */
4588 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4589 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4590 }
4591
bellard2ab83ea2003-06-15 19:56:46 +00004592 /* we patch the ioctl size if necessary. We rely on the fact that
4593 no ioctl has all the bits at '1' in the size field */
4594 ie = ioctl_entries;
4595 while (ie->target_cmd != 0) {
4596 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4597 TARGET_IOC_SIZEMASK) {
4598 arg_type = ie->arg_type;
4599 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004600 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004601 ie->target_cmd);
4602 exit(1);
4603 }
4604 arg_type++;
4605 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004606 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004607 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4608 (size << TARGET_IOC_SIZESHIFT);
4609 }
thsb92c47c2007-11-01 00:07:38 +00004610
bellard2ab83ea2003-06-15 19:56:46 +00004611 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004612#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4613 (defined(__x86_64__) && defined(TARGET_X86_64))
4614 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4615 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4616 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004617 }
4618#endif
4619 ie++;
4620 }
bellard31e31b82003-02-18 22:55:36 +00004621}
bellardc573ff62004-01-04 15:51:36 +00004622
blueswir1992f48a2007-10-14 16:27:31 +00004623#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004624static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4625{
thsaf325d32008-06-10 15:29:15 +00004626#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004627 return ((uint64_t)word0 << 32) | word1;
4628#else
4629 return ((uint64_t)word1 << 32) | word0;
4630#endif
4631}
blueswir1992f48a2007-10-14 16:27:31 +00004632#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004633static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4634{
4635 return word0;
4636}
blueswir1992f48a2007-10-14 16:27:31 +00004637#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004638
4639#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004640static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4641 abi_long arg2,
4642 abi_long arg3,
4643 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004644{
Riku Voipio48e515d2011-07-12 15:40:51 +03004645 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004646 arg2 = arg3;
4647 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004648 }
pbrookce4defa2006-02-09 16:49:55 +00004649 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4650}
4651#endif
4652
4653#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004654static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4655 abi_long arg2,
4656 abi_long arg3,
4657 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004658{
Riku Voipio48e515d2011-07-12 15:40:51 +03004659 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004660 arg2 = arg3;
4661 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004662 }
pbrookce4defa2006-02-09 16:49:55 +00004663 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4664}
4665#endif
4666
bellard579a97f2007-11-11 14:26:47 +00004667static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4668 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004669{
4670 struct target_timespec *target_ts;
4671
bellard579a97f2007-11-11 14:26:47 +00004672 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4673 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004674 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4675 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004676 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004677 return 0;
pbrook53a59602006-03-25 19:31:22 +00004678}
4679
bellard579a97f2007-11-11 14:26:47 +00004680static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4681 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004682{
4683 struct target_timespec *target_ts;
4684
bellard579a97f2007-11-11 14:26:47 +00004685 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4686 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004687 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4688 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004689 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004690 return 0;
pbrook53a59602006-03-25 19:31:22 +00004691}
4692
aurel329d33b762009-04-08 23:07:05 +00004693#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004694static inline abi_long host_to_target_stat64(void *cpu_env,
4695 abi_ulong target_addr,
4696 struct stat *host_st)
4697{
4698#ifdef TARGET_ARM
4699 if (((CPUARMState *)cpu_env)->eabi) {
4700 struct target_eabi_stat64 *target_st;
4701
4702 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4703 return -TARGET_EFAULT;
4704 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4705 __put_user(host_st->st_dev, &target_st->st_dev);
4706 __put_user(host_st->st_ino, &target_st->st_ino);
4707#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4708 __put_user(host_st->st_ino, &target_st->__st_ino);
4709#endif
4710 __put_user(host_st->st_mode, &target_st->st_mode);
4711 __put_user(host_st->st_nlink, &target_st->st_nlink);
4712 __put_user(host_st->st_uid, &target_st->st_uid);
4713 __put_user(host_st->st_gid, &target_st->st_gid);
4714 __put_user(host_st->st_rdev, &target_st->st_rdev);
4715 __put_user(host_st->st_size, &target_st->st_size);
4716 __put_user(host_st->st_blksize, &target_st->st_blksize);
4717 __put_user(host_st->st_blocks, &target_st->st_blocks);
4718 __put_user(host_st->st_atime, &target_st->target_st_atime);
4719 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4720 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4721 unlock_user_struct(target_st, target_addr, 1);
4722 } else
4723#endif
4724 {
Richard Hendersoned18c5c2010-04-26 10:27:22 -07004725#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
aurel329d33b762009-04-08 23:07:05 +00004726 struct target_stat *target_st;
4727#else
balrog6a24a772008-09-20 02:23:36 +00004728 struct target_stat64 *target_st;
aurel329d33b762009-04-08 23:07:05 +00004729#endif
balrog6a24a772008-09-20 02:23:36 +00004730
4731 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4732 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004733 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004734 __put_user(host_st->st_dev, &target_st->st_dev);
4735 __put_user(host_st->st_ino, &target_st->st_ino);
4736#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4737 __put_user(host_st->st_ino, &target_st->__st_ino);
4738#endif
4739 __put_user(host_st->st_mode, &target_st->st_mode);
4740 __put_user(host_st->st_nlink, &target_st->st_nlink);
4741 __put_user(host_st->st_uid, &target_st->st_uid);
4742 __put_user(host_st->st_gid, &target_st->st_gid);
4743 __put_user(host_st->st_rdev, &target_st->st_rdev);
4744 /* XXX: better use of kernel struct */
4745 __put_user(host_st->st_size, &target_st->st_size);
4746 __put_user(host_st->st_blksize, &target_st->st_blksize);
4747 __put_user(host_st->st_blocks, &target_st->st_blocks);
4748 __put_user(host_st->st_atime, &target_st->target_st_atime);
4749 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4750 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4751 unlock_user_struct(target_st, target_addr, 1);
4752 }
4753
4754 return 0;
4755}
4756#endif
4757
Juan Quintela2f7bb872009-07-27 16:13:24 +02004758#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00004759/* ??? Using host futex calls even when target atomic operations
4760 are not really atomic probably breaks things. However implementing
4761 futexes locally would make futexes shared between multiple processes
4762 tricky. However they're probably useless because guest atomic
4763 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004764static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4765 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004766{
4767 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004768 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004769
4770 /* ??? We assume FUTEX_* constants are the same on both host
4771 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004772#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004773 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004774#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004775 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004776#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004777 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004778 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07004779 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00004780 if (timeout) {
4781 pts = &ts;
4782 target_to_host_timespec(pts, timeout);
4783 } else {
4784 pts = NULL;
4785 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004786 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07004787 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00004788 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004789 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004790 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004791 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004792 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004793 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004794 case FUTEX_WAKE_OP:
4795 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4796 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4797 But the prototype takes a `struct timespec *'; insert casts
4798 to satisfy the compiler. We do not need to tswap TIMEOUT
4799 since it's not compared to guest memory. */
4800 pts = (struct timespec *)(uintptr_t) timeout;
4801 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4802 g2h(uaddr2),
4803 (base_op == FUTEX_CMP_REQUEUE
4804 ? tswap32(val3)
4805 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004806 default:
4807 return -TARGET_ENOSYS;
4808 }
4809}
4810#endif
4811
pbrook1d9d8b52009-04-16 15:17:02 +00004812/* Map host to target signal numbers for the wait family of syscalls.
4813 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07004814int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00004815{
4816 if (WIFSIGNALED(status)) {
4817 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4818 }
4819 if (WIFSTOPPED(status)) {
4820 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4821 | (status & 0xff);
4822 }
4823 return status;
4824}
4825
pbrooka745ec62008-05-06 15:36:17 +00004826int get_osversion(void)
4827{
4828 static int osversion;
4829 struct new_utsname buf;
4830 const char *s;
4831 int i, n, tmp;
4832 if (osversion)
4833 return osversion;
4834 if (qemu_uname_release && *qemu_uname_release) {
4835 s = qemu_uname_release;
4836 } else {
4837 if (sys_uname(&buf))
4838 return 0;
4839 s = buf.release;
4840 }
4841 tmp = 0;
4842 for (i = 0; i < 3; i++) {
4843 n = 0;
4844 while (*s >= '0' && *s <= '9') {
4845 n *= 10;
4846 n += *s - '0';
4847 s++;
4848 }
4849 tmp = (tmp << 8) + n;
4850 if (*s == '.')
4851 s++;
4852 }
4853 osversion = tmp;
4854 return osversion;
4855}
4856
Alexander Graf36c08d42011-11-02 20:23:24 +01004857
4858static int open_self_maps(void *cpu_env, int fd)
4859{
Alexander Graf1a49ef22012-05-01 16:30:28 +01004860#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Andreas Färber9349b4f2012-03-14 01:38:32 +01004861 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01004862#endif
4863 FILE *fp;
4864 char *line = NULL;
4865 size_t len = 0;
4866 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01004867
Alexander Graf1a49ef22012-05-01 16:30:28 +01004868 fp = fopen("/proc/self/maps", "r");
4869 if (fp == NULL) {
4870 return -EACCES;
4871 }
4872
4873 while ((read = getline(&line, &len, fp)) != -1) {
4874 int fields, dev_maj, dev_min, inode;
4875 uint64_t min, max, offset;
4876 char flag_r, flag_w, flag_x, flag_p;
4877 char path[512] = "";
4878 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
4879 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
4880 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
4881
4882 if ((fields < 10) || (fields > 11)) {
4883 continue;
4884 }
4885 if (!strncmp(path, "[stack]", 7)) {
4886 continue;
4887 }
4888 if (h2g_valid(min) && h2g_valid(max)) {
4889 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02004890 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Alexander Graf1a49ef22012-05-01 16:30:28 +01004891 h2g(min), h2g(max), flag_r, flag_w,
4892 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02004893 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01004894 }
4895 }
4896
4897 free(line);
4898 fclose(fp);
4899
4900#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Alexander Graf36c08d42011-11-02 20:23:24 +01004901 dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
4902 (unsigned long long)ts->info->stack_limit,
Alexander Graf1bdd7c72012-05-30 14:45:21 +02004903 (unsigned long long)(ts->info->start_stack +
4904 (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK,
Alexander Graf1a49ef22012-05-01 16:30:28 +01004905 (unsigned long long)0);
4906#endif
Alexander Graf36c08d42011-11-02 20:23:24 +01004907
4908 return 0;
4909}
4910
Alexander Graf480b8e72011-11-02 20:23:25 +01004911static int open_self_stat(void *cpu_env, int fd)
4912{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004913 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01004914 abi_ulong start_stack = ts->info->start_stack;
4915 int i;
4916
4917 for (i = 0; i < 44; i++) {
4918 char buf[128];
4919 int len;
4920 uint64_t val = 0;
4921
Fabio Erculianie0e65be2012-01-03 09:38:34 +00004922 if (i == 0) {
4923 /* pid */
4924 val = getpid();
4925 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
4926 } else if (i == 1) {
4927 /* app name */
4928 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
4929 } else if (i == 27) {
4930 /* stack bottom */
4931 val = start_stack;
4932 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
4933 } else {
4934 /* for the rest, there is MasterCard */
4935 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01004936 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00004937
Alexander Graf480b8e72011-11-02 20:23:25 +01004938 len = strlen(buf);
4939 if (write(fd, buf, len) != len) {
4940 return -1;
4941 }
4942 }
4943
4944 return 0;
4945}
4946
Alexander Graf257450e2011-11-02 20:23:26 +01004947static int open_self_auxv(void *cpu_env, int fd)
4948{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004949 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01004950 abi_ulong auxv = ts->info->saved_auxv;
4951 abi_ulong len = ts->info->auxv_len;
4952 char *ptr;
4953
4954 /*
4955 * Auxiliary vector is stored in target process stack.
4956 * read in whole auxv vector and copy it to file
4957 */
4958 ptr = lock_user(VERIFY_READ, auxv, len, 0);
4959 if (ptr != NULL) {
4960 while (len > 0) {
4961 ssize_t r;
4962 r = write(fd, ptr, len);
4963 if (r <= 0) {
4964 break;
4965 }
4966 len -= r;
4967 ptr += r;
4968 }
4969 lseek(fd, 0, SEEK_SET);
4970 unlock_user(ptr, auxv, len);
4971 }
4972
4973 return 0;
4974}
4975
Alexander Graf3be14d02011-11-02 20:23:23 +01004976static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
4977{
4978 struct fake_open {
4979 const char *filename;
4980 int (*fill)(void *cpu_env, int fd);
4981 };
4982 const struct fake_open *fake_open;
4983 static const struct fake_open fakes[] = {
Alexander Graf36c08d42011-11-02 20:23:24 +01004984 { "/proc/self/maps", open_self_maps },
Alexander Graf480b8e72011-11-02 20:23:25 +01004985 { "/proc/self/stat", open_self_stat },
Alexander Graf257450e2011-11-02 20:23:26 +01004986 { "/proc/self/auxv", open_self_auxv },
Alexander Graf3be14d02011-11-02 20:23:23 +01004987 { NULL, NULL }
4988 };
4989
4990 for (fake_open = fakes; fake_open->filename; fake_open++) {
4991 if (!strncmp(pathname, fake_open->filename,
4992 strlen(fake_open->filename))) {
4993 break;
4994 }
4995 }
4996
4997 if (fake_open->filename) {
4998 const char *tmpdir;
4999 char filename[PATH_MAX];
5000 int fd, r;
5001
5002 /* create temporary file to map stat to */
5003 tmpdir = getenv("TMPDIR");
5004 if (!tmpdir)
5005 tmpdir = "/tmp";
5006 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5007 fd = mkstemp(filename);
5008 if (fd < 0) {
5009 return fd;
5010 }
5011 unlink(filename);
5012
5013 if ((r = fake_open->fill(cpu_env, fd))) {
5014 close(fd);
5015 return r;
5016 }
5017 lseek(fd, 0, SEEK_SET);
5018
5019 return fd;
5020 }
5021
5022 return get_errno(open(path(pathname), flags, mode));
5023}
5024
ths0da46a62007-10-20 20:23:07 +00005025/* do_syscall() should always have a single exit point at the end so
5026 that actions, such as logging of syscall results, can be performed.
5027 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005028abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5029 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005030 abi_long arg5, abi_long arg6, abi_long arg7,
5031 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005032{
Andreas Färber182735e2013-05-29 22:29:20 +02005033#ifdef CONFIG_USE_NPTL
5034 CPUState *cpu = ENV_GET_CPU(cpu_env);
5035#endif
blueswir1992f48a2007-10-14 16:27:31 +00005036 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005037 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005038 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005039 void *p;
ths3b46e622007-09-17 08:09:54 +00005040
bellard72f03902003-02-18 23:33:18 +00005041#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005042 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005043#endif
thsb92c47c2007-11-01 00:07:38 +00005044 if(do_strace)
5045 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5046
bellard31e31b82003-02-18 22:55:36 +00005047 switch(num) {
5048 case TARGET_NR_exit:
Juan Quintela2f7bb872009-07-27 16:13:24 +02005049#ifdef CONFIG_USE_NPTL
Andreas Färber9b056fc2013-06-24 23:53:10 +02005050 /* In old applications this may be used to implement _exit(2).
5051 However in threaded applictions it is used for thread termination,
5052 and _exit_group is used for application termination.
5053 Do thread termination if we have more then one thread. */
5054 /* FIXME: This probably breaks if a signal arrives. We should probably
5055 be disabling signals. */
5056 if (first_cpu->next_cpu) {
5057 TaskState *ts;
Andreas Färber182735e2013-05-29 22:29:20 +02005058 CPUState **lastp;
5059 CPUState *p;
pbrookc2764712009-03-07 15:24:59 +00005060
Andreas Färber9b056fc2013-06-24 23:53:10 +02005061 cpu_list_lock();
5062 lastp = &first_cpu;
5063 p = first_cpu;
Andreas Färber182735e2013-05-29 22:29:20 +02005064 while (p && p != cpu) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005065 lastp = &p->next_cpu;
5066 p = p->next_cpu;
5067 }
5068 /* If we didn't find the CPU for this thread then something is
5069 horribly wrong. */
5070 if (!p) {
5071 abort();
5072 }
5073 /* Remove the CPU from the list. */
5074 *lastp = p->next_cpu;
5075 cpu_list_unlock();
5076 ts = ((CPUArchState *)cpu_env)->opaque;
5077 if (ts->child_tidptr) {
5078 put_user_u32(0, ts->child_tidptr);
5079 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5080 NULL, NULL, 0);
5081 }
5082 thread_env = NULL;
5083 object_unref(OBJECT(ENV_GET_CPU(cpu_env)));
5084 g_free(ts);
5085 pthread_exit(NULL);
5086 }
pbrookc2764712009-03-07 15:24:59 +00005087#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +02005088#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005089 _mcleanup();
5090#endif
bellarde9009672005-04-26 20:42:36 +00005091 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005092 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005093 ret = 0; /* avoid warning */
5094 break;
5095 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005096 if (arg3 == 0)
5097 ret = 0;
5098 else {
5099 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5100 goto efault;
5101 ret = get_errno(read(arg1, p, arg3));
5102 unlock_user(p, arg2, ret);
5103 }
bellard31e31b82003-02-18 22:55:36 +00005104 break;
5105 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005106 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5107 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005108 ret = get_errno(write(arg1, p, arg3));
5109 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005110 break;
5111 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005112 if (!(p = lock_user_string(arg1)))
5113 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005114 ret = get_errno(do_open(cpu_env, p,
5115 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5116 arg3));
pbrook53a59602006-03-25 19:31:22 +00005117 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005118 break;
ths82424832007-09-24 09:21:55 +00005119#if defined(TARGET_NR_openat) && defined(__NR_openat)
5120 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005121 if (!(p = lock_user_string(arg2)))
5122 goto efault;
5123 ret = get_errno(sys_openat(arg1,
5124 path(p),
5125 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5126 arg4));
5127 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005128 break;
5129#endif
bellard31e31b82003-02-18 22:55:36 +00005130 case TARGET_NR_close:
5131 ret = get_errno(close(arg1));
5132 break;
5133 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005134 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005135 break;
5136 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005137 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005138 break;
thse5febef2007-04-01 18:31:35 +00005139#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005140 case TARGET_NR_waitpid:
5141 {
pbrook53a59602006-03-25 19:31:22 +00005142 int status;
5143 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005144 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005145 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005146 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005147 }
5148 break;
thse5febef2007-04-01 18:31:35 +00005149#endif
pbrookf0cbb612008-05-30 18:20:05 +00005150#ifdef TARGET_NR_waitid
5151 case TARGET_NR_waitid:
5152 {
5153 siginfo_t info;
5154 info.si_pid = 0;
5155 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5156 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005157 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005158 goto efault;
5159 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005160 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005161 }
5162 }
5163 break;
5164#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005165#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005166 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005167 if (!(p = lock_user_string(arg1)))
5168 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005169 ret = get_errno(creat(p, arg2));
5170 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005171 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005172#endif
bellard31e31b82003-02-18 22:55:36 +00005173 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005174 {
5175 void * p2;
5176 p = lock_user_string(arg1);
5177 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005178 if (!p || !p2)
5179 ret = -TARGET_EFAULT;
5180 else
5181 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005182 unlock_user(p2, arg2, 0);
5183 unlock_user(p, arg1, 0);
5184 }
bellard31e31b82003-02-18 22:55:36 +00005185 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005186#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00005187 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005188 {
5189 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005190 if (!arg2 || !arg4)
5191 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005192 p = lock_user_string(arg2);
5193 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005194 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005195 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005196 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005197 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005198 unlock_user(p, arg2, 0);
5199 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005200 }
5201 break;
5202#endif
bellard31e31b82003-02-18 22:55:36 +00005203 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005204 if (!(p = lock_user_string(arg1)))
5205 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005206 ret = get_errno(unlink(p));
5207 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005208 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005209#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00005210 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005211 if (!(p = lock_user_string(arg2)))
5212 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005213 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005214 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005215 break;
balrogb7d35e62007-12-12 00:40:24 +00005216#endif
bellard31e31b82003-02-18 22:55:36 +00005217 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005218 {
5219 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005220 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005221 abi_ulong gp;
5222 abi_ulong guest_argp;
5223 abi_ulong guest_envp;
5224 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005225 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005226 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005227
bellardf7341ff2003-03-30 21:00:25 +00005228 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005229 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005230 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005231 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005232 goto efault;
ths03aa1972007-12-02 06:28:08 +00005233 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005234 break;
bellard7854b052003-03-29 17:22:23 +00005235 argc++;
bellard2f619692007-11-16 10:46:05 +00005236 }
bellardf7341ff2003-03-30 21:00:25 +00005237 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005238 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005239 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005240 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005241 goto efault;
ths03aa1972007-12-02 06:28:08 +00005242 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005243 break;
bellard7854b052003-03-29 17:22:23 +00005244 envc++;
bellard2f619692007-11-16 10:46:05 +00005245 }
bellard7854b052003-03-29 17:22:23 +00005246
bellardf7341ff2003-03-30 21:00:25 +00005247 argp = alloca((argc + 1) * sizeof(void *));
5248 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005249
pbrookda94d262008-05-30 18:24:00 +00005250 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005251 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005252 if (get_user_ual(addr, gp))
5253 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005254 if (!addr)
5255 break;
bellard2f619692007-11-16 10:46:05 +00005256 if (!(*q = lock_user_string(addr)))
5257 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005258 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005259 }
bellardf7341ff2003-03-30 21:00:25 +00005260 *q = NULL;
5261
pbrookda94d262008-05-30 18:24:00 +00005262 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005263 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005264 if (get_user_ual(addr, gp))
5265 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005266 if (!addr)
5267 break;
bellard2f619692007-11-16 10:46:05 +00005268 if (!(*q = lock_user_string(addr)))
5269 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005270 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005271 }
bellardf7341ff2003-03-30 21:00:25 +00005272 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005273
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005274 /* This case will not be caught by the host's execve() if its
5275 page size is bigger than the target's. */
5276 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5277 ret = -TARGET_E2BIG;
5278 goto execve_end;
5279 }
bellard2f619692007-11-16 10:46:05 +00005280 if (!(p = lock_user_string(arg1)))
5281 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005282 ret = get_errno(execve(p, argp, envp));
5283 unlock_user(p, arg1, 0);
5284
bellard2f619692007-11-16 10:46:05 +00005285 goto execve_end;
5286
5287 execve_efault:
5288 ret = -TARGET_EFAULT;
5289
5290 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005291 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005292 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005293 if (get_user_ual(addr, gp)
5294 || !addr)
5295 break;
pbrook53a59602006-03-25 19:31:22 +00005296 unlock_user(*q, addr, 0);
5297 }
5298 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005299 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005300 if (get_user_ual(addr, gp)
5301 || !addr)
5302 break;
pbrook53a59602006-03-25 19:31:22 +00005303 unlock_user(*q, addr, 0);
5304 }
bellard7854b052003-03-29 17:22:23 +00005305 }
bellard31e31b82003-02-18 22:55:36 +00005306 break;
5307 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005308 if (!(p = lock_user_string(arg1)))
5309 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005310 ret = get_errno(chdir(p));
5311 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005312 break;
bellarda315a142005-01-30 22:59:18 +00005313#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005314 case TARGET_NR_time:
5315 {
pbrook53a59602006-03-25 19:31:22 +00005316 time_t host_time;
5317 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005318 if (!is_error(ret)
5319 && arg1
5320 && put_user_sal(host_time, arg1))
5321 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005322 }
5323 break;
bellarda315a142005-01-30 22:59:18 +00005324#endif
bellard31e31b82003-02-18 22:55:36 +00005325 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005326 if (!(p = lock_user_string(arg1)))
5327 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005328 ret = get_errno(mknod(p, arg2, arg3));
5329 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005330 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005331#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00005332 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005333 if (!(p = lock_user_string(arg2)))
5334 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005335 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00005336 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005337 break;
5338#endif
bellard31e31b82003-02-18 22:55:36 +00005339 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005340 if (!(p = lock_user_string(arg1)))
5341 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005342 ret = get_errno(chmod(p, arg2));
5343 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005344 break;
bellardebc05482003-09-30 21:08:41 +00005345#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005346 case TARGET_NR_break:
5347 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005348#endif
5349#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005350 case TARGET_NR_oldstat:
5351 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005352#endif
bellard31e31b82003-02-18 22:55:36 +00005353 case TARGET_NR_lseek:
5354 ret = get_errno(lseek(arg1, arg2, arg3));
5355 break;
Richard Henderson92317332010-05-03 10:07:53 -07005356#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5357 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005358 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005359 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005360 ret = get_errno(getpid());
5361 break;
Richard Henderson92317332010-05-03 10:07:53 -07005362#endif
5363#ifdef TARGET_NR_getpid
5364 case TARGET_NR_getpid:
5365 ret = get_errno(getpid());
5366 break;
5367#endif
bellard31e31b82003-02-18 22:55:36 +00005368 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00005369 {
5370 /* need to look at the data field */
5371 void *p2, *p3;
5372 p = lock_user_string(arg1);
5373 p2 = lock_user_string(arg2);
5374 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005375 if (!p || !p2 || !p3)
5376 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005377 else {
bellard579a97f2007-11-11 14:26:47 +00005378 /* FIXME - arg5 should be locked, but it isn't clear how to
5379 * do that since it's not guaranteed to be a NULL-terminated
5380 * string.
5381 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005382 if ( ! arg5 )
5383 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
5384 else
5385 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
5386 }
bellard579a97f2007-11-11 14:26:47 +00005387 unlock_user(p, arg1, 0);
5388 unlock_user(p2, arg2, 0);
5389 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00005390 break;
5391 }
thse5febef2007-04-01 18:31:35 +00005392#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005393 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005394 if (!(p = lock_user_string(arg1)))
5395 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005396 ret = get_errno(umount(p));
5397 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005398 break;
thse5febef2007-04-01 18:31:35 +00005399#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005400#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005401 case TARGET_NR_stime:
5402 {
pbrook53a59602006-03-25 19:31:22 +00005403 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005404 if (get_user_sal(host_time, arg1))
5405 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005406 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005407 }
5408 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005409#endif
bellard31e31b82003-02-18 22:55:36 +00005410 case TARGET_NR_ptrace:
5411 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005412#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005413 case TARGET_NR_alarm:
5414 ret = alarm(arg1);
5415 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005416#endif
bellardebc05482003-09-30 21:08:41 +00005417#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005418 case TARGET_NR_oldfstat:
5419 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005420#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005421#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005422 case TARGET_NR_pause:
5423 ret = get_errno(pause());
5424 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005425#endif
thse5febef2007-04-01 18:31:35 +00005426#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005427 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005428 {
pbrook53a59602006-03-25 19:31:22 +00005429 struct utimbuf tbuf, *host_tbuf;
5430 struct target_utimbuf *target_tbuf;
5431 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005432 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5433 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005434 tbuf.actime = tswapal(target_tbuf->actime);
5435 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005436 unlock_user_struct(target_tbuf, arg2, 0);
5437 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005438 } else {
pbrook53a59602006-03-25 19:31:22 +00005439 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005440 }
bellard579a97f2007-11-11 14:26:47 +00005441 if (!(p = lock_user_string(arg1)))
5442 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005443 ret = get_errno(utime(p, host_tbuf));
5444 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005445 }
5446 break;
thse5febef2007-04-01 18:31:35 +00005447#endif
bellard978a66f2004-12-06 22:58:05 +00005448 case TARGET_NR_utimes:
5449 {
bellard978a66f2004-12-06 22:58:05 +00005450 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005451 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005452 if (copy_from_user_timeval(&tv[0], arg2)
5453 || copy_from_user_timeval(&tv[1],
5454 arg2 + sizeof(struct target_timeval)))
5455 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005456 tvp = tv;
5457 } else {
5458 tvp = NULL;
5459 }
bellard579a97f2007-11-11 14:26:47 +00005460 if (!(p = lock_user_string(arg1)))
5461 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005462 ret = get_errno(utimes(p, tvp));
5463 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005464 }
5465 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005466#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00005467 case TARGET_NR_futimesat:
5468 {
5469 struct timeval *tvp, tv[2];
5470 if (arg3) {
5471 if (copy_from_user_timeval(&tv[0], arg3)
5472 || copy_from_user_timeval(&tv[1],
5473 arg3 + sizeof(struct target_timeval)))
5474 goto efault;
5475 tvp = tv;
5476 } else {
5477 tvp = NULL;
5478 }
5479 if (!(p = lock_user_string(arg2)))
5480 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005481 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00005482 unlock_user(p, arg2, 0);
5483 }
5484 break;
5485#endif
bellardebc05482003-09-30 21:08:41 +00005486#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005487 case TARGET_NR_stty:
5488 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005489#endif
5490#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005491 case TARGET_NR_gtty:
5492 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005493#endif
bellard31e31b82003-02-18 22:55:36 +00005494 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005495 if (!(p = lock_user_string(arg1)))
5496 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005497 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005498 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005499 break;
ths92a34c12007-09-24 09:27:49 +00005500#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5501 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005502 if (!(p = lock_user_string(arg2)))
5503 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005504 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00005505 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005506 break;
5507#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005508#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005509 case TARGET_NR_nice:
5510 ret = get_errno(nice(arg1));
5511 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005512#endif
bellardebc05482003-09-30 21:08:41 +00005513#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005514 case TARGET_NR_ftime:
5515 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005516#endif
bellard31e31b82003-02-18 22:55:36 +00005517 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005518 sync();
5519 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005520 break;
5521 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005522 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005523 break;
5524 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005525 {
5526 void *p2;
5527 p = lock_user_string(arg1);
5528 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005529 if (!p || !p2)
5530 ret = -TARGET_EFAULT;
5531 else
5532 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005533 unlock_user(p2, arg2, 0);
5534 unlock_user(p, arg1, 0);
5535 }
bellard31e31b82003-02-18 22:55:36 +00005536 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005537#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00005538 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005539 {
bellard579a97f2007-11-11 14:26:47 +00005540 void *p2;
ths722183f2007-09-24 09:24:37 +00005541 p = lock_user_string(arg2);
5542 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005543 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005544 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005545 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005546 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005547 unlock_user(p2, arg4, 0);
5548 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005549 }
5550 break;
5551#endif
bellard31e31b82003-02-18 22:55:36 +00005552 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005553 if (!(p = lock_user_string(arg1)))
5554 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005555 ret = get_errno(mkdir(p, arg2));
5556 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005557 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005558#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00005559 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005560 if (!(p = lock_user_string(arg2)))
5561 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005562 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005563 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005564 break;
5565#endif
bellard31e31b82003-02-18 22:55:36 +00005566 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005567 if (!(p = lock_user_string(arg1)))
5568 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005569 ret = get_errno(rmdir(p));
5570 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005571 break;
5572 case TARGET_NR_dup:
5573 ret = get_errno(dup(arg1));
5574 break;
5575 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005576 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005577 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005578#ifdef TARGET_NR_pipe2
5579 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07005580 ret = do_pipe(cpu_env, arg1,
5581 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005582 break;
5583#endif
bellard31e31b82003-02-18 22:55:36 +00005584 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005585 {
pbrook53a59602006-03-25 19:31:22 +00005586 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005587 struct tms tms;
5588 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005589 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005590 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5591 if (!tmsp)
5592 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005593 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5594 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5595 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5596 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005597 }
bellardc596ed12003-07-13 17:32:31 +00005598 if (!is_error(ret))
5599 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005600 }
5601 break;
bellardebc05482003-09-30 21:08:41 +00005602#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005603 case TARGET_NR_prof:
5604 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005605#endif
thse5febef2007-04-01 18:31:35 +00005606#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005607 case TARGET_NR_signal:
5608 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005609#endif
bellard31e31b82003-02-18 22:55:36 +00005610 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005611 if (arg1 == 0) {
5612 ret = get_errno(acct(NULL));
5613 } else {
5614 if (!(p = lock_user_string(arg1)))
5615 goto efault;
5616 ret = get_errno(acct(path(p)));
5617 unlock_user(p, arg1, 0);
5618 }
pbrook24836682006-04-16 14:14:53 +00005619 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005620#ifdef TARGET_NR_umount2 /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005621 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005622 if (!(p = lock_user_string(arg1)))
5623 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005624 ret = get_errno(umount2(p, arg2));
5625 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005626 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005627#endif
bellardebc05482003-09-30 21:08:41 +00005628#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005629 case TARGET_NR_lock:
5630 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005631#endif
bellard31e31b82003-02-18 22:55:36 +00005632 case TARGET_NR_ioctl:
5633 ret = do_ioctl(arg1, arg2, arg3);
5634 break;
5635 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005636 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005637 break;
bellardebc05482003-09-30 21:08:41 +00005638#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005639 case TARGET_NR_mpx:
5640 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005641#endif
bellard31e31b82003-02-18 22:55:36 +00005642 case TARGET_NR_setpgid:
5643 ret = get_errno(setpgid(arg1, arg2));
5644 break;
bellardebc05482003-09-30 21:08:41 +00005645#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005646 case TARGET_NR_ulimit:
5647 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005648#endif
5649#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005650 case TARGET_NR_oldolduname:
5651 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005652#endif
bellard31e31b82003-02-18 22:55:36 +00005653 case TARGET_NR_umask:
5654 ret = get_errno(umask(arg1));
5655 break;
5656 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005657 if (!(p = lock_user_string(arg1)))
5658 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005659 ret = get_errno(chroot(p));
5660 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005661 break;
5662 case TARGET_NR_ustat:
5663 goto unimplemented;
5664 case TARGET_NR_dup2:
5665 ret = get_errno(dup2(arg1, arg2));
5666 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005667#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5668 case TARGET_NR_dup3:
5669 ret = get_errno(dup3(arg1, arg2, arg3));
5670 break;
5671#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005672#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005673 case TARGET_NR_getppid:
5674 ret = get_errno(getppid());
5675 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005676#endif
bellard31e31b82003-02-18 22:55:36 +00005677 case TARGET_NR_getpgrp:
5678 ret = get_errno(getpgrp());
5679 break;
5680 case TARGET_NR_setsid:
5681 ret = get_errno(setsid());
5682 break;
thse5febef2007-04-01 18:31:35 +00005683#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005684 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005685 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005686#if defined(TARGET_ALPHA)
5687 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005688 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005689 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005690 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5691 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005692 act._sa_handler = old_act->_sa_handler;
5693 target_siginitset(&act.sa_mask, old_act->sa_mask);
5694 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005695 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005696 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005697 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005698 }
5699 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005700 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005701 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5702 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005703 old_act->_sa_handler = oact._sa_handler;
5704 old_act->sa_mask = oact.sa_mask.sig[0];
5705 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005706 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005707 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005708#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005709 struct target_sigaction act, oact, *pact, *old_act;
5710
5711 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005712 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5713 goto efault;
bellard106ec872006-06-27 21:08:10 +00005714 act._sa_handler = old_act->_sa_handler;
5715 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5716 act.sa_flags = old_act->sa_flags;
5717 unlock_user_struct(old_act, arg2, 0);
5718 pact = &act;
5719 } else {
5720 pact = NULL;
5721 }
5722
5723 ret = get_errno(do_sigaction(arg1, pact, &oact));
5724
5725 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005726 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5727 goto efault;
bellard106ec872006-06-27 21:08:10 +00005728 old_act->_sa_handler = oact._sa_handler;
5729 old_act->sa_flags = oact.sa_flags;
5730 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5731 old_act->sa_mask.sig[1] = 0;
5732 old_act->sa_mask.sig[2] = 0;
5733 old_act->sa_mask.sig[3] = 0;
5734 unlock_user_struct(old_act, arg3, 1);
5735 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005736#else
5737 struct target_old_sigaction *old_act;
5738 struct target_sigaction act, oact, *pact;
5739 if (arg2) {
5740 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5741 goto efault;
5742 act._sa_handler = old_act->_sa_handler;
5743 target_siginitset(&act.sa_mask, old_act->sa_mask);
5744 act.sa_flags = old_act->sa_flags;
5745 act.sa_restorer = old_act->sa_restorer;
5746 unlock_user_struct(old_act, arg2, 0);
5747 pact = &act;
5748 } else {
5749 pact = NULL;
5750 }
5751 ret = get_errno(do_sigaction(arg1, pact, &oact));
5752 if (!is_error(ret) && arg3) {
5753 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5754 goto efault;
5755 old_act->_sa_handler = oact._sa_handler;
5756 old_act->sa_mask = oact.sa_mask.sig[0];
5757 old_act->sa_flags = oact.sa_flags;
5758 old_act->sa_restorer = oact.sa_restorer;
5759 unlock_user_struct(old_act, arg3, 1);
5760 }
ths388bb212007-05-13 13:58:00 +00005761#endif
bellard31e31b82003-02-18 22:55:36 +00005762 }
5763 break;
thse5febef2007-04-01 18:31:35 +00005764#endif
bellard66fb9762003-03-23 01:06:05 +00005765 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005766 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005767#if defined(TARGET_ALPHA)
5768 struct target_sigaction act, oact, *pact = 0;
5769 struct target_rt_sigaction *rt_act;
5770 /* ??? arg4 == sizeof(sigset_t). */
5771 if (arg2) {
5772 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5773 goto efault;
5774 act._sa_handler = rt_act->_sa_handler;
5775 act.sa_mask = rt_act->sa_mask;
5776 act.sa_flags = rt_act->sa_flags;
5777 act.sa_restorer = arg5;
5778 unlock_user_struct(rt_act, arg2, 0);
5779 pact = &act;
5780 }
5781 ret = get_errno(do_sigaction(arg1, pact, &oact));
5782 if (!is_error(ret) && arg3) {
5783 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5784 goto efault;
5785 rt_act->_sa_handler = oact._sa_handler;
5786 rt_act->sa_mask = oact.sa_mask;
5787 rt_act->sa_flags = oact.sa_flags;
5788 unlock_user_struct(rt_act, arg3, 1);
5789 }
5790#else
pbrook53a59602006-03-25 19:31:22 +00005791 struct target_sigaction *act;
5792 struct target_sigaction *oact;
5793
bellard579a97f2007-11-11 14:26:47 +00005794 if (arg2) {
5795 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5796 goto efault;
5797 } else
pbrook53a59602006-03-25 19:31:22 +00005798 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005799 if (arg3) {
5800 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5801 ret = -TARGET_EFAULT;
5802 goto rt_sigaction_fail;
5803 }
5804 } else
pbrook53a59602006-03-25 19:31:22 +00005805 oact = NULL;
5806 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005807 rt_sigaction_fail:
5808 if (act)
pbrook53a59602006-03-25 19:31:22 +00005809 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005810 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005811 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005812#endif
pbrook53a59602006-03-25 19:31:22 +00005813 }
bellard66fb9762003-03-23 01:06:05 +00005814 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005815#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005816 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005817 {
5818 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005819 abi_ulong target_set;
bellard66fb9762003-03-23 01:06:05 +00005820 sigprocmask(0, NULL, &cur_set);
5821 host_to_target_old_sigset(&target_set, &cur_set);
5822 ret = target_set;
5823 }
5824 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005825#endif
5826#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005827 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005828 {
5829 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005830 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00005831 sigprocmask(0, NULL, &cur_set);
5832 target_to_host_old_sigset(&set, &target_set);
5833 sigorset(&set, &set, &cur_set);
5834 sigprocmask(SIG_SETMASK, &set, &oset);
5835 host_to_target_old_sigset(&target_set, &oset);
5836 ret = target_set;
5837 }
5838 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005839#endif
thse5febef2007-04-01 18:31:35 +00005840#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00005841 case TARGET_NR_sigprocmask:
5842 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005843#if defined(TARGET_ALPHA)
5844 sigset_t set, oldset;
5845 abi_ulong mask;
5846 int how;
5847
5848 switch (arg1) {
5849 case TARGET_SIG_BLOCK:
5850 how = SIG_BLOCK;
5851 break;
5852 case TARGET_SIG_UNBLOCK:
5853 how = SIG_UNBLOCK;
5854 break;
5855 case TARGET_SIG_SETMASK:
5856 how = SIG_SETMASK;
5857 break;
5858 default:
5859 ret = -TARGET_EINVAL;
5860 goto fail;
5861 }
5862 mask = arg2;
5863 target_to_host_old_sigset(&set, &mask);
5864
5865 ret = get_errno(sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07005866 if (!is_error(ret)) {
5867 host_to_target_old_sigset(&mask, &oldset);
5868 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07005869 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07005870 }
5871#else
bellard66fb9762003-03-23 01:06:05 +00005872 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07005873 int how;
ths3b46e622007-09-17 08:09:54 +00005874
pbrook53a59602006-03-25 19:31:22 +00005875 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005876 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00005877 case TARGET_SIG_BLOCK:
5878 how = SIG_BLOCK;
5879 break;
5880 case TARGET_SIG_UNBLOCK:
5881 how = SIG_UNBLOCK;
5882 break;
5883 case TARGET_SIG_SETMASK:
5884 how = SIG_SETMASK;
5885 break;
5886 default:
ths0da46a62007-10-20 20:23:07 +00005887 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005888 goto fail;
5889 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005890 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005891 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005892 target_to_host_old_sigset(&set, p);
5893 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005894 set_ptr = &set;
5895 } else {
5896 how = 0;
5897 set_ptr = NULL;
5898 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005899 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005900 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005901 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005902 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005903 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005904 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005905 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005906#endif
bellard66fb9762003-03-23 01:06:05 +00005907 }
5908 break;
thse5febef2007-04-01 18:31:35 +00005909#endif
bellard66fb9762003-03-23 01:06:05 +00005910 case TARGET_NR_rt_sigprocmask:
5911 {
5912 int how = arg1;
5913 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00005914
pbrook53a59602006-03-25 19:31:22 +00005915 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00005916 switch(how) {
5917 case TARGET_SIG_BLOCK:
5918 how = SIG_BLOCK;
5919 break;
5920 case TARGET_SIG_UNBLOCK:
5921 how = SIG_UNBLOCK;
5922 break;
5923 case TARGET_SIG_SETMASK:
5924 how = SIG_SETMASK;
5925 break;
5926 default:
ths0da46a62007-10-20 20:23:07 +00005927 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005928 goto fail;
5929 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005930 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005931 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005932 target_to_host_sigset(&set, p);
5933 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005934 set_ptr = &set;
5935 } else {
5936 how = 0;
5937 set_ptr = NULL;
5938 }
5939 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005940 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005941 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005942 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005943 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005944 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005945 }
5946 }
5947 break;
thse5febef2007-04-01 18:31:35 +00005948#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00005949 case TARGET_NR_sigpending:
5950 {
5951 sigset_t set;
5952 ret = get_errno(sigpending(&set));
5953 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005954 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005955 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005956 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005957 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005958 }
5959 }
5960 break;
thse5febef2007-04-01 18:31:35 +00005961#endif
bellard66fb9762003-03-23 01:06:05 +00005962 case TARGET_NR_rt_sigpending:
5963 {
5964 sigset_t set;
5965 ret = get_errno(sigpending(&set));
5966 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005967 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005968 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005969 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005970 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005971 }
5972 }
5973 break;
thse5febef2007-04-01 18:31:35 +00005974#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00005975 case TARGET_NR_sigsuspend:
5976 {
5977 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07005978#if defined(TARGET_ALPHA)
5979 abi_ulong mask = arg1;
5980 target_to_host_old_sigset(&set, &mask);
5981#else
Anthony Liguoric227f092009-10-01 16:12:16 -05005982 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005983 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005984 target_to_host_old_sigset(&set, p);
5985 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07005986#endif
bellard66fb9762003-03-23 01:06:05 +00005987 ret = get_errno(sigsuspend(&set));
5988 }
5989 break;
thse5febef2007-04-01 18:31:35 +00005990#endif
bellard66fb9762003-03-23 01:06:05 +00005991 case TARGET_NR_rt_sigsuspend:
5992 {
5993 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005994 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005995 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005996 target_to_host_sigset(&set, p);
5997 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005998 ret = get_errno(sigsuspend(&set));
5999 }
6000 break;
6001 case TARGET_NR_rt_sigtimedwait:
6002 {
bellard66fb9762003-03-23 01:06:05 +00006003 sigset_t set;
6004 struct timespec uts, *puts;
6005 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006006
Anthony Liguoric227f092009-10-01 16:12:16 -05006007 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006008 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006009 target_to_host_sigset(&set, p);
6010 unlock_user(p, arg1, 0);
6011 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006012 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006013 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006014 } else {
6015 puts = NULL;
6016 }
6017 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
pbrook53a59602006-03-25 19:31:22 +00006018 if (!is_error(ret) && arg2) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006019 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006020 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006021 host_to_target_siginfo(p, &uinfo);
Anthony Liguoric227f092009-10-01 16:12:16 -05006022 unlock_user(p, arg2, sizeof(target_siginfo_t));
bellard66fb9762003-03-23 01:06:05 +00006023 }
6024 }
6025 break;
6026 case TARGET_NR_rt_sigqueueinfo:
6027 {
6028 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006029 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006030 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006031 target_to_host_siginfo(&uinfo, p);
6032 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006033 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6034 }
6035 break;
thse5febef2007-04-01 18:31:35 +00006036#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006037 case TARGET_NR_sigreturn:
6038 /* NOTE: ret is eax, so not transcoding must be done */
6039 ret = do_sigreturn(cpu_env);
6040 break;
thse5febef2007-04-01 18:31:35 +00006041#endif
bellard66fb9762003-03-23 01:06:05 +00006042 case TARGET_NR_rt_sigreturn:
6043 /* NOTE: ret is eax, so not transcoding must be done */
6044 ret = do_rt_sigreturn(cpu_env);
6045 break;
bellard31e31b82003-02-18 22:55:36 +00006046 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006047 if (!(p = lock_user_string(arg1)))
6048 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006049 ret = get_errno(sethostname(p, arg2));
6050 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006051 break;
6052 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006053 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006054 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006055 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006056 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006057 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6058 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006059 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6060 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006061 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006062 ret = get_errno(setrlimit(resource, &rlim));
6063 }
6064 break;
bellard31e31b82003-02-18 22:55:36 +00006065 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006066 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006067 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006068 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006069 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006070
bellard9de5e442003-03-23 16:49:39 +00006071 ret = get_errno(getrlimit(resource, &rlim));
6072 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006073 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6074 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006075 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6076 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006077 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006078 }
6079 }
6080 break;
bellard31e31b82003-02-18 22:55:36 +00006081 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006082 {
6083 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006084 ret = get_errno(getrusage(arg1, &rusage));
6085 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006086 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006087 }
6088 }
6089 break;
bellard31e31b82003-02-18 22:55:36 +00006090 case TARGET_NR_gettimeofday:
6091 {
bellard31e31b82003-02-18 22:55:36 +00006092 struct timeval tv;
6093 ret = get_errno(gettimeofday(&tv, NULL));
6094 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006095 if (copy_to_user_timeval(arg1, &tv))
6096 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006097 }
6098 }
6099 break;
6100 case TARGET_NR_settimeofday:
6101 {
bellard31e31b82003-02-18 22:55:36 +00006102 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00006103 if (copy_from_user_timeval(&tv, arg1))
6104 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006105 ret = get_errno(settimeofday(&tv, NULL));
6106 }
6107 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006108#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006109 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006110#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6111 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6112#else
bellardf2674e32003-07-09 12:26:09 +00006113 {
pbrook53a59602006-03-25 19:31:22 +00006114 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006115 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006116 long nsel;
6117
bellard579a97f2007-11-11 14:26:47 +00006118 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6119 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006120 nsel = tswapal(sel->n);
6121 inp = tswapal(sel->inp);
6122 outp = tswapal(sel->outp);
6123 exp = tswapal(sel->exp);
6124 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006125 unlock_user_struct(sel, arg1, 0);
6126 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006127 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006128#endif
bellardf2674e32003-07-09 12:26:09 +00006129 break;
bellard048f6b42005-11-26 18:47:20 +00006130#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006131#ifdef TARGET_NR_pselect6
6132 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006133 {
6134 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6135 fd_set rfds, wfds, efds;
6136 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6137 struct timespec ts, *ts_ptr;
6138
6139 /*
6140 * The 6th arg is actually two args smashed together,
6141 * so we cannot use the C library.
6142 */
6143 sigset_t set;
6144 struct {
6145 sigset_t *set;
6146 size_t size;
6147 } sig, *sig_ptr;
6148
6149 abi_ulong arg_sigset, arg_sigsize, *arg7;
6150 target_sigset_t *target_sigset;
6151
6152 n = arg1;
6153 rfd_addr = arg2;
6154 wfd_addr = arg3;
6155 efd_addr = arg4;
6156 ts_addr = arg5;
6157
6158 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6159 if (ret) {
6160 goto fail;
6161 }
6162 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6163 if (ret) {
6164 goto fail;
6165 }
6166 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6167 if (ret) {
6168 goto fail;
6169 }
6170
6171 /*
6172 * This takes a timespec, and not a timeval, so we cannot
6173 * use the do_select() helper ...
6174 */
6175 if (ts_addr) {
6176 if (target_to_host_timespec(&ts, ts_addr)) {
6177 goto efault;
6178 }
6179 ts_ptr = &ts;
6180 } else {
6181 ts_ptr = NULL;
6182 }
6183
6184 /* Extract the two packed args for the sigset */
6185 if (arg6) {
6186 sig_ptr = &sig;
6187 sig.size = _NSIG / 8;
6188
6189 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6190 if (!arg7) {
6191 goto efault;
6192 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006193 arg_sigset = tswapal(arg7[0]);
6194 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006195 unlock_user(arg7, arg6, 0);
6196
6197 if (arg_sigset) {
6198 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006199 if (arg_sigsize != sizeof(*target_sigset)) {
6200 /* Like the kernel, we enforce correct size sigsets */
6201 ret = -TARGET_EINVAL;
6202 goto fail;
6203 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006204 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6205 sizeof(*target_sigset), 1);
6206 if (!target_sigset) {
6207 goto efault;
6208 }
6209 target_to_host_sigset(&set, target_sigset);
6210 unlock_user(target_sigset, arg_sigset, 0);
6211 } else {
6212 sig.set = NULL;
6213 }
6214 } else {
6215 sig_ptr = NULL;
6216 }
6217
6218 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6219 ts_ptr, sig_ptr));
6220
6221 if (!is_error(ret)) {
6222 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6223 goto efault;
6224 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6225 goto efault;
6226 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6227 goto efault;
6228
6229 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6230 goto efault;
6231 }
6232 }
6233 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006234#endif
bellard31e31b82003-02-18 22:55:36 +00006235 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006236 {
6237 void *p2;
6238 p = lock_user_string(arg1);
6239 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006240 if (!p || !p2)
6241 ret = -TARGET_EFAULT;
6242 else
6243 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006244 unlock_user(p2, arg2, 0);
6245 unlock_user(p, arg1, 0);
6246 }
bellard31e31b82003-02-18 22:55:36 +00006247 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006248#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00006249 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006250 {
bellard579a97f2007-11-11 14:26:47 +00006251 void *p2;
thsf0b62432007-09-24 09:25:40 +00006252 p = lock_user_string(arg1);
6253 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006254 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006255 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006256 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006257 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006258 unlock_user(p2, arg3, 0);
6259 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006260 }
6261 break;
6262#endif
bellardebc05482003-09-30 21:08:41 +00006263#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006264 case TARGET_NR_oldlstat:
6265 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006266#endif
bellard31e31b82003-02-18 22:55:36 +00006267 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006268 {
aurel32d088d662009-01-30 20:09:01 +00006269 void *p2, *temp;
pbrook53a59602006-03-25 19:31:22 +00006270 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006271 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
6272 if (!p || !p2)
6273 ret = -TARGET_EFAULT;
aurel32d088d662009-01-30 20:09:01 +00006274 else {
6275 if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
6276 char real[PATH_MAX];
6277 temp = realpath(exec_path,real);
6278 ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
6279 snprintf((char *)p2, arg3, "%s", real);
6280 }
6281 else
6282 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006283 }
pbrook53a59602006-03-25 19:31:22 +00006284 unlock_user(p2, arg2, ret);
6285 unlock_user(p, arg1, 0);
6286 }
bellard31e31b82003-02-18 22:55:36 +00006287 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006288#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00006289 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006290 {
bellard579a97f2007-11-11 14:26:47 +00006291 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006292 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006293 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
6294 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006295 ret = -TARGET_EFAULT;
ths5e0ccb12007-09-24 09:26:10 +00006296 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006297 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
bellard579a97f2007-11-11 14:26:47 +00006298 unlock_user(p2, arg3, ret);
6299 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006300 }
6301 break;
6302#endif
thse5febef2007-04-01 18:31:35 +00006303#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006304 case TARGET_NR_uselib:
6305 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006306#endif
6307#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006308 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006309 if (!(p = lock_user_string(arg1)))
6310 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006311 ret = get_errno(swapon(p, arg2));
6312 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006313 break;
thse5febef2007-04-01 18:31:35 +00006314#endif
bellard31e31b82003-02-18 22:55:36 +00006315 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006316 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6317 /* arg4 must be ignored in all other cases */
6318 p = lock_user_string(arg4);
6319 if (!p) {
6320 goto efault;
6321 }
6322 ret = get_errno(reboot(arg1, arg2, arg3, p));
6323 unlock_user(p, arg4, 0);
6324 } else {
6325 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6326 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006327 break;
thse5febef2007-04-01 18:31:35 +00006328#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006329 case TARGET_NR_readdir:
6330 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006331#endif
6332#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006333 case TARGET_NR_mmap:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006334#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
6335 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6336 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006337 {
blueswir1992f48a2007-10-14 16:27:31 +00006338 abi_ulong *v;
6339 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006340 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6341 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006342 v1 = tswapal(v[0]);
6343 v2 = tswapal(v[1]);
6344 v3 = tswapal(v[2]);
6345 v4 = tswapal(v[3]);
6346 v5 = tswapal(v[4]);
6347 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006348 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006349 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006350 target_to_host_bitmask(v4, mmap_flags_tbl),
6351 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006352 }
bellard31e31b82003-02-18 22:55:36 +00006353#else
ths5fafdf22007-09-16 21:08:06 +00006354 ret = get_errno(target_mmap(arg1, arg2, arg3,
6355 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006356 arg5,
6357 arg6));
bellard31e31b82003-02-18 22:55:36 +00006358#endif
bellard6fb883e2003-07-09 17:12:39 +00006359 break;
thse5febef2007-04-01 18:31:35 +00006360#endif
bellarda315a142005-01-30 22:59:18 +00006361#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006362 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006363#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006364#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006365#endif
ths5fafdf22007-09-16 21:08:06 +00006366 ret = get_errno(target_mmap(arg1, arg2, arg3,
6367 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006368 arg5,
bellardc573ff62004-01-04 15:51:36 +00006369 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006370 break;
bellarda315a142005-01-30 22:59:18 +00006371#endif
bellard31e31b82003-02-18 22:55:36 +00006372 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006373 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006374 break;
bellard9de5e442003-03-23 16:49:39 +00006375 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006376 {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006377 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006378 /* Special hack to detect libc making the stack executable. */
6379 if ((arg3 & PROT_GROWSDOWN)
6380 && arg1 >= ts->info->stack_limit
6381 && arg1 <= ts->info->start_stack) {
6382 arg3 &= ~PROT_GROWSDOWN;
6383 arg2 = arg2 + arg1 - ts->info->stack_limit;
6384 arg1 = ts->info->stack_limit;
6385 }
6386 }
bellard54936002003-05-13 00:25:15 +00006387 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006388 break;
thse5febef2007-04-01 18:31:35 +00006389#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006390 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006391 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006392 break;
thse5febef2007-04-01 18:31:35 +00006393#endif
pbrook53a59602006-03-25 19:31:22 +00006394 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006395#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006396 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006397 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006398 break;
thse5febef2007-04-01 18:31:35 +00006399#endif
6400#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006401 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006402 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006403 break;
thse5febef2007-04-01 18:31:35 +00006404#endif
6405#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006406 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006407 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006408 break;
thse5febef2007-04-01 18:31:35 +00006409#endif
6410#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006411 case TARGET_NR_mlockall:
6412 ret = get_errno(mlockall(arg1));
6413 break;
thse5febef2007-04-01 18:31:35 +00006414#endif
6415#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006416 case TARGET_NR_munlockall:
6417 ret = get_errno(munlockall());
6418 break;
thse5febef2007-04-01 18:31:35 +00006419#endif
bellard31e31b82003-02-18 22:55:36 +00006420 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006421 if (!(p = lock_user_string(arg1)))
6422 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006423 ret = get_errno(truncate(p, arg2));
6424 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006425 break;
6426 case TARGET_NR_ftruncate:
6427 ret = get_errno(ftruncate(arg1, arg2));
6428 break;
6429 case TARGET_NR_fchmod:
6430 ret = get_errno(fchmod(arg1, arg2));
6431 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006432#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00006433 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006434 if (!(p = lock_user_string(arg2)))
6435 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006436 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006437 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006438 break;
6439#endif
bellard31e31b82003-02-18 22:55:36 +00006440 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006441 /* Note that negative values are valid for getpriority, so we must
6442 differentiate based on errno settings. */
6443 errno = 0;
6444 ret = getpriority(arg1, arg2);
6445 if (ret == -1 && errno != 0) {
6446 ret = -host_to_target_errno(errno);
6447 break;
6448 }
6449#ifdef TARGET_ALPHA
6450 /* Return value is the unbiased priority. Signal no error. */
6451 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6452#else
6453 /* Return value is a biased priority to avoid negative numbers. */
6454 ret = 20 - ret;
6455#endif
bellard31e31b82003-02-18 22:55:36 +00006456 break;
6457 case TARGET_NR_setpriority:
6458 ret = get_errno(setpriority(arg1, arg2, arg3));
6459 break;
bellardebc05482003-09-30 21:08:41 +00006460#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006461 case TARGET_NR_profil:
6462 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006463#endif
bellard31e31b82003-02-18 22:55:36 +00006464 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006465 if (!(p = lock_user_string(arg1)))
6466 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006467 ret = get_errno(statfs(path(p), &stfs));
6468 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006469 convert_statfs:
6470 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006471 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006472
bellard579a97f2007-11-11 14:26:47 +00006473 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6474 goto efault;
6475 __put_user(stfs.f_type, &target_stfs->f_type);
6476 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6477 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6478 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6479 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6480 __put_user(stfs.f_files, &target_stfs->f_files);
6481 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6482 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6483 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6484 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006485 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6486 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006487 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006488 }
6489 break;
6490 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006491 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006492 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006493#ifdef TARGET_NR_statfs64
6494 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006495 if (!(p = lock_user_string(arg1)))
6496 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006497 ret = get_errno(statfs(path(p), &stfs));
6498 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006499 convert_statfs64:
6500 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006501 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006502
bellard579a97f2007-11-11 14:26:47 +00006503 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6504 goto efault;
6505 __put_user(stfs.f_type, &target_stfs->f_type);
6506 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6507 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6508 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6509 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6510 __put_user(stfs.f_files, &target_stfs->f_files);
6511 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6512 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6513 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6514 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006515 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6516 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00006517 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006518 }
6519 break;
6520 case TARGET_NR_fstatfs64:
6521 ret = get_errno(fstatfs(arg1, &stfs));
6522 goto convert_statfs64;
6523#endif
bellardebc05482003-09-30 21:08:41 +00006524#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006525 case TARGET_NR_ioperm:
6526 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006527#endif
thse5febef2007-04-01 18:31:35 +00006528#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006529 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006530 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006531 break;
thse5febef2007-04-01 18:31:35 +00006532#endif
bellard3532fa72006-06-24 15:06:03 +00006533#ifdef TARGET_NR_accept
6534 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00006535 ret = do_accept4(arg1, arg2, arg3, 0);
6536 break;
6537#endif
6538#ifdef TARGET_NR_accept4
6539 case TARGET_NR_accept4:
6540#ifdef CONFIG_ACCEPT4
6541 ret = do_accept4(arg1, arg2, arg3, arg4);
6542#else
6543 goto unimplemented;
6544#endif
bellard3532fa72006-06-24 15:06:03 +00006545 break;
6546#endif
6547#ifdef TARGET_NR_bind
6548 case TARGET_NR_bind:
6549 ret = do_bind(arg1, arg2, arg3);
6550 break;
6551#endif
6552#ifdef TARGET_NR_connect
6553 case TARGET_NR_connect:
6554 ret = do_connect(arg1, arg2, arg3);
6555 break;
6556#endif
6557#ifdef TARGET_NR_getpeername
6558 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006559 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006560 break;
6561#endif
6562#ifdef TARGET_NR_getsockname
6563 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006564 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006565 break;
6566#endif
6567#ifdef TARGET_NR_getsockopt
6568 case TARGET_NR_getsockopt:
6569 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6570 break;
6571#endif
6572#ifdef TARGET_NR_listen
6573 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006574 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006575 break;
6576#endif
6577#ifdef TARGET_NR_recv
6578 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006579 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006580 break;
6581#endif
6582#ifdef TARGET_NR_recvfrom
6583 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006584 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006585 break;
6586#endif
6587#ifdef TARGET_NR_recvmsg
6588 case TARGET_NR_recvmsg:
6589 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6590 break;
6591#endif
6592#ifdef TARGET_NR_send
6593 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006594 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006595 break;
6596#endif
6597#ifdef TARGET_NR_sendmsg
6598 case TARGET_NR_sendmsg:
6599 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6600 break;
6601#endif
6602#ifdef TARGET_NR_sendto
6603 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006604 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006605 break;
6606#endif
6607#ifdef TARGET_NR_shutdown
6608 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006609 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006610 break;
6611#endif
6612#ifdef TARGET_NR_socket
6613 case TARGET_NR_socket:
6614 ret = do_socket(arg1, arg2, arg3);
6615 break;
6616#endif
6617#ifdef TARGET_NR_socketpair
6618 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006619 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006620 break;
6621#endif
6622#ifdef TARGET_NR_setsockopt
6623 case TARGET_NR_setsockopt:
6624 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6625 break;
6626#endif
ths7494b0f2007-02-11 18:26:53 +00006627
bellard31e31b82003-02-18 22:55:36 +00006628 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006629 if (!(p = lock_user_string(arg2)))
6630 goto efault;
thse5574482007-02-11 20:03:13 +00006631 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6632 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006633 break;
6634
bellard31e31b82003-02-18 22:55:36 +00006635 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006636 {
bellard66fb9762003-03-23 01:06:05 +00006637 struct itimerval value, ovalue, *pvalue;
6638
pbrook53a59602006-03-25 19:31:22 +00006639 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006640 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006641 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6642 || copy_from_user_timeval(&pvalue->it_value,
6643 arg2 + sizeof(struct target_timeval)))
6644 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006645 } else {
6646 pvalue = NULL;
6647 }
6648 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006649 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006650 if (copy_to_user_timeval(arg3,
6651 &ovalue.it_interval)
6652 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6653 &ovalue.it_value))
6654 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006655 }
6656 }
6657 break;
bellard31e31b82003-02-18 22:55:36 +00006658 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006659 {
bellard66fb9762003-03-23 01:06:05 +00006660 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006661
bellard66fb9762003-03-23 01:06:05 +00006662 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006663 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006664 if (copy_to_user_timeval(arg2,
6665 &value.it_interval)
6666 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6667 &value.it_value))
6668 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006669 }
6670 }
6671 break;
bellard31e31b82003-02-18 22:55:36 +00006672 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006673 if (!(p = lock_user_string(arg1)))
6674 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006675 ret = get_errno(stat(path(p), &st));
6676 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006677 goto do_stat;
6678 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006679 if (!(p = lock_user_string(arg1)))
6680 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006681 ret = get_errno(lstat(path(p), &st));
6682 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006683 goto do_stat;
6684 case TARGET_NR_fstat:
6685 {
6686 ret = get_errno(fstat(arg1, &st));
6687 do_stat:
6688 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006689 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006690
bellard579a97f2007-11-11 14:26:47 +00006691 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6692 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006693 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006694 __put_user(st.st_dev, &target_st->st_dev);
6695 __put_user(st.st_ino, &target_st->st_ino);
6696 __put_user(st.st_mode, &target_st->st_mode);
6697 __put_user(st.st_uid, &target_st->st_uid);
6698 __put_user(st.st_gid, &target_st->st_gid);
6699 __put_user(st.st_nlink, &target_st->st_nlink);
6700 __put_user(st.st_rdev, &target_st->st_rdev);
6701 __put_user(st.st_size, &target_st->st_size);
6702 __put_user(st.st_blksize, &target_st->st_blksize);
6703 __put_user(st.st_blocks, &target_st->st_blocks);
6704 __put_user(st.st_atime, &target_st->target_st_atime);
6705 __put_user(st.st_mtime, &target_st->target_st_mtime);
6706 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006707 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006708 }
6709 }
6710 break;
bellardebc05482003-09-30 21:08:41 +00006711#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006712 case TARGET_NR_olduname:
6713 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006714#endif
6715#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006716 case TARGET_NR_iopl:
6717 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006718#endif
bellard31e31b82003-02-18 22:55:36 +00006719 case TARGET_NR_vhangup:
6720 ret = get_errno(vhangup());
6721 break;
bellardebc05482003-09-30 21:08:41 +00006722#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006723 case TARGET_NR_idle:
6724 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006725#endif
bellard42ad6ae2005-01-03 22:48:11 +00006726#ifdef TARGET_NR_syscall
6727 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006728 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6729 arg6, arg7, arg8, 0);
6730 break;
bellard42ad6ae2005-01-03 22:48:11 +00006731#endif
bellard31e31b82003-02-18 22:55:36 +00006732 case TARGET_NR_wait4:
6733 {
6734 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006735 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006736 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006737 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00006738 if (target_rusage)
6739 rusage_ptr = &rusage;
6740 else
6741 rusage_ptr = NULL;
6742 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6743 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01006744 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00006745 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006746 if (put_user_s32(status, status_ptr))
6747 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006748 }
bellard2f619692007-11-16 10:46:05 +00006749 if (target_rusage)
6750 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00006751 }
6752 }
6753 break;
thse5febef2007-04-01 18:31:35 +00006754#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006755 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006756 if (!(p = lock_user_string(arg1)))
6757 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006758 ret = get_errno(swapoff(p));
6759 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006760 break;
thse5febef2007-04-01 18:31:35 +00006761#endif
bellard31e31b82003-02-18 22:55:36 +00006762 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006763 {
pbrook53a59602006-03-25 19:31:22 +00006764 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006765 struct sysinfo value;
6766 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006767 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006768 {
bellard579a97f2007-11-11 14:26:47 +00006769 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6770 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006771 __put_user(value.uptime, &target_value->uptime);
6772 __put_user(value.loads[0], &target_value->loads[0]);
6773 __put_user(value.loads[1], &target_value->loads[1]);
6774 __put_user(value.loads[2], &target_value->loads[2]);
6775 __put_user(value.totalram, &target_value->totalram);
6776 __put_user(value.freeram, &target_value->freeram);
6777 __put_user(value.sharedram, &target_value->sharedram);
6778 __put_user(value.bufferram, &target_value->bufferram);
6779 __put_user(value.totalswap, &target_value->totalswap);
6780 __put_user(value.freeswap, &target_value->freeswap);
6781 __put_user(value.procs, &target_value->procs);
6782 __put_user(value.totalhigh, &target_value->totalhigh);
6783 __put_user(value.freehigh, &target_value->freehigh);
6784 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006785 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006786 }
6787 }
6788 break;
thse5febef2007-04-01 18:31:35 +00006789#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006790 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006791 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6792 break;
thse5febef2007-04-01 18:31:35 +00006793#endif
aurel32e5289082009-04-18 16:16:12 +00006794#ifdef TARGET_NR_semget
6795 case TARGET_NR_semget:
6796 ret = get_errno(semget(arg1, arg2, arg3));
6797 break;
6798#endif
6799#ifdef TARGET_NR_semop
6800 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00006801 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00006802 break;
6803#endif
6804#ifdef TARGET_NR_semctl
6805 case TARGET_NR_semctl:
6806 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6807 break;
6808#endif
aurel32eeb438c2008-10-13 21:08:55 +00006809#ifdef TARGET_NR_msgctl
6810 case TARGET_NR_msgctl:
6811 ret = do_msgctl(arg1, arg2, arg3);
6812 break;
6813#endif
6814#ifdef TARGET_NR_msgget
6815 case TARGET_NR_msgget:
6816 ret = get_errno(msgget(arg1, arg2));
6817 break;
6818#endif
6819#ifdef TARGET_NR_msgrcv
6820 case TARGET_NR_msgrcv:
6821 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
6822 break;
6823#endif
6824#ifdef TARGET_NR_msgsnd
6825 case TARGET_NR_msgsnd:
6826 ret = do_msgsnd(arg1, arg2, arg3, arg4);
6827 break;
6828#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03006829#ifdef TARGET_NR_shmget
6830 case TARGET_NR_shmget:
6831 ret = get_errno(shmget(arg1, arg2, arg3));
6832 break;
6833#endif
6834#ifdef TARGET_NR_shmctl
6835 case TARGET_NR_shmctl:
6836 ret = do_shmctl(arg1, arg2, arg3);
6837 break;
6838#endif
6839#ifdef TARGET_NR_shmat
6840 case TARGET_NR_shmat:
6841 ret = do_shmat(arg1, arg2, arg3);
6842 break;
6843#endif
6844#ifdef TARGET_NR_shmdt
6845 case TARGET_NR_shmdt:
6846 ret = do_shmdt(arg1);
6847 break;
6848#endif
bellard31e31b82003-02-18 22:55:36 +00006849 case TARGET_NR_fsync:
6850 ret = get_errno(fsync(arg1));
6851 break;
bellard31e31b82003-02-18 22:55:36 +00006852 case TARGET_NR_clone:
Richard Hendersona4b388f2010-04-12 16:17:22 -07006853#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
aurel320b6d3ae2008-09-15 07:43:43 +00006854 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
edgar_iglb15ad612009-01-07 19:43:47 +00006855#elif defined(TARGET_CRIS)
6856 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02006857#elif defined(TARGET_MICROBLAZE)
6858 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006859#elif defined(TARGET_S390X)
6860 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00006861#else
pbrookd865bab2008-06-07 22:12:17 +00006862 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
aurel320b6d3ae2008-09-15 07:43:43 +00006863#endif
bellard1b6b0292003-03-22 17:31:38 +00006864 break;
bellardec86b0f2003-04-11 00:15:04 +00006865#ifdef __NR_exit_group
6866 /* new thread calls */
6867 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02006868#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00006869 _mcleanup();
6870#endif
bellarde9009672005-04-26 20:42:36 +00006871 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00006872 ret = get_errno(exit_group(arg1));
6873 break;
6874#endif
bellard31e31b82003-02-18 22:55:36 +00006875 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00006876 if (!(p = lock_user_string(arg1)))
6877 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006878 ret = get_errno(setdomainname(p, arg2));
6879 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006880 break;
6881 case TARGET_NR_uname:
6882 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00006883 {
6884 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00006885
bellard579a97f2007-11-11 14:26:47 +00006886 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
6887 goto efault;
bellard29e619b2004-09-13 21:41:04 +00006888 ret = get_errno(sys_uname(buf));
6889 if (!is_error(ret)) {
6890 /* Overrite the native machine name with whatever is being
6891 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01006892 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00006893 /* Allow the user to override the reported release. */
6894 if (qemu_uname_release && *qemu_uname_release)
6895 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00006896 }
pbrook53a59602006-03-25 19:31:22 +00006897 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00006898 }
bellard31e31b82003-02-18 22:55:36 +00006899 break;
bellard6dbad632003-03-16 18:05:05 +00006900#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00006901 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00006902 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00006903 break;
j_mayer84409dd2007-04-06 08:56:50 +00006904#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00006905 case TARGET_NR_vm86old:
6906 goto unimplemented;
6907 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00006908 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00006909 break;
6910#endif
j_mayer84409dd2007-04-06 08:56:50 +00006911#endif
bellard31e31b82003-02-18 22:55:36 +00006912 case TARGET_NR_adjtimex:
6913 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006914#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00006915 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00006916#endif
bellard31e31b82003-02-18 22:55:36 +00006917 case TARGET_NR_init_module:
6918 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00006919#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00006920 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00006921#endif
bellard31e31b82003-02-18 22:55:36 +00006922 goto unimplemented;
6923 case TARGET_NR_quotactl:
6924 goto unimplemented;
6925 case TARGET_NR_getpgid:
6926 ret = get_errno(getpgid(arg1));
6927 break;
6928 case TARGET_NR_fchdir:
6929 ret = get_errno(fchdir(arg1));
6930 break;
j_mayer84409dd2007-04-06 08:56:50 +00006931#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00006932 case TARGET_NR_bdflush:
6933 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00006934#endif
thse5febef2007-04-01 18:31:35 +00006935#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00006936 case TARGET_NR_sysfs:
6937 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006938#endif
bellard31e31b82003-02-18 22:55:36 +00006939 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00006940 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00006941 break;
thse5febef2007-04-01 18:31:35 +00006942#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00006943 case TARGET_NR_afs_syscall:
6944 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006945#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006946#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006947 case TARGET_NR__llseek:
6948 {
6949 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00006950#if !defined(__NR_llseek)
6951 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
6952 if (res == -1) {
6953 ret = get_errno(res);
6954 } else {
6955 ret = 0;
6956 }
6957#else
bellard31e31b82003-02-18 22:55:36 +00006958 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00006959#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00006960 if ((ret == 0) && put_user_s64(res, arg4)) {
6961 goto efault;
6962 }
bellard31e31b82003-02-18 22:55:36 +00006963 }
6964 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006965#endif
bellard31e31b82003-02-18 22:55:36 +00006966 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01006967#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02006968#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00006969 {
pbrook53a59602006-03-25 19:31:22 +00006970 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00006971 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006972 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00006973
6974 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00006975 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00006976 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00006977 goto fail;
6978 }
ths3b46e622007-09-17 08:09:54 +00006979
bellard4add45b2003-06-05 01:52:59 +00006980 ret = get_errno(sys_getdents(arg1, dirp, count));
6981 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006982 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00006983 struct target_dirent *tde;
6984 int len = ret;
6985 int reclen, treclen;
6986 int count1, tnamelen;
6987
6988 count1 = 0;
6989 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00006990 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6991 goto efault;
bellard4add45b2003-06-05 01:52:59 +00006992 tde = target_dirp;
6993 while (len > 0) {
6994 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04006995 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
6996 assert(tnamelen >= 0);
6997 treclen = tnamelen + offsetof(struct target_dirent, d_name);
6998 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00006999 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007000 tde->d_ino = tswapal(de->d_ino);
7001 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007002 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007003 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007004 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007005 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007006 count1 += treclen;
7007 }
7008 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007009 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007010 }
7011 free(dirp);
7012 }
7013#else
bellard31e31b82003-02-18 22:55:36 +00007014 {
aurel326556a832008-10-13 21:08:17 +00007015 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007016 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007017
bellard579a97f2007-11-11 14:26:47 +00007018 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7019 goto efault;
bellard72f03902003-02-18 23:33:18 +00007020 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007021 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007022 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007023 int len = ret;
7024 int reclen;
7025 de = dirp;
7026 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007027 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007028 if (reclen > len)
7029 break;
bellard8083a3e2003-03-24 23:12:16 +00007030 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007031 tswapls(&de->d_ino);
7032 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007033 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007034 len -= reclen;
7035 }
7036 }
pbrook53a59602006-03-25 19:31:22 +00007037 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007038 }
bellard4add45b2003-06-05 01:52:59 +00007039#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007040#else
7041 /* Implement getdents in terms of getdents64 */
7042 {
7043 struct linux_dirent64 *dirp;
7044 abi_long count = arg3;
7045
7046 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7047 if (!dirp) {
7048 goto efault;
7049 }
7050 ret = get_errno(sys_getdents64(arg1, dirp, count));
7051 if (!is_error(ret)) {
7052 /* Convert the dirent64 structs to target dirent. We do this
7053 * in-place, since we can guarantee that a target_dirent is no
7054 * larger than a dirent64; however this means we have to be
7055 * careful to read everything before writing in the new format.
7056 */
7057 struct linux_dirent64 *de;
7058 struct target_dirent *tde;
7059 int len = ret;
7060 int tlen = 0;
7061
7062 de = dirp;
7063 tde = (struct target_dirent *)dirp;
7064 while (len > 0) {
7065 int namelen, treclen;
7066 int reclen = de->d_reclen;
7067 uint64_t ino = de->d_ino;
7068 int64_t off = de->d_off;
7069 uint8_t type = de->d_type;
7070
7071 namelen = strlen(de->d_name);
7072 treclen = offsetof(struct target_dirent, d_name)
7073 + namelen + 2;
7074 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
7075
7076 memmove(tde->d_name, de->d_name, namelen + 1);
7077 tde->d_ino = tswapal(ino);
7078 tde->d_off = tswapal(off);
7079 tde->d_reclen = tswap16(treclen);
7080 /* The target_dirent type is in what was formerly a padding
7081 * byte at the end of the structure:
7082 */
7083 *(((char *)tde) + treclen - 1) = type;
7084
7085 de = (struct linux_dirent64 *)((char *)de + reclen);
7086 tde = (struct target_dirent *)((char *)tde + treclen);
7087 len -= reclen;
7088 tlen += treclen;
7089 }
7090 ret = tlen;
7091 }
7092 unlock_user(dirp, arg2, ret);
7093 }
7094#endif
bellard31e31b82003-02-18 22:55:36 +00007095 break;
ths3ae43202007-09-16 21:39:48 +00007096#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007097 case TARGET_NR_getdents64:
7098 {
aurel326556a832008-10-13 21:08:17 +00007099 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007100 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007101 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7102 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007103 ret = get_errno(sys_getdents64(arg1, dirp, count));
7104 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007105 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007106 int len = ret;
7107 int reclen;
7108 de = dirp;
7109 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007110 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007111 if (reclen > len)
7112 break;
bellard8083a3e2003-03-24 23:12:16 +00007113 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007114 tswap64s((uint64_t *)&de->d_ino);
7115 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007116 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007117 len -= reclen;
7118 }
7119 }
pbrook53a59602006-03-25 19:31:22 +00007120 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007121 }
7122 break;
bellarda541f292004-04-12 20:39:29 +00007123#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007124#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007125 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007126 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007127 break;
thse5febef2007-04-01 18:31:35 +00007128#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007129#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7130# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007131 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007132# endif
7133# ifdef TARGET_NR_ppoll
7134 case TARGET_NR_ppoll:
7135# endif
bellard9de5e442003-03-23 16:49:39 +00007136 {
pbrook53a59602006-03-25 19:31:22 +00007137 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007138 unsigned int nfds = arg2;
7139 int timeout = arg3;
7140 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007141 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007142
bellard579a97f2007-11-11 14:26:47 +00007143 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7144 if (!target_pfd)
7145 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007146
bellard9de5e442003-03-23 16:49:39 +00007147 pfd = alloca(sizeof(struct pollfd) * nfds);
7148 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007149 pfd[i].fd = tswap32(target_pfd[i].fd);
7150 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007151 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007152
7153# ifdef TARGET_NR_ppoll
7154 if (num == TARGET_NR_ppoll) {
7155 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7156 target_sigset_t *target_set;
7157 sigset_t _set, *set = &_set;
7158
7159 if (arg3) {
7160 if (target_to_host_timespec(timeout_ts, arg3)) {
7161 unlock_user(target_pfd, arg1, 0);
7162 goto efault;
7163 }
7164 } else {
7165 timeout_ts = NULL;
7166 }
7167
7168 if (arg4) {
7169 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7170 if (!target_set) {
7171 unlock_user(target_pfd, arg1, 0);
7172 goto efault;
7173 }
7174 target_to_host_sigset(set, target_set);
7175 } else {
7176 set = NULL;
7177 }
7178
7179 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7180
7181 if (!is_error(ret) && arg3) {
7182 host_to_target_timespec(arg3, timeout_ts);
7183 }
7184 if (arg4) {
7185 unlock_user(target_set, arg4, 0);
7186 }
7187 } else
7188# endif
7189 ret = get_errno(poll(pfd, nfds, timeout));
7190
bellard9de5e442003-03-23 16:49:39 +00007191 if (!is_error(ret)) {
7192 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007193 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007194 }
7195 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007196 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007197 }
7198 break;
thse5febef2007-04-01 18:31:35 +00007199#endif
bellard31e31b82003-02-18 22:55:36 +00007200 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007201 /* NOTE: the flock constant seems to be the same for every
7202 Linux platform */
7203 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007204 break;
7205 case TARGET_NR_readv:
7206 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007207 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7208 if (vec != NULL) {
7209 ret = get_errno(readv(arg1, vec, arg3));
7210 unlock_iovec(vec, arg2, arg3, 1);
7211 } else {
7212 ret = -host_to_target_errno(errno);
7213 }
bellard31e31b82003-02-18 22:55:36 +00007214 }
7215 break;
7216 case TARGET_NR_writev:
7217 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007218 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7219 if (vec != NULL) {
7220 ret = get_errno(writev(arg1, vec, arg3));
7221 unlock_iovec(vec, arg2, arg3, 0);
7222 } else {
7223 ret = -host_to_target_errno(errno);
7224 }
bellard31e31b82003-02-18 22:55:36 +00007225 }
7226 break;
7227 case TARGET_NR_getsid:
7228 ret = get_errno(getsid(arg1));
7229 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007230#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007231 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007232 ret = get_errno(fdatasync(arg1));
7233 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007234#endif
bellard31e31b82003-02-18 22:55:36 +00007235 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007236 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007237 return value. */
ths0da46a62007-10-20 20:23:07 +00007238 ret = -TARGET_ENOTDIR;
7239 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007240 case TARGET_NR_sched_getaffinity:
7241 {
7242 unsigned int mask_size;
7243 unsigned long *mask;
7244
7245 /*
7246 * sched_getaffinity needs multiples of ulong, so need to take
7247 * care of mismatches between target ulong and host ulong sizes.
7248 */
7249 if (arg2 & (sizeof(abi_ulong) - 1)) {
7250 ret = -TARGET_EINVAL;
7251 break;
7252 }
7253 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7254
7255 mask = alloca(mask_size);
7256 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7257
7258 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09007259 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007260 goto efault;
7261 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007262 }
7263 }
7264 break;
7265 case TARGET_NR_sched_setaffinity:
7266 {
7267 unsigned int mask_size;
7268 unsigned long *mask;
7269
7270 /*
7271 * sched_setaffinity needs multiples of ulong, so need to take
7272 * care of mismatches between target ulong and host ulong sizes.
7273 */
7274 if (arg2 & (sizeof(abi_ulong) - 1)) {
7275 ret = -TARGET_EINVAL;
7276 break;
7277 }
7278 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7279
7280 mask = alloca(mask_size);
7281 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7282 goto efault;
7283 }
7284 memcpy(mask, p, arg2);
7285 unlock_user_struct(p, arg2, 0);
7286
7287 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7288 }
7289 break;
bellard31e31b82003-02-18 22:55:36 +00007290 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007291 {
pbrook53a59602006-03-25 19:31:22 +00007292 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007293 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007294
bellard579a97f2007-11-11 14:26:47 +00007295 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7296 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007297 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007298 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007299 ret = get_errno(sched_setparam(arg1, &schp));
7300 }
7301 break;
bellard31e31b82003-02-18 22:55:36 +00007302 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007303 {
pbrook53a59602006-03-25 19:31:22 +00007304 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007305 struct sched_param schp;
7306 ret = get_errno(sched_getparam(arg1, &schp));
7307 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007308 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7309 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007310 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007311 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007312 }
7313 }
7314 break;
bellard31e31b82003-02-18 22:55:36 +00007315 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007316 {
pbrook53a59602006-03-25 19:31:22 +00007317 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007318 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007319 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7320 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007321 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007322 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007323 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7324 }
7325 break;
bellard31e31b82003-02-18 22:55:36 +00007326 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007327 ret = get_errno(sched_getscheduler(arg1));
7328 break;
bellard31e31b82003-02-18 22:55:36 +00007329 case TARGET_NR_sched_yield:
7330 ret = get_errno(sched_yield());
7331 break;
7332 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007333 ret = get_errno(sched_get_priority_max(arg1));
7334 break;
bellard31e31b82003-02-18 22:55:36 +00007335 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007336 ret = get_errno(sched_get_priority_min(arg1));
7337 break;
bellard31e31b82003-02-18 22:55:36 +00007338 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007339 {
bellard5cd43932003-03-29 16:54:36 +00007340 struct timespec ts;
7341 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7342 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007343 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007344 }
7345 }
7346 break;
bellard31e31b82003-02-18 22:55:36 +00007347 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007348 {
bellard1b6b0292003-03-22 17:31:38 +00007349 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007350 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007351 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007352 if (is_error(ret) && arg2) {
7353 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007354 }
7355 }
7356 break;
thse5febef2007-04-01 18:31:35 +00007357#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007358 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007359 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007360#endif
7361#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007362 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007363 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007364#endif
bellard31e31b82003-02-18 22:55:36 +00007365 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007366 switch (arg1) {
7367 case PR_GET_PDEATHSIG:
7368 {
7369 int deathsig;
7370 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7371 if (!is_error(ret) && arg2
7372 && put_user_ual(deathsig, arg2)) {
7373 goto efault;
thse5574482007-02-11 20:03:13 +00007374 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007375 break;
7376 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007377#ifdef PR_GET_NAME
7378 case PR_GET_NAME:
7379 {
7380 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7381 if (!name) {
7382 goto efault;
7383 }
7384 ret = get_errno(prctl(arg1, (unsigned long)name,
7385 arg3, arg4, arg5));
7386 unlock_user(name, arg2, 16);
7387 break;
7388 }
7389 case PR_SET_NAME:
7390 {
7391 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7392 if (!name) {
7393 goto efault;
7394 }
7395 ret = get_errno(prctl(arg1, (unsigned long)name,
7396 arg3, arg4, arg5));
7397 unlock_user(name, arg2, 0);
7398 break;
7399 }
7400#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007401 default:
7402 /* Most prctl options have no pointer arguments */
7403 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7404 break;
7405 }
ths39b9aae2007-02-11 18:36:44 +00007406 break;
bellardd2fd1af2007-11-14 18:08:56 +00007407#ifdef TARGET_NR_arch_prctl
7408 case TARGET_NR_arch_prctl:
7409#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7410 ret = do_arch_prctl(cpu_env, arg1, arg2);
7411 break;
7412#else
7413 goto unimplemented;
7414#endif
7415#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007416#ifdef TARGET_NR_pread64
7417 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007418 if (regpairs_aligned(cpu_env)) {
7419 arg4 = arg5;
7420 arg5 = arg6;
7421 }
aurel32f2c7ba12008-03-28 22:32:06 +00007422 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7423 goto efault;
7424 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7425 unlock_user(p, arg2, ret);
7426 break;
7427 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00007428 if (regpairs_aligned(cpu_env)) {
7429 arg4 = arg5;
7430 arg5 = arg6;
7431 }
aurel32f2c7ba12008-03-28 22:32:06 +00007432 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7433 goto efault;
7434 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7435 unlock_user(p, arg2, 0);
7436 break;
7437#endif
bellard31e31b82003-02-18 22:55:36 +00007438 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007439 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7440 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007441 ret = get_errno(sys_getcwd1(p, arg2));
7442 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007443 break;
7444 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00007445 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007446 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00007447 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007448 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007449#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007450 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08007451 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007452 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007453 break;
7454#else
bellard5cd43932003-03-29 16:54:36 +00007455 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007456#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007457
7458#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00007459 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007460 {
7461 off_t *offp = NULL;
7462 off_t off;
7463 if (arg3) {
7464 ret = get_user_sal(off, arg3);
7465 if (is_error(ret)) {
7466 break;
7467 }
7468 offp = &off;
7469 }
7470 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7471 if (!is_error(ret) && arg3) {
7472 abi_long ret2 = put_user_sal(off, arg3);
7473 if (is_error(ret2)) {
7474 ret = ret2;
7475 }
7476 }
7477 break;
7478 }
7479#ifdef TARGET_NR_sendfile64
7480 case TARGET_NR_sendfile64:
7481 {
7482 off_t *offp = NULL;
7483 off_t off;
7484 if (arg3) {
7485 ret = get_user_s64(off, arg3);
7486 if (is_error(ret)) {
7487 break;
7488 }
7489 offp = &off;
7490 }
7491 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7492 if (!is_error(ret) && arg3) {
7493 abi_long ret2 = put_user_s64(off, arg3);
7494 if (is_error(ret2)) {
7495 ret = ret2;
7496 }
7497 }
7498 break;
7499 }
7500#endif
7501#else
7502 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01007503#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007504 case TARGET_NR_sendfile64:
7505#endif
bellard5cd43932003-03-29 16:54:36 +00007506 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007507#endif
7508
bellardebc05482003-09-30 21:08:41 +00007509#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007510 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007511 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007512#endif
7513#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007514 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007515 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007516#endif
bellard048f6b42005-11-26 18:47:20 +00007517#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007518 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007519 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7520 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007521 break;
bellard048f6b42005-11-26 18:47:20 +00007522#endif
bellardebc05482003-09-30 21:08:41 +00007523#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007524 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007525 {
7526 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007527 int resource = target_to_host_resource(arg1);
7528 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007529 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007530 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007531 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7532 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007533 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7534 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007535 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007536 }
7537 break;
7538 }
bellardebc05482003-09-30 21:08:41 +00007539#endif
bellarda315a142005-01-30 22:59:18 +00007540#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007541 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007542 if (!(p = lock_user_string(arg1)))
7543 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007544 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7545 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007546 break;
bellarda315a142005-01-30 22:59:18 +00007547#endif
7548#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00007549 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00007550 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00007551 break;
bellarda315a142005-01-30 22:59:18 +00007552#endif
7553#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00007554 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00007555 if (!(p = lock_user_string(arg1)))
7556 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007557 ret = get_errno(stat(path(p), &st));
7558 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007559 if (!is_error(ret))
7560 ret = host_to_target_stat64(cpu_env, arg2, &st);
7561 break;
bellarda315a142005-01-30 22:59:18 +00007562#endif
7563#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00007564 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00007565 if (!(p = lock_user_string(arg1)))
7566 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007567 ret = get_errno(lstat(path(p), &st));
7568 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007569 if (!is_error(ret))
7570 ret = host_to_target_stat64(cpu_env, arg2, &st);
7571 break;
bellarda315a142005-01-30 22:59:18 +00007572#endif
7573#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00007574 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00007575 ret = get_errno(fstat(arg1, &st));
7576 if (!is_error(ret))
7577 ret = host_to_target_stat64(cpu_env, arg2, &st);
7578 break;
bellardec86b0f2003-04-11 00:15:04 +00007579#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007580#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00007581#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007582 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007583#endif
7584#ifdef TARGET_NR_newfstatat
7585 case TARGET_NR_newfstatat:
7586#endif
balrog6a24a772008-09-20 02:23:36 +00007587 if (!(p = lock_user_string(arg2)))
7588 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007589 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00007590 if (!is_error(ret))
7591 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007592 break;
bellarda315a142005-01-30 22:59:18 +00007593#endif
bellard67867302003-11-23 17:05:30 +00007594 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007595 if (!(p = lock_user_string(arg1)))
7596 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007597 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7598 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007599 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007600#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007601 case TARGET_NR_getuid:
7602 ret = get_errno(high2lowuid(getuid()));
7603 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007604#endif
7605#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007606 case TARGET_NR_getgid:
7607 ret = get_errno(high2lowgid(getgid()));
7608 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007609#endif
7610#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007611 case TARGET_NR_geteuid:
7612 ret = get_errno(high2lowuid(geteuid()));
7613 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007614#endif
7615#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007616 case TARGET_NR_getegid:
7617 ret = get_errno(high2lowgid(getegid()));
7618 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007619#endif
bellard67867302003-11-23 17:05:30 +00007620 case TARGET_NR_setreuid:
7621 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7622 break;
7623 case TARGET_NR_setregid:
7624 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7625 break;
7626 case TARGET_NR_getgroups:
7627 {
7628 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007629 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007630 gid_t *grouplist;
7631 int i;
7632
7633 grouplist = alloca(gidsetsize * sizeof(gid_t));
7634 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007635 if (gidsetsize == 0)
7636 break;
bellard67867302003-11-23 17:05:30 +00007637 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00007638 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00007639 if (!target_grouplist)
7640 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007641 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007642 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007643 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00007644 }
7645 }
7646 break;
7647 case TARGET_NR_setgroups:
7648 {
7649 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007650 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007651 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00007652 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007653 if (gidsetsize) {
7654 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007655 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007656 if (!target_grouplist) {
7657 ret = -TARGET_EFAULT;
7658 goto fail;
7659 }
7660 for (i = 0; i < gidsetsize; i++) {
7661 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
7662 }
7663 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007664 }
bellard67867302003-11-23 17:05:30 +00007665 ret = get_errno(setgroups(gidsetsize, grouplist));
7666 }
7667 break;
7668 case TARGET_NR_fchown:
7669 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7670 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007671#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00007672 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007673 if (!(p = lock_user_string(arg2)))
7674 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007675 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
7676 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00007677 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007678 break;
7679#endif
bellard67867302003-11-23 17:05:30 +00007680#ifdef TARGET_NR_setresuid
7681 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007682 ret = get_errno(setresuid(low2highuid(arg1),
7683 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007684 low2highuid(arg3)));
7685 break;
7686#endif
7687#ifdef TARGET_NR_getresuid
7688 case TARGET_NR_getresuid:
7689 {
pbrook53a59602006-03-25 19:31:22 +00007690 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007691 ret = get_errno(getresuid(&ruid, &euid, &suid));
7692 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007693 if (put_user_u16(high2lowuid(ruid), arg1)
7694 || put_user_u16(high2lowuid(euid), arg2)
7695 || put_user_u16(high2lowuid(suid), arg3))
7696 goto efault;
bellard67867302003-11-23 17:05:30 +00007697 }
7698 }
7699 break;
7700#endif
7701#ifdef TARGET_NR_getresgid
7702 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007703 ret = get_errno(setresgid(low2highgid(arg1),
7704 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007705 low2highgid(arg3)));
7706 break;
7707#endif
7708#ifdef TARGET_NR_getresgid
7709 case TARGET_NR_getresgid:
7710 {
pbrook53a59602006-03-25 19:31:22 +00007711 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007712 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7713 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007714 if (put_user_u16(high2lowgid(rgid), arg1)
7715 || put_user_u16(high2lowgid(egid), arg2)
7716 || put_user_u16(high2lowgid(sgid), arg3))
7717 goto efault;
bellard67867302003-11-23 17:05:30 +00007718 }
7719 }
7720 break;
7721#endif
7722 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007723 if (!(p = lock_user_string(arg1)))
7724 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007725 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7726 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007727 break;
7728 case TARGET_NR_setuid:
7729 ret = get_errno(setuid(low2highuid(arg1)));
7730 break;
7731 case TARGET_NR_setgid:
7732 ret = get_errno(setgid(low2highgid(arg1)));
7733 break;
7734 case TARGET_NR_setfsuid:
7735 ret = get_errno(setfsuid(arg1));
7736 break;
7737 case TARGET_NR_setfsgid:
7738 ret = get_errno(setfsgid(arg1));
7739 break;
bellard67867302003-11-23 17:05:30 +00007740
bellarda315a142005-01-30 22:59:18 +00007741#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00007742 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00007743 if (!(p = lock_user_string(arg1)))
7744 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007745 ret = get_errno(lchown(p, arg2, arg3));
7746 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007747 break;
bellarda315a142005-01-30 22:59:18 +00007748#endif
7749#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00007750 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00007751 ret = get_errno(getuid());
7752 break;
bellarda315a142005-01-30 22:59:18 +00007753#endif
aurel3264b4d282008-11-14 17:20:15 +00007754
7755#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
7756 /* Alpha specific */
7757 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007758 {
7759 uid_t euid;
7760 euid=geteuid();
7761 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
7762 }
aurel3264b4d282008-11-14 17:20:15 +00007763 ret = get_errno(getuid());
7764 break;
7765#endif
7766#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
7767 /* Alpha specific */
7768 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007769 {
7770 uid_t egid;
7771 egid=getegid();
7772 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
7773 }
aurel3264b4d282008-11-14 17:20:15 +00007774 ret = get_errno(getgid());
7775 break;
7776#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08007777#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
7778 /* Alpha specific */
7779 case TARGET_NR_osf_getsysinfo:
7780 ret = -TARGET_EOPNOTSUPP;
7781 switch (arg1) {
7782 case TARGET_GSI_IEEE_FP_CONTROL:
7783 {
7784 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
7785
7786 /* Copied from linux ieee_fpcr_to_swcr. */
7787 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
7788 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
7789 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
7790 | SWCR_TRAP_ENABLE_DZE
7791 | SWCR_TRAP_ENABLE_OVF);
7792 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
7793 | SWCR_TRAP_ENABLE_INE);
7794 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
7795 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
7796
7797 if (put_user_u64 (swcr, arg2))
7798 goto efault;
7799 ret = 0;
7800 }
7801 break;
7802
7803 /* case GSI_IEEE_STATE_AT_SIGNAL:
7804 -- Not implemented in linux kernel.
7805 case GSI_UACPROC:
7806 -- Retrieves current unaligned access state; not much used.
7807 case GSI_PROC_TYPE:
7808 -- Retrieves implver information; surely not used.
7809 case GSI_GET_HWRPB:
7810 -- Grabs a copy of the HWRPB; surely not used.
7811 */
7812 }
7813 break;
7814#endif
7815#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
7816 /* Alpha specific */
7817 case TARGET_NR_osf_setsysinfo:
7818 ret = -TARGET_EOPNOTSUPP;
7819 switch (arg1) {
7820 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007821 {
7822 uint64_t swcr, fpcr, orig_fpcr;
7823
Richard Henderson6e06d512012-06-01 09:08:21 -07007824 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08007825 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07007826 }
7827 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007828 fpcr = orig_fpcr & FPCR_DYN_MASK;
7829
7830 /* Copied from linux ieee_swcr_to_fpcr. */
7831 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
7832 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
7833 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
7834 | SWCR_TRAP_ENABLE_DZE
7835 | SWCR_TRAP_ENABLE_OVF)) << 48;
7836 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
7837 | SWCR_TRAP_ENABLE_INE)) << 57;
7838 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
7839 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
7840
Richard Henderson6e06d512012-06-01 09:08:21 -07007841 cpu_alpha_store_fpcr(cpu_env, fpcr);
7842 ret = 0;
7843 }
7844 break;
7845
7846 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
7847 {
7848 uint64_t exc, fpcr, orig_fpcr;
7849 int si_code;
7850
7851 if (get_user_u64(exc, arg2)) {
7852 goto efault;
7853 }
7854
7855 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
7856
7857 /* We only add to the exception status here. */
7858 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
7859
7860 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007861 ret = 0;
7862
Richard Henderson6e06d512012-06-01 09:08:21 -07007863 /* Old exceptions are not signaled. */
7864 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007865
Richard Henderson6e06d512012-06-01 09:08:21 -07007866 /* If any exceptions set by this call,
7867 and are unmasked, send a signal. */
7868 si_code = 0;
7869 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
7870 si_code = TARGET_FPE_FLTRES;
7871 }
7872 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
7873 si_code = TARGET_FPE_FLTUND;
7874 }
7875 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
7876 si_code = TARGET_FPE_FLTOVF;
7877 }
7878 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
7879 si_code = TARGET_FPE_FLTDIV;
7880 }
7881 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
7882 si_code = TARGET_FPE_FLTINV;
7883 }
7884 if (si_code != 0) {
7885 target_siginfo_t info;
7886 info.si_signo = SIGFPE;
7887 info.si_errno = 0;
7888 info.si_code = si_code;
7889 info._sifields._sigfault._addr
7890 = ((CPUArchState *)cpu_env)->pc;
7891 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007892 }
7893 }
7894 break;
7895
7896 /* case SSI_NVPAIRS:
7897 -- Used with SSIN_UACPROC to enable unaligned accesses.
7898 case SSI_IEEE_STATE_AT_SIGNAL:
7899 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
7900 -- Not implemented in linux kernel
7901 */
7902 }
7903 break;
7904#endif
7905#ifdef TARGET_NR_osf_sigprocmask
7906 /* Alpha specific. */
7907 case TARGET_NR_osf_sigprocmask:
7908 {
7909 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01007910 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08007911 sigset_t set, oldset;
7912
7913 switch(arg1) {
7914 case TARGET_SIG_BLOCK:
7915 how = SIG_BLOCK;
7916 break;
7917 case TARGET_SIG_UNBLOCK:
7918 how = SIG_UNBLOCK;
7919 break;
7920 case TARGET_SIG_SETMASK:
7921 how = SIG_SETMASK;
7922 break;
7923 default:
7924 ret = -TARGET_EINVAL;
7925 goto fail;
7926 }
7927 mask = arg2;
7928 target_to_host_old_sigset(&set, &mask);
Juan Quintelabc088ba2011-06-16 17:37:10 +01007929 sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007930 host_to_target_old_sigset(&mask, &oldset);
7931 ret = mask;
7932 }
7933 break;
7934#endif
aurel3264b4d282008-11-14 17:20:15 +00007935
bellarda315a142005-01-30 22:59:18 +00007936#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00007937 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00007938 ret = get_errno(getgid());
7939 break;
bellarda315a142005-01-30 22:59:18 +00007940#endif
7941#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00007942 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00007943 ret = get_errno(geteuid());
7944 break;
bellarda315a142005-01-30 22:59:18 +00007945#endif
7946#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00007947 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00007948 ret = get_errno(getegid());
7949 break;
bellarda315a142005-01-30 22:59:18 +00007950#endif
7951#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00007952 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00007953 ret = get_errno(setreuid(arg1, arg2));
7954 break;
bellarda315a142005-01-30 22:59:18 +00007955#endif
7956#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00007957 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00007958 ret = get_errno(setregid(arg1, arg2));
7959 break;
bellarda315a142005-01-30 22:59:18 +00007960#endif
7961#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00007962 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00007963 {
7964 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007965 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007966 gid_t *grouplist;
7967 int i;
7968
7969 grouplist = alloca(gidsetsize * sizeof(gid_t));
7970 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007971 if (gidsetsize == 0)
7972 break;
bellard99c475a2005-01-31 20:45:13 +00007973 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007974 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
7975 if (!target_grouplist) {
7976 ret = -TARGET_EFAULT;
7977 goto fail;
7978 }
balroga2155fc2008-09-20 02:12:08 +00007979 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00007980 target_grouplist[i] = tswap32(grouplist[i]);
7981 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00007982 }
7983 }
7984 break;
bellarda315a142005-01-30 22:59:18 +00007985#endif
7986#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00007987 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00007988 {
7989 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007990 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007991 gid_t *grouplist;
7992 int i;
ths3b46e622007-09-17 08:09:54 +00007993
bellard99c475a2005-01-31 20:45:13 +00007994 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007995 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
7996 if (!target_grouplist) {
7997 ret = -TARGET_EFAULT;
7998 goto fail;
7999 }
bellard99c475a2005-01-31 20:45:13 +00008000 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00008001 grouplist[i] = tswap32(target_grouplist[i]);
8002 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00008003 ret = get_errno(setgroups(gidsetsize, grouplist));
8004 }
8005 break;
bellarda315a142005-01-30 22:59:18 +00008006#endif
8007#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00008008 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008009 ret = get_errno(fchown(arg1, arg2, arg3));
8010 break;
bellarda315a142005-01-30 22:59:18 +00008011#endif
8012#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008013 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008014 ret = get_errno(setresuid(arg1, arg2, arg3));
8015 break;
bellarda315a142005-01-30 22:59:18 +00008016#endif
8017#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008018 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008019 {
pbrook53a59602006-03-25 19:31:22 +00008020 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008021 ret = get_errno(getresuid(&ruid, &euid, &suid));
8022 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008023 if (put_user_u32(ruid, arg1)
8024 || put_user_u32(euid, arg2)
8025 || put_user_u32(suid, arg3))
8026 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008027 }
8028 }
8029 break;
bellarda315a142005-01-30 22:59:18 +00008030#endif
8031#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008032 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008033 ret = get_errno(setresgid(arg1, arg2, arg3));
8034 break;
bellarda315a142005-01-30 22:59:18 +00008035#endif
8036#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008037 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008038 {
pbrook53a59602006-03-25 19:31:22 +00008039 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008040 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8041 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008042 if (put_user_u32(rgid, arg1)
8043 || put_user_u32(egid, arg2)
8044 || put_user_u32(sgid, arg3))
8045 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008046 }
8047 }
8048 break;
bellarda315a142005-01-30 22:59:18 +00008049#endif
8050#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008051 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008052 if (!(p = lock_user_string(arg1)))
8053 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008054 ret = get_errno(chown(p, arg2, arg3));
8055 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008056 break;
bellarda315a142005-01-30 22:59:18 +00008057#endif
8058#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008059 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008060 ret = get_errno(setuid(arg1));
8061 break;
bellarda315a142005-01-30 22:59:18 +00008062#endif
8063#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008064 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008065 ret = get_errno(setgid(arg1));
8066 break;
bellarda315a142005-01-30 22:59:18 +00008067#endif
8068#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008069 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008070 ret = get_errno(setfsuid(arg1));
8071 break;
bellarda315a142005-01-30 22:59:18 +00008072#endif
8073#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008074 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008075 ret = get_errno(setfsgid(arg1));
8076 break;
bellarda315a142005-01-30 22:59:18 +00008077#endif
bellard67867302003-11-23 17:05:30 +00008078
bellard31e31b82003-02-18 22:55:36 +00008079 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008080 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008081#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008082 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008083 {
8084 void *a;
8085 ret = -TARGET_EFAULT;
8086 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8087 goto efault;
8088 if (!(p = lock_user_string(arg3)))
8089 goto mincore_fail;
8090 ret = get_errno(mincore(a, arg2, p));
8091 unlock_user(p, arg3, ret);
8092 mincore_fail:
8093 unlock_user(a, arg1, 0);
8094 }
8095 break;
bellardffa65c32004-01-04 23:57:22 +00008096#endif
aurel32408321b2008-10-01 21:46:32 +00008097#ifdef TARGET_NR_arm_fadvise64_64
8098 case TARGET_NR_arm_fadvise64_64:
8099 {
8100 /*
8101 * arm_fadvise64_64 looks like fadvise64_64 but
8102 * with different argument order
8103 */
8104 abi_long temp;
8105 temp = arg3;
8106 arg3 = arg4;
8107 arg4 = temp;
8108 }
8109#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008110#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008111#ifdef TARGET_NR_fadvise64_64
8112 case TARGET_NR_fadvise64_64:
8113#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008114#ifdef TARGET_NR_fadvise64
8115 case TARGET_NR_fadvise64:
8116#endif
8117#ifdef TARGET_S390X
8118 switch (arg4) {
8119 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8120 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8121 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8122 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8123 default: break;
8124 }
8125#endif
8126 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008127 break;
8128#endif
bellardffa65c32004-01-04 23:57:22 +00008129#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008130 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008131 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08008132 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00008133 This will break MADV_DONTNEED.
8134 This is a hint, so ignoring and returning success is ok. */
8135 ret = get_errno(0);
8136 break;
bellardffa65c32004-01-04 23:57:22 +00008137#endif
blueswir1992f48a2007-10-14 16:27:31 +00008138#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008139 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008140 {
thsb1e341e2007-03-20 21:50:52 +00008141 int cmd;
bellard77e46722003-04-29 20:39:06 +00008142 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008143 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008144#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008145 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008146#endif
bellard77e46722003-04-29 20:39:06 +00008147
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008148 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008149 if (cmd == -TARGET_EINVAL) {
8150 ret = cmd;
8151 break;
8152 }
thsb1e341e2007-03-20 21:50:52 +00008153
bellard60cd49d2003-03-16 22:53:56 +00008154 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008155 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008156#ifdef TARGET_ARM
8157 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008158 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8159 goto efault;
ths58134272007-03-31 18:59:32 +00008160 fl.l_type = tswap16(target_efl->l_type);
8161 fl.l_whence = tswap16(target_efl->l_whence);
8162 fl.l_start = tswap64(target_efl->l_start);
8163 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008164 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008165 unlock_user_struct(target_efl, arg3, 0);
8166 } else
8167#endif
8168 {
bellard9ee1fa22007-11-11 15:11:19 +00008169 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8170 goto efault;
ths58134272007-03-31 18:59:32 +00008171 fl.l_type = tswap16(target_fl->l_type);
8172 fl.l_whence = tswap16(target_fl->l_whence);
8173 fl.l_start = tswap64(target_fl->l_start);
8174 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008175 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008176 unlock_user_struct(target_fl, arg3, 0);
8177 }
thsb1e341e2007-03-20 21:50:52 +00008178 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008179 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008180#ifdef TARGET_ARM
8181 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008182 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8183 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008184 target_efl->l_type = tswap16(fl.l_type);
8185 target_efl->l_whence = tswap16(fl.l_whence);
8186 target_efl->l_start = tswap64(fl.l_start);
8187 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008188 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008189 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008190 } else
8191#endif
8192 {
bellard9ee1fa22007-11-11 15:11:19 +00008193 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8194 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008195 target_fl->l_type = tswap16(fl.l_type);
8196 target_fl->l_whence = tswap16(fl.l_whence);
8197 target_fl->l_start = tswap64(fl.l_start);
8198 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008199 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008200 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008201 }
bellard77e46722003-04-29 20:39:06 +00008202 }
8203 break;
8204
thsb1e341e2007-03-20 21:50:52 +00008205 case TARGET_F_SETLK64:
8206 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008207#ifdef TARGET_ARM
8208 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008209 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8210 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008211 fl.l_type = tswap16(target_efl->l_type);
8212 fl.l_whence = tswap16(target_efl->l_whence);
8213 fl.l_start = tswap64(target_efl->l_start);
8214 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008215 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008216 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008217 } else
8218#endif
8219 {
bellard9ee1fa22007-11-11 15:11:19 +00008220 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8221 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008222 fl.l_type = tswap16(target_fl->l_type);
8223 fl.l_whence = tswap16(target_fl->l_whence);
8224 fl.l_start = tswap64(target_fl->l_start);
8225 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008226 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008227 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008228 }
thsb1e341e2007-03-20 21:50:52 +00008229 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008230 break;
bellard60cd49d2003-03-16 22:53:56 +00008231 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008232 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008233 break;
8234 }
bellard77e46722003-04-29 20:39:06 +00008235 break;
8236 }
bellard60cd49d2003-03-16 22:53:56 +00008237#endif
ths7d600c82006-12-08 01:32:58 +00008238#ifdef TARGET_NR_cacheflush
8239 case TARGET_NR_cacheflush:
8240 /* self-modifying code is handled automatically, so nothing needed */
8241 ret = 0;
8242 break;
8243#endif
bellardebc05482003-09-30 21:08:41 +00008244#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008245 case TARGET_NR_security:
8246 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008247#endif
bellardc573ff62004-01-04 15:51:36 +00008248#ifdef TARGET_NR_getpagesize
8249 case TARGET_NR_getpagesize:
8250 ret = TARGET_PAGE_SIZE;
8251 break;
8252#endif
bellard31e31b82003-02-18 22:55:36 +00008253 case TARGET_NR_gettid:
8254 ret = get_errno(gettid());
8255 break;
thse5febef2007-04-01 18:31:35 +00008256#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008257 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008258#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008259 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008260 arg2 = arg3;
8261 arg3 = arg4;
8262 arg4 = arg5;
8263 }
aurel322054ac92008-10-13 21:08:07 +00008264 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8265#else
8266 ret = get_errno(readahead(arg1, arg2, arg3));
8267#endif
8268 break;
thse5febef2007-04-01 18:31:35 +00008269#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008270#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008271#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008272 case TARGET_NR_listxattr:
8273 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008274 {
8275 void *p, *b = 0;
8276 if (arg2) {
8277 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8278 if (!b) {
8279 ret = -TARGET_EFAULT;
8280 break;
8281 }
8282 }
8283 p = lock_user_string(arg1);
8284 if (p) {
8285 if (num == TARGET_NR_listxattr) {
8286 ret = get_errno(listxattr(p, b, arg3));
8287 } else {
8288 ret = get_errno(llistxattr(p, b, arg3));
8289 }
8290 } else {
8291 ret = -TARGET_EFAULT;
8292 }
8293 unlock_user(p, arg1, 0);
8294 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008295 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008296 }
8297 case TARGET_NR_flistxattr:
8298 {
8299 void *b = 0;
8300 if (arg2) {
8301 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8302 if (!b) {
8303 ret = -TARGET_EFAULT;
8304 break;
8305 }
8306 }
8307 ret = get_errno(flistxattr(arg1, b, arg3));
8308 unlock_user(b, arg2, arg3);
8309 break;
8310 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008311 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008312 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008313 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008314 void *p, *n, *v = 0;
8315 if (arg3) {
8316 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8317 if (!v) {
8318 ret = -TARGET_EFAULT;
8319 break;
8320 }
8321 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008322 p = lock_user_string(arg1);
8323 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008324 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008325 if (num == TARGET_NR_setxattr) {
8326 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8327 } else {
8328 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8329 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008330 } else {
8331 ret = -TARGET_EFAULT;
8332 }
8333 unlock_user(p, arg1, 0);
8334 unlock_user(n, arg2, 0);
8335 unlock_user(v, arg3, 0);
8336 }
8337 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008338 case TARGET_NR_fsetxattr:
8339 {
8340 void *n, *v = 0;
8341 if (arg3) {
8342 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8343 if (!v) {
8344 ret = -TARGET_EFAULT;
8345 break;
8346 }
8347 }
8348 n = lock_user_string(arg2);
8349 if (n) {
8350 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8351 } else {
8352 ret = -TARGET_EFAULT;
8353 }
8354 unlock_user(n, arg2, 0);
8355 unlock_user(v, arg3, 0);
8356 }
8357 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008358 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008359 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008360 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008361 void *p, *n, *v = 0;
8362 if (arg3) {
8363 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8364 if (!v) {
8365 ret = -TARGET_EFAULT;
8366 break;
8367 }
8368 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008369 p = lock_user_string(arg1);
8370 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008371 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008372 if (num == TARGET_NR_getxattr) {
8373 ret = get_errno(getxattr(p, n, v, arg4));
8374 } else {
8375 ret = get_errno(lgetxattr(p, n, v, arg4));
8376 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008377 } else {
8378 ret = -TARGET_EFAULT;
8379 }
8380 unlock_user(p, arg1, 0);
8381 unlock_user(n, arg2, 0);
8382 unlock_user(v, arg3, arg4);
8383 }
8384 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008385 case TARGET_NR_fgetxattr:
8386 {
8387 void *n, *v = 0;
8388 if (arg3) {
8389 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8390 if (!v) {
8391 ret = -TARGET_EFAULT;
8392 break;
8393 }
8394 }
8395 n = lock_user_string(arg2);
8396 if (n) {
8397 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8398 } else {
8399 ret = -TARGET_EFAULT;
8400 }
8401 unlock_user(n, arg2, 0);
8402 unlock_user(v, arg3, arg4);
8403 }
8404 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008405 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008406 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008407 {
8408 void *p, *n;
8409 p = lock_user_string(arg1);
8410 n = lock_user_string(arg2);
8411 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008412 if (num == TARGET_NR_removexattr) {
8413 ret = get_errno(removexattr(p, n));
8414 } else {
8415 ret = get_errno(lremovexattr(p, n));
8416 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008417 } else {
8418 ret = -TARGET_EFAULT;
8419 }
8420 unlock_user(p, arg1, 0);
8421 unlock_user(n, arg2, 0);
8422 }
8423 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008424 case TARGET_NR_fremovexattr:
8425 {
8426 void *n;
8427 n = lock_user_string(arg2);
8428 if (n) {
8429 ret = get_errno(fremovexattr(arg1, n));
8430 } else {
8431 ret = -TARGET_EFAULT;
8432 }
8433 unlock_user(n, arg2, 0);
8434 }
8435 break;
bellardebc05482003-09-30 21:08:41 +00008436#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008437#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008438#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008439 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008440#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00008441 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
8442 ret = 0;
8443 break;
edgar_iglef967792009-01-07 14:19:38 +00008444#elif defined(TARGET_CRIS)
8445 if (arg1 & 0xff)
8446 ret = -TARGET_EINVAL;
8447 else {
8448 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8449 ret = 0;
8450 }
8451 break;
bellard8d18e892007-11-14 15:18:40 +00008452#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8453 ret = do_set_thread_area(cpu_env, arg1);
8454 break;
ths6f5b89a2007-03-02 20:48:00 +00008455#else
8456 goto unimplemented_nowarn;
8457#endif
8458#endif
8459#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008460 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008461#if defined(TARGET_I386) && defined(TARGET_ABI32)
8462 ret = do_get_thread_area(cpu_env, arg1);
8463#else
bellard5cd43932003-03-29 16:54:36 +00008464 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008465#endif
bellard8d18e892007-11-14 15:18:40 +00008466#endif
bellard48dc41e2006-06-21 18:15:50 +00008467#ifdef TARGET_NR_getdomainname
8468 case TARGET_NR_getdomainname:
8469 goto unimplemented_nowarn;
8470#endif
ths6f5b89a2007-03-02 20:48:00 +00008471
thsb5906f92007-03-19 13:32:45 +00008472#ifdef TARGET_NR_clock_gettime
8473 case TARGET_NR_clock_gettime:
8474 {
8475 struct timespec ts;
8476 ret = get_errno(clock_gettime(arg1, &ts));
8477 if (!is_error(ret)) {
8478 host_to_target_timespec(arg2, &ts);
8479 }
8480 break;
8481 }
8482#endif
8483#ifdef TARGET_NR_clock_getres
8484 case TARGET_NR_clock_getres:
8485 {
8486 struct timespec ts;
8487 ret = get_errno(clock_getres(arg1, &ts));
8488 if (!is_error(ret)) {
8489 host_to_target_timespec(arg2, &ts);
8490 }
8491 break;
8492 }
8493#endif
pbrook63d76512008-05-29 13:43:29 +00008494#ifdef TARGET_NR_clock_nanosleep
8495 case TARGET_NR_clock_nanosleep:
8496 {
8497 struct timespec ts;
8498 target_to_host_timespec(&ts, arg3);
8499 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8500 if (arg4)
8501 host_to_target_timespec(arg4, &ts);
8502 break;
8503 }
8504#endif
thsb5906f92007-03-19 13:32:45 +00008505
ths6f5b89a2007-03-02 20:48:00 +00008506#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8507 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008508 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8509 break;
ths6f5b89a2007-03-02 20:48:00 +00008510#endif
8511
ths3ae43202007-09-16 21:39:48 +00008512#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008513 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008514 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008515 break;
8516#endif
8517
ths3ae43202007-09-16 21:39:48 +00008518#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008519 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008520 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8521 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008522 break;
8523#endif
8524
ths4f2b1fe2007-06-21 21:57:12 +00008525#ifdef TARGET_NR_set_robust_list
8526 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00008527 case TARGET_NR_get_robust_list:
8528 /* The ABI for supporting robust futexes has userspace pass
8529 * the kernel a pointer to a linked list which is updated by
8530 * userspace after the syscall; the list is walked by the kernel
8531 * when the thread exits. Since the linked list in QEMU guest
8532 * memory isn't a valid linked list for the host and we have
8533 * no way to reliably intercept the thread-death event, we can't
8534 * support these. Silently return ENOSYS so that guest userspace
8535 * falls back to a non-robust futex implementation (which should
8536 * be OK except in the corner case of the guest crashing while
8537 * holding a mutex that is shared with another process via
8538 * shared memory).
8539 */
8540 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00008541#endif
8542
ths9007f0e2007-09-25 17:50:37 +00008543#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
8544 case TARGET_NR_utimensat:
8545 {
Riku Voipioebc996f2009-04-21 15:01:51 +03008546 struct timespec *tsp, ts[2];
8547 if (!arg3) {
8548 tsp = NULL;
8549 } else {
8550 target_to_host_timespec(ts, arg3);
8551 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
8552 tsp = ts;
8553 }
ths9007f0e2007-09-25 17:50:37 +00008554 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03008555 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00008556 else {
bellard579a97f2007-11-11 14:26:47 +00008557 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00008558 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008559 goto fail;
8560 }
Riku Voipioebc996f2009-04-21 15:01:51 +03008561 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00008562 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00008563 }
8564 }
8565 break;
8566#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +02008567#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00008568 case TARGET_NR_futex:
8569 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
8570 break;
8571#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008572#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00008573 case TARGET_NR_inotify_init:
8574 ret = get_errno(sys_inotify_init());
8575 break;
8576#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008577#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00008578#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
8579 case TARGET_NR_inotify_init1:
8580 ret = get_errno(sys_inotify_init1(arg1));
8581 break;
8582#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008583#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008584#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00008585 case TARGET_NR_inotify_add_watch:
8586 p = lock_user_string(arg2);
8587 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
8588 unlock_user(p, arg2, 0);
8589 break;
8590#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008591#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00008592 case TARGET_NR_inotify_rm_watch:
8593 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
8594 break;
8595#endif
ths9007f0e2007-09-25 17:50:37 +00008596
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07008597#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00008598 case TARGET_NR_mq_open:
8599 {
8600 struct mq_attr posix_mq_attr;
8601
8602 p = lock_user_string(arg1 - 1);
8603 if (arg4 != 0)
8604 copy_from_user_mq_attr (&posix_mq_attr, arg4);
8605 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
8606 unlock_user (p, arg1, 0);
8607 }
8608 break;
8609
8610 case TARGET_NR_mq_unlink:
8611 p = lock_user_string(arg1 - 1);
8612 ret = get_errno(mq_unlink(p));
8613 unlock_user (p, arg1, 0);
8614 break;
8615
8616 case TARGET_NR_mq_timedsend:
8617 {
8618 struct timespec ts;
8619
8620 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8621 if (arg5 != 0) {
8622 target_to_host_timespec(&ts, arg5);
8623 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
8624 host_to_target_timespec(arg5, &ts);
8625 }
8626 else
8627 ret = get_errno(mq_send(arg1, p, arg3, arg4));
8628 unlock_user (p, arg2, arg3);
8629 }
8630 break;
8631
8632 case TARGET_NR_mq_timedreceive:
8633 {
8634 struct timespec ts;
8635 unsigned int prio;
8636
8637 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8638 if (arg5 != 0) {
8639 target_to_host_timespec(&ts, arg5);
8640 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
8641 host_to_target_timespec(arg5, &ts);
8642 }
8643 else
8644 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
8645 unlock_user (p, arg2, arg3);
8646 if (arg4 != 0)
8647 put_user_u32(prio, arg4);
8648 }
8649 break;
8650
8651 /* Not implemented for now... */
8652/* case TARGET_NR_mq_notify: */
8653/* break; */
8654
8655 case TARGET_NR_mq_getsetattr:
8656 {
8657 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
8658 ret = 0;
8659 if (arg3 != 0) {
8660 ret = mq_getattr(arg1, &posix_mq_attr_out);
8661 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
8662 }
8663 if (arg2 != 0) {
8664 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
8665 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
8666 }
8667
8668 }
8669 break;
8670#endif
8671
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308672#ifdef CONFIG_SPLICE
8673#ifdef TARGET_NR_tee
8674 case TARGET_NR_tee:
8675 {
8676 ret = get_errno(tee(arg1,arg2,arg3,arg4));
8677 }
8678 break;
8679#endif
8680#ifdef TARGET_NR_splice
8681 case TARGET_NR_splice:
8682 {
8683 loff_t loff_in, loff_out;
8684 loff_t *ploff_in = NULL, *ploff_out = NULL;
8685 if(arg2) {
8686 get_user_u64(loff_in, arg2);
8687 ploff_in = &loff_in;
8688 }
8689 if(arg4) {
8690 get_user_u64(loff_out, arg2);
8691 ploff_out = &loff_out;
8692 }
8693 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
8694 }
8695 break;
8696#endif
8697#ifdef TARGET_NR_vmsplice
8698 case TARGET_NR_vmsplice:
8699 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008700 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
8701 if (vec != NULL) {
8702 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
8703 unlock_iovec(vec, arg2, arg3, 0);
8704 } else {
8705 ret = -host_to_target_errno(errno);
8706 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308707 }
8708 break;
8709#endif
8710#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03008711#ifdef CONFIG_EVENTFD
8712#if defined(TARGET_NR_eventfd)
8713 case TARGET_NR_eventfd:
8714 ret = get_errno(eventfd(arg1, 0));
8715 break;
8716#endif
8717#if defined(TARGET_NR_eventfd2)
8718 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02008719 {
8720 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
8721 if (arg2 & TARGET_O_NONBLOCK) {
8722 host_flags |= O_NONBLOCK;
8723 }
8724 if (arg2 & TARGET_O_CLOEXEC) {
8725 host_flags |= O_CLOEXEC;
8726 }
8727 ret = get_errno(eventfd(arg1, host_flags));
Riku Voipioc2882b92009-08-12 15:08:24 +03008728 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02008729 }
Riku Voipioc2882b92009-08-12 15:08:24 +03008730#endif
8731#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03008732#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
8733 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01008734#if TARGET_ABI_BITS == 32
8735 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
8736 target_offset64(arg5, arg6)));
8737#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03008738 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01008739#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008740 break;
8741#endif
Peter Maydellc727f472011-01-06 11:05:10 +00008742#if defined(CONFIG_SYNC_FILE_RANGE)
8743#if defined(TARGET_NR_sync_file_range)
8744 case TARGET_NR_sync_file_range:
8745#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03008746#if defined(TARGET_MIPS)
8747 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8748 target_offset64(arg5, arg6), arg7));
8749#else
Peter Maydellc727f472011-01-06 11:05:10 +00008750 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
8751 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03008752#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00008753#else
8754 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
8755#endif
8756 break;
8757#endif
8758#if defined(TARGET_NR_sync_file_range2)
8759 case TARGET_NR_sync_file_range2:
8760 /* This is like sync_file_range but the arguments are reordered */
8761#if TARGET_ABI_BITS == 32
8762 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8763 target_offset64(arg5, arg6), arg2));
8764#else
8765 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
8766#endif
8767 break;
8768#endif
8769#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00008770#if defined(CONFIG_EPOLL)
8771#if defined(TARGET_NR_epoll_create)
8772 case TARGET_NR_epoll_create:
8773 ret = get_errno(epoll_create(arg1));
8774 break;
8775#endif
8776#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
8777 case TARGET_NR_epoll_create1:
8778 ret = get_errno(epoll_create1(arg1));
8779 break;
8780#endif
8781#if defined(TARGET_NR_epoll_ctl)
8782 case TARGET_NR_epoll_ctl:
8783 {
8784 struct epoll_event ep;
8785 struct epoll_event *epp = 0;
8786 if (arg4) {
8787 struct target_epoll_event *target_ep;
8788 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
8789 goto efault;
8790 }
8791 ep.events = tswap32(target_ep->events);
8792 /* The epoll_data_t union is just opaque data to the kernel,
8793 * so we transfer all 64 bits across and need not worry what
8794 * actual data type it is.
8795 */
8796 ep.data.u64 = tswap64(target_ep->data.u64);
8797 unlock_user_struct(target_ep, arg4, 0);
8798 epp = &ep;
8799 }
8800 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
8801 break;
8802 }
8803#endif
8804
8805#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
8806#define IMPLEMENT_EPOLL_PWAIT
8807#endif
8808#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
8809#if defined(TARGET_NR_epoll_wait)
8810 case TARGET_NR_epoll_wait:
8811#endif
8812#if defined(IMPLEMENT_EPOLL_PWAIT)
8813 case TARGET_NR_epoll_pwait:
8814#endif
8815 {
8816 struct target_epoll_event *target_ep;
8817 struct epoll_event *ep;
8818 int epfd = arg1;
8819 int maxevents = arg3;
8820 int timeout = arg4;
8821
8822 target_ep = lock_user(VERIFY_WRITE, arg2,
8823 maxevents * sizeof(struct target_epoll_event), 1);
8824 if (!target_ep) {
8825 goto efault;
8826 }
8827
8828 ep = alloca(maxevents * sizeof(struct epoll_event));
8829
8830 switch (num) {
8831#if defined(IMPLEMENT_EPOLL_PWAIT)
8832 case TARGET_NR_epoll_pwait:
8833 {
8834 target_sigset_t *target_set;
8835 sigset_t _set, *set = &_set;
8836
8837 if (arg5) {
8838 target_set = lock_user(VERIFY_READ, arg5,
8839 sizeof(target_sigset_t), 1);
8840 if (!target_set) {
8841 unlock_user(target_ep, arg2, 0);
8842 goto efault;
8843 }
8844 target_to_host_sigset(set, target_set);
8845 unlock_user(target_set, arg5, 0);
8846 } else {
8847 set = NULL;
8848 }
8849
8850 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
8851 break;
8852 }
8853#endif
8854#if defined(TARGET_NR_epoll_wait)
8855 case TARGET_NR_epoll_wait:
8856 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
8857 break;
8858#endif
8859 default:
8860 ret = -TARGET_ENOSYS;
8861 }
8862 if (!is_error(ret)) {
8863 int i;
8864 for (i = 0; i < ret; i++) {
8865 target_ep[i].events = tswap32(ep[i].events);
8866 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
8867 }
8868 }
8869 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
8870 break;
8871 }
8872#endif
8873#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01008874#ifdef TARGET_NR_prlimit64
8875 case TARGET_NR_prlimit64:
8876 {
8877 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
8878 struct target_rlimit64 *target_rnew, *target_rold;
8879 struct host_rlimit64 rnew, rold, *rnewp = 0;
8880 if (arg3) {
8881 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
8882 goto efault;
8883 }
8884 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
8885 rnew.rlim_max = tswap64(target_rnew->rlim_max);
8886 unlock_user_struct(target_rnew, arg3, 0);
8887 rnewp = &rnew;
8888 }
8889
8890 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
8891 if (!is_error(ret) && arg4) {
8892 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
8893 goto efault;
8894 }
8895 target_rold->rlim_cur = tswap64(rold.rlim_cur);
8896 target_rold->rlim_max = tswap64(rold.rlim_max);
8897 unlock_user_struct(target_rold, arg4, 1);
8898 }
8899 break;
8900 }
8901#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07008902#ifdef TARGET_NR_gethostname
8903 case TARGET_NR_gethostname:
8904 {
8905 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
8906 if (name) {
8907 ret = get_errno(gethostname(name, arg2));
8908 unlock_user(name, arg1, arg2);
8909 } else {
8910 ret = -TARGET_EFAULT;
8911 }
8912 break;
8913 }
8914#endif
bellard31e31b82003-02-18 22:55:36 +00008915 default:
8916 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00008917 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00008918#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 +00008919 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00008920#endif
ths0da46a62007-10-20 20:23:07 +00008921 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00008922 break;
8923 }
bellard579a97f2007-11-11 14:26:47 +00008924fail:
bellardc573ff62004-01-04 15:51:36 +00008925#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00008926 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00008927#endif
thsb92c47c2007-11-01 00:07:38 +00008928 if(do_strace)
8929 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00008930 return ret;
bellard579a97f2007-11-11 14:26:47 +00008931efault:
8932 ret = -TARGET_EFAULT;
8933 goto fail;
bellard31e31b82003-02-18 22:55:36 +00008934}