blob: e404a32c0fb82b8a16183e49bf0ecba1d9547319 [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>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100108#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200109#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100110#include <linux/blkpg.h>
pbrookd7e40362008-05-23 16:06:43 +0000111#include "linux_loop.h"
Loïc Minierda790302009-12-29 22:06:13 +0100112#include "cpu-uname.h"
bellard31e31b82003-02-18 22:55:36 +0000113
bellard3ef693a2003-03-23 20:17:16 +0000114#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000115
pbrookd865bab2008-06-07 22:12:17 +0000116#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
117 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000118
bellard72f03902003-02-18 23:33:18 +0000119//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000120
bellard1a9353d2003-03-16 20:28:50 +0000121//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000122#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
123#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000124
bellard70a194b2003-08-11 22:20:16 +0000125
bellard70a194b2003-08-11 22:20:16 +0000126#undef _syscall0
127#undef _syscall1
128#undef _syscall2
129#undef _syscall3
130#undef _syscall4
131#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000132#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000133
bellard83fcb512006-06-14 13:37:16 +0000134#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000135static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000136{ \
137 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000138}
139
bellard83fcb512006-06-14 13:37:16 +0000140#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000141static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000142{ \
143 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000144}
145
bellard83fcb512006-06-14 13:37:16 +0000146#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000147static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000148{ \
149 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000150}
151
bellard83fcb512006-06-14 13:37:16 +0000152#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000153static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000154{ \
155 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000156}
157
bellard83fcb512006-06-14 13:37:16 +0000158#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000159static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000160{ \
161 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000162}
163
bellard83fcb512006-06-14 13:37:16 +0000164#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
165 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000166static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000167{ \
168 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000169}
bellard83fcb512006-06-14 13:37:16 +0000170
171
172#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
173 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000174static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
175 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000176{ \
177 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
178}
179
bellard70a194b2003-08-11 22:20:16 +0000180
bellard31e31b82003-02-18 22:55:36 +0000181#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000182#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000183#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000184#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000185#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000186#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000187#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000188#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000189#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000190#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000191#define __NR_sys_inotify_init __NR_inotify_init
192#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
193#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000194
Alexander Graf42a39fb2011-04-15 17:32:45 +0200195#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
196 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000197#define __NR__llseek __NR_lseek
198#endif
199
bellard72f03902003-02-18 23:33:18 +0000200#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000201_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000202#else
ths0da46a62007-10-20 20:23:07 +0000203/* This is a replacement for the host gettid() and must return a host
204 errno. */
bellard72f03902003-02-18 23:33:18 +0000205static int gettid(void) {
206 return -ENOSYS;
207}
208#endif
Peter Maydell3307e232013-06-12 16:20:21 +0100209#ifdef __NR_getdents
aurel323b3f24a2009-04-15 16:12:13 +0000210_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100211#endif
212#if !defined(__NR_getdents) || \
213 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000214_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
215#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700216#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000217_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
218 loff_t *, res, uint, wh);
219#endif
220_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
221_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
222#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
223_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
224#endif
225#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
226_syscall2(int,sys_tkill,int,tid,int,sig)
227#endif
228#ifdef __NR_exit_group
229_syscall1(int,exit_group,int,error_code)
230#endif
231#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
232_syscall1(int,set_tid_address,int *,tidptr)
233#endif
aurel323b3f24a2009-04-15 16:12:13 +0000234#if defined(TARGET_NR_futex) && defined(__NR_futex)
235_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
236 const struct timespec *,timeout,int *,uaddr2,int,val3)
237#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500238#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
239_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
240 unsigned long *, user_mask_ptr);
241#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
242_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
243 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200244_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
245 void *, arg);
aurel323b3f24a2009-04-15 16:12:13 +0000246
247static bitmask_transtbl fcntl_flags_tbl[] = {
248 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
249 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
250 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
251 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
252 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
253 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
254 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
255 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700256 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000257 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
258 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
259 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
260 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000261#if defined(O_DIRECT)
262 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
263#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700264#if defined(O_NOATIME)
265 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
266#endif
267#if defined(O_CLOEXEC)
268 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
269#endif
270#if defined(O_PATH)
271 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
272#endif
273 /* Don't terminate the list prematurely on 64-bit host+guest. */
274#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
275 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
276#endif
aurel323b3f24a2009-04-15 16:12:13 +0000277 { 0, 0, 0, 0 }
278};
279
280#define COPY_UTSNAME_FIELD(dest, src) \
281 do { \
282 /* __NEW_UTS_LEN doesn't include terminating null */ \
283 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
284 (dest)[__NEW_UTS_LEN] = '\0'; \
285 } while (0)
286
287static int sys_uname(struct new_utsname *buf)
288{
289 struct utsname uts_buf;
290
291 if (uname(&uts_buf) < 0)
292 return (-1);
293
294 /*
295 * Just in case these have some differences, we
296 * translate utsname to new_utsname (which is the
297 * struct linux kernel uses).
298 */
299
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200300 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000301 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
302 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
303 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
304 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
305 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
306#ifdef _GNU_SOURCE
307 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
308#endif
309 return (0);
310
311#undef COPY_UTSNAME_FIELD
312}
313
314static int sys_getcwd1(char *buf, size_t size)
315{
316 if (getcwd(buf, size) == NULL) {
317 /* getcwd() sets errno */
318 return (-1);
319 }
aurel32aaf4ad32009-04-16 14:17:14 +0000320 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000321}
322
aurel323b3f24a2009-04-15 16:12:13 +0000323#ifdef TARGET_NR_openat
Alexander Graff4c69012011-09-25 06:25:35 +0200324static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000325{
326 /*
327 * open(2) has extra parameter 'mode' when called with
328 * flag O_CREAT.
329 */
330 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000331 return (openat(dirfd, pathname, flags, mode));
332 }
333 return (openat(dirfd, pathname, flags));
334}
335#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300336
Peter Maydell1acae9f2013-07-02 14:04:12 +0100337#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300338#ifdef CONFIG_UTIMENSAT
339static int sys_utimensat(int dirfd, const char *pathname,
340 const struct timespec times[2], int flags)
341{
342 if (pathname == NULL)
343 return futimens(dirfd, times);
344 else
345 return utimensat(dirfd, pathname, times, flags);
346}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100347#elif defined(__NR_utimensat)
348#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000349_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
350 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100351#else
352static int sys_utimensat(int dirfd, const char *pathname,
353 const struct timespec times[2], int flags)
354{
355 errno = ENOSYS;
356 return -1;
357}
ths9007f0e2007-09-25 17:50:37 +0000358#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100359#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000360
361#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000362#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000363
aurel3239b59762008-10-01 21:46:50 +0000364#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000365static int sys_inotify_init(void)
366{
367 return (inotify_init());
368}
aurel3239b59762008-10-01 21:46:50 +0000369#endif
370#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000371static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
372{
373 return (inotify_add_watch(fd, pathname, mask));
374}
aurel3239b59762008-10-01 21:46:50 +0000375#endif
376#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000377static int sys_inotify_rm_watch(int fd, int32_t wd)
378{
aurel328690e422009-04-17 13:50:32 +0000379 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000380}
aurel3239b59762008-10-01 21:46:50 +0000381#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000382#ifdef CONFIG_INOTIFY1
383#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
384static int sys_inotify_init1(int flags)
385{
386 return (inotify_init1(flags));
387}
388#endif
389#endif
aurel323b3f24a2009-04-15 16:12:13 +0000390#else
391/* Userspace can usually survive runtime without inotify */
392#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000393#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000394#undef TARGET_NR_inotify_add_watch
395#undef TARGET_NR_inotify_rm_watch
396#endif /* CONFIG_INOTIFY */
397
Mike Frysingerd8035d42011-02-07 01:05:51 -0500398#if defined(TARGET_NR_ppoll)
399#ifndef __NR_ppoll
400# define __NR_ppoll -1
401#endif
402#define __NR_sys_ppoll __NR_ppoll
403_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
404 struct timespec *, timeout, const __sigset_t *, sigmask,
405 size_t, sigsetsize)
406#endif
bellard66fb9762003-03-23 01:06:05 +0000407
Mike Frysinger055e0902011-06-03 17:01:49 -0400408#if defined(TARGET_NR_pselect6)
409#ifndef __NR_pselect6
410# define __NR_pselect6 -1
411#endif
412#define __NR_sys_pselect6 __NR_pselect6
413_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
414 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
415#endif
416
Peter Maydell163a05a2011-06-27 17:44:52 +0100417#if defined(TARGET_NR_prlimit64)
418#ifndef __NR_prlimit64
419# define __NR_prlimit64 -1
420#endif
421#define __NR_sys_prlimit64 __NR_prlimit64
422/* The glibc rlimit structure may not be that used by the underlying syscall */
423struct host_rlimit64 {
424 uint64_t rlim_cur;
425 uint64_t rlim_max;
426};
427_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
428 const struct host_rlimit64 *, new_limit,
429 struct host_rlimit64 *, old_limit)
430#endif
431
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100432
433#if defined(TARGET_NR_timer_create)
434/* Maxiumum of 32 active POSIX timers allowed at any one time. */
435static timer_t g_posix_timers[32] = { 0, } ;
436
437static inline int next_free_host_timer(void)
438{
439 int k ;
440 /* FIXME: Does finding the next free slot require a lock? */
441 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
442 if (g_posix_timers[k] == 0) {
443 g_posix_timers[k] = (timer_t) 1;
444 return k;
445 }
446 }
447 return -1;
448}
449#endif
450
Riku Voipio48e515d2011-07-12 15:40:51 +0300451/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000452#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300453static inline int regpairs_aligned(void *cpu_env) {
454 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
455}
456#elif defined(TARGET_MIPS)
457static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000458#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
459/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
460 * of registers which translates to the same as ARM/MIPS, because we start with
461 * r3 as arg1 */
462static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300463#else
464static inline int regpairs_aligned(void *cpu_env) { return 0; }
465#endif
466
thsb92c47c2007-11-01 00:07:38 +0000467#define ERRNO_TABLE_SIZE 1200
468
469/* target_to_host_errno_table[] is initialized from
470 * host_to_target_errno_table[] in syscall_init(). */
471static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
472};
473
ths637947f2007-06-01 12:09:19 +0000474/*
thsfe8f0962007-07-12 10:59:21 +0000475 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000476 * minus the errnos that are not actually generic to all archs.
477 */
thsb92c47c2007-11-01 00:07:38 +0000478static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000479 [EIDRM] = TARGET_EIDRM,
480 [ECHRNG] = TARGET_ECHRNG,
481 [EL2NSYNC] = TARGET_EL2NSYNC,
482 [EL3HLT] = TARGET_EL3HLT,
483 [EL3RST] = TARGET_EL3RST,
484 [ELNRNG] = TARGET_ELNRNG,
485 [EUNATCH] = TARGET_EUNATCH,
486 [ENOCSI] = TARGET_ENOCSI,
487 [EL2HLT] = TARGET_EL2HLT,
488 [EDEADLK] = TARGET_EDEADLK,
489 [ENOLCK] = TARGET_ENOLCK,
490 [EBADE] = TARGET_EBADE,
491 [EBADR] = TARGET_EBADR,
492 [EXFULL] = TARGET_EXFULL,
493 [ENOANO] = TARGET_ENOANO,
494 [EBADRQC] = TARGET_EBADRQC,
495 [EBADSLT] = TARGET_EBADSLT,
496 [EBFONT] = TARGET_EBFONT,
497 [ENOSTR] = TARGET_ENOSTR,
498 [ENODATA] = TARGET_ENODATA,
499 [ETIME] = TARGET_ETIME,
500 [ENOSR] = TARGET_ENOSR,
501 [ENONET] = TARGET_ENONET,
502 [ENOPKG] = TARGET_ENOPKG,
503 [EREMOTE] = TARGET_EREMOTE,
504 [ENOLINK] = TARGET_ENOLINK,
505 [EADV] = TARGET_EADV,
506 [ESRMNT] = TARGET_ESRMNT,
507 [ECOMM] = TARGET_ECOMM,
508 [EPROTO] = TARGET_EPROTO,
509 [EDOTDOT] = TARGET_EDOTDOT,
510 [EMULTIHOP] = TARGET_EMULTIHOP,
511 [EBADMSG] = TARGET_EBADMSG,
512 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
513 [EOVERFLOW] = TARGET_EOVERFLOW,
514 [ENOTUNIQ] = TARGET_ENOTUNIQ,
515 [EBADFD] = TARGET_EBADFD,
516 [EREMCHG] = TARGET_EREMCHG,
517 [ELIBACC] = TARGET_ELIBACC,
518 [ELIBBAD] = TARGET_ELIBBAD,
519 [ELIBSCN] = TARGET_ELIBSCN,
520 [ELIBMAX] = TARGET_ELIBMAX,
521 [ELIBEXEC] = TARGET_ELIBEXEC,
522 [EILSEQ] = TARGET_EILSEQ,
523 [ENOSYS] = TARGET_ENOSYS,
524 [ELOOP] = TARGET_ELOOP,
525 [ERESTART] = TARGET_ERESTART,
526 [ESTRPIPE] = TARGET_ESTRPIPE,
527 [ENOTEMPTY] = TARGET_ENOTEMPTY,
528 [EUSERS] = TARGET_EUSERS,
529 [ENOTSOCK] = TARGET_ENOTSOCK,
530 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
531 [EMSGSIZE] = TARGET_EMSGSIZE,
532 [EPROTOTYPE] = TARGET_EPROTOTYPE,
533 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
534 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
535 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
536 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
537 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
538 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
539 [EADDRINUSE] = TARGET_EADDRINUSE,
540 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
541 [ENETDOWN] = TARGET_ENETDOWN,
542 [ENETUNREACH] = TARGET_ENETUNREACH,
543 [ENETRESET] = TARGET_ENETRESET,
544 [ECONNABORTED] = TARGET_ECONNABORTED,
545 [ECONNRESET] = TARGET_ECONNRESET,
546 [ENOBUFS] = TARGET_ENOBUFS,
547 [EISCONN] = TARGET_EISCONN,
548 [ENOTCONN] = TARGET_ENOTCONN,
549 [EUCLEAN] = TARGET_EUCLEAN,
550 [ENOTNAM] = TARGET_ENOTNAM,
551 [ENAVAIL] = TARGET_ENAVAIL,
552 [EISNAM] = TARGET_EISNAM,
553 [EREMOTEIO] = TARGET_EREMOTEIO,
554 [ESHUTDOWN] = TARGET_ESHUTDOWN,
555 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
556 [ETIMEDOUT] = TARGET_ETIMEDOUT,
557 [ECONNREFUSED] = TARGET_ECONNREFUSED,
558 [EHOSTDOWN] = TARGET_EHOSTDOWN,
559 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
560 [EALREADY] = TARGET_EALREADY,
561 [EINPROGRESS] = TARGET_EINPROGRESS,
562 [ESTALE] = TARGET_ESTALE,
563 [ECANCELED] = TARGET_ECANCELED,
564 [ENOMEDIUM] = TARGET_ENOMEDIUM,
565 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000566#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000567 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000568#endif
569#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000570 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000571#endif
572#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000573 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000574#endif
575#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000576 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000577#endif
578#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000579 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000580#endif
581#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000582 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000583#endif
thsb92c47c2007-11-01 00:07:38 +0000584};
ths637947f2007-06-01 12:09:19 +0000585
586static inline int host_to_target_errno(int err)
587{
588 if(host_to_target_errno_table[err])
589 return host_to_target_errno_table[err];
590 return err;
591}
592
thsb92c47c2007-11-01 00:07:38 +0000593static inline int target_to_host_errno(int err)
594{
595 if (target_to_host_errno_table[err])
596 return target_to_host_errno_table[err];
597 return err;
598}
599
blueswir1992f48a2007-10-14 16:27:31 +0000600static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000601{
602 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000603 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000604 else
605 return ret;
606}
607
blueswir1992f48a2007-10-14 16:27:31 +0000608static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000609{
blueswir1992f48a2007-10-14 16:27:31 +0000610 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000611}
612
thsb92c47c2007-11-01 00:07:38 +0000613char *target_strerror(int err)
614{
Alexander Graf962b2892011-11-21 12:04:07 +0100615 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
616 return NULL;
617 }
thsb92c47c2007-11-01 00:07:38 +0000618 return strerror(target_to_host_errno(err));
619}
620
blueswir1992f48a2007-10-14 16:27:31 +0000621static abi_ulong target_brk;
622static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000623static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000624
blueswir1992f48a2007-10-14 16:27:31 +0000625void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000626{
blueswir14c1de732007-07-07 20:45:44 +0000627 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000628 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000629}
630
vincent4d1de872011-06-14 21:56:33 +0000631//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
632#define DEBUGF_BRK(message, args...)
633
ths0da46a62007-10-20 20:23:07 +0000634/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000635abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000636{
blueswir1992f48a2007-10-14 16:27:31 +0000637 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000638 int new_alloc_size;
639
Paul Brook3a0c6c42012-02-09 19:04:27 +0000640 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000641
vincent4d1de872011-06-14 21:56:33 +0000642 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000643 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000644 return target_brk;
645 }
646 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000647 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
648 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000649 return target_brk;
650 }
bellard31e31b82003-02-18 22:55:36 +0000651
vincent4d1de872011-06-14 21:56:33 +0000652 /* If the new brk is less than the highest page reserved to the
653 * target heap allocation, set it and we're almost done... */
654 if (new_brk <= brk_page) {
655 /* Heap contents are initialized to zero, as for anonymous
656 * mapped pages. */
657 if (new_brk > target_brk) {
658 memset(g2h(target_brk), 0, new_brk - target_brk);
659 }
bellard31e31b82003-02-18 22:55:36 +0000660 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000661 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000662 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000663 }
664
Peter Maydell00faf082011-04-18 16:34:24 +0100665 /* We need to allocate more memory after the brk... Note that
666 * we don't use MAP_FIXED because that will map over the top of
667 * any existing mapping (like the one with the host libc or qemu
668 * itself); instead we treat "mapped but at wrong address" as
669 * a failure and unmap again.
670 */
vincent4d1de872011-06-14 21:56:33 +0000671 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000672 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000673 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100674 MAP_ANON|MAP_PRIVATE, 0, 0));
675
676 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200677 /* Heap contents are initialized to zero, as for anonymous
678 * mapped pages. Technically the new pages are already
679 * initialized to zero since they *are* anonymous mapped
680 * pages, however we have to take care with the contents that
681 * come from the remaining part of the previous page: it may
682 * contains garbage data due to a previous heap usage (grown
683 * then shrunken). */
684 memset(g2h(target_brk), 0, brk_page - target_brk);
685
Peter Maydell00faf082011-04-18 16:34:24 +0100686 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000687 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000688 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
689 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100690 return target_brk;
691 } else if (mapped_addr != -1) {
692 /* Mapped but at wrong address, meaning there wasn't actually
693 * enough space for this brk.
694 */
695 target_munmap(mapped_addr, new_alloc_size);
696 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000697 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000698 }
699 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000700 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100701 }
balrog7ab240a2008-04-26 12:17:34 +0000702
Richard Henderson7dd46c02010-05-03 10:07:49 -0700703#if defined(TARGET_ALPHA)
704 /* We (partially) emulate OSF/1 on Alpha, which requires we
705 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100706 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700707#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100708 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000709 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000710}
711
ths26edcf42007-12-09 02:25:24 +0000712static inline abi_long copy_from_user_fdset(fd_set *fds,
713 abi_ulong target_fds_addr,
714 int n)
bellard31e31b82003-02-18 22:55:36 +0000715{
ths26edcf42007-12-09 02:25:24 +0000716 int i, nw, j, k;
717 abi_ulong b, *target_fds;
718
719 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
720 if (!(target_fds = lock_user(VERIFY_READ,
721 target_fds_addr,
722 sizeof(abi_ulong) * nw,
723 1)))
724 return -TARGET_EFAULT;
725
726 FD_ZERO(fds);
727 k = 0;
728 for (i = 0; i < nw; i++) {
729 /* grab the abi_ulong */
730 __get_user(b, &target_fds[i]);
731 for (j = 0; j < TARGET_ABI_BITS; j++) {
732 /* check the bit inside the abi_ulong */
733 if ((b >> j) & 1)
734 FD_SET(k, fds);
735 k++;
bellard31e31b82003-02-18 22:55:36 +0000736 }
bellard31e31b82003-02-18 22:55:36 +0000737 }
ths26edcf42007-12-09 02:25:24 +0000738
739 unlock_user(target_fds, target_fds_addr, 0);
740
741 return 0;
bellard31e31b82003-02-18 22:55:36 +0000742}
743
Mike Frysinger055e0902011-06-03 17:01:49 -0400744static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
745 abi_ulong target_fds_addr,
746 int n)
747{
748 if (target_fds_addr) {
749 if (copy_from_user_fdset(fds, target_fds_addr, n))
750 return -TARGET_EFAULT;
751 *fds_ptr = fds;
752 } else {
753 *fds_ptr = NULL;
754 }
755 return 0;
756}
757
ths26edcf42007-12-09 02:25:24 +0000758static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
759 const fd_set *fds,
760 int n)
bellard31e31b82003-02-18 22:55:36 +0000761{
bellard31e31b82003-02-18 22:55:36 +0000762 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000763 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000764 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000765
ths26edcf42007-12-09 02:25:24 +0000766 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
767 if (!(target_fds = lock_user(VERIFY_WRITE,
768 target_fds_addr,
769 sizeof(abi_ulong) * nw,
770 0)))
771 return -TARGET_EFAULT;
772
773 k = 0;
774 for (i = 0; i < nw; i++) {
775 v = 0;
776 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000777 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000778 k++;
bellard31e31b82003-02-18 22:55:36 +0000779 }
ths26edcf42007-12-09 02:25:24 +0000780 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000781 }
ths26edcf42007-12-09 02:25:24 +0000782
783 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
784
785 return 0;
bellard31e31b82003-02-18 22:55:36 +0000786}
787
bellardc596ed12003-07-13 17:32:31 +0000788#if defined(__alpha__)
789#define HOST_HZ 1024
790#else
791#define HOST_HZ 100
792#endif
793
blueswir1992f48a2007-10-14 16:27:31 +0000794static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000795{
796#if HOST_HZ == TARGET_HZ
797 return ticks;
798#else
799 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
800#endif
801}
802
bellard579a97f2007-11-11 14:26:47 +0000803static inline abi_long host_to_target_rusage(abi_ulong target_addr,
804 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000805{
pbrook53a59602006-03-25 19:31:22 +0000806 struct target_rusage *target_rusage;
807
bellard579a97f2007-11-11 14:26:47 +0000808 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
809 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200810 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
811 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
812 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
813 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
814 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
815 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
816 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
817 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
818 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
819 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
820 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
821 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
822 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
823 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
824 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
825 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
826 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
827 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000828 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000829
830 return 0;
bellardb4091862003-05-16 15:39:34 +0000831}
832
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200833static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900834{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200835 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300836 rlim_t result;
837
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200838 target_rlim_swap = tswapal(target_rlim);
839 if (target_rlim_swap == TARGET_RLIM_INFINITY)
840 return RLIM_INFINITY;
841
842 result = target_rlim_swap;
843 if (target_rlim_swap != (rlim_t)result)
844 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300845
846 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900847}
848
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200849static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900850{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200851 abi_ulong target_rlim_swap;
852 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300853
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200854 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300855 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900856 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300857 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200858 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300859
860 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900861}
862
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300863static inline int target_to_host_resource(int code)
864{
865 switch (code) {
866 case TARGET_RLIMIT_AS:
867 return RLIMIT_AS;
868 case TARGET_RLIMIT_CORE:
869 return RLIMIT_CORE;
870 case TARGET_RLIMIT_CPU:
871 return RLIMIT_CPU;
872 case TARGET_RLIMIT_DATA:
873 return RLIMIT_DATA;
874 case TARGET_RLIMIT_FSIZE:
875 return RLIMIT_FSIZE;
876 case TARGET_RLIMIT_LOCKS:
877 return RLIMIT_LOCKS;
878 case TARGET_RLIMIT_MEMLOCK:
879 return RLIMIT_MEMLOCK;
880 case TARGET_RLIMIT_MSGQUEUE:
881 return RLIMIT_MSGQUEUE;
882 case TARGET_RLIMIT_NICE:
883 return RLIMIT_NICE;
884 case TARGET_RLIMIT_NOFILE:
885 return RLIMIT_NOFILE;
886 case TARGET_RLIMIT_NPROC:
887 return RLIMIT_NPROC;
888 case TARGET_RLIMIT_RSS:
889 return RLIMIT_RSS;
890 case TARGET_RLIMIT_RTPRIO:
891 return RLIMIT_RTPRIO;
892 case TARGET_RLIMIT_SIGPENDING:
893 return RLIMIT_SIGPENDING;
894 case TARGET_RLIMIT_STACK:
895 return RLIMIT_STACK;
896 default:
897 return code;
898 }
899}
900
ths788f5ec2007-12-09 02:37:05 +0000901static inline abi_long copy_from_user_timeval(struct timeval *tv,
902 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000903{
pbrook53a59602006-03-25 19:31:22 +0000904 struct target_timeval *target_tv;
905
ths788f5ec2007-12-09 02:37:05 +0000906 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000907 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000908
909 __get_user(tv->tv_sec, &target_tv->tv_sec);
910 __get_user(tv->tv_usec, &target_tv->tv_usec);
911
912 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000913
914 return 0;
bellard31e31b82003-02-18 22:55:36 +0000915}
916
ths788f5ec2007-12-09 02:37:05 +0000917static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
918 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000919{
pbrook53a59602006-03-25 19:31:22 +0000920 struct target_timeval *target_tv;
921
ths788f5ec2007-12-09 02:37:05 +0000922 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000923 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000924
925 __put_user(tv->tv_sec, &target_tv->tv_sec);
926 __put_user(tv->tv_usec, &target_tv->tv_usec);
927
928 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000929
930 return 0;
bellard31e31b82003-02-18 22:55:36 +0000931}
932
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700933#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
934#include <mqueue.h>
935
aurel3224e10032009-04-15 16:11:43 +0000936static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
937 abi_ulong target_mq_attr_addr)
938{
939 struct target_mq_attr *target_mq_attr;
940
941 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
942 target_mq_attr_addr, 1))
943 return -TARGET_EFAULT;
944
945 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
946 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
947 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
948 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
949
950 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
951
952 return 0;
953}
954
955static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
956 const struct mq_attr *attr)
957{
958 struct target_mq_attr *target_mq_attr;
959
960 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
961 target_mq_attr_addr, 0))
962 return -TARGET_EFAULT;
963
964 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
965 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
966 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
967 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
968
969 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
970
971 return 0;
972}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700973#endif
bellard31e31b82003-02-18 22:55:36 +0000974
Mike Frysinger055e0902011-06-03 17:01:49 -0400975#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +0000976/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000977static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +0000978 abi_ulong rfd_addr, abi_ulong wfd_addr,
979 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000980{
981 fd_set rfds, wfds, efds;
982 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
983 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +0000984 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +0000985
Mike Frysinger055e0902011-06-03 17:01:49 -0400986 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
987 if (ret) {
988 return ret;
pbrook53a59602006-03-25 19:31:22 +0000989 }
Mike Frysinger055e0902011-06-03 17:01:49 -0400990 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
991 if (ret) {
992 return ret;
pbrook53a59602006-03-25 19:31:22 +0000993 }
Mike Frysinger055e0902011-06-03 17:01:49 -0400994 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
995 if (ret) {
996 return ret;
pbrook53a59602006-03-25 19:31:22 +0000997 }
ths3b46e622007-09-17 08:09:54 +0000998
ths26edcf42007-12-09 02:25:24 +0000999 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001000 if (copy_from_user_timeval(&tv, target_tv_addr))
1001 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001002 tv_ptr = &tv;
1003 } else {
1004 tv_ptr = NULL;
1005 }
ths26edcf42007-12-09 02:25:24 +00001006
bellard31e31b82003-02-18 22:55:36 +00001007 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001008
ths26edcf42007-12-09 02:25:24 +00001009 if (!is_error(ret)) {
1010 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1011 return -TARGET_EFAULT;
1012 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1013 return -TARGET_EFAULT;
1014 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1015 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001016
ths788f5ec2007-12-09 02:37:05 +00001017 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1018 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001019 }
bellard579a97f2007-11-11 14:26:47 +00001020
bellard31e31b82003-02-18 22:55:36 +00001021 return ret;
1022}
Mike Frysinger055e0902011-06-03 17:01:49 -04001023#endif
bellard31e31b82003-02-18 22:55:36 +00001024
Riku Voipio099d6b02009-05-05 12:10:04 +03001025static abi_long do_pipe2(int host_pipe[], int flags)
1026{
1027#ifdef CONFIG_PIPE2
1028 return pipe2(host_pipe, flags);
1029#else
1030 return -ENOSYS;
1031#endif
1032}
1033
Richard Hendersonfb41a662010-05-03 10:07:52 -07001034static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1035 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001036{
1037 int host_pipe[2];
1038 abi_long ret;
1039 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1040
1041 if (is_error(ret))
1042 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001043
1044 /* Several targets have special calling conventions for the original
1045 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1046 if (!is_pipe2) {
1047#if defined(TARGET_ALPHA)
1048 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1049 return host_pipe[0];
1050#elif defined(TARGET_MIPS)
1051 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1052 return host_pipe[0];
1053#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001054 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001055 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001056#elif defined(TARGET_SPARC)
1057 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1058 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001059#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001060 }
1061
Riku Voipio099d6b02009-05-05 12:10:04 +03001062 if (put_user_s32(host_pipe[0], pipedes)
1063 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1064 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001065 return get_errno(ret);
1066}
1067
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001068static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1069 abi_ulong target_addr,
1070 socklen_t len)
1071{
1072 struct target_ip_mreqn *target_smreqn;
1073
1074 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1075 if (!target_smreqn)
1076 return -TARGET_EFAULT;
1077 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1078 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1079 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001080 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001081 unlock_user(target_smreqn, target_addr, 0);
1082
1083 return 0;
1084}
1085
bellard579a97f2007-11-11 14:26:47 +00001086static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1087 abi_ulong target_addr,
1088 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001089{
aurel32607175e2009-04-15 16:11:59 +00001090 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1091 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001092 struct target_sockaddr *target_saddr;
1093
bellard579a97f2007-11-11 14:26:47 +00001094 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1095 if (!target_saddr)
1096 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001097
1098 sa_family = tswap16(target_saddr->sa_family);
1099
1100 /* Oops. The caller might send a incomplete sun_path; sun_path
1101 * must be terminated by \0 (see the manual page), but
1102 * unfortunately it is quite common to specify sockaddr_un
1103 * length as "strlen(x->sun_path)" while it should be
1104 * "strlen(...) + 1". We'll fix that here if needed.
1105 * Linux kernel has a similar feature.
1106 */
1107
1108 if (sa_family == AF_UNIX) {
1109 if (len < unix_maxlen && len > 0) {
1110 char *cp = (char*)target_saddr;
1111
1112 if ( cp[len-1] && !cp[len] )
1113 len++;
1114 }
1115 if (len > unix_maxlen)
1116 len = unix_maxlen;
1117 }
1118
pbrook53a59602006-03-25 19:31:22 +00001119 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001120 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001121 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001122
1123 return 0;
bellard7854b052003-03-29 17:22:23 +00001124}
1125
bellard579a97f2007-11-11 14:26:47 +00001126static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1127 struct sockaddr *addr,
1128 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001129{
pbrook53a59602006-03-25 19:31:22 +00001130 struct target_sockaddr *target_saddr;
1131
bellard579a97f2007-11-11 14:26:47 +00001132 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1133 if (!target_saddr)
1134 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001135 memcpy(target_saddr, addr, len);
1136 target_saddr->sa_family = tswap16(addr->sa_family);
1137 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001138
1139 return 0;
bellard7854b052003-03-29 17:22:23 +00001140}
1141
bellard5a4a8982007-11-11 17:39:18 +00001142static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1143 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001144{
1145 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001146 abi_long msg_controllen;
1147 abi_ulong target_cmsg_addr;
1148 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001149 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001150
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001151 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001152 if (msg_controllen < sizeof (struct target_cmsghdr))
1153 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001154 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001155 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1156 if (!target_cmsg)
1157 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001158
1159 while (cmsg && target_cmsg) {
1160 void *data = CMSG_DATA(cmsg);
1161 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1162
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001163 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001164 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1165
1166 space += CMSG_SPACE(len);
1167 if (space > msgh->msg_controllen) {
1168 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001169 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001170 break;
1171 }
1172
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001173 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1174 cmsg->cmsg_level = SOL_SOCKET;
1175 } else {
1176 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1177 }
bellard7854b052003-03-29 17:22:23 +00001178 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1179 cmsg->cmsg_len = CMSG_LEN(len);
1180
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001181 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001182 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1183 memcpy(data, target_data, len);
1184 } else {
1185 int *fd = (int *)data;
1186 int *target_fd = (int *)target_data;
1187 int i, numfds = len / sizeof(int);
1188
1189 for (i = 0; i < numfds; i++)
1190 fd[i] = tswap32(target_fd[i]);
1191 }
1192
1193 cmsg = CMSG_NXTHDR(msgh, cmsg);
1194 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1195 }
bellard5a4a8982007-11-11 17:39:18 +00001196 unlock_user(target_cmsg, target_cmsg_addr, 0);
1197 the_end:
bellard7854b052003-03-29 17:22:23 +00001198 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001199 return 0;
bellard7854b052003-03-29 17:22:23 +00001200}
1201
bellard5a4a8982007-11-11 17:39:18 +00001202static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1203 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001204{
1205 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001206 abi_long msg_controllen;
1207 abi_ulong target_cmsg_addr;
1208 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001209 socklen_t space = 0;
1210
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001211 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001212 if (msg_controllen < sizeof (struct target_cmsghdr))
1213 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001214 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001215 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1216 if (!target_cmsg)
1217 return -TARGET_EFAULT;
1218
bellard7854b052003-03-29 17:22:23 +00001219 while (cmsg && target_cmsg) {
1220 void *data = CMSG_DATA(cmsg);
1221 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1222
1223 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1224
1225 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001226 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001227 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001228 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001229 break;
1230 }
1231
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001232 if (cmsg->cmsg_level == SOL_SOCKET) {
1233 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1234 } else {
1235 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1236 }
bellard7854b052003-03-29 17:22:23 +00001237 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001238 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001239
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001240 if ((cmsg->cmsg_level == SOL_SOCKET) &&
Jing Huangaebf5bc2012-07-24 14:01:42 +00001241 (cmsg->cmsg_type == SCM_RIGHTS)) {
bellard7854b052003-03-29 17:22:23 +00001242 int *fd = (int *)data;
1243 int *target_fd = (int *)target_data;
1244 int i, numfds = len / sizeof(int);
1245
1246 for (i = 0; i < numfds; i++)
1247 target_fd[i] = tswap32(fd[i]);
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001248 } else if ((cmsg->cmsg_level == SOL_SOCKET) &&
Jing Huangaebf5bc2012-07-24 14:01:42 +00001249 (cmsg->cmsg_type == SO_TIMESTAMP) &&
1250 (len == sizeof(struct timeval))) {
1251 /* copy struct timeval to target */
1252 struct timeval *tv = (struct timeval *)data;
1253 struct target_timeval *target_tv =
1254 (struct target_timeval *)target_data;
1255
1256 target_tv->tv_sec = tswapal(tv->tv_sec);
1257 target_tv->tv_usec = tswapal(tv->tv_usec);
1258 } else {
1259 gemu_log("Unsupported ancillary data: %d/%d\n",
1260 cmsg->cmsg_level, cmsg->cmsg_type);
1261 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001262 }
1263
1264 cmsg = CMSG_NXTHDR(msgh, cmsg);
1265 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1266 }
bellard5a4a8982007-11-11 17:39:18 +00001267 unlock_user(target_cmsg, target_cmsg_addr, space);
1268 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001269 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001270 return 0;
bellard7854b052003-03-29 17:22:23 +00001271}
1272
ths0da46a62007-10-20 20:23:07 +00001273/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001274static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001275 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001276{
blueswir1992f48a2007-10-14 16:27:31 +00001277 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001278 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001279 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001280 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001281
bellard8853f862004-02-22 14:57:26 +00001282 switch(level) {
1283 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001284 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001285 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001286 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001287
bellard2f619692007-11-16 10:46:05 +00001288 if (get_user_u32(val, optval_addr))
1289 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001290 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1291 break;
1292 case SOL_IP:
1293 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001294 case IP_TOS:
1295 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001296 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001297 case IP_ROUTER_ALERT:
1298 case IP_RECVOPTS:
1299 case IP_RETOPTS:
1300 case IP_PKTINFO:
1301 case IP_MTU_DISCOVER:
1302 case IP_RECVERR:
1303 case IP_RECVTOS:
1304#ifdef IP_FREEBIND
1305 case IP_FREEBIND:
1306#endif
1307 case IP_MULTICAST_TTL:
1308 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001309 val = 0;
1310 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001311 if (get_user_u32(val, optval_addr))
1312 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001313 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001314 if (get_user_u8(val, optval_addr))
1315 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001316 }
1317 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1318 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001319 case IP_ADD_MEMBERSHIP:
1320 case IP_DROP_MEMBERSHIP:
1321 if (optlen < sizeof (struct target_ip_mreq) ||
1322 optlen > sizeof (struct target_ip_mreqn))
1323 return -TARGET_EINVAL;
1324
1325 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1326 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1327 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1328 break;
1329
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001330 case IP_BLOCK_SOURCE:
1331 case IP_UNBLOCK_SOURCE:
1332 case IP_ADD_SOURCE_MEMBERSHIP:
1333 case IP_DROP_SOURCE_MEMBERSHIP:
1334 if (optlen != sizeof (struct target_ip_mreq_source))
1335 return -TARGET_EINVAL;
1336
1337 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1338 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1339 unlock_user (ip_mreq_source, optval_addr, 0);
1340 break;
1341
bellard8853f862004-02-22 14:57:26 +00001342 default:
1343 goto unimplemented;
1344 }
1345 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001346 case SOL_IPV6:
1347 switch (optname) {
1348 case IPV6_MTU_DISCOVER:
1349 case IPV6_MTU:
1350 case IPV6_V6ONLY:
1351 case IPV6_RECVPKTINFO:
1352 val = 0;
1353 if (optlen < sizeof(uint32_t)) {
1354 return -TARGET_EINVAL;
1355 }
1356 if (get_user_u32(val, optval_addr)) {
1357 return -TARGET_EFAULT;
1358 }
1359 ret = get_errno(setsockopt(sockfd, level, optname,
1360 &val, sizeof(val)));
1361 break;
1362 default:
1363 goto unimplemented;
1364 }
1365 break;
Jing Huang920394d2012-07-24 13:59:23 +00001366 case SOL_RAW:
1367 switch (optname) {
1368 case ICMP_FILTER:
1369 /* struct icmp_filter takes an u32 value */
1370 if (optlen < sizeof(uint32_t)) {
1371 return -TARGET_EINVAL;
1372 }
1373
1374 if (get_user_u32(val, optval_addr)) {
1375 return -TARGET_EFAULT;
1376 }
1377 ret = get_errno(setsockopt(sockfd, level, optname,
1378 &val, sizeof(val)));
1379 break;
1380
1381 default:
1382 goto unimplemented;
1383 }
1384 break;
bellard3532fa72006-06-24 15:06:03 +00001385 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001386 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001387 case TARGET_SO_RCVTIMEO:
1388 {
1389 struct timeval tv;
1390
1391 optname = SO_RCVTIMEO;
1392
1393set_timeout:
1394 if (optlen != sizeof(struct target_timeval)) {
1395 return -TARGET_EINVAL;
1396 }
1397
1398 if (copy_from_user_timeval(&tv, optval_addr)) {
1399 return -TARGET_EFAULT;
1400 }
1401
1402 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1403 &tv, sizeof(tv)));
1404 return ret;
1405 }
1406 case TARGET_SO_SNDTIMEO:
1407 optname = SO_SNDTIMEO;
1408 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001409 case TARGET_SO_ATTACH_FILTER:
1410 {
1411 struct target_sock_fprog *tfprog;
1412 struct target_sock_filter *tfilter;
1413 struct sock_fprog fprog;
1414 struct sock_filter *filter;
1415 int i;
1416
1417 if (optlen != sizeof(*tfprog)) {
1418 return -TARGET_EINVAL;
1419 }
1420 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
1421 return -TARGET_EFAULT;
1422 }
1423 if (!lock_user_struct(VERIFY_READ, tfilter,
1424 tswapal(tfprog->filter), 0)) {
1425 unlock_user_struct(tfprog, optval_addr, 1);
1426 return -TARGET_EFAULT;
1427 }
1428
1429 fprog.len = tswap16(tfprog->len);
1430 filter = malloc(fprog.len * sizeof(*filter));
1431 if (filter == NULL) {
1432 unlock_user_struct(tfilter, tfprog->filter, 1);
1433 unlock_user_struct(tfprog, optval_addr, 1);
1434 return -TARGET_ENOMEM;
1435 }
1436 for (i = 0; i < fprog.len; i++) {
1437 filter[i].code = tswap16(tfilter[i].code);
1438 filter[i].jt = tfilter[i].jt;
1439 filter[i].jf = tfilter[i].jf;
1440 filter[i].k = tswap32(tfilter[i].k);
1441 }
1442 fprog.filter = filter;
1443
1444 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
1445 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
1446 free(filter);
1447
1448 unlock_user_struct(tfilter, tfprog->filter, 1);
1449 unlock_user_struct(tfprog, optval_addr, 1);
1450 return ret;
1451 }
bellard8853f862004-02-22 14:57:26 +00001452 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001453 case TARGET_SO_DEBUG:
1454 optname = SO_DEBUG;
1455 break;
1456 case TARGET_SO_REUSEADDR:
1457 optname = SO_REUSEADDR;
1458 break;
1459 case TARGET_SO_TYPE:
1460 optname = SO_TYPE;
1461 break;
1462 case TARGET_SO_ERROR:
1463 optname = SO_ERROR;
1464 break;
1465 case TARGET_SO_DONTROUTE:
1466 optname = SO_DONTROUTE;
1467 break;
1468 case TARGET_SO_BROADCAST:
1469 optname = SO_BROADCAST;
1470 break;
1471 case TARGET_SO_SNDBUF:
1472 optname = SO_SNDBUF;
1473 break;
1474 case TARGET_SO_RCVBUF:
1475 optname = SO_RCVBUF;
1476 break;
1477 case TARGET_SO_KEEPALIVE:
1478 optname = SO_KEEPALIVE;
1479 break;
1480 case TARGET_SO_OOBINLINE:
1481 optname = SO_OOBINLINE;
1482 break;
1483 case TARGET_SO_NO_CHECK:
1484 optname = SO_NO_CHECK;
1485 break;
1486 case TARGET_SO_PRIORITY:
1487 optname = SO_PRIORITY;
1488 break;
bellard5e83e8e2005-03-01 22:32:06 +00001489#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001490 case TARGET_SO_BSDCOMPAT:
1491 optname = SO_BSDCOMPAT;
1492 break;
bellard5e83e8e2005-03-01 22:32:06 +00001493#endif
bellard3532fa72006-06-24 15:06:03 +00001494 case TARGET_SO_PASSCRED:
1495 optname = SO_PASSCRED;
1496 break;
1497 case TARGET_SO_TIMESTAMP:
1498 optname = SO_TIMESTAMP;
1499 break;
1500 case TARGET_SO_RCVLOWAT:
1501 optname = SO_RCVLOWAT;
1502 break;
bellard8853f862004-02-22 14:57:26 +00001503 break;
1504 default:
1505 goto unimplemented;
1506 }
bellard3532fa72006-06-24 15:06:03 +00001507 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001508 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001509
bellard2f619692007-11-16 10:46:05 +00001510 if (get_user_u32(val, optval_addr))
1511 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001512 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001513 break;
bellard7854b052003-03-29 17:22:23 +00001514 default:
bellard8853f862004-02-22 14:57:26 +00001515 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001516 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001517 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001518 }
bellard8853f862004-02-22 14:57:26 +00001519 return ret;
bellard7854b052003-03-29 17:22:23 +00001520}
1521
ths0da46a62007-10-20 20:23:07 +00001522/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001523static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001524 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001525{
blueswir1992f48a2007-10-14 16:27:31 +00001526 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001527 int len, val;
1528 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001529
1530 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001531 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001532 level = SOL_SOCKET;
1533 switch (optname) {
1534 /* These don't just return a single integer */
1535 case TARGET_SO_LINGER:
1536 case TARGET_SO_RCVTIMEO:
1537 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001538 case TARGET_SO_PEERNAME:
1539 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001540 case TARGET_SO_PEERCRED: {
1541 struct ucred cr;
1542 socklen_t crlen;
1543 struct target_ucred *tcr;
1544
1545 if (get_user_u32(len, optlen)) {
1546 return -TARGET_EFAULT;
1547 }
1548 if (len < 0) {
1549 return -TARGET_EINVAL;
1550 }
1551
1552 crlen = sizeof(cr);
1553 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1554 &cr, &crlen));
1555 if (ret < 0) {
1556 return ret;
1557 }
1558 if (len > crlen) {
1559 len = crlen;
1560 }
1561 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1562 return -TARGET_EFAULT;
1563 }
1564 __put_user(cr.pid, &tcr->pid);
1565 __put_user(cr.uid, &tcr->uid);
1566 __put_user(cr.gid, &tcr->gid);
1567 unlock_user_struct(tcr, optval_addr, 1);
1568 if (put_user_u32(len, optlen)) {
1569 return -TARGET_EFAULT;
1570 }
1571 break;
1572 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001573 /* Options with 'int' argument. */
1574 case TARGET_SO_DEBUG:
1575 optname = SO_DEBUG;
1576 goto int_case;
1577 case TARGET_SO_REUSEADDR:
1578 optname = SO_REUSEADDR;
1579 goto int_case;
1580 case TARGET_SO_TYPE:
1581 optname = SO_TYPE;
1582 goto int_case;
1583 case TARGET_SO_ERROR:
1584 optname = SO_ERROR;
1585 goto int_case;
1586 case TARGET_SO_DONTROUTE:
1587 optname = SO_DONTROUTE;
1588 goto int_case;
1589 case TARGET_SO_BROADCAST:
1590 optname = SO_BROADCAST;
1591 goto int_case;
1592 case TARGET_SO_SNDBUF:
1593 optname = SO_SNDBUF;
1594 goto int_case;
1595 case TARGET_SO_RCVBUF:
1596 optname = SO_RCVBUF;
1597 goto int_case;
1598 case TARGET_SO_KEEPALIVE:
1599 optname = SO_KEEPALIVE;
1600 goto int_case;
1601 case TARGET_SO_OOBINLINE:
1602 optname = SO_OOBINLINE;
1603 goto int_case;
1604 case TARGET_SO_NO_CHECK:
1605 optname = SO_NO_CHECK;
1606 goto int_case;
1607 case TARGET_SO_PRIORITY:
1608 optname = SO_PRIORITY;
1609 goto int_case;
1610#ifdef SO_BSDCOMPAT
1611 case TARGET_SO_BSDCOMPAT:
1612 optname = SO_BSDCOMPAT;
1613 goto int_case;
1614#endif
1615 case TARGET_SO_PASSCRED:
1616 optname = SO_PASSCRED;
1617 goto int_case;
1618 case TARGET_SO_TIMESTAMP:
1619 optname = SO_TIMESTAMP;
1620 goto int_case;
1621 case TARGET_SO_RCVLOWAT:
1622 optname = SO_RCVLOWAT;
1623 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001624 default:
bellard2efbe912005-07-23 15:10:20 +00001625 goto int_case;
1626 }
1627 break;
1628 case SOL_TCP:
1629 /* TCP options all take an 'int' value. */
1630 int_case:
bellard2f619692007-11-16 10:46:05 +00001631 if (get_user_u32(len, optlen))
1632 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001633 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001634 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001635 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001636 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1637 if (ret < 0)
1638 return ret;
bellard2efbe912005-07-23 15:10:20 +00001639 if (len > lv)
1640 len = lv;
bellard2f619692007-11-16 10:46:05 +00001641 if (len == 4) {
1642 if (put_user_u32(val, optval_addr))
1643 return -TARGET_EFAULT;
1644 } else {
1645 if (put_user_u8(val, optval_addr))
1646 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001647 }
bellard2f619692007-11-16 10:46:05 +00001648 if (put_user_u32(len, optlen))
1649 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001650 break;
1651 case SOL_IP:
1652 switch(optname) {
1653 case IP_TOS:
1654 case IP_TTL:
1655 case IP_HDRINCL:
1656 case IP_ROUTER_ALERT:
1657 case IP_RECVOPTS:
1658 case IP_RETOPTS:
1659 case IP_PKTINFO:
1660 case IP_MTU_DISCOVER:
1661 case IP_RECVERR:
1662 case IP_RECVTOS:
1663#ifdef IP_FREEBIND
1664 case IP_FREEBIND:
1665#endif
1666 case IP_MULTICAST_TTL:
1667 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001668 if (get_user_u32(len, optlen))
1669 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001670 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001671 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001672 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001673 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1674 if (ret < 0)
1675 return ret;
bellard2efbe912005-07-23 15:10:20 +00001676 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001677 len = 1;
bellard2f619692007-11-16 10:46:05 +00001678 if (put_user_u32(len, optlen)
1679 || put_user_u8(val, optval_addr))
1680 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001681 } else {
bellard2efbe912005-07-23 15:10:20 +00001682 if (len > sizeof(int))
1683 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001684 if (put_user_u32(len, optlen)
1685 || put_user_u32(val, optval_addr))
1686 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001687 }
bellard8853f862004-02-22 14:57:26 +00001688 break;
bellard2efbe912005-07-23 15:10:20 +00001689 default:
thsc02f4992007-12-18 02:39:59 +00001690 ret = -TARGET_ENOPROTOOPT;
1691 break;
bellard8853f862004-02-22 14:57:26 +00001692 }
1693 break;
1694 default:
1695 unimplemented:
1696 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1697 level, optname);
thsc02f4992007-12-18 02:39:59 +00001698 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001699 break;
1700 }
1701 return ret;
bellard7854b052003-03-29 17:22:23 +00001702}
1703
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001704static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1705 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001706{
1707 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001708 struct iovec *vec;
1709 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001710 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00001711 int err = 0;
pbrook53a59602006-03-25 19:31:22 +00001712
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001713 if (count == 0) {
1714 errno = 0;
1715 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001716 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001717 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001718 errno = EINVAL;
1719 return NULL;
1720 }
1721
1722 vec = calloc(count, sizeof(struct iovec));
1723 if (vec == NULL) {
1724 errno = ENOMEM;
1725 return NULL;
1726 }
1727
1728 target_vec = lock_user(VERIFY_READ, target_addr,
1729 count * sizeof(struct target_iovec), 1);
1730 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001731 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001732 goto fail2;
1733 }
1734
1735 /* ??? If host page size > target page size, this will result in a
1736 value larger than what we can actually support. */
1737 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1738 total_len = 0;
1739
1740 for (i = 0; i < count; i++) {
1741 abi_ulong base = tswapal(target_vec[i].iov_base);
1742 abi_long len = tswapal(target_vec[i].iov_len);
1743
1744 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001745 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001746 goto fail;
1747 } else if (len == 0) {
1748 /* Zero length pointer is ignored. */
1749 vec[i].iov_base = 0;
1750 } else {
1751 vec[i].iov_base = lock_user(type, base, len, copy);
1752 if (!vec[i].iov_base) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001753 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001754 goto fail;
1755 }
1756 if (len > max_len - total_len) {
1757 len = max_len - total_len;
1758 }
1759 }
1760 vec[i].iov_len = len;
1761 total_len += len;
1762 }
1763
1764 unlock_user(target_vec, target_addr, 0);
1765 return vec;
1766
1767 fail:
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001768 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00001769 fail2:
1770 free(vec);
1771 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001772 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001773}
1774
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001775static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1776 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001777{
1778 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00001779 int i;
1780
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001781 target_vec = lock_user(VERIFY_READ, target_addr,
1782 count * sizeof(struct target_iovec), 1);
1783 if (target_vec) {
1784 for (i = 0; i < count; i++) {
1785 abi_ulong base = tswapal(target_vec[i].iov_base);
1786 abi_long len = tswapal(target_vec[i].iov_base);
1787 if (len < 0) {
1788 break;
1789 }
balrogd732dcb2008-10-28 10:21:03 +00001790 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1791 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001792 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00001793 }
bellard579a97f2007-11-11 14:26:47 +00001794
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001795 free(vec);
pbrook53a59602006-03-25 19:31:22 +00001796}
1797
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001798static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001799{
1800 int host_type = 0;
1801 int target_type = *type;
1802
1803 switch (target_type & TARGET_SOCK_TYPE_MASK) {
1804 case TARGET_SOCK_DGRAM:
1805 host_type = SOCK_DGRAM;
1806 break;
1807 case TARGET_SOCK_STREAM:
1808 host_type = SOCK_STREAM;
1809 break;
1810 default:
1811 host_type = target_type & TARGET_SOCK_TYPE_MASK;
1812 break;
1813 }
1814 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001815#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001816 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001817#else
1818 return -TARGET_EINVAL;
1819#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001820 }
1821 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001822#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001823 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001824#elif !defined(O_NONBLOCK)
1825 return -TARGET_EINVAL;
1826#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001827 }
1828 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001829 return 0;
1830}
1831
1832/* Try to emulate socket type flags after socket creation. */
1833static int sock_flags_fixup(int fd, int target_type)
1834{
1835#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
1836 if (target_type & TARGET_SOCK_NONBLOCK) {
1837 int flags = fcntl(fd, F_GETFL);
1838 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
1839 close(fd);
1840 return -TARGET_EINVAL;
1841 }
1842 }
1843#endif
1844 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001845}
1846
ths0da46a62007-10-20 20:23:07 +00001847/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001848static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001849{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001850 int target_type = type;
1851 int ret;
1852
1853 ret = target_to_host_sock_type(&type);
1854 if (ret) {
1855 return ret;
1856 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001857
balrog12bc92a2007-10-30 21:06:14 +00001858 if (domain == PF_NETLINK)
1859 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001860 ret = get_errno(socket(domain, type, protocol));
1861 if (ret >= 0) {
1862 ret = sock_flags_fixup(ret, target_type);
1863 }
1864 return ret;
bellard3532fa72006-06-24 15:06:03 +00001865}
1866
ths0da46a62007-10-20 20:23:07 +00001867/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001868static abi_long do_bind(int sockfd, abi_ulong target_addr,
1869 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001870{
aurel328f7aeaf2009-01-30 19:47:57 +00001871 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001872 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001873
Blue Swirl38724252010-09-18 05:53:14 +00001874 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001875 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001876 }
aurel328f7aeaf2009-01-30 19:47:57 +00001877
aurel32607175e2009-04-15 16:11:59 +00001878 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001879
Arnaud Patard917507b2009-06-19 10:44:45 +03001880 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1881 if (ret)
1882 return ret;
1883
bellard3532fa72006-06-24 15:06:03 +00001884 return get_errno(bind(sockfd, addr, addrlen));
1885}
1886
ths0da46a62007-10-20 20:23:07 +00001887/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001888static abi_long do_connect(int sockfd, abi_ulong target_addr,
1889 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001890{
aurel328f7aeaf2009-01-30 19:47:57 +00001891 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001892 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001893
Blue Swirl38724252010-09-18 05:53:14 +00001894 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001895 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001896 }
aurel328f7aeaf2009-01-30 19:47:57 +00001897
1898 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001899
Arnaud Patard917507b2009-06-19 10:44:45 +03001900 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1901 if (ret)
1902 return ret;
1903
bellard3532fa72006-06-24 15:06:03 +00001904 return get_errno(connect(sockfd, addr, addrlen));
1905}
1906
Alexander Graff19e00d2014-03-02 19:36:42 +00001907/* do_sendrecvmsg_locked() Must return target values and target errnos. */
1908static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
1909 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001910{
balrog6de645c2008-10-28 10:26:29 +00001911 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001912 struct msghdr msg;
1913 int count;
1914 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001915 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001916
bellard3532fa72006-06-24 15:06:03 +00001917 if (msgp->msg_name) {
1918 msg.msg_namelen = tswap32(msgp->msg_namelen);
1919 msg.msg_name = alloca(msg.msg_namelen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001920 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001921 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001922 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001923 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03001924 }
bellard3532fa72006-06-24 15:06:03 +00001925 } else {
1926 msg.msg_name = NULL;
1927 msg.msg_namelen = 0;
1928 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001929 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00001930 msg.msg_control = alloca(msg.msg_controllen);
1931 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001932
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001933 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001934 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001935 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
1936 target_vec, count, send);
1937 if (vec == NULL) {
1938 ret = -host_to_target_errno(errno);
1939 goto out2;
1940 }
bellard3532fa72006-06-24 15:06:03 +00001941 msg.msg_iovlen = count;
1942 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001943
bellard3532fa72006-06-24 15:06:03 +00001944 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001945 ret = target_to_host_cmsg(&msg, msgp);
1946 if (ret == 0)
1947 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001948 } else {
1949 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001950 if (!is_error(ret)) {
1951 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001952 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00001953 if (!is_error(ret)) {
1954 msgp->msg_namelen = tswap32(msg.msg_namelen);
1955 if (msg.msg_name != NULL) {
1956 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
1957 msg.msg_name, msg.msg_namelen);
1958 if (ret) {
1959 goto out;
1960 }
1961 }
1962
balrog6de645c2008-10-28 10:26:29 +00001963 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00001964 }
balrog6de645c2008-10-28 10:26:29 +00001965 }
bellard3532fa72006-06-24 15:06:03 +00001966 }
Jing Huangca619062012-07-24 13:58:02 +00001967
1968out:
bellard3532fa72006-06-24 15:06:03 +00001969 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001970out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00001971 return ret;
1972}
1973
1974static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1975 int flags, int send)
1976{
1977 abi_long ret;
1978 struct target_msghdr *msgp;
1979
1980 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1981 msgp,
1982 target_msg,
1983 send ? 1 : 0)) {
1984 return -TARGET_EFAULT;
1985 }
1986 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00001987 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001988 return ret;
1989}
1990
Alexander Graff19e00d2014-03-02 19:36:42 +00001991#ifdef TARGET_NR_sendmmsg
1992/* We don't rely on the C library to have sendmmsg/recvmmsg support,
1993 * so it might not have this *mmsg-specific flag either.
1994 */
1995#ifndef MSG_WAITFORONE
1996#define MSG_WAITFORONE 0x10000
1997#endif
1998
1999static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2000 unsigned int vlen, unsigned int flags,
2001 int send)
2002{
2003 struct target_mmsghdr *mmsgp;
2004 abi_long ret = 0;
2005 int i;
2006
2007 if (vlen > UIO_MAXIOV) {
2008 vlen = UIO_MAXIOV;
2009 }
2010
2011 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2012 if (!mmsgp) {
2013 return -TARGET_EFAULT;
2014 }
2015
2016 for (i = 0; i < vlen; i++) {
2017 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2018 if (is_error(ret)) {
2019 break;
2020 }
2021 mmsgp[i].msg_len = tswap32(ret);
2022 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2023 if (flags & MSG_WAITFORONE) {
2024 flags |= MSG_DONTWAIT;
2025 }
2026 }
2027
2028 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
2029
2030 /* Return number of datagrams sent if we sent any at all;
2031 * otherwise return the error.
2032 */
2033 if (i) {
2034 return i;
2035 }
2036 return ret;
2037}
2038#endif
2039
Peter Maydella94b4982013-02-08 04:35:04 +00002040/* If we don't have a system accept4() then just call accept.
2041 * The callsites to do_accept4() will ensure that they don't
2042 * pass a non-zero flags argument in this config.
2043 */
2044#ifndef CONFIG_ACCEPT4
2045static inline int accept4(int sockfd, struct sockaddr *addr,
2046 socklen_t *addrlen, int flags)
2047{
2048 assert(flags == 0);
2049 return accept(sockfd, addr, addrlen);
2050}
2051#endif
2052
2053/* do_accept4() Must return target values and target errnos. */
2054static abi_long do_accept4(int fd, abi_ulong target_addr,
2055 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002056{
bellard2f619692007-11-16 10:46:05 +00002057 socklen_t addrlen;
2058 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002059 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002060
Peter Maydella94b4982013-02-08 04:35:04 +00002061 if (target_addr == 0) {
2062 return get_errno(accept4(fd, NULL, NULL, flags));
2063 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002064
2065 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002066 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002067 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002068
Blue Swirl38724252010-09-18 05:53:14 +00002069 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002070 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002071 }
aurel328f7aeaf2009-01-30 19:47:57 +00002072
Arnaud Patard917507b2009-06-19 10:44:45 +03002073 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2074 return -TARGET_EINVAL;
2075
bellard2f619692007-11-16 10:46:05 +00002076 addr = alloca(addrlen);
2077
Peter Maydella94b4982013-02-08 04:35:04 +00002078 ret = get_errno(accept4(fd, addr, &addrlen, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002079 if (!is_error(ret)) {
2080 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002081 if (put_user_u32(addrlen, target_addrlen_addr))
2082 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002083 }
2084 return ret;
2085}
2086
ths0da46a62007-10-20 20:23:07 +00002087/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002088static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002089 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002090{
bellard2f619692007-11-16 10:46:05 +00002091 socklen_t addrlen;
2092 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002093 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002094
bellard2f619692007-11-16 10:46:05 +00002095 if (get_user_u32(addrlen, target_addrlen_addr))
2096 return -TARGET_EFAULT;
2097
Blue Swirl38724252010-09-18 05:53:14 +00002098 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002099 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002100 }
aurel328f7aeaf2009-01-30 19:47:57 +00002101
Arnaud Patard917507b2009-06-19 10:44:45 +03002102 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2103 return -TARGET_EFAULT;
2104
bellard2f619692007-11-16 10:46:05 +00002105 addr = alloca(addrlen);
2106
pbrook1be9e1d2006-11-19 15:26:04 +00002107 ret = get_errno(getpeername(fd, addr, &addrlen));
2108 if (!is_error(ret)) {
2109 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002110 if (put_user_u32(addrlen, target_addrlen_addr))
2111 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002112 }
2113 return ret;
2114}
2115
ths0da46a62007-10-20 20:23:07 +00002116/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002117static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002118 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002119{
bellard2f619692007-11-16 10:46:05 +00002120 socklen_t addrlen;
2121 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002122 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002123
bellard2f619692007-11-16 10:46:05 +00002124 if (get_user_u32(addrlen, target_addrlen_addr))
2125 return -TARGET_EFAULT;
2126
Blue Swirl38724252010-09-18 05:53:14 +00002127 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002128 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002129 }
aurel328f7aeaf2009-01-30 19:47:57 +00002130
Arnaud Patard917507b2009-06-19 10:44:45 +03002131 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2132 return -TARGET_EFAULT;
2133
bellard2f619692007-11-16 10:46:05 +00002134 addr = alloca(addrlen);
2135
pbrook1be9e1d2006-11-19 15:26:04 +00002136 ret = get_errno(getsockname(fd, addr, &addrlen));
2137 if (!is_error(ret)) {
2138 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002139 if (put_user_u32(addrlen, target_addrlen_addr))
2140 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002141 }
2142 return ret;
2143}
2144
ths0da46a62007-10-20 20:23:07 +00002145/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002146static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002147 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002148{
2149 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002150 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002151
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002152 target_to_host_sock_type(&type);
2153
pbrook1be9e1d2006-11-19 15:26:04 +00002154 ret = get_errno(socketpair(domain, type, protocol, tab));
2155 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002156 if (put_user_s32(tab[0], target_tab_addr)
2157 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2158 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002159 }
2160 return ret;
2161}
2162
ths0da46a62007-10-20 20:23:07 +00002163/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002164static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2165 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002166{
2167 void *addr;
2168 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002169 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002170
Blue Swirl38724252010-09-18 05:53:14 +00002171 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002172 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002173 }
aurel328f7aeaf2009-01-30 19:47:57 +00002174
bellard579a97f2007-11-11 14:26:47 +00002175 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2176 if (!host_msg)
2177 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002178 if (target_addr) {
2179 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002180 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2181 if (ret) {
2182 unlock_user(host_msg, msg, 0);
2183 return ret;
2184 }
pbrook1be9e1d2006-11-19 15:26:04 +00002185 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2186 } else {
2187 ret = get_errno(send(fd, host_msg, len, flags));
2188 }
2189 unlock_user(host_msg, msg, 0);
2190 return ret;
2191}
2192
ths0da46a62007-10-20 20:23:07 +00002193/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002194static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2195 abi_ulong target_addr,
2196 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002197{
2198 socklen_t addrlen;
2199 void *addr;
2200 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002201 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002202
bellard579a97f2007-11-11 14:26:47 +00002203 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2204 if (!host_msg)
2205 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002206 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002207 if (get_user_u32(addrlen, target_addrlen)) {
2208 ret = -TARGET_EFAULT;
2209 goto fail;
2210 }
Blue Swirl38724252010-09-18 05:53:14 +00002211 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002212 ret = -TARGET_EINVAL;
2213 goto fail;
2214 }
pbrook1be9e1d2006-11-19 15:26:04 +00002215 addr = alloca(addrlen);
2216 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2217 } else {
2218 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002219 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002220 }
2221 if (!is_error(ret)) {
2222 if (target_addr) {
2223 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002224 if (put_user_u32(addrlen, target_addrlen)) {
2225 ret = -TARGET_EFAULT;
2226 goto fail;
2227 }
pbrook1be9e1d2006-11-19 15:26:04 +00002228 }
2229 unlock_user(host_msg, msg, len);
2230 } else {
bellard2f619692007-11-16 10:46:05 +00002231fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002232 unlock_user(host_msg, msg, 0);
2233 }
2234 return ret;
2235}
2236
j_mayer32407102007-09-26 23:01:49 +00002237#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002238/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002239static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002240{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002241 static const unsigned ac[] = { /* number of arguments per call */
2242 [SOCKOP_socket] = 3, /* domain, type, protocol */
2243 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
2244 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
2245 [SOCKOP_listen] = 2, /* sockfd, backlog */
2246 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
2247 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
2248 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
2249 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
2250 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
2251 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
2252 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
2253 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2254 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2255 [SOCKOP_shutdown] = 2, /* sockfd, how */
2256 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
2257 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
2258 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2259 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2260 };
2261 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00002262
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002263 /* first, collect the arguments in a[] according to ac[] */
2264 if (num >= 0 && num < ARRAY_SIZE(ac)) {
2265 unsigned i;
2266 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
2267 for (i = 0; i < ac[num]; ++i) {
2268 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01002269 return -TARGET_EFAULT;
2270 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01002271 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002272 }
bellard2f619692007-11-16 10:46:05 +00002273
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002274 /* now when we have the args, actually handle the call */
2275 switch (num) {
2276 case SOCKOP_socket: /* domain, type, protocol */
2277 return do_socket(a[0], a[1], a[2]);
2278 case SOCKOP_bind: /* sockfd, addr, addrlen */
2279 return do_bind(a[0], a[1], a[2]);
2280 case SOCKOP_connect: /* sockfd, addr, addrlen */
2281 return do_connect(a[0], a[1], a[2]);
2282 case SOCKOP_listen: /* sockfd, backlog */
2283 return get_errno(listen(a[0], a[1]));
2284 case SOCKOP_accept: /* sockfd, addr, addrlen */
2285 return do_accept4(a[0], a[1], a[2], 0);
2286 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
2287 return do_accept4(a[0], a[1], a[2], a[3]);
2288 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
2289 return do_getsockname(a[0], a[1], a[2]);
2290 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
2291 return do_getpeername(a[0], a[1], a[2]);
2292 case SOCKOP_socketpair: /* domain, type, protocol, tab */
2293 return do_socketpair(a[0], a[1], a[2], a[3]);
2294 case SOCKOP_send: /* sockfd, msg, len, flags */
2295 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
2296 case SOCKOP_recv: /* sockfd, msg, len, flags */
2297 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
2298 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
2299 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
2300 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
2301 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
2302 case SOCKOP_shutdown: /* sockfd, how */
2303 return get_errno(shutdown(a[0], a[1]));
2304 case SOCKOP_sendmsg: /* sockfd, msg, flags */
2305 return do_sendrecvmsg(a[0], a[1], a[2], 1);
2306 case SOCKOP_recvmsg: /* sockfd, msg, flags */
2307 return do_sendrecvmsg(a[0], a[1], a[2], 0);
2308 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
2309 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
2310 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
2311 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00002312 default:
2313 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002314 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002315 }
bellard31e31b82003-02-18 22:55:36 +00002316}
j_mayer32407102007-09-26 23:01:49 +00002317#endif
bellard31e31b82003-02-18 22:55:36 +00002318
bellard8853f862004-02-22 14:57:26 +00002319#define N_SHM_REGIONS 32
2320
2321static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002322 abi_ulong start;
2323 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002324} shm_regions[N_SHM_REGIONS];
2325
ths3eb6b042007-06-03 14:26:27 +00002326struct target_semid_ds
2327{
2328 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002329 abi_ulong sem_otime;
2330 abi_ulong __unused1;
2331 abi_ulong sem_ctime;
2332 abi_ulong __unused2;
2333 abi_ulong sem_nsems;
2334 abi_ulong __unused3;
2335 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002336};
2337
bellard579a97f2007-11-11 14:26:47 +00002338static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2339 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002340{
2341 struct target_ipc_perm *target_ip;
2342 struct target_semid_ds *target_sd;
2343
bellard579a97f2007-11-11 14:26:47 +00002344 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2345 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002346 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002347 host_ip->__key = tswap32(target_ip->__key);
2348 host_ip->uid = tswap32(target_ip->uid);
2349 host_ip->gid = tswap32(target_ip->gid);
2350 host_ip->cuid = tswap32(target_ip->cuid);
2351 host_ip->cgid = tswap32(target_ip->cgid);
2352#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2353 host_ip->mode = tswap32(target_ip->mode);
2354#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002355 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002356#endif
2357#if defined(TARGET_PPC)
2358 host_ip->__seq = tswap32(target_ip->__seq);
2359#else
2360 host_ip->__seq = tswap16(target_ip->__seq);
2361#endif
ths3eb6b042007-06-03 14:26:27 +00002362 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002363 return 0;
ths3eb6b042007-06-03 14:26:27 +00002364}
2365
bellard579a97f2007-11-11 14:26:47 +00002366static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2367 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002368{
2369 struct target_ipc_perm *target_ip;
2370 struct target_semid_ds *target_sd;
2371
bellard579a97f2007-11-11 14:26:47 +00002372 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2373 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002374 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002375 target_ip->__key = tswap32(host_ip->__key);
2376 target_ip->uid = tswap32(host_ip->uid);
2377 target_ip->gid = tswap32(host_ip->gid);
2378 target_ip->cuid = tswap32(host_ip->cuid);
2379 target_ip->cgid = tswap32(host_ip->cgid);
2380#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2381 target_ip->mode = tswap32(host_ip->mode);
2382#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002383 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002384#endif
2385#if defined(TARGET_PPC)
2386 target_ip->__seq = tswap32(host_ip->__seq);
2387#else
2388 target_ip->__seq = tswap16(host_ip->__seq);
2389#endif
ths3eb6b042007-06-03 14:26:27 +00002390 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002391 return 0;
ths3eb6b042007-06-03 14:26:27 +00002392}
2393
bellard579a97f2007-11-11 14:26:47 +00002394static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2395 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002396{
2397 struct target_semid_ds *target_sd;
2398
bellard579a97f2007-11-11 14:26:47 +00002399 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2400 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002401 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2402 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002403 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2404 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2405 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002406 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002407 return 0;
ths3eb6b042007-06-03 14:26:27 +00002408}
2409
bellard579a97f2007-11-11 14:26:47 +00002410static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2411 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002412{
2413 struct target_semid_ds *target_sd;
2414
bellard579a97f2007-11-11 14:26:47 +00002415 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2416 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002417 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002418 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002419 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2420 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2421 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002422 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002423 return 0;
ths3eb6b042007-06-03 14:26:27 +00002424}
2425
aurel32e5289082009-04-18 16:16:12 +00002426struct target_seminfo {
2427 int semmap;
2428 int semmni;
2429 int semmns;
2430 int semmnu;
2431 int semmsl;
2432 int semopm;
2433 int semume;
2434 int semusz;
2435 int semvmx;
2436 int semaem;
2437};
2438
2439static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2440 struct seminfo *host_seminfo)
2441{
2442 struct target_seminfo *target_seminfo;
2443 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2444 return -TARGET_EFAULT;
2445 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2446 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2447 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2448 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2449 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2450 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2451 __put_user(host_seminfo->semume, &target_seminfo->semume);
2452 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2453 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2454 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2455 unlock_user_struct(target_seminfo, target_addr, 1);
2456 return 0;
2457}
2458
thsfa294812007-02-02 22:05:00 +00002459union semun {
2460 int val;
ths3eb6b042007-06-03 14:26:27 +00002461 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002462 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002463 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002464};
2465
ths3eb6b042007-06-03 14:26:27 +00002466union target_semun {
2467 int val;
aurel32e5289082009-04-18 16:16:12 +00002468 abi_ulong buf;
2469 abi_ulong array;
2470 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002471};
2472
aurel32e5289082009-04-18 16:16:12 +00002473static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2474 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002475{
aurel32e5289082009-04-18 16:16:12 +00002476 int nsems;
2477 unsigned short *array;
2478 union semun semun;
2479 struct semid_ds semid_ds;
2480 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002481
aurel32e5289082009-04-18 16:16:12 +00002482 semun.buf = &semid_ds;
2483
2484 ret = semctl(semid, 0, IPC_STAT, semun);
2485 if (ret == -1)
2486 return get_errno(ret);
2487
2488 nsems = semid_ds.sem_nsems;
2489
2490 *host_array = malloc(nsems*sizeof(unsigned short));
Peter Maydell69d4c702014-02-17 18:55:34 +00002491 if (!*host_array) {
2492 return -TARGET_ENOMEM;
2493 }
aurel32e5289082009-04-18 16:16:12 +00002494 array = lock_user(VERIFY_READ, target_addr,
2495 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00002496 if (!array) {
2497 free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002498 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00002499 }
aurel32e5289082009-04-18 16:16:12 +00002500
2501 for(i=0; i<nsems; i++) {
2502 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002503 }
aurel32e5289082009-04-18 16:16:12 +00002504 unlock_user(array, target_addr, 0);
2505
bellard579a97f2007-11-11 14:26:47 +00002506 return 0;
ths3eb6b042007-06-03 14:26:27 +00002507}
2508
aurel32e5289082009-04-18 16:16:12 +00002509static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2510 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002511{
aurel32e5289082009-04-18 16:16:12 +00002512 int nsems;
2513 unsigned short *array;
2514 union semun semun;
2515 struct semid_ds semid_ds;
2516 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002517
aurel32e5289082009-04-18 16:16:12 +00002518 semun.buf = &semid_ds;
2519
2520 ret = semctl(semid, 0, IPC_STAT, semun);
2521 if (ret == -1)
2522 return get_errno(ret);
2523
2524 nsems = semid_ds.sem_nsems;
2525
2526 array = lock_user(VERIFY_WRITE, target_addr,
2527 nsems*sizeof(unsigned short), 0);
2528 if (!array)
2529 return -TARGET_EFAULT;
2530
2531 for(i=0; i<nsems; i++) {
2532 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002533 }
aurel32e5289082009-04-18 16:16:12 +00002534 free(*host_array);
2535 unlock_user(array, target_addr, 1);
2536
bellard579a97f2007-11-11 14:26:47 +00002537 return 0;
ths3eb6b042007-06-03 14:26:27 +00002538}
2539
aurel32e5289082009-04-18 16:16:12 +00002540static inline abi_long do_semctl(int semid, int semnum, int cmd,
2541 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002542{
2543 union semun arg;
2544 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302545 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002546 struct seminfo seminfo;
2547 abi_long ret = -TARGET_EINVAL;
2548 abi_long err;
2549 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002550
2551 switch( cmd ) {
2552 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002553 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002554 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002555 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002556 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002557 break;
2558 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002559 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002560 err = target_to_host_semarray(semid, &array, target_su.array);
2561 if (err)
2562 return err;
2563 arg.array = array;
2564 ret = get_errno(semctl(semid, semnum, cmd, arg));
2565 err = host_to_target_semarray(semid, target_su.array, &array);
2566 if (err)
2567 return err;
ths3eb6b042007-06-03 14:26:27 +00002568 break;
2569 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002570 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002571 case SEM_STAT:
2572 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2573 if (err)
2574 return err;
2575 arg.buf = &dsarg;
2576 ret = get_errno(semctl(semid, semnum, cmd, arg));
2577 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2578 if (err)
2579 return err;
ths3eb6b042007-06-03 14:26:27 +00002580 break;
aurel32e5289082009-04-18 16:16:12 +00002581 case IPC_INFO:
2582 case SEM_INFO:
2583 arg.__buf = &seminfo;
2584 ret = get_errno(semctl(semid, semnum, cmd, arg));
2585 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2586 if (err)
2587 return err;
2588 break;
2589 case IPC_RMID:
2590 case GETPID:
2591 case GETNCNT:
2592 case GETZCNT:
2593 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2594 break;
ths3eb6b042007-06-03 14:26:27 +00002595 }
2596
2597 return ret;
2598}
2599
aurel32e5289082009-04-18 16:16:12 +00002600struct target_sembuf {
2601 unsigned short sem_num;
2602 short sem_op;
2603 short sem_flg;
2604};
2605
2606static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2607 abi_ulong target_addr,
2608 unsigned nsops)
2609{
2610 struct target_sembuf *target_sembuf;
2611 int i;
2612
2613 target_sembuf = lock_user(VERIFY_READ, target_addr,
2614 nsops*sizeof(struct target_sembuf), 1);
2615 if (!target_sembuf)
2616 return -TARGET_EFAULT;
2617
2618 for(i=0; i<nsops; i++) {
2619 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2620 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2621 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2622 }
2623
2624 unlock_user(target_sembuf, target_addr, 0);
2625
2626 return 0;
2627}
2628
2629static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2630{
2631 struct sembuf sops[nsops];
2632
2633 if (target_to_host_sembuf(sops, ptr, nsops))
2634 return -TARGET_EFAULT;
2635
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002636 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002637}
2638
ths1bc012f2007-06-03 14:27:49 +00002639struct target_msqid_ds
2640{
aurel321c54ff92008-10-13 21:08:44 +00002641 struct target_ipc_perm msg_perm;
2642 abi_ulong msg_stime;
2643#if TARGET_ABI_BITS == 32
2644 abi_ulong __unused1;
2645#endif
2646 abi_ulong msg_rtime;
2647#if TARGET_ABI_BITS == 32
2648 abi_ulong __unused2;
2649#endif
2650 abi_ulong msg_ctime;
2651#if TARGET_ABI_BITS == 32
2652 abi_ulong __unused3;
2653#endif
2654 abi_ulong __msg_cbytes;
2655 abi_ulong msg_qnum;
2656 abi_ulong msg_qbytes;
2657 abi_ulong msg_lspid;
2658 abi_ulong msg_lrpid;
2659 abi_ulong __unused4;
2660 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002661};
2662
bellard579a97f2007-11-11 14:26:47 +00002663static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2664 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002665{
2666 struct target_msqid_ds *target_md;
2667
bellard579a97f2007-11-11 14:26:47 +00002668 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2669 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002670 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2671 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002672 host_md->msg_stime = tswapal(target_md->msg_stime);
2673 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2674 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2675 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2676 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2677 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2678 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2679 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002680 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002681 return 0;
ths1bc012f2007-06-03 14:27:49 +00002682}
2683
bellard579a97f2007-11-11 14:26:47 +00002684static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2685 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002686{
2687 struct target_msqid_ds *target_md;
2688
bellard579a97f2007-11-11 14:26:47 +00002689 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2690 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002691 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2692 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002693 target_md->msg_stime = tswapal(host_md->msg_stime);
2694 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2695 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2696 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2697 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2698 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2699 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2700 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002701 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002702 return 0;
ths1bc012f2007-06-03 14:27:49 +00002703}
2704
aurel321c54ff92008-10-13 21:08:44 +00002705struct target_msginfo {
2706 int msgpool;
2707 int msgmap;
2708 int msgmax;
2709 int msgmnb;
2710 int msgmni;
2711 int msgssz;
2712 int msgtql;
2713 unsigned short int msgseg;
2714};
2715
2716static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2717 struct msginfo *host_msginfo)
2718{
2719 struct target_msginfo *target_msginfo;
2720 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2721 return -TARGET_EFAULT;
2722 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2723 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2724 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2725 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2726 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2727 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2728 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2729 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2730 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002731 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002732}
2733
2734static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002735{
2736 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002737 struct msginfo msginfo;
2738 abi_long ret = -TARGET_EINVAL;
2739
2740 cmd &= 0xff;
2741
2742 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002743 case IPC_STAT:
2744 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002745 case MSG_STAT:
2746 if (target_to_host_msqid_ds(&dsarg,ptr))
2747 return -TARGET_EFAULT;
2748 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2749 if (host_to_target_msqid_ds(ptr,&dsarg))
2750 return -TARGET_EFAULT;
2751 break;
2752 case IPC_RMID:
2753 ret = get_errno(msgctl(msgid, cmd, NULL));
2754 break;
2755 case IPC_INFO:
2756 case MSG_INFO:
2757 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2758 if (host_to_target_msginfo(ptr, &msginfo))
2759 return -TARGET_EFAULT;
2760 break;
ths1bc012f2007-06-03 14:27:49 +00002761 }
aurel321c54ff92008-10-13 21:08:44 +00002762
ths1bc012f2007-06-03 14:27:49 +00002763 return ret;
2764}
2765
2766struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002767 abi_long mtype;
2768 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002769};
2770
blueswir1992f48a2007-10-14 16:27:31 +00002771static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2772 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002773{
2774 struct target_msgbuf *target_mb;
2775 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002776 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002777
bellard579a97f2007-11-11 14:26:47 +00002778 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2779 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002780 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002781 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002782 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002783 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2784 free(host_mb);
2785 unlock_user_struct(target_mb, msgp, 0);
2786
2787 return ret;
2788}
2789
blueswir1992f48a2007-10-14 16:27:31 +00002790static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002791 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002792 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002793{
2794 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002795 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002796 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002797 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002798
bellard579a97f2007-11-11 14:26:47 +00002799 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2800 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002801
Jim Meyering0d07fe42012-08-22 13:55:53 +02002802 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00002803 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002804
bellard579a97f2007-11-11 14:26:47 +00002805 if (ret > 0) {
2806 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2807 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2808 if (!target_mtext) {
2809 ret = -TARGET_EFAULT;
2810 goto end;
2811 }
aurel321c54ff92008-10-13 21:08:44 +00002812 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002813 unlock_user(target_mtext, target_mtext_addr, ret);
2814 }
aurel321c54ff92008-10-13 21:08:44 +00002815
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002816 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002817
bellard579a97f2007-11-11 14:26:47 +00002818end:
2819 if (target_mb)
2820 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02002821 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002822 return ret;
2823}
2824
Riku Voipio88a8c982009-04-03 10:42:00 +03002825static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2826 abi_ulong target_addr)
2827{
2828 struct target_shmid_ds *target_sd;
2829
2830 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2831 return -TARGET_EFAULT;
2832 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2833 return -TARGET_EFAULT;
2834 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2835 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2836 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2837 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2838 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2839 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2840 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2841 unlock_user_struct(target_sd, target_addr, 0);
2842 return 0;
2843}
2844
2845static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2846 struct shmid_ds *host_sd)
2847{
2848 struct target_shmid_ds *target_sd;
2849
2850 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2851 return -TARGET_EFAULT;
2852 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2853 return -TARGET_EFAULT;
2854 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2855 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2856 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2857 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2858 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2859 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2860 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2861 unlock_user_struct(target_sd, target_addr, 1);
2862 return 0;
2863}
2864
2865struct target_shminfo {
2866 abi_ulong shmmax;
2867 abi_ulong shmmin;
2868 abi_ulong shmmni;
2869 abi_ulong shmseg;
2870 abi_ulong shmall;
2871};
2872
2873static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2874 struct shminfo *host_shminfo)
2875{
2876 struct target_shminfo *target_shminfo;
2877 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2878 return -TARGET_EFAULT;
2879 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2880 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2881 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2882 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2883 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2884 unlock_user_struct(target_shminfo, target_addr, 1);
2885 return 0;
2886}
2887
2888struct target_shm_info {
2889 int used_ids;
2890 abi_ulong shm_tot;
2891 abi_ulong shm_rss;
2892 abi_ulong shm_swp;
2893 abi_ulong swap_attempts;
2894 abi_ulong swap_successes;
2895};
2896
2897static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2898 struct shm_info *host_shm_info)
2899{
2900 struct target_shm_info *target_shm_info;
2901 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2902 return -TARGET_EFAULT;
2903 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2904 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2905 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2906 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2907 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2908 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
2909 unlock_user_struct(target_shm_info, target_addr, 1);
2910 return 0;
2911}
2912
2913static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
2914{
2915 struct shmid_ds dsarg;
2916 struct shminfo shminfo;
2917 struct shm_info shm_info;
2918 abi_long ret = -TARGET_EINVAL;
2919
2920 cmd &= 0xff;
2921
2922 switch(cmd) {
2923 case IPC_STAT:
2924 case IPC_SET:
2925 case SHM_STAT:
2926 if (target_to_host_shmid_ds(&dsarg, buf))
2927 return -TARGET_EFAULT;
2928 ret = get_errno(shmctl(shmid, cmd, &dsarg));
2929 if (host_to_target_shmid_ds(buf, &dsarg))
2930 return -TARGET_EFAULT;
2931 break;
2932 case IPC_INFO:
2933 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
2934 if (host_to_target_shminfo(buf, &shminfo))
2935 return -TARGET_EFAULT;
2936 break;
2937 case SHM_INFO:
2938 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
2939 if (host_to_target_shm_info(buf, &shm_info))
2940 return -TARGET_EFAULT;
2941 break;
2942 case IPC_RMID:
2943 case SHM_LOCK:
2944 case SHM_UNLOCK:
2945 ret = get_errno(shmctl(shmid, cmd, NULL));
2946 break;
2947 }
2948
2949 return ret;
2950}
2951
2952static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
2953{
2954 abi_long raddr;
2955 void *host_raddr;
2956 struct shmid_ds shm_info;
2957 int i,ret;
2958
2959 /* find out the length of the shared memory segment */
2960 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
2961 if (is_error(ret)) {
2962 /* can't get length, bail out */
2963 return ret;
2964 }
2965
2966 mmap_lock();
2967
2968 if (shmaddr)
2969 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
2970 else {
2971 abi_ulong mmap_start;
2972
2973 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
2974
2975 if (mmap_start == -1) {
2976 errno = ENOMEM;
2977 host_raddr = (void *)-1;
2978 } else
2979 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
2980 }
2981
2982 if (host_raddr == (void *)-1) {
2983 mmap_unlock();
2984 return get_errno((long)host_raddr);
2985 }
2986 raddr=h2g((unsigned long)host_raddr);
2987
2988 page_set_flags(raddr, raddr + shm_info.shm_segsz,
2989 PAGE_VALID | PAGE_READ |
2990 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
2991
2992 for (i = 0; i < N_SHM_REGIONS; i++) {
2993 if (shm_regions[i].start == 0) {
2994 shm_regions[i].start = raddr;
2995 shm_regions[i].size = shm_info.shm_segsz;
2996 break;
2997 }
2998 }
2999
3000 mmap_unlock();
3001 return raddr;
3002
3003}
3004
3005static inline abi_long do_shmdt(abi_ulong shmaddr)
3006{
3007 int i;
3008
3009 for (i = 0; i < N_SHM_REGIONS; ++i) {
3010 if (shm_regions[i].start == shmaddr) {
3011 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003012 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003013 break;
3014 }
3015 }
3016
3017 return get_errno(shmdt(g2h(shmaddr)));
3018}
3019
aurel321c54ff92008-10-13 21:08:44 +00003020#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003021/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003022/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003023static abi_long do_ipc(unsigned int call, int first,
3024 int second, int third,
3025 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003026{
3027 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003028 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003029
3030 version = call >> 16;
3031 call &= 0xffff;
3032
3033 switch (call) {
thsfa294812007-02-02 22:05:00 +00003034 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003035 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003036 break;
3037
3038 case IPCOP_semget:
3039 ret = get_errno(semget(first, second, third));
3040 break;
3041
3042 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003043 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003044 break;
thsd96372e2007-02-02 22:05:44 +00003045
aurel321c54ff92008-10-13 21:08:44 +00003046 case IPCOP_msgget:
3047 ret = get_errno(msgget(first, second));
3048 break;
thsd96372e2007-02-02 22:05:44 +00003049
aurel321c54ff92008-10-13 21:08:44 +00003050 case IPCOP_msgsnd:
3051 ret = do_msgsnd(first, ptr, second, third);
3052 break;
thsd96372e2007-02-02 22:05:44 +00003053
aurel321c54ff92008-10-13 21:08:44 +00003054 case IPCOP_msgctl:
3055 ret = do_msgctl(first, second, ptr);
3056 break;
thsd96372e2007-02-02 22:05:44 +00003057
aurel321c54ff92008-10-13 21:08:44 +00003058 case IPCOP_msgrcv:
3059 switch (version) {
3060 case 0:
3061 {
3062 struct target_ipc_kludge {
3063 abi_long msgp;
3064 abi_long msgtyp;
3065 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003066
aurel321c54ff92008-10-13 21:08:44 +00003067 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3068 ret = -TARGET_EFAULT;
3069 break;
ths1bc012f2007-06-03 14:27:49 +00003070 }
aurel321c54ff92008-10-13 21:08:44 +00003071
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003072 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003073
3074 unlock_user_struct(tmp, ptr, 0);
3075 break;
3076 }
3077 default:
3078 ret = do_msgrcv(first, ptr, second, fifth, third);
3079 }
3080 break;
thsd96372e2007-02-02 22:05:44 +00003081
bellard8853f862004-02-22 14:57:26 +00003082 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003083 switch (version) {
3084 default:
bellard5a4a8982007-11-11 17:39:18 +00003085 {
3086 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003087 raddr = do_shmat(first, ptr, second);
3088 if (is_error(raddr))
3089 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003090 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003091 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003092 break;
3093 }
3094 case 1:
3095 ret = -TARGET_EINVAL;
3096 break;
bellard5a4a8982007-11-11 17:39:18 +00003097 }
bellard8853f862004-02-22 14:57:26 +00003098 break;
3099 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003100 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003101 break;
3102
3103 case IPCOP_shmget:
3104 /* IPC_* flag values are the same on all linux platforms */
3105 ret = get_errno(shmget(first, second, third));
3106 break;
3107
3108 /* IPC_* and SHM_* command values are the same on all linux platforms */
3109 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01003110 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00003111 break;
3112 default:
j_mayer32407102007-09-26 23:01:49 +00003113 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003114 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003115 break;
3116 }
3117 return ret;
3118}
j_mayer32407102007-09-26 23:01:49 +00003119#endif
bellard8853f862004-02-22 14:57:26 +00003120
bellard31e31b82003-02-18 22:55:36 +00003121/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003122
Blue Swirl001faf32009-05-13 17:53:17 +00003123#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003124#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3125enum {
3126#include "syscall_types.h"
3127};
3128#undef STRUCT
3129#undef STRUCT_SPECIAL
3130
Blue Swirl001faf32009-05-13 17:53:17 +00003131#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003132#define STRUCT_SPECIAL(name)
3133#include "syscall_types.h"
3134#undef STRUCT
3135#undef STRUCT_SPECIAL
3136
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003137typedef struct IOCTLEntry IOCTLEntry;
3138
3139typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3140 int fd, abi_long cmd, abi_long arg);
3141
3142struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003143 unsigned int target_cmd;
3144 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003145 const char *name;
3146 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003147 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003148 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003149};
bellard31e31b82003-02-18 22:55:36 +00003150
3151#define IOC_R 0x0001
3152#define IOC_W 0x0002
3153#define IOC_RW (IOC_R | IOC_W)
3154
3155#define MAX_STRUCT_SIZE 4096
3156
Peter Maydelldace20d2011-01-10 13:11:24 +00003157#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003158/* So fiemap access checks don't overflow on 32 bit systems.
3159 * This is very slightly smaller than the limit imposed by
3160 * the underlying kernel.
3161 */
3162#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3163 / sizeof(struct fiemap_extent))
3164
3165static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3166 int fd, abi_long cmd, abi_long arg)
3167{
3168 /* The parameter for this ioctl is a struct fiemap followed
3169 * by an array of struct fiemap_extent whose size is set
3170 * in fiemap->fm_extent_count. The array is filled in by the
3171 * ioctl.
3172 */
3173 int target_size_in, target_size_out;
3174 struct fiemap *fm;
3175 const argtype *arg_type = ie->arg_type;
3176 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3177 void *argptr, *p;
3178 abi_long ret;
3179 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3180 uint32_t outbufsz;
3181 int free_fm = 0;
3182
3183 assert(arg_type[0] == TYPE_PTR);
3184 assert(ie->access == IOC_RW);
3185 arg_type++;
3186 target_size_in = thunk_type_size(arg_type, 0);
3187 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3188 if (!argptr) {
3189 return -TARGET_EFAULT;
3190 }
3191 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3192 unlock_user(argptr, arg, 0);
3193 fm = (struct fiemap *)buf_temp;
3194 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3195 return -TARGET_EINVAL;
3196 }
3197
3198 outbufsz = sizeof (*fm) +
3199 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3200
3201 if (outbufsz > MAX_STRUCT_SIZE) {
3202 /* We can't fit all the extents into the fixed size buffer.
3203 * Allocate one that is large enough and use it instead.
3204 */
3205 fm = malloc(outbufsz);
3206 if (!fm) {
3207 return -TARGET_ENOMEM;
3208 }
3209 memcpy(fm, buf_temp, sizeof(struct fiemap));
3210 free_fm = 1;
3211 }
3212 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3213 if (!is_error(ret)) {
3214 target_size_out = target_size_in;
3215 /* An extent_count of 0 means we were only counting the extents
3216 * so there are no structs to copy
3217 */
3218 if (fm->fm_extent_count != 0) {
3219 target_size_out += fm->fm_mapped_extents * extent_size;
3220 }
3221 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3222 if (!argptr) {
3223 ret = -TARGET_EFAULT;
3224 } else {
3225 /* Convert the struct fiemap */
3226 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3227 if (fm->fm_extent_count != 0) {
3228 p = argptr + target_size_in;
3229 /* ...and then all the struct fiemap_extents */
3230 for (i = 0; i < fm->fm_mapped_extents; i++) {
3231 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3232 THUNK_TARGET);
3233 p += extent_size;
3234 }
3235 }
3236 unlock_user(argptr, arg, target_size_out);
3237 }
3238 }
3239 if (free_fm) {
3240 free(fm);
3241 }
3242 return ret;
3243}
Peter Maydelldace20d2011-01-10 13:11:24 +00003244#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003245
Laurent Vivier059c2f22011-03-30 00:12:12 +02003246static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3247 int fd, abi_long cmd, abi_long arg)
3248{
3249 const argtype *arg_type = ie->arg_type;
3250 int target_size;
3251 void *argptr;
3252 int ret;
3253 struct ifconf *host_ifconf;
3254 uint32_t outbufsz;
3255 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3256 int target_ifreq_size;
3257 int nb_ifreq;
3258 int free_buf = 0;
3259 int i;
3260 int target_ifc_len;
3261 abi_long target_ifc_buf;
3262 int host_ifc_len;
3263 char *host_ifc_buf;
3264
3265 assert(arg_type[0] == TYPE_PTR);
3266 assert(ie->access == IOC_RW);
3267
3268 arg_type++;
3269 target_size = thunk_type_size(arg_type, 0);
3270
3271 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3272 if (!argptr)
3273 return -TARGET_EFAULT;
3274 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3275 unlock_user(argptr, arg, 0);
3276
3277 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3278 target_ifc_len = host_ifconf->ifc_len;
3279 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3280
3281 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3282 nb_ifreq = target_ifc_len / target_ifreq_size;
3283 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3284
3285 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3286 if (outbufsz > MAX_STRUCT_SIZE) {
3287 /* We can't fit all the extents into the fixed size buffer.
3288 * Allocate one that is large enough and use it instead.
3289 */
3290 host_ifconf = malloc(outbufsz);
3291 if (!host_ifconf) {
3292 return -TARGET_ENOMEM;
3293 }
3294 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3295 free_buf = 1;
3296 }
3297 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3298
3299 host_ifconf->ifc_len = host_ifc_len;
3300 host_ifconf->ifc_buf = host_ifc_buf;
3301
3302 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3303 if (!is_error(ret)) {
3304 /* convert host ifc_len to target ifc_len */
3305
3306 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3307 target_ifc_len = nb_ifreq * target_ifreq_size;
3308 host_ifconf->ifc_len = target_ifc_len;
3309
3310 /* restore target ifc_buf */
3311
3312 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3313
3314 /* copy struct ifconf to target user */
3315
3316 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3317 if (!argptr)
3318 return -TARGET_EFAULT;
3319 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3320 unlock_user(argptr, arg, target_size);
3321
3322 /* copy ifreq[] to target user */
3323
3324 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3325 for (i = 0; i < nb_ifreq ; i++) {
3326 thunk_convert(argptr + i * target_ifreq_size,
3327 host_ifc_buf + i * sizeof(struct ifreq),
3328 ifreq_arg_type, THUNK_TARGET);
3329 }
3330 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3331 }
3332
3333 if (free_buf) {
3334 free(host_ifconf);
3335 }
3336
3337 return ret;
3338}
3339
Alexander Graf56e904e2012-01-31 18:42:06 +01003340static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3341 abi_long cmd, abi_long arg)
3342{
3343 void *argptr;
3344 struct dm_ioctl *host_dm;
3345 abi_long guest_data;
3346 uint32_t guest_data_size;
3347 int target_size;
3348 const argtype *arg_type = ie->arg_type;
3349 abi_long ret;
3350 void *big_buf = NULL;
3351 char *host_data;
3352
3353 arg_type++;
3354 target_size = thunk_type_size(arg_type, 0);
3355 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3356 if (!argptr) {
3357 ret = -TARGET_EFAULT;
3358 goto out;
3359 }
3360 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3361 unlock_user(argptr, arg, 0);
3362
3363 /* buf_temp is too small, so fetch things into a bigger buffer */
3364 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3365 memcpy(big_buf, buf_temp, target_size);
3366 buf_temp = big_buf;
3367 host_dm = big_buf;
3368
3369 guest_data = arg + host_dm->data_start;
3370 if ((guest_data - arg) < 0) {
3371 ret = -EINVAL;
3372 goto out;
3373 }
3374 guest_data_size = host_dm->data_size - host_dm->data_start;
3375 host_data = (char*)host_dm + host_dm->data_start;
3376
3377 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3378 switch (ie->host_cmd) {
3379 case DM_REMOVE_ALL:
3380 case DM_LIST_DEVICES:
3381 case DM_DEV_CREATE:
3382 case DM_DEV_REMOVE:
3383 case DM_DEV_SUSPEND:
3384 case DM_DEV_STATUS:
3385 case DM_DEV_WAIT:
3386 case DM_TABLE_STATUS:
3387 case DM_TABLE_CLEAR:
3388 case DM_TABLE_DEPS:
3389 case DM_LIST_VERSIONS:
3390 /* no input data */
3391 break;
3392 case DM_DEV_RENAME:
3393 case DM_DEV_SET_GEOMETRY:
3394 /* data contains only strings */
3395 memcpy(host_data, argptr, guest_data_size);
3396 break;
3397 case DM_TARGET_MSG:
3398 memcpy(host_data, argptr, guest_data_size);
3399 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3400 break;
3401 case DM_TABLE_LOAD:
3402 {
3403 void *gspec = argptr;
3404 void *cur_data = host_data;
3405 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3406 int spec_size = thunk_type_size(arg_type, 0);
3407 int i;
3408
3409 for (i = 0; i < host_dm->target_count; i++) {
3410 struct dm_target_spec *spec = cur_data;
3411 uint32_t next;
3412 int slen;
3413
3414 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3415 slen = strlen((char*)gspec + spec_size) + 1;
3416 next = spec->next;
3417 spec->next = sizeof(*spec) + slen;
3418 strcpy((char*)&spec[1], gspec + spec_size);
3419 gspec += next;
3420 cur_data += spec->next;
3421 }
3422 break;
3423 }
3424 default:
3425 ret = -TARGET_EINVAL;
3426 goto out;
3427 }
3428 unlock_user(argptr, guest_data, 0);
3429
3430 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3431 if (!is_error(ret)) {
3432 guest_data = arg + host_dm->data_start;
3433 guest_data_size = host_dm->data_size - host_dm->data_start;
3434 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3435 switch (ie->host_cmd) {
3436 case DM_REMOVE_ALL:
3437 case DM_DEV_CREATE:
3438 case DM_DEV_REMOVE:
3439 case DM_DEV_RENAME:
3440 case DM_DEV_SUSPEND:
3441 case DM_DEV_STATUS:
3442 case DM_TABLE_LOAD:
3443 case DM_TABLE_CLEAR:
3444 case DM_TARGET_MSG:
3445 case DM_DEV_SET_GEOMETRY:
3446 /* no return data */
3447 break;
3448 case DM_LIST_DEVICES:
3449 {
3450 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3451 uint32_t remaining_data = guest_data_size;
3452 void *cur_data = argptr;
3453 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3454 int nl_size = 12; /* can't use thunk_size due to alignment */
3455
3456 while (1) {
3457 uint32_t next = nl->next;
3458 if (next) {
3459 nl->next = nl_size + (strlen(nl->name) + 1);
3460 }
3461 if (remaining_data < nl->next) {
3462 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3463 break;
3464 }
3465 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3466 strcpy(cur_data + nl_size, nl->name);
3467 cur_data += nl->next;
3468 remaining_data -= nl->next;
3469 if (!next) {
3470 break;
3471 }
3472 nl = (void*)nl + next;
3473 }
3474 break;
3475 }
3476 case DM_DEV_WAIT:
3477 case DM_TABLE_STATUS:
3478 {
3479 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3480 void *cur_data = argptr;
3481 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3482 int spec_size = thunk_type_size(arg_type, 0);
3483 int i;
3484
3485 for (i = 0; i < host_dm->target_count; i++) {
3486 uint32_t next = spec->next;
3487 int slen = strlen((char*)&spec[1]) + 1;
3488 spec->next = (cur_data - argptr) + spec_size + slen;
3489 if (guest_data_size < spec->next) {
3490 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3491 break;
3492 }
3493 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3494 strcpy(cur_data + spec_size, (char*)&spec[1]);
3495 cur_data = argptr + spec->next;
3496 spec = (void*)host_dm + host_dm->data_start + next;
3497 }
3498 break;
3499 }
3500 case DM_TABLE_DEPS:
3501 {
3502 void *hdata = (void*)host_dm + host_dm->data_start;
3503 int count = *(uint32_t*)hdata;
3504 uint64_t *hdev = hdata + 8;
3505 uint64_t *gdev = argptr + 8;
3506 int i;
3507
3508 *(uint32_t*)argptr = tswap32(count);
3509 for (i = 0; i < count; i++) {
3510 *gdev = tswap64(*hdev);
3511 gdev++;
3512 hdev++;
3513 }
3514 break;
3515 }
3516 case DM_LIST_VERSIONS:
3517 {
3518 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3519 uint32_t remaining_data = guest_data_size;
3520 void *cur_data = argptr;
3521 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3522 int vers_size = thunk_type_size(arg_type, 0);
3523
3524 while (1) {
3525 uint32_t next = vers->next;
3526 if (next) {
3527 vers->next = vers_size + (strlen(vers->name) + 1);
3528 }
3529 if (remaining_data < vers->next) {
3530 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3531 break;
3532 }
3533 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3534 strcpy(cur_data + vers_size, vers->name);
3535 cur_data += vers->next;
3536 remaining_data -= vers->next;
3537 if (!next) {
3538 break;
3539 }
3540 vers = (void*)vers + next;
3541 }
3542 break;
3543 }
3544 default:
3545 ret = -TARGET_EINVAL;
3546 goto out;
3547 }
3548 unlock_user(argptr, guest_data, guest_data_size);
3549
3550 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3551 if (!argptr) {
3552 ret = -TARGET_EFAULT;
3553 goto out;
3554 }
3555 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3556 unlock_user(argptr, arg, target_size);
3557 }
3558out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003559 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003560 return ret;
3561}
3562
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003563static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
3564 int fd, abi_long cmd, abi_long arg)
3565{
3566 const argtype *arg_type = ie->arg_type;
3567 const StructEntry *se;
3568 const argtype *field_types;
3569 const int *dst_offsets, *src_offsets;
3570 int target_size;
3571 void *argptr;
3572 abi_ulong *target_rt_dev_ptr;
3573 unsigned long *host_rt_dev_ptr;
3574 abi_long ret;
3575 int i;
3576
3577 assert(ie->access == IOC_W);
3578 assert(*arg_type == TYPE_PTR);
3579 arg_type++;
3580 assert(*arg_type == TYPE_STRUCT);
3581 target_size = thunk_type_size(arg_type, 0);
3582 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3583 if (!argptr) {
3584 return -TARGET_EFAULT;
3585 }
3586 arg_type++;
3587 assert(*arg_type == (int)STRUCT_rtentry);
3588 se = struct_entries + *arg_type++;
3589 assert(se->convert[0] == NULL);
3590 /* convert struct here to be able to catch rt_dev string */
3591 field_types = se->field_types;
3592 dst_offsets = se->field_offsets[THUNK_HOST];
3593 src_offsets = se->field_offsets[THUNK_TARGET];
3594 for (i = 0; i < se->nb_fields; i++) {
3595 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
3596 assert(*field_types == TYPE_PTRVOID);
3597 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
3598 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
3599 if (*target_rt_dev_ptr != 0) {
3600 *host_rt_dev_ptr = (unsigned long)lock_user_string(
3601 tswapal(*target_rt_dev_ptr));
3602 if (!*host_rt_dev_ptr) {
3603 unlock_user(argptr, arg, 0);
3604 return -TARGET_EFAULT;
3605 }
3606 } else {
3607 *host_rt_dev_ptr = 0;
3608 }
3609 field_types++;
3610 continue;
3611 }
3612 field_types = thunk_convert(buf_temp + dst_offsets[i],
3613 argptr + src_offsets[i],
3614 field_types, THUNK_HOST);
3615 }
3616 unlock_user(argptr, arg, 0);
3617
3618 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3619 if (*host_rt_dev_ptr != 0) {
3620 unlock_user((void *)*host_rt_dev_ptr,
3621 *target_rt_dev_ptr, 0);
3622 }
3623 return ret;
3624}
3625
blueswir19f106a72008-10-05 10:52:52 +00003626static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003627#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003628 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3629#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3630 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003631#include "ioctls.h"
3632 { 0, 0, },
3633};
3634
pbrook53a59602006-03-25 19:31:22 +00003635/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003636/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003637static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003638{
3639 const IOCTLEntry *ie;
3640 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003641 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003642 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003643 int target_size;
3644 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003645
3646 ie = ioctl_entries;
3647 for(;;) {
3648 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003649 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003650 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003651 }
3652 if (ie->target_cmd == cmd)
3653 break;
3654 ie++;
3655 }
3656 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003657#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003658 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003659#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003660 if (ie->do_ioctl) {
3661 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3662 }
3663
bellard31e31b82003-02-18 22:55:36 +00003664 switch(arg_type[0]) {
3665 case TYPE_NULL:
3666 /* no argument */
3667 ret = get_errno(ioctl(fd, ie->host_cmd));
3668 break;
3669 case TYPE_PTRVOID:
3670 case TYPE_INT:
3671 /* int argment */
3672 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3673 break;
3674 case TYPE_PTR:
3675 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003676 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003677 switch(ie->access) {
3678 case IOC_R:
3679 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3680 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003681 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3682 if (!argptr)
3683 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003684 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3685 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003686 }
3687 break;
3688 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003689 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3690 if (!argptr)
3691 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003692 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3693 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003694 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3695 break;
3696 default:
3697 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003698 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3699 if (!argptr)
3700 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003701 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3702 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003703 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3704 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003705 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3706 if (!argptr)
3707 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003708 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3709 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003710 }
3711 break;
3712 }
3713 break;
3714 default:
j_mayer32407102007-09-26 23:01:49 +00003715 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3716 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003717 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003718 break;
3719 }
3720 return ret;
3721}
3722
blueswir1b39bc502008-10-05 10:51:10 +00003723static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003724 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3725 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3726 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3727 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3728 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3729 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3730 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3731 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3732 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3733 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3734 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3735 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3736 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3737 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3738 { 0, 0, 0, 0 }
3739};
3740
blueswir1b39bc502008-10-05 10:51:10 +00003741static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003742 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3743 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3744 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3745 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3746 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3747 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3748 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3749 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3750 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3751 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3752 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3753 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3754 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3755 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3756 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3757 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3758 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3759 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3760 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3761 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3762 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3763 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3764 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3765 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3766 { 0, 0, 0, 0 }
3767};
3768
blueswir1b39bc502008-10-05 10:51:10 +00003769static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003770 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3771 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3772 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3773 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3774 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3775 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3776 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3777 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3778 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3779 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3780 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3781 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3782 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3783 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3784 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3785 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3786 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3787 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3788 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3789 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3790 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3791 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3792 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3793 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3794 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3795 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3796 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3797 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3798 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3799 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3800 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3801 { 0, 0, 0, 0 }
3802};
3803
blueswir1b39bc502008-10-05 10:51:10 +00003804static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003805 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3806 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3807 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3808 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3809 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3810 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3811 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3812 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3813 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3814 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3815 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3816 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3817 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3818 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3819 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3820 { 0, 0, 0, 0 }
3821};
3822
3823static void target_to_host_termios (void *dst, const void *src)
3824{
3825 struct host_termios *host = dst;
3826 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003827
ths5fafdf22007-09-16 21:08:06 +00003828 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003829 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003830 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003831 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003832 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003833 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003834 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003835 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3836 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003837
Arnaud Patard44607122009-04-21 17:39:08 +03003838 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003839 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3840 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003841 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003842 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003843 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003844 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003845 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003846 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003847 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003848 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3849 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003850 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3851 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3852 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3853 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3854 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003855 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003856}
ths3b46e622007-09-17 08:09:54 +00003857
bellard31e31b82003-02-18 22:55:36 +00003858static void host_to_target_termios (void *dst, const void *src)
3859{
3860 struct target_termios *target = dst;
3861 const struct host_termios *host = src;
3862
ths5fafdf22007-09-16 21:08:06 +00003863 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003864 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003865 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003866 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003867 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003868 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003869 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003870 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3871 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003872
Arnaud Patard44607122009-04-21 17:39:08 +03003873 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003874 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3875 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3876 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3877 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3878 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3879 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3880 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3881 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3882 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3883 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3884 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3885 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3886 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3887 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3888 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3889 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3890 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3891}
3892
blueswir18e853dc2008-10-05 10:49:32 +00003893static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003894 .convert = { host_to_target_termios, target_to_host_termios },
3895 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3896 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3897};
3898
bellard5286db72003-06-05 00:57:30 +00003899static bitmask_transtbl mmap_flags_tbl[] = {
3900 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3901 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3902 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3903 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3904 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3905 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3906 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3907 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3908 { 0, 0, 0, 0 }
3909};
3910
bellard2ab83ea2003-06-15 19:56:46 +00003911#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003912
3913/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003914static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003915
bellard03acab62007-11-11 14:57:14 +00003916static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003917{
3918 int size;
pbrook53a59602006-03-25 19:31:22 +00003919 void *p;
bellard6dbad632003-03-16 18:05:05 +00003920
3921 if (!ldt_table)
3922 return 0;
3923 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3924 if (size > bytecount)
3925 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003926 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3927 if (!p)
bellard03acab62007-11-11 14:57:14 +00003928 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003929 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003930 memcpy(p, ldt_table, size);
3931 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003932 return size;
3933}
3934
3935/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003936static abi_long write_ldt(CPUX86State *env,
3937 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003938{
3939 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003940 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003941 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003942 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003943 uint32_t *lp, entry_1, entry_2;
3944
3945 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003946 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003947 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003948 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003949 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003950 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00003951 ldt_info.limit = tswap32(target_ldt_info->limit);
3952 ldt_info.flags = tswap32(target_ldt_info->flags);
3953 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003954
bellard6dbad632003-03-16 18:05:05 +00003955 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003956 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003957 seg_32bit = ldt_info.flags & 1;
3958 contents = (ldt_info.flags >> 1) & 3;
3959 read_exec_only = (ldt_info.flags >> 3) & 1;
3960 limit_in_pages = (ldt_info.flags >> 4) & 1;
3961 seg_not_present = (ldt_info.flags >> 5) & 1;
3962 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00003963#ifdef TARGET_ABI32
3964 lm = 0;
3965#else
3966 lm = (ldt_info.flags >> 7) & 1;
3967#endif
bellard6dbad632003-03-16 18:05:05 +00003968 if (contents == 3) {
3969 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00003970 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003971 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00003972 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003973 }
3974 /* allocate the LDT */
3975 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00003976 env->ldt.base = target_mmap(0,
3977 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
3978 PROT_READ|PROT_WRITE,
3979 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3980 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00003981 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00003982 memset(g2h(env->ldt.base), 0,
3983 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00003984 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00003985 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00003986 }
3987
3988 /* NOTE: same code as Linux kernel */
3989 /* Allow LDTs to be cleared by the user. */
3990 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3991 if (oldmode ||
3992 (contents == 0 &&
3993 read_exec_only == 1 &&
3994 seg_32bit == 0 &&
3995 limit_in_pages == 0 &&
3996 seg_not_present == 1 &&
3997 useable == 0 )) {
3998 entry_1 = 0;
3999 entry_2 = 0;
4000 goto install;
4001 }
4002 }
ths3b46e622007-09-17 08:09:54 +00004003
bellard6dbad632003-03-16 18:05:05 +00004004 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4005 (ldt_info.limit & 0x0ffff);
4006 entry_2 = (ldt_info.base_addr & 0xff000000) |
4007 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4008 (ldt_info.limit & 0xf0000) |
4009 ((read_exec_only ^ 1) << 9) |
4010 (contents << 10) |
4011 ((seg_not_present ^ 1) << 15) |
4012 (seg_32bit << 22) |
4013 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004014 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004015 0x7000;
4016 if (!oldmode)
4017 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004018
bellard6dbad632003-03-16 18:05:05 +00004019 /* Install the new entry ... */
4020install:
4021 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4022 lp[0] = tswap32(entry_1);
4023 lp[1] = tswap32(entry_2);
4024 return 0;
4025}
4026
4027/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004028static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4029 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004030{
bellard03acab62007-11-11 14:57:14 +00004031 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004032
bellard6dbad632003-03-16 18:05:05 +00004033 switch (func) {
4034 case 0:
4035 ret = read_ldt(ptr, bytecount);
4036 break;
4037 case 1:
4038 ret = write_ldt(env, ptr, bytecount, 1);
4039 break;
4040 case 0x11:
4041 ret = write_ldt(env, ptr, bytecount, 0);
4042 break;
bellard03acab62007-11-11 14:57:14 +00004043 default:
4044 ret = -TARGET_ENOSYS;
4045 break;
bellard6dbad632003-03-16 18:05:05 +00004046 }
4047 return ret;
4048}
bellard1b6b0292003-03-22 17:31:38 +00004049
blueswir14583f582008-08-24 10:35:55 +00004050#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004051abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004052{
4053 uint64_t *gdt_table = g2h(env->gdt.base);
4054 struct target_modify_ldt_ldt_s ldt_info;
4055 struct target_modify_ldt_ldt_s *target_ldt_info;
4056 int seg_32bit, contents, read_exec_only, limit_in_pages;
4057 int seg_not_present, useable, lm;
4058 uint32_t *lp, entry_1, entry_2;
4059 int i;
4060
4061 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4062 if (!target_ldt_info)
4063 return -TARGET_EFAULT;
4064 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004065 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004066 ldt_info.limit = tswap32(target_ldt_info->limit);
4067 ldt_info.flags = tswap32(target_ldt_info->flags);
4068 if (ldt_info.entry_number == -1) {
4069 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4070 if (gdt_table[i] == 0) {
4071 ldt_info.entry_number = i;
4072 target_ldt_info->entry_number = tswap32(i);
4073 break;
4074 }
4075 }
4076 }
4077 unlock_user_struct(target_ldt_info, ptr, 1);
4078
4079 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4080 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4081 return -TARGET_EINVAL;
4082 seg_32bit = ldt_info.flags & 1;
4083 contents = (ldt_info.flags >> 1) & 3;
4084 read_exec_only = (ldt_info.flags >> 3) & 1;
4085 limit_in_pages = (ldt_info.flags >> 4) & 1;
4086 seg_not_present = (ldt_info.flags >> 5) & 1;
4087 useable = (ldt_info.flags >> 6) & 1;
4088#ifdef TARGET_ABI32
4089 lm = 0;
4090#else
4091 lm = (ldt_info.flags >> 7) & 1;
4092#endif
4093
4094 if (contents == 3) {
4095 if (seg_not_present == 0)
4096 return -TARGET_EINVAL;
4097 }
4098
4099 /* NOTE: same code as Linux kernel */
4100 /* Allow LDTs to be cleared by the user. */
4101 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4102 if ((contents == 0 &&
4103 read_exec_only == 1 &&
4104 seg_32bit == 0 &&
4105 limit_in_pages == 0 &&
4106 seg_not_present == 1 &&
4107 useable == 0 )) {
4108 entry_1 = 0;
4109 entry_2 = 0;
4110 goto install;
4111 }
4112 }
4113
4114 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4115 (ldt_info.limit & 0x0ffff);
4116 entry_2 = (ldt_info.base_addr & 0xff000000) |
4117 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4118 (ldt_info.limit & 0xf0000) |
4119 ((read_exec_only ^ 1) << 9) |
4120 (contents << 10) |
4121 ((seg_not_present ^ 1) << 15) |
4122 (seg_32bit << 22) |
4123 (limit_in_pages << 23) |
4124 (useable << 20) |
4125 (lm << 21) |
4126 0x7000;
4127
4128 /* Install the new entry ... */
4129install:
4130 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4131 lp[0] = tswap32(entry_1);
4132 lp[1] = tswap32(entry_2);
4133 return 0;
4134}
4135
blueswir18fcd3692008-08-17 20:26:25 +00004136static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004137{
4138 struct target_modify_ldt_ldt_s *target_ldt_info;
4139 uint64_t *gdt_table = g2h(env->gdt.base);
4140 uint32_t base_addr, limit, flags;
4141 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4142 int seg_not_present, useable, lm;
4143 uint32_t *lp, entry_1, entry_2;
4144
4145 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4146 if (!target_ldt_info)
4147 return -TARGET_EFAULT;
4148 idx = tswap32(target_ldt_info->entry_number);
4149 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4150 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4151 unlock_user_struct(target_ldt_info, ptr, 1);
4152 return -TARGET_EINVAL;
4153 }
4154 lp = (uint32_t *)(gdt_table + idx);
4155 entry_1 = tswap32(lp[0]);
4156 entry_2 = tswap32(lp[1]);
4157
4158 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4159 contents = (entry_2 >> 10) & 3;
4160 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4161 seg_32bit = (entry_2 >> 22) & 1;
4162 limit_in_pages = (entry_2 >> 23) & 1;
4163 useable = (entry_2 >> 20) & 1;
4164#ifdef TARGET_ABI32
4165 lm = 0;
4166#else
4167 lm = (entry_2 >> 21) & 1;
4168#endif
4169 flags = (seg_32bit << 0) | (contents << 1) |
4170 (read_exec_only << 3) | (limit_in_pages << 4) |
4171 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4172 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4173 base_addr = (entry_1 >> 16) |
4174 (entry_2 & 0xff000000) |
4175 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004176 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004177 target_ldt_info->limit = tswap32(limit);
4178 target_ldt_info->flags = tswap32(flags);
4179 unlock_user_struct(target_ldt_info, ptr, 1);
4180 return 0;
4181}
blueswir14583f582008-08-24 10:35:55 +00004182#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004183
bellardd2fd1af2007-11-14 18:08:56 +00004184#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004185abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004186{
Juan Quintela1add8692011-06-16 17:37:09 +01004187 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004188 abi_ulong val;
4189 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004190
bellardd2fd1af2007-11-14 18:08:56 +00004191 switch(code) {
4192 case TARGET_ARCH_SET_GS:
4193 case TARGET_ARCH_SET_FS:
4194 if (code == TARGET_ARCH_SET_GS)
4195 idx = R_GS;
4196 else
4197 idx = R_FS;
4198 cpu_x86_load_seg(env, idx, 0);
4199 env->segs[idx].base = addr;
4200 break;
4201 case TARGET_ARCH_GET_GS:
4202 case TARGET_ARCH_GET_FS:
4203 if (code == TARGET_ARCH_GET_GS)
4204 idx = R_GS;
4205 else
4206 idx = R_FS;
4207 val = env->segs[idx].base;
4208 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004209 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004210 break;
4211 default:
4212 ret = -TARGET_EINVAL;
4213 break;
4214 }
Juan Quintela1add8692011-06-16 17:37:09 +01004215 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004216}
4217#endif
4218
bellard2ab83ea2003-06-15 19:56:46 +00004219#endif /* defined(TARGET_I386) */
4220
Riku Voipio05098a92011-03-04 15:27:29 +02004221#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004222
pbrookd865bab2008-06-07 22:12:17 +00004223
4224static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4225typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004226 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004227 pthread_mutex_t mutex;
4228 pthread_cond_t cond;
4229 pthread_t thread;
4230 uint32_t tid;
4231 abi_ulong child_tidptr;
4232 abi_ulong parent_tidptr;
4233 sigset_t sigmask;
4234} new_thread_info;
4235
4236static void *clone_func(void *arg)
4237{
4238 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004239 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004240 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004241 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004242
4243 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004244 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004245 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02004246 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004247 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004248 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004249 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004250 if (info->child_tidptr)
4251 put_user_u32(info->tid, info->child_tidptr);
4252 if (info->parent_tidptr)
4253 put_user_u32(info->tid, info->parent_tidptr);
4254 /* Enable signals. */
4255 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4256 /* Signal to the parent that we're ready. */
4257 pthread_mutex_lock(&info->mutex);
4258 pthread_cond_broadcast(&info->cond);
4259 pthread_mutex_unlock(&info->mutex);
4260 /* Wait until the parent has finshed initializing the tls state. */
4261 pthread_mutex_lock(&clone_lock);
4262 pthread_mutex_unlock(&clone_lock);
4263 cpu_loop(env);
4264 /* never exits */
4265 return NULL;
4266}
bellard1b6b0292003-03-22 17:31:38 +00004267
ths0da46a62007-10-20 20:23:07 +00004268/* do_fork() Must return host values and target errnos (unlike most
4269 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004270static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004271 abi_ulong parent_tidptr, target_ulong newtls,
4272 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004273{
Andreas Färber0429a972013-08-26 18:14:44 +02004274 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00004275 int ret;
bellard5cd43932003-03-29 16:54:36 +00004276 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02004277 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004278 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004279 unsigned int nptl_flags;
4280 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004281
balrog436d1242008-09-21 02:39:45 +00004282 /* Emulate vfork() with fork() */
4283 if (flags & CLONE_VFORK)
4284 flags &= ~(CLONE_VFORK | CLONE_VM);
4285
bellard1b6b0292003-03-22 17:31:38 +00004286 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02004287 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004288 new_thread_info info;
4289 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004290
Anthony Liguori7267c092011-08-20 22:09:37 -05004291 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004292 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004293 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004294 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004295 /* Init regs that differ from the parent. */
4296 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02004297 new_cpu = ENV_GET_CPU(new_env);
4298 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004299 ts->bprm = parent_ts->bprm;
4300 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004301 nptl_flags = flags;
4302 flags &= ~CLONE_NPTL_FLAGS2;
4303
pbrookc2764712009-03-07 15:24:59 +00004304 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4305 ts->child_tidptr = child_tidptr;
4306 }
4307
pbrookd865bab2008-06-07 22:12:17 +00004308 if (nptl_flags & CLONE_SETTLS)
4309 cpu_set_tls (new_env, newtls);
4310
4311 /* Grab a mutex so that thread setup appears atomic. */
4312 pthread_mutex_lock(&clone_lock);
4313
4314 memset(&info, 0, sizeof(info));
4315 pthread_mutex_init(&info.mutex, NULL);
4316 pthread_mutex_lock(&info.mutex);
4317 pthread_cond_init(&info.cond, NULL);
4318 info.env = new_env;
4319 if (nptl_flags & CLONE_CHILD_SETTID)
4320 info.child_tidptr = child_tidptr;
4321 if (nptl_flags & CLONE_PARENT_SETTID)
4322 info.parent_tidptr = parent_tidptr;
4323
4324 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004325 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4326 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004327 /* It is not safe to deliver signals until the child has finished
4328 initializing, so temporarily block all signals. */
4329 sigfillset(&sigmask);
4330 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4331
4332 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004333 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004334
4335 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4336 pthread_attr_destroy(&attr);
4337 if (ret == 0) {
4338 /* Wait for the child to initialize. */
4339 pthread_cond_wait(&info.cond, &info.mutex);
4340 ret = info.tid;
4341 if (flags & CLONE_PARENT_SETTID)
4342 put_user_u32(ret, parent_tidptr);
4343 } else {
4344 ret = -1;
4345 }
4346 pthread_mutex_unlock(&info.mutex);
4347 pthread_cond_destroy(&info.cond);
4348 pthread_mutex_destroy(&info.mutex);
4349 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004350 } else {
4351 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004352 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004353 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004354 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004355 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004356 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004357 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004358 cpu_clone_regs(env, newsp);
4359 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004360 /* There is a race condition here. The parent process could
4361 theoretically read the TID in the child process before the child
4362 tid is set. This would require using either ptrace
4363 (not implemented) or having *_tidptr to point at a shared memory
4364 mapping. We can't repeat the spinlock hack used above because
4365 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004366 if (flags & CLONE_CHILD_SETTID)
4367 put_user_u32(gettid(), child_tidptr);
4368 if (flags & CLONE_PARENT_SETTID)
4369 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02004370 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004371 if (flags & CLONE_SETTLS)
4372 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004373 if (flags & CLONE_CHILD_CLEARTID)
4374 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004375 } else {
4376 fork_end(0);
4377 }
bellard1b6b0292003-03-22 17:31:38 +00004378 }
4379 return ret;
4380}
4381
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004382/* warning : doesn't handle linux specific flags... */
4383static int target_to_host_fcntl_cmd(int cmd)
4384{
4385 switch(cmd) {
4386 case TARGET_F_DUPFD:
4387 case TARGET_F_GETFD:
4388 case TARGET_F_SETFD:
4389 case TARGET_F_GETFL:
4390 case TARGET_F_SETFL:
4391 return cmd;
4392 case TARGET_F_GETLK:
4393 return F_GETLK;
4394 case TARGET_F_SETLK:
4395 return F_SETLK;
4396 case TARGET_F_SETLKW:
4397 return F_SETLKW;
4398 case TARGET_F_GETOWN:
4399 return F_GETOWN;
4400 case TARGET_F_SETOWN:
4401 return F_SETOWN;
4402 case TARGET_F_GETSIG:
4403 return F_GETSIG;
4404 case TARGET_F_SETSIG:
4405 return F_SETSIG;
4406#if TARGET_ABI_BITS == 32
4407 case TARGET_F_GETLK64:
4408 return F_GETLK64;
4409 case TARGET_F_SETLK64:
4410 return F_SETLK64;
4411 case TARGET_F_SETLKW64:
4412 return F_SETLKW64;
4413#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004414 case TARGET_F_SETLEASE:
4415 return F_SETLEASE;
4416 case TARGET_F_GETLEASE:
4417 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004418#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004419 case TARGET_F_DUPFD_CLOEXEC:
4420 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004421#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004422 case TARGET_F_NOTIFY:
4423 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004424#ifdef F_GETOWN_EX
4425 case TARGET_F_GETOWN_EX:
4426 return F_GETOWN_EX;
4427#endif
4428#ifdef F_SETOWN_EX
4429 case TARGET_F_SETOWN_EX:
4430 return F_SETOWN_EX;
4431#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004432 default:
4433 return -TARGET_EINVAL;
4434 }
4435 return -TARGET_EINVAL;
4436}
4437
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004438#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4439static const bitmask_transtbl flock_tbl[] = {
4440 TRANSTBL_CONVERT(F_RDLCK),
4441 TRANSTBL_CONVERT(F_WRLCK),
4442 TRANSTBL_CONVERT(F_UNLCK),
4443 TRANSTBL_CONVERT(F_EXLCK),
4444 TRANSTBL_CONVERT(F_SHLCK),
4445 { 0, 0, 0, 0 }
4446};
4447
blueswir1992f48a2007-10-14 16:27:31 +00004448static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004449{
4450 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004451 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004452 struct flock64 fl64;
4453 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004454#ifdef F_GETOWN_EX
4455 struct f_owner_ex fox;
4456 struct target_f_owner_ex *target_fox;
4457#endif
blueswir1992f48a2007-10-14 16:27:31 +00004458 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004459 int host_cmd = target_to_host_fcntl_cmd(cmd);
4460
4461 if (host_cmd == -TARGET_EINVAL)
4462 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004463
bellard7775e9e2003-05-14 22:46:48 +00004464 switch(cmd) {
4465 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004466 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4467 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004468 fl.l_type =
4469 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004470 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004471 fl.l_start = tswapal(target_fl->l_start);
4472 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004473 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004474 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004475 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004476 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004477 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4478 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004479 target_fl->l_type =
4480 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004481 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004482 target_fl->l_start = tswapal(fl.l_start);
4483 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004484 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004485 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004486 }
4487 break;
ths3b46e622007-09-17 08:09:54 +00004488
bellard7775e9e2003-05-14 22:46:48 +00004489 case TARGET_F_SETLK:
4490 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004491 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4492 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004493 fl.l_type =
4494 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004495 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004496 fl.l_start = tswapal(target_fl->l_start);
4497 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004498 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004499 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004500 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004501 break;
ths3b46e622007-09-17 08:09:54 +00004502
bellard7775e9e2003-05-14 22:46:48 +00004503 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004504 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4505 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004506 fl64.l_type =
4507 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004508 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004509 fl64.l_start = tswap64(target_fl64->l_start);
4510 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004511 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004512 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004513 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004514 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004515 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4516 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004517 target_fl64->l_type =
4518 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004519 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004520 target_fl64->l_start = tswap64(fl64.l_start);
4521 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004522 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004523 unlock_user_struct(target_fl64, arg, 1);
4524 }
bellard9ee1fa22007-11-11 15:11:19 +00004525 break;
bellard7775e9e2003-05-14 22:46:48 +00004526 case TARGET_F_SETLK64:
4527 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004528 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4529 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004530 fl64.l_type =
4531 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004532 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004533 fl64.l_start = tswap64(target_fl64->l_start);
4534 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004535 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004536 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004537 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004538 break;
4539
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004540 case TARGET_F_GETFL:
4541 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004542 if (ret >= 0) {
4543 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4544 }
bellardffa65c32004-01-04 23:57:22 +00004545 break;
4546
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004547 case TARGET_F_SETFL:
4548 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4549 break;
4550
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004551#ifdef F_GETOWN_EX
4552 case TARGET_F_GETOWN_EX:
4553 ret = get_errno(fcntl(fd, host_cmd, &fox));
4554 if (ret >= 0) {
4555 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
4556 return -TARGET_EFAULT;
4557 target_fox->type = tswap32(fox.type);
4558 target_fox->pid = tswap32(fox.pid);
4559 unlock_user_struct(target_fox, arg, 1);
4560 }
4561 break;
4562#endif
4563
4564#ifdef F_SETOWN_EX
4565 case TARGET_F_SETOWN_EX:
4566 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
4567 return -TARGET_EFAULT;
4568 fox.type = tswap32(target_fox->type);
4569 fox.pid = tswap32(target_fox->pid);
4570 unlock_user_struct(target_fox, arg, 0);
4571 ret = get_errno(fcntl(fd, host_cmd, &fox));
4572 break;
4573#endif
4574
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004575 case TARGET_F_SETOWN:
4576 case TARGET_F_GETOWN:
4577 case TARGET_F_SETSIG:
4578 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004579 case TARGET_F_SETLEASE:
4580 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004581 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004582 break;
4583
bellard7775e9e2003-05-14 22:46:48 +00004584 default:
bellard9ee1fa22007-11-11 15:11:19 +00004585 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004586 break;
4587 }
4588 return ret;
4589}
4590
bellard67867302003-11-23 17:05:30 +00004591#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004592
bellard67867302003-11-23 17:05:30 +00004593static inline int high2lowuid(int uid)
4594{
4595 if (uid > 65535)
4596 return 65534;
4597 else
4598 return uid;
4599}
4600
4601static inline int high2lowgid(int gid)
4602{
4603 if (gid > 65535)
4604 return 65534;
4605 else
4606 return gid;
4607}
4608
4609static inline int low2highuid(int uid)
4610{
4611 if ((int16_t)uid == -1)
4612 return -1;
4613 else
4614 return uid;
4615}
4616
4617static inline int low2highgid(int gid)
4618{
4619 if ((int16_t)gid == -1)
4620 return -1;
4621 else
4622 return gid;
4623}
Riku Voipio0c866a72011-04-18 15:23:06 +03004624static inline int tswapid(int id)
4625{
4626 return tswap16(id);
4627}
Peter Maydell76ca3102014-03-02 19:36:41 +00004628
4629#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
4630
Riku Voipio0c866a72011-04-18 15:23:06 +03004631#else /* !USE_UID16 */
4632static inline int high2lowuid(int uid)
4633{
4634 return uid;
4635}
4636static inline int high2lowgid(int gid)
4637{
4638 return gid;
4639}
4640static inline int low2highuid(int uid)
4641{
4642 return uid;
4643}
4644static inline int low2highgid(int gid)
4645{
4646 return gid;
4647}
4648static inline int tswapid(int id)
4649{
4650 return tswap32(id);
4651}
Peter Maydell76ca3102014-03-02 19:36:41 +00004652
4653#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
4654
bellard67867302003-11-23 17:05:30 +00004655#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004656
bellard31e31b82003-02-18 22:55:36 +00004657void syscall_init(void)
4658{
bellard2ab83ea2003-06-15 19:56:46 +00004659 IOCTLEntry *ie;
4660 const argtype *arg_type;
4661 int size;
thsb92c47c2007-11-01 00:07:38 +00004662 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004663
Blue Swirl001faf32009-05-13 17:53:17 +00004664#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004665#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004666#include "syscall_types.h"
4667#undef STRUCT
4668#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004669
Peter Maydelldd6e9572012-07-23 08:07:22 +00004670 /* Build target_to_host_errno_table[] table from
4671 * host_to_target_errno_table[]. */
4672 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4673 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4674 }
4675
bellard2ab83ea2003-06-15 19:56:46 +00004676 /* we patch the ioctl size if necessary. We rely on the fact that
4677 no ioctl has all the bits at '1' in the size field */
4678 ie = ioctl_entries;
4679 while (ie->target_cmd != 0) {
4680 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4681 TARGET_IOC_SIZEMASK) {
4682 arg_type = ie->arg_type;
4683 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004684 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004685 ie->target_cmd);
4686 exit(1);
4687 }
4688 arg_type++;
4689 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004690 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004691 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4692 (size << TARGET_IOC_SIZESHIFT);
4693 }
thsb92c47c2007-11-01 00:07:38 +00004694
bellard2ab83ea2003-06-15 19:56:46 +00004695 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004696#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4697 (defined(__x86_64__) && defined(TARGET_X86_64))
4698 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4699 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4700 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004701 }
4702#endif
4703 ie++;
4704 }
bellard31e31b82003-02-18 22:55:36 +00004705}
bellardc573ff62004-01-04 15:51:36 +00004706
blueswir1992f48a2007-10-14 16:27:31 +00004707#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004708static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4709{
thsaf325d32008-06-10 15:29:15 +00004710#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004711 return ((uint64_t)word0 << 32) | word1;
4712#else
4713 return ((uint64_t)word1 << 32) | word0;
4714#endif
4715}
blueswir1992f48a2007-10-14 16:27:31 +00004716#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004717static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4718{
4719 return word0;
4720}
blueswir1992f48a2007-10-14 16:27:31 +00004721#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004722
4723#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004724static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4725 abi_long arg2,
4726 abi_long arg3,
4727 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004728{
Riku Voipio48e515d2011-07-12 15:40:51 +03004729 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004730 arg2 = arg3;
4731 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004732 }
pbrookce4defa2006-02-09 16:49:55 +00004733 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4734}
4735#endif
4736
4737#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004738static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4739 abi_long arg2,
4740 abi_long arg3,
4741 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004742{
Riku Voipio48e515d2011-07-12 15:40:51 +03004743 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004744 arg2 = arg3;
4745 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004746 }
pbrookce4defa2006-02-09 16:49:55 +00004747 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4748}
4749#endif
4750
bellard579a97f2007-11-11 14:26:47 +00004751static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4752 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004753{
4754 struct target_timespec *target_ts;
4755
bellard579a97f2007-11-11 14:26:47 +00004756 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4757 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004758 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4759 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004760 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004761 return 0;
pbrook53a59602006-03-25 19:31:22 +00004762}
4763
bellard579a97f2007-11-11 14:26:47 +00004764static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4765 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004766{
4767 struct target_timespec *target_ts;
4768
bellard579a97f2007-11-11 14:26:47 +00004769 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4770 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004771 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4772 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004773 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004774 return 0;
pbrook53a59602006-03-25 19:31:22 +00004775}
4776
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11004777static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
4778 abi_ulong target_addr)
4779{
4780 struct target_itimerspec *target_itspec;
4781
4782 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
4783 return -TARGET_EFAULT;
4784 }
4785
4786 host_itspec->it_interval.tv_sec =
4787 tswapal(target_itspec->it_interval.tv_sec);
4788 host_itspec->it_interval.tv_nsec =
4789 tswapal(target_itspec->it_interval.tv_nsec);
4790 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
4791 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
4792
4793 unlock_user_struct(target_itspec, target_addr, 1);
4794 return 0;
4795}
4796
4797static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
4798 struct itimerspec *host_its)
4799{
4800 struct target_itimerspec *target_itspec;
4801
4802 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
4803 return -TARGET_EFAULT;
4804 }
4805
4806 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
4807 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
4808
4809 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
4810 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
4811
4812 unlock_user_struct(target_itspec, target_addr, 0);
4813 return 0;
4814}
4815
aurel329d33b762009-04-08 23:07:05 +00004816#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004817static inline abi_long host_to_target_stat64(void *cpu_env,
4818 abi_ulong target_addr,
4819 struct stat *host_st)
4820{
Alexander Graf09701192013-09-03 20:12:15 +01004821#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00004822 if (((CPUARMState *)cpu_env)->eabi) {
4823 struct target_eabi_stat64 *target_st;
4824
4825 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4826 return -TARGET_EFAULT;
4827 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4828 __put_user(host_st->st_dev, &target_st->st_dev);
4829 __put_user(host_st->st_ino, &target_st->st_ino);
4830#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4831 __put_user(host_st->st_ino, &target_st->__st_ino);
4832#endif
4833 __put_user(host_st->st_mode, &target_st->st_mode);
4834 __put_user(host_st->st_nlink, &target_st->st_nlink);
4835 __put_user(host_st->st_uid, &target_st->st_uid);
4836 __put_user(host_st->st_gid, &target_st->st_gid);
4837 __put_user(host_st->st_rdev, &target_st->st_rdev);
4838 __put_user(host_st->st_size, &target_st->st_size);
4839 __put_user(host_st->st_blksize, &target_st->st_blksize);
4840 __put_user(host_st->st_blocks, &target_st->st_blocks);
4841 __put_user(host_st->st_atime, &target_st->target_st_atime);
4842 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4843 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4844 unlock_user_struct(target_st, target_addr, 1);
4845 } else
4846#endif
4847 {
Stefan Weil20d155b2013-10-30 22:52:24 +01004848#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00004849 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01004850#else
4851 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00004852#endif
balrog6a24a772008-09-20 02:23:36 +00004853
4854 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4855 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004856 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004857 __put_user(host_st->st_dev, &target_st->st_dev);
4858 __put_user(host_st->st_ino, &target_st->st_ino);
4859#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4860 __put_user(host_st->st_ino, &target_st->__st_ino);
4861#endif
4862 __put_user(host_st->st_mode, &target_st->st_mode);
4863 __put_user(host_st->st_nlink, &target_st->st_nlink);
4864 __put_user(host_st->st_uid, &target_st->st_uid);
4865 __put_user(host_st->st_gid, &target_st->st_gid);
4866 __put_user(host_st->st_rdev, &target_st->st_rdev);
4867 /* XXX: better use of kernel struct */
4868 __put_user(host_st->st_size, &target_st->st_size);
4869 __put_user(host_st->st_blksize, &target_st->st_blksize);
4870 __put_user(host_st->st_blocks, &target_st->st_blocks);
4871 __put_user(host_st->st_atime, &target_st->target_st_atime);
4872 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4873 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4874 unlock_user_struct(target_st, target_addr, 1);
4875 }
4876
4877 return 0;
4878}
4879#endif
4880
pbrookbd0c5662008-05-29 14:34:11 +00004881/* ??? Using host futex calls even when target atomic operations
4882 are not really atomic probably breaks things. However implementing
4883 futexes locally would make futexes shared between multiple processes
4884 tricky. However they're probably useless because guest atomic
4885 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004886static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4887 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004888{
4889 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004890 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004891
4892 /* ??? We assume FUTEX_* constants are the same on both host
4893 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004894#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004895 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004896#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004897 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004898#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004899 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004900 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07004901 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00004902 if (timeout) {
4903 pts = &ts;
4904 target_to_host_timespec(pts, timeout);
4905 } else {
4906 pts = NULL;
4907 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004908 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07004909 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00004910 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004911 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004912 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004913 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004914 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004915 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004916 case FUTEX_WAKE_OP:
4917 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4918 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4919 But the prototype takes a `struct timespec *'; insert casts
4920 to satisfy the compiler. We do not need to tswap TIMEOUT
4921 since it's not compared to guest memory. */
4922 pts = (struct timespec *)(uintptr_t) timeout;
4923 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4924 g2h(uaddr2),
4925 (base_op == FUTEX_CMP_REQUEUE
4926 ? tswap32(val3)
4927 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004928 default:
4929 return -TARGET_ENOSYS;
4930 }
4931}
pbrookbd0c5662008-05-29 14:34:11 +00004932
pbrook1d9d8b52009-04-16 15:17:02 +00004933/* Map host to target signal numbers for the wait family of syscalls.
4934 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07004935int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00004936{
4937 if (WIFSIGNALED(status)) {
4938 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4939 }
4940 if (WIFSTOPPED(status)) {
4941 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4942 | (status & 0xff);
4943 }
4944 return status;
4945}
4946
Peter Maydell4a24a752013-09-03 20:12:20 +01004947static int relstr_to_int(const char *s)
pbrooka745ec62008-05-06 15:36:17 +00004948{
Peter Maydell4a24a752013-09-03 20:12:20 +01004949 /* Convert a uname release string like "2.6.18" to an integer
4950 * of the form 0x020612. (Beware that 0x020612 is *not* 2.6.12.)
4951 */
pbrooka745ec62008-05-06 15:36:17 +00004952 int i, n, tmp;
Peter Maydell4a24a752013-09-03 20:12:20 +01004953
pbrooka745ec62008-05-06 15:36:17 +00004954 tmp = 0;
4955 for (i = 0; i < 3; i++) {
4956 n = 0;
4957 while (*s >= '0' && *s <= '9') {
4958 n *= 10;
4959 n += *s - '0';
4960 s++;
4961 }
4962 tmp = (tmp << 8) + n;
Peter Maydell4a24a752013-09-03 20:12:20 +01004963 if (*s == '.') {
pbrooka745ec62008-05-06 15:36:17 +00004964 s++;
Peter Maydell4a24a752013-09-03 20:12:20 +01004965 }
pbrooka745ec62008-05-06 15:36:17 +00004966 }
Peter Maydell4a24a752013-09-03 20:12:20 +01004967 return tmp;
4968}
4969
4970int get_osversion(void)
4971{
4972 static int osversion;
4973 struct new_utsname buf;
4974 const char *s;
4975
4976 if (osversion)
4977 return osversion;
4978 if (qemu_uname_release && *qemu_uname_release) {
4979 s = qemu_uname_release;
4980 } else {
4981 if (sys_uname(&buf))
4982 return 0;
4983 s = buf.release;
4984 }
4985 osversion = relstr_to_int(s);
pbrooka745ec62008-05-06 15:36:17 +00004986 return osversion;
4987}
4988
Peter Maydell4a24a752013-09-03 20:12:20 +01004989void init_qemu_uname_release(void)
4990{
4991 /* Initialize qemu_uname_release for later use.
4992 * If the host kernel is too old and the user hasn't asked for
4993 * a specific fake version number, we might want to fake a minimum
4994 * target kernel version.
4995 */
4996#ifdef UNAME_MINIMUM_RELEASE
4997 struct new_utsname buf;
4998
4999 if (qemu_uname_release && *qemu_uname_release) {
5000 return;
5001 }
5002
5003 if (sys_uname(&buf)) {
5004 return;
5005 }
5006
5007 if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) {
5008 qemu_uname_release = UNAME_MINIMUM_RELEASE;
5009 }
5010#endif
5011}
Alexander Graf36c08d42011-11-02 20:23:24 +01005012
5013static int open_self_maps(void *cpu_env, int fd)
5014{
Alexander Graf1a49ef22012-05-01 16:30:28 +01005015#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Andreas Färber0429a972013-08-26 18:14:44 +02005016 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5017 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005018#endif
5019 FILE *fp;
5020 char *line = NULL;
5021 size_t len = 0;
5022 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005023
Alexander Graf1a49ef22012-05-01 16:30:28 +01005024 fp = fopen("/proc/self/maps", "r");
5025 if (fp == NULL) {
5026 return -EACCES;
5027 }
5028
5029 while ((read = getline(&line, &len, fp)) != -1) {
5030 int fields, dev_maj, dev_min, inode;
5031 uint64_t min, max, offset;
5032 char flag_r, flag_w, flag_x, flag_p;
5033 char path[512] = "";
5034 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5035 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5036 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5037
5038 if ((fields < 10) || (fields > 11)) {
5039 continue;
5040 }
5041 if (!strncmp(path, "[stack]", 7)) {
5042 continue;
5043 }
5044 if (h2g_valid(min) && h2g_valid(max)) {
5045 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02005046 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Alexander Graf1a49ef22012-05-01 16:30:28 +01005047 h2g(min), h2g(max), flag_r, flag_w,
5048 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02005049 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01005050 }
5051 }
5052
5053 free(line);
5054 fclose(fp);
5055
5056#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Alexander Graf36c08d42011-11-02 20:23:24 +01005057 dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
5058 (unsigned long long)ts->info->stack_limit,
Alexander Graf1bdd7c72012-05-30 14:45:21 +02005059 (unsigned long long)(ts->info->start_stack +
5060 (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005061 (unsigned long long)0);
5062#endif
Alexander Graf36c08d42011-11-02 20:23:24 +01005063
5064 return 0;
5065}
5066
Alexander Graf480b8e72011-11-02 20:23:25 +01005067static int open_self_stat(void *cpu_env, int fd)
5068{
Andreas Färber0429a972013-08-26 18:14:44 +02005069 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5070 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005071 abi_ulong start_stack = ts->info->start_stack;
5072 int i;
5073
5074 for (i = 0; i < 44; i++) {
5075 char buf[128];
5076 int len;
5077 uint64_t val = 0;
5078
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005079 if (i == 0) {
5080 /* pid */
5081 val = getpid();
5082 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5083 } else if (i == 1) {
5084 /* app name */
5085 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5086 } else if (i == 27) {
5087 /* stack bottom */
5088 val = start_stack;
5089 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5090 } else {
5091 /* for the rest, there is MasterCard */
5092 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005093 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005094
Alexander Graf480b8e72011-11-02 20:23:25 +01005095 len = strlen(buf);
5096 if (write(fd, buf, len) != len) {
5097 return -1;
5098 }
5099 }
5100
5101 return 0;
5102}
5103
Alexander Graf257450e2011-11-02 20:23:26 +01005104static int open_self_auxv(void *cpu_env, int fd)
5105{
Andreas Färber0429a972013-08-26 18:14:44 +02005106 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5107 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005108 abi_ulong auxv = ts->info->saved_auxv;
5109 abi_ulong len = ts->info->auxv_len;
5110 char *ptr;
5111
5112 /*
5113 * Auxiliary vector is stored in target process stack.
5114 * read in whole auxv vector and copy it to file
5115 */
5116 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5117 if (ptr != NULL) {
5118 while (len > 0) {
5119 ssize_t r;
5120 r = write(fd, ptr, len);
5121 if (r <= 0) {
5122 break;
5123 }
5124 len -= r;
5125 ptr += r;
5126 }
5127 lseek(fd, 0, SEEK_SET);
5128 unlock_user(ptr, auxv, len);
5129 }
5130
5131 return 0;
5132}
5133
Andreas Schwab463d8e72013-07-02 14:04:12 +01005134static int is_proc_myself(const char *filename, const char *entry)
5135{
5136 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5137 filename += strlen("/proc/");
5138 if (!strncmp(filename, "self/", strlen("self/"))) {
5139 filename += strlen("self/");
5140 } else if (*filename >= '1' && *filename <= '9') {
5141 char myself[80];
5142 snprintf(myself, sizeof(myself), "%d/", getpid());
5143 if (!strncmp(filename, myself, strlen(myself))) {
5144 filename += strlen(myself);
5145 } else {
5146 return 0;
5147 }
5148 } else {
5149 return 0;
5150 }
5151 if (!strcmp(filename, entry)) {
5152 return 1;
5153 }
5154 }
5155 return 0;
5156}
5157
Laurent Vivierde6b9932013-08-30 01:46:40 +02005158#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5159static int is_proc(const char *filename, const char *entry)
5160{
5161 return strcmp(filename, entry) == 0;
5162}
5163
5164static int open_net_route(void *cpu_env, int fd)
5165{
5166 FILE *fp;
5167 char *line = NULL;
5168 size_t len = 0;
5169 ssize_t read;
5170
5171 fp = fopen("/proc/net/route", "r");
5172 if (fp == NULL) {
5173 return -EACCES;
5174 }
5175
5176 /* read header */
5177
5178 read = getline(&line, &len, fp);
5179 dprintf(fd, "%s", line);
5180
5181 /* read routes */
5182
5183 while ((read = getline(&line, &len, fp)) != -1) {
5184 char iface[16];
5185 uint32_t dest, gw, mask;
5186 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5187 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5188 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5189 &mask, &mtu, &window, &irtt);
5190 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5191 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5192 metric, tswap32(mask), mtu, window, irtt);
5193 }
5194
5195 free(line);
5196 fclose(fp);
5197
5198 return 0;
5199}
5200#endif
5201
Alexander Graf3be14d02011-11-02 20:23:23 +01005202static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
5203{
5204 struct fake_open {
5205 const char *filename;
5206 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005207 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005208 };
5209 const struct fake_open *fake_open;
5210 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005211 { "maps", open_self_maps, is_proc_myself },
5212 { "stat", open_self_stat, is_proc_myself },
5213 { "auxv", open_self_auxv, is_proc_myself },
5214#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5215 { "/proc/net/route", open_net_route, is_proc },
5216#endif
5217 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005218 };
5219
5220 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005221 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005222 break;
5223 }
5224 }
5225
5226 if (fake_open->filename) {
5227 const char *tmpdir;
5228 char filename[PATH_MAX];
5229 int fd, r;
5230
5231 /* create temporary file to map stat to */
5232 tmpdir = getenv("TMPDIR");
5233 if (!tmpdir)
5234 tmpdir = "/tmp";
5235 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5236 fd = mkstemp(filename);
5237 if (fd < 0) {
5238 return fd;
5239 }
5240 unlink(filename);
5241
5242 if ((r = fake_open->fill(cpu_env, fd))) {
5243 close(fd);
5244 return r;
5245 }
5246 lseek(fd, 0, SEEK_SET);
5247
5248 return fd;
5249 }
5250
5251 return get_errno(open(path(pathname), flags, mode));
5252}
5253
ths0da46a62007-10-20 20:23:07 +00005254/* do_syscall() should always have a single exit point at the end so
5255 that actions, such as logging of syscall results, can be performed.
5256 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005257abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5258 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005259 abi_long arg5, abi_long arg6, abi_long arg7,
5260 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005261{
Andreas Färber182735e2013-05-29 22:29:20 +02005262 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005263 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005264 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005265 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005266 void *p;
ths3b46e622007-09-17 08:09:54 +00005267
bellard72f03902003-02-18 23:33:18 +00005268#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005269 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005270#endif
thsb92c47c2007-11-01 00:07:38 +00005271 if(do_strace)
5272 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5273
bellard31e31b82003-02-18 22:55:36 +00005274 switch(num) {
5275 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005276 /* In old applications this may be used to implement _exit(2).
5277 However in threaded applictions it is used for thread termination,
5278 and _exit_group is used for application termination.
5279 Do thread termination if we have more then one thread. */
5280 /* FIXME: This probably breaks if a signal arrives. We should probably
5281 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005282 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005283 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005284
Andreas Färber9b056fc2013-06-24 23:53:10 +02005285 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005286 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005287 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005288 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005289 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005290 if (ts->child_tidptr) {
5291 put_user_u32(0, ts->child_tidptr);
5292 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5293 NULL, NULL, 0);
5294 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005295 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005296 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005297 g_free(ts);
5298 pthread_exit(NULL);
5299 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005300#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005301 _mcleanup();
5302#endif
bellarde9009672005-04-26 20:42:36 +00005303 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005304 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005305 ret = 0; /* avoid warning */
5306 break;
5307 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005308 if (arg3 == 0)
5309 ret = 0;
5310 else {
5311 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5312 goto efault;
5313 ret = get_errno(read(arg1, p, arg3));
5314 unlock_user(p, arg2, ret);
5315 }
bellard31e31b82003-02-18 22:55:36 +00005316 break;
5317 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005318 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5319 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005320 ret = get_errno(write(arg1, p, arg3));
5321 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005322 break;
5323 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005324 if (!(p = lock_user_string(arg1)))
5325 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005326 ret = get_errno(do_open(cpu_env, p,
5327 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5328 arg3));
pbrook53a59602006-03-25 19:31:22 +00005329 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005330 break;
ths82424832007-09-24 09:21:55 +00005331#if defined(TARGET_NR_openat) && defined(__NR_openat)
5332 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005333 if (!(p = lock_user_string(arg2)))
5334 goto efault;
5335 ret = get_errno(sys_openat(arg1,
5336 path(p),
5337 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5338 arg4));
5339 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005340 break;
5341#endif
bellard31e31b82003-02-18 22:55:36 +00005342 case TARGET_NR_close:
5343 ret = get_errno(close(arg1));
5344 break;
5345 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005346 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005347 break;
5348 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005349 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005350 break;
thse5febef2007-04-01 18:31:35 +00005351#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005352 case TARGET_NR_waitpid:
5353 {
pbrook53a59602006-03-25 19:31:22 +00005354 int status;
5355 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005356 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005357 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005358 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005359 }
5360 break;
thse5febef2007-04-01 18:31:35 +00005361#endif
pbrookf0cbb612008-05-30 18:20:05 +00005362#ifdef TARGET_NR_waitid
5363 case TARGET_NR_waitid:
5364 {
5365 siginfo_t info;
5366 info.si_pid = 0;
5367 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5368 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005369 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005370 goto efault;
5371 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005372 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005373 }
5374 }
5375 break;
5376#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005377#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005378 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005379 if (!(p = lock_user_string(arg1)))
5380 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005381 ret = get_errno(creat(p, arg2));
5382 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005383 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005384#endif
bellard31e31b82003-02-18 22:55:36 +00005385 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005386 {
5387 void * p2;
5388 p = lock_user_string(arg1);
5389 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005390 if (!p || !p2)
5391 ret = -TARGET_EFAULT;
5392 else
5393 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005394 unlock_user(p2, arg2, 0);
5395 unlock_user(p, arg1, 0);
5396 }
bellard31e31b82003-02-18 22:55:36 +00005397 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005398#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00005399 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005400 {
5401 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005402 if (!arg2 || !arg4)
5403 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005404 p = lock_user_string(arg2);
5405 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005406 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005407 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005408 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005409 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005410 unlock_user(p, arg2, 0);
5411 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005412 }
5413 break;
5414#endif
bellard31e31b82003-02-18 22:55:36 +00005415 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005416 if (!(p = lock_user_string(arg1)))
5417 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005418 ret = get_errno(unlink(p));
5419 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005420 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005421#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00005422 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005423 if (!(p = lock_user_string(arg2)))
5424 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005425 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005426 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005427 break;
balrogb7d35e62007-12-12 00:40:24 +00005428#endif
bellard31e31b82003-02-18 22:55:36 +00005429 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005430 {
5431 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005432 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005433 abi_ulong gp;
5434 abi_ulong guest_argp;
5435 abi_ulong guest_envp;
5436 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005437 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005438 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005439
bellardf7341ff2003-03-30 21:00:25 +00005440 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005441 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005442 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005443 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005444 goto efault;
ths03aa1972007-12-02 06:28:08 +00005445 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005446 break;
bellard7854b052003-03-29 17:22:23 +00005447 argc++;
bellard2f619692007-11-16 10:46:05 +00005448 }
bellardf7341ff2003-03-30 21:00:25 +00005449 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005450 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005451 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005452 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005453 goto efault;
ths03aa1972007-12-02 06:28:08 +00005454 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005455 break;
bellard7854b052003-03-29 17:22:23 +00005456 envc++;
bellard2f619692007-11-16 10:46:05 +00005457 }
bellard7854b052003-03-29 17:22:23 +00005458
bellardf7341ff2003-03-30 21:00:25 +00005459 argp = alloca((argc + 1) * sizeof(void *));
5460 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005461
pbrookda94d262008-05-30 18:24:00 +00005462 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005463 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005464 if (get_user_ual(addr, gp))
5465 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005466 if (!addr)
5467 break;
bellard2f619692007-11-16 10:46:05 +00005468 if (!(*q = lock_user_string(addr)))
5469 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005470 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005471 }
bellardf7341ff2003-03-30 21:00:25 +00005472 *q = NULL;
5473
pbrookda94d262008-05-30 18:24:00 +00005474 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005475 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005476 if (get_user_ual(addr, gp))
5477 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005478 if (!addr)
5479 break;
bellard2f619692007-11-16 10:46:05 +00005480 if (!(*q = lock_user_string(addr)))
5481 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005482 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005483 }
bellardf7341ff2003-03-30 21:00:25 +00005484 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005485
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005486 /* This case will not be caught by the host's execve() if its
5487 page size is bigger than the target's. */
5488 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5489 ret = -TARGET_E2BIG;
5490 goto execve_end;
5491 }
bellard2f619692007-11-16 10:46:05 +00005492 if (!(p = lock_user_string(arg1)))
5493 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005494 ret = get_errno(execve(p, argp, envp));
5495 unlock_user(p, arg1, 0);
5496
bellard2f619692007-11-16 10:46:05 +00005497 goto execve_end;
5498
5499 execve_efault:
5500 ret = -TARGET_EFAULT;
5501
5502 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005503 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005504 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005505 if (get_user_ual(addr, gp)
5506 || !addr)
5507 break;
pbrook53a59602006-03-25 19:31:22 +00005508 unlock_user(*q, addr, 0);
5509 }
5510 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005511 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005512 if (get_user_ual(addr, gp)
5513 || !addr)
5514 break;
pbrook53a59602006-03-25 19:31:22 +00005515 unlock_user(*q, addr, 0);
5516 }
bellard7854b052003-03-29 17:22:23 +00005517 }
bellard31e31b82003-02-18 22:55:36 +00005518 break;
5519 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005520 if (!(p = lock_user_string(arg1)))
5521 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005522 ret = get_errno(chdir(p));
5523 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005524 break;
bellarda315a142005-01-30 22:59:18 +00005525#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005526 case TARGET_NR_time:
5527 {
pbrook53a59602006-03-25 19:31:22 +00005528 time_t host_time;
5529 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005530 if (!is_error(ret)
5531 && arg1
5532 && put_user_sal(host_time, arg1))
5533 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005534 }
5535 break;
bellarda315a142005-01-30 22:59:18 +00005536#endif
bellard31e31b82003-02-18 22:55:36 +00005537 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005538 if (!(p = lock_user_string(arg1)))
5539 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005540 ret = get_errno(mknod(p, arg2, arg3));
5541 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005542 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005543#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00005544 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005545 if (!(p = lock_user_string(arg2)))
5546 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005547 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00005548 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005549 break;
5550#endif
bellard31e31b82003-02-18 22:55:36 +00005551 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005552 if (!(p = lock_user_string(arg1)))
5553 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005554 ret = get_errno(chmod(p, arg2));
5555 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005556 break;
bellardebc05482003-09-30 21:08:41 +00005557#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005558 case TARGET_NR_break:
5559 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005560#endif
5561#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005562 case TARGET_NR_oldstat:
5563 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005564#endif
bellard31e31b82003-02-18 22:55:36 +00005565 case TARGET_NR_lseek:
5566 ret = get_errno(lseek(arg1, arg2, arg3));
5567 break;
Richard Henderson92317332010-05-03 10:07:53 -07005568#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5569 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005570 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005571 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005572 ret = get_errno(getpid());
5573 break;
Richard Henderson92317332010-05-03 10:07:53 -07005574#endif
5575#ifdef TARGET_NR_getpid
5576 case TARGET_NR_getpid:
5577 ret = get_errno(getpid());
5578 break;
5579#endif
bellard31e31b82003-02-18 22:55:36 +00005580 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00005581 {
5582 /* need to look at the data field */
5583 void *p2, *p3;
5584 p = lock_user_string(arg1);
5585 p2 = lock_user_string(arg2);
5586 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005587 if (!p || !p2 || !p3)
5588 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005589 else {
bellard579a97f2007-11-11 14:26:47 +00005590 /* FIXME - arg5 should be locked, but it isn't clear how to
5591 * do that since it's not guaranteed to be a NULL-terminated
5592 * string.
5593 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005594 if ( ! arg5 )
5595 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
5596 else
5597 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
5598 }
bellard579a97f2007-11-11 14:26:47 +00005599 unlock_user(p, arg1, 0);
5600 unlock_user(p2, arg2, 0);
5601 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00005602 break;
5603 }
thse5febef2007-04-01 18:31:35 +00005604#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005605 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005606 if (!(p = lock_user_string(arg1)))
5607 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005608 ret = get_errno(umount(p));
5609 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005610 break;
thse5febef2007-04-01 18:31:35 +00005611#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005612#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005613 case TARGET_NR_stime:
5614 {
pbrook53a59602006-03-25 19:31:22 +00005615 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005616 if (get_user_sal(host_time, arg1))
5617 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005618 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005619 }
5620 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005621#endif
bellard31e31b82003-02-18 22:55:36 +00005622 case TARGET_NR_ptrace:
5623 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005624#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005625 case TARGET_NR_alarm:
5626 ret = alarm(arg1);
5627 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005628#endif
bellardebc05482003-09-30 21:08:41 +00005629#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005630 case TARGET_NR_oldfstat:
5631 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005632#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005633#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005634 case TARGET_NR_pause:
5635 ret = get_errno(pause());
5636 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005637#endif
thse5febef2007-04-01 18:31:35 +00005638#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005639 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005640 {
pbrook53a59602006-03-25 19:31:22 +00005641 struct utimbuf tbuf, *host_tbuf;
5642 struct target_utimbuf *target_tbuf;
5643 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005644 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5645 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005646 tbuf.actime = tswapal(target_tbuf->actime);
5647 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005648 unlock_user_struct(target_tbuf, arg2, 0);
5649 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005650 } else {
pbrook53a59602006-03-25 19:31:22 +00005651 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005652 }
bellard579a97f2007-11-11 14:26:47 +00005653 if (!(p = lock_user_string(arg1)))
5654 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005655 ret = get_errno(utime(p, host_tbuf));
5656 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005657 }
5658 break;
thse5febef2007-04-01 18:31:35 +00005659#endif
bellard978a66f2004-12-06 22:58:05 +00005660 case TARGET_NR_utimes:
5661 {
bellard978a66f2004-12-06 22:58:05 +00005662 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005663 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005664 if (copy_from_user_timeval(&tv[0], arg2)
5665 || copy_from_user_timeval(&tv[1],
5666 arg2 + sizeof(struct target_timeval)))
5667 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005668 tvp = tv;
5669 } else {
5670 tvp = NULL;
5671 }
bellard579a97f2007-11-11 14:26:47 +00005672 if (!(p = lock_user_string(arg1)))
5673 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005674 ret = get_errno(utimes(p, tvp));
5675 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005676 }
5677 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005678#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00005679 case TARGET_NR_futimesat:
5680 {
5681 struct timeval *tvp, tv[2];
5682 if (arg3) {
5683 if (copy_from_user_timeval(&tv[0], arg3)
5684 || copy_from_user_timeval(&tv[1],
5685 arg3 + sizeof(struct target_timeval)))
5686 goto efault;
5687 tvp = tv;
5688 } else {
5689 tvp = NULL;
5690 }
5691 if (!(p = lock_user_string(arg2)))
5692 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005693 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00005694 unlock_user(p, arg2, 0);
5695 }
5696 break;
5697#endif
bellardebc05482003-09-30 21:08:41 +00005698#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005699 case TARGET_NR_stty:
5700 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005701#endif
5702#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005703 case TARGET_NR_gtty:
5704 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005705#endif
bellard31e31b82003-02-18 22:55:36 +00005706 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005707 if (!(p = lock_user_string(arg1)))
5708 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005709 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005710 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005711 break;
ths92a34c12007-09-24 09:27:49 +00005712#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5713 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005714 if (!(p = lock_user_string(arg2)))
5715 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005716 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00005717 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005718 break;
5719#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005720#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005721 case TARGET_NR_nice:
5722 ret = get_errno(nice(arg1));
5723 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005724#endif
bellardebc05482003-09-30 21:08:41 +00005725#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005726 case TARGET_NR_ftime:
5727 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005728#endif
bellard31e31b82003-02-18 22:55:36 +00005729 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005730 sync();
5731 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005732 break;
5733 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005734 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005735 break;
5736 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005737 {
5738 void *p2;
5739 p = lock_user_string(arg1);
5740 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005741 if (!p || !p2)
5742 ret = -TARGET_EFAULT;
5743 else
5744 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005745 unlock_user(p2, arg2, 0);
5746 unlock_user(p, arg1, 0);
5747 }
bellard31e31b82003-02-18 22:55:36 +00005748 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005749#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00005750 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005751 {
bellard579a97f2007-11-11 14:26:47 +00005752 void *p2;
ths722183f2007-09-24 09:24:37 +00005753 p = lock_user_string(arg2);
5754 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005755 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005756 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005757 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005758 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005759 unlock_user(p2, arg4, 0);
5760 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005761 }
5762 break;
5763#endif
bellard31e31b82003-02-18 22:55:36 +00005764 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005765 if (!(p = lock_user_string(arg1)))
5766 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005767 ret = get_errno(mkdir(p, arg2));
5768 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005769 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005770#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00005771 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005772 if (!(p = lock_user_string(arg2)))
5773 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005774 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005775 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005776 break;
5777#endif
bellard31e31b82003-02-18 22:55:36 +00005778 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005779 if (!(p = lock_user_string(arg1)))
5780 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005781 ret = get_errno(rmdir(p));
5782 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005783 break;
5784 case TARGET_NR_dup:
5785 ret = get_errno(dup(arg1));
5786 break;
5787 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005788 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005789 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005790#ifdef TARGET_NR_pipe2
5791 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07005792 ret = do_pipe(cpu_env, arg1,
5793 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005794 break;
5795#endif
bellard31e31b82003-02-18 22:55:36 +00005796 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005797 {
pbrook53a59602006-03-25 19:31:22 +00005798 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005799 struct tms tms;
5800 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005801 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005802 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5803 if (!tmsp)
5804 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005805 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5806 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5807 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5808 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005809 }
bellardc596ed12003-07-13 17:32:31 +00005810 if (!is_error(ret))
5811 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005812 }
5813 break;
bellardebc05482003-09-30 21:08:41 +00005814#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005815 case TARGET_NR_prof:
5816 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005817#endif
thse5febef2007-04-01 18:31:35 +00005818#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005819 case TARGET_NR_signal:
5820 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005821#endif
bellard31e31b82003-02-18 22:55:36 +00005822 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005823 if (arg1 == 0) {
5824 ret = get_errno(acct(NULL));
5825 } else {
5826 if (!(p = lock_user_string(arg1)))
5827 goto efault;
5828 ret = get_errno(acct(path(p)));
5829 unlock_user(p, arg1, 0);
5830 }
pbrook24836682006-04-16 14:14:53 +00005831 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10005832#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00005833 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005834 if (!(p = lock_user_string(arg1)))
5835 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005836 ret = get_errno(umount2(p, arg2));
5837 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005838 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005839#endif
bellardebc05482003-09-30 21:08:41 +00005840#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005841 case TARGET_NR_lock:
5842 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005843#endif
bellard31e31b82003-02-18 22:55:36 +00005844 case TARGET_NR_ioctl:
5845 ret = do_ioctl(arg1, arg2, arg3);
5846 break;
5847 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005848 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005849 break;
bellardebc05482003-09-30 21:08:41 +00005850#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005851 case TARGET_NR_mpx:
5852 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005853#endif
bellard31e31b82003-02-18 22:55:36 +00005854 case TARGET_NR_setpgid:
5855 ret = get_errno(setpgid(arg1, arg2));
5856 break;
bellardebc05482003-09-30 21:08:41 +00005857#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005858 case TARGET_NR_ulimit:
5859 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005860#endif
5861#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005862 case TARGET_NR_oldolduname:
5863 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005864#endif
bellard31e31b82003-02-18 22:55:36 +00005865 case TARGET_NR_umask:
5866 ret = get_errno(umask(arg1));
5867 break;
5868 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005869 if (!(p = lock_user_string(arg1)))
5870 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005871 ret = get_errno(chroot(p));
5872 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005873 break;
5874 case TARGET_NR_ustat:
5875 goto unimplemented;
5876 case TARGET_NR_dup2:
5877 ret = get_errno(dup2(arg1, arg2));
5878 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005879#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5880 case TARGET_NR_dup3:
5881 ret = get_errno(dup3(arg1, arg2, arg3));
5882 break;
5883#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005884#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005885 case TARGET_NR_getppid:
5886 ret = get_errno(getppid());
5887 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005888#endif
bellard31e31b82003-02-18 22:55:36 +00005889 case TARGET_NR_getpgrp:
5890 ret = get_errno(getpgrp());
5891 break;
5892 case TARGET_NR_setsid:
5893 ret = get_errno(setsid());
5894 break;
thse5febef2007-04-01 18:31:35 +00005895#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005896 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005897 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005898#if defined(TARGET_ALPHA)
5899 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005900 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005901 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005902 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5903 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005904 act._sa_handler = old_act->_sa_handler;
5905 target_siginitset(&act.sa_mask, old_act->sa_mask);
5906 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005907 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005908 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005909 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005910 }
5911 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005912 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005913 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5914 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005915 old_act->_sa_handler = oact._sa_handler;
5916 old_act->sa_mask = oact.sa_mask.sig[0];
5917 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005918 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005919 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005920#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005921 struct target_sigaction act, oact, *pact, *old_act;
5922
5923 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005924 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5925 goto efault;
bellard106ec872006-06-27 21:08:10 +00005926 act._sa_handler = old_act->_sa_handler;
5927 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5928 act.sa_flags = old_act->sa_flags;
5929 unlock_user_struct(old_act, arg2, 0);
5930 pact = &act;
5931 } else {
5932 pact = NULL;
5933 }
5934
5935 ret = get_errno(do_sigaction(arg1, pact, &oact));
5936
5937 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005938 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5939 goto efault;
bellard106ec872006-06-27 21:08:10 +00005940 old_act->_sa_handler = oact._sa_handler;
5941 old_act->sa_flags = oact.sa_flags;
5942 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5943 old_act->sa_mask.sig[1] = 0;
5944 old_act->sa_mask.sig[2] = 0;
5945 old_act->sa_mask.sig[3] = 0;
5946 unlock_user_struct(old_act, arg3, 1);
5947 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005948#else
5949 struct target_old_sigaction *old_act;
5950 struct target_sigaction act, oact, *pact;
5951 if (arg2) {
5952 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5953 goto efault;
5954 act._sa_handler = old_act->_sa_handler;
5955 target_siginitset(&act.sa_mask, old_act->sa_mask);
5956 act.sa_flags = old_act->sa_flags;
5957 act.sa_restorer = old_act->sa_restorer;
5958 unlock_user_struct(old_act, arg2, 0);
5959 pact = &act;
5960 } else {
5961 pact = NULL;
5962 }
5963 ret = get_errno(do_sigaction(arg1, pact, &oact));
5964 if (!is_error(ret) && arg3) {
5965 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5966 goto efault;
5967 old_act->_sa_handler = oact._sa_handler;
5968 old_act->sa_mask = oact.sa_mask.sig[0];
5969 old_act->sa_flags = oact.sa_flags;
5970 old_act->sa_restorer = oact.sa_restorer;
5971 unlock_user_struct(old_act, arg3, 1);
5972 }
ths388bb212007-05-13 13:58:00 +00005973#endif
bellard31e31b82003-02-18 22:55:36 +00005974 }
5975 break;
thse5febef2007-04-01 18:31:35 +00005976#endif
bellard66fb9762003-03-23 01:06:05 +00005977 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005978 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005979#if defined(TARGET_ALPHA)
5980 struct target_sigaction act, oact, *pact = 0;
5981 struct target_rt_sigaction *rt_act;
5982 /* ??? arg4 == sizeof(sigset_t). */
5983 if (arg2) {
5984 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5985 goto efault;
5986 act._sa_handler = rt_act->_sa_handler;
5987 act.sa_mask = rt_act->sa_mask;
5988 act.sa_flags = rt_act->sa_flags;
5989 act.sa_restorer = arg5;
5990 unlock_user_struct(rt_act, arg2, 0);
5991 pact = &act;
5992 }
5993 ret = get_errno(do_sigaction(arg1, pact, &oact));
5994 if (!is_error(ret) && arg3) {
5995 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5996 goto efault;
5997 rt_act->_sa_handler = oact._sa_handler;
5998 rt_act->sa_mask = oact.sa_mask;
5999 rt_act->sa_flags = oact.sa_flags;
6000 unlock_user_struct(rt_act, arg3, 1);
6001 }
6002#else
pbrook53a59602006-03-25 19:31:22 +00006003 struct target_sigaction *act;
6004 struct target_sigaction *oact;
6005
bellard579a97f2007-11-11 14:26:47 +00006006 if (arg2) {
6007 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
6008 goto efault;
6009 } else
pbrook53a59602006-03-25 19:31:22 +00006010 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00006011 if (arg3) {
6012 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
6013 ret = -TARGET_EFAULT;
6014 goto rt_sigaction_fail;
6015 }
6016 } else
pbrook53a59602006-03-25 19:31:22 +00006017 oact = NULL;
6018 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00006019 rt_sigaction_fail:
6020 if (act)
pbrook53a59602006-03-25 19:31:22 +00006021 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00006022 if (oact)
pbrook53a59602006-03-25 19:31:22 +00006023 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08006024#endif
pbrook53a59602006-03-25 19:31:22 +00006025 }
bellard66fb9762003-03-23 01:06:05 +00006026 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006027#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006028 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00006029 {
6030 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006031 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00006032 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006033 host_to_target_old_sigset(&target_set, &cur_set);
6034 ret = target_set;
6035 }
6036 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006037#endif
6038#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006039 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00006040 {
6041 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006042 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00006043 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006044 target_to_host_old_sigset(&set, &target_set);
6045 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00006046 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00006047 host_to_target_old_sigset(&target_set, &oset);
6048 ret = target_set;
6049 }
6050 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006051#endif
thse5febef2007-04-01 18:31:35 +00006052#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006053 case TARGET_NR_sigprocmask:
6054 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006055#if defined(TARGET_ALPHA)
6056 sigset_t set, oldset;
6057 abi_ulong mask;
6058 int how;
6059
6060 switch (arg1) {
6061 case TARGET_SIG_BLOCK:
6062 how = SIG_BLOCK;
6063 break;
6064 case TARGET_SIG_UNBLOCK:
6065 how = SIG_UNBLOCK;
6066 break;
6067 case TARGET_SIG_SETMASK:
6068 how = SIG_SETMASK;
6069 break;
6070 default:
6071 ret = -TARGET_EINVAL;
6072 goto fail;
6073 }
6074 mask = arg2;
6075 target_to_host_old_sigset(&set, &mask);
6076
Alex Barcelo1c275922014-03-14 14:36:55 +00006077 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006078 if (!is_error(ret)) {
6079 host_to_target_old_sigset(&mask, &oldset);
6080 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006081 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006082 }
6083#else
bellard66fb9762003-03-23 01:06:05 +00006084 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006085 int how;
ths3b46e622007-09-17 08:09:54 +00006086
pbrook53a59602006-03-25 19:31:22 +00006087 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006088 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006089 case TARGET_SIG_BLOCK:
6090 how = SIG_BLOCK;
6091 break;
6092 case TARGET_SIG_UNBLOCK:
6093 how = SIG_UNBLOCK;
6094 break;
6095 case TARGET_SIG_SETMASK:
6096 how = SIG_SETMASK;
6097 break;
6098 default:
ths0da46a62007-10-20 20:23:07 +00006099 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006100 goto fail;
6101 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006102 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006103 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006104 target_to_host_old_sigset(&set, p);
6105 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006106 set_ptr = &set;
6107 } else {
6108 how = 0;
6109 set_ptr = NULL;
6110 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006111 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006112 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006113 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006114 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006115 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006116 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006117 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006118#endif
bellard66fb9762003-03-23 01:06:05 +00006119 }
6120 break;
thse5febef2007-04-01 18:31:35 +00006121#endif
bellard66fb9762003-03-23 01:06:05 +00006122 case TARGET_NR_rt_sigprocmask:
6123 {
6124 int how = arg1;
6125 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006126
pbrook53a59602006-03-25 19:31:22 +00006127 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006128 switch(how) {
6129 case TARGET_SIG_BLOCK:
6130 how = SIG_BLOCK;
6131 break;
6132 case TARGET_SIG_UNBLOCK:
6133 how = SIG_UNBLOCK;
6134 break;
6135 case TARGET_SIG_SETMASK:
6136 how = SIG_SETMASK;
6137 break;
6138 default:
ths0da46a62007-10-20 20:23:07 +00006139 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006140 goto fail;
6141 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006142 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006143 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006144 target_to_host_sigset(&set, p);
6145 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006146 set_ptr = &set;
6147 } else {
6148 how = 0;
6149 set_ptr = NULL;
6150 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006151 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006152 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006153 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006154 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006155 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006156 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006157 }
6158 }
6159 break;
thse5febef2007-04-01 18:31:35 +00006160#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006161 case TARGET_NR_sigpending:
6162 {
6163 sigset_t set;
6164 ret = get_errno(sigpending(&set));
6165 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006166 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006167 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006168 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006169 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006170 }
6171 }
6172 break;
thse5febef2007-04-01 18:31:35 +00006173#endif
bellard66fb9762003-03-23 01:06:05 +00006174 case TARGET_NR_rt_sigpending:
6175 {
6176 sigset_t set;
6177 ret = get_errno(sigpending(&set));
6178 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006179 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006180 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006181 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006182 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006183 }
6184 }
6185 break;
thse5febef2007-04-01 18:31:35 +00006186#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006187 case TARGET_NR_sigsuspend:
6188 {
6189 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006190#if defined(TARGET_ALPHA)
6191 abi_ulong mask = arg1;
6192 target_to_host_old_sigset(&set, &mask);
6193#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006194 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006195 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006196 target_to_host_old_sigset(&set, p);
6197 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006198#endif
bellard66fb9762003-03-23 01:06:05 +00006199 ret = get_errno(sigsuspend(&set));
6200 }
6201 break;
thse5febef2007-04-01 18:31:35 +00006202#endif
bellard66fb9762003-03-23 01:06:05 +00006203 case TARGET_NR_rt_sigsuspend:
6204 {
6205 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006206 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006207 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006208 target_to_host_sigset(&set, p);
6209 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006210 ret = get_errno(sigsuspend(&set));
6211 }
6212 break;
6213 case TARGET_NR_rt_sigtimedwait:
6214 {
bellard66fb9762003-03-23 01:06:05 +00006215 sigset_t set;
6216 struct timespec uts, *puts;
6217 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006218
Anthony Liguoric227f092009-10-01 16:12:16 -05006219 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006220 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006221 target_to_host_sigset(&set, p);
6222 unlock_user(p, arg1, 0);
6223 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006224 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006225 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006226 } else {
6227 puts = NULL;
6228 }
6229 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006230 if (!is_error(ret)) {
6231 if (arg2) {
6232 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6233 0);
6234 if (!p) {
6235 goto efault;
6236 }
6237 host_to_target_siginfo(p, &uinfo);
6238 unlock_user(p, arg2, sizeof(target_siginfo_t));
6239 }
6240 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00006241 }
6242 }
6243 break;
6244 case TARGET_NR_rt_sigqueueinfo:
6245 {
6246 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006247 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006248 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006249 target_to_host_siginfo(&uinfo, p);
6250 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006251 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6252 }
6253 break;
thse5febef2007-04-01 18:31:35 +00006254#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006255 case TARGET_NR_sigreturn:
6256 /* NOTE: ret is eax, so not transcoding must be done */
6257 ret = do_sigreturn(cpu_env);
6258 break;
thse5febef2007-04-01 18:31:35 +00006259#endif
bellard66fb9762003-03-23 01:06:05 +00006260 case TARGET_NR_rt_sigreturn:
6261 /* NOTE: ret is eax, so not transcoding must be done */
6262 ret = do_rt_sigreturn(cpu_env);
6263 break;
bellard31e31b82003-02-18 22:55:36 +00006264 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006265 if (!(p = lock_user_string(arg1)))
6266 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006267 ret = get_errno(sethostname(p, arg2));
6268 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006269 break;
6270 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006271 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006272 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006273 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006274 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006275 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6276 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006277 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6278 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006279 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006280 ret = get_errno(setrlimit(resource, &rlim));
6281 }
6282 break;
bellard31e31b82003-02-18 22:55:36 +00006283 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006284 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006285 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006286 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006287 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006288
bellard9de5e442003-03-23 16:49:39 +00006289 ret = get_errno(getrlimit(resource, &rlim));
6290 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006291 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6292 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006293 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6294 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006295 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006296 }
6297 }
6298 break;
bellard31e31b82003-02-18 22:55:36 +00006299 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006300 {
6301 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006302 ret = get_errno(getrusage(arg1, &rusage));
6303 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006304 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006305 }
6306 }
6307 break;
bellard31e31b82003-02-18 22:55:36 +00006308 case TARGET_NR_gettimeofday:
6309 {
bellard31e31b82003-02-18 22:55:36 +00006310 struct timeval tv;
6311 ret = get_errno(gettimeofday(&tv, NULL));
6312 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006313 if (copy_to_user_timeval(arg1, &tv))
6314 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006315 }
6316 }
6317 break;
6318 case TARGET_NR_settimeofday:
6319 {
bellard31e31b82003-02-18 22:55:36 +00006320 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00006321 if (copy_from_user_timeval(&tv, arg1))
6322 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006323 ret = get_errno(settimeofday(&tv, NULL));
6324 }
6325 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006326#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006327 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006328#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6329 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6330#else
bellardf2674e32003-07-09 12:26:09 +00006331 {
pbrook53a59602006-03-25 19:31:22 +00006332 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006333 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006334 long nsel;
6335
bellard579a97f2007-11-11 14:26:47 +00006336 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6337 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006338 nsel = tswapal(sel->n);
6339 inp = tswapal(sel->inp);
6340 outp = tswapal(sel->outp);
6341 exp = tswapal(sel->exp);
6342 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006343 unlock_user_struct(sel, arg1, 0);
6344 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006345 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006346#endif
bellardf2674e32003-07-09 12:26:09 +00006347 break;
bellard048f6b42005-11-26 18:47:20 +00006348#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006349#ifdef TARGET_NR_pselect6
6350 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006351 {
6352 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6353 fd_set rfds, wfds, efds;
6354 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6355 struct timespec ts, *ts_ptr;
6356
6357 /*
6358 * The 6th arg is actually two args smashed together,
6359 * so we cannot use the C library.
6360 */
6361 sigset_t set;
6362 struct {
6363 sigset_t *set;
6364 size_t size;
6365 } sig, *sig_ptr;
6366
6367 abi_ulong arg_sigset, arg_sigsize, *arg7;
6368 target_sigset_t *target_sigset;
6369
6370 n = arg1;
6371 rfd_addr = arg2;
6372 wfd_addr = arg3;
6373 efd_addr = arg4;
6374 ts_addr = arg5;
6375
6376 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6377 if (ret) {
6378 goto fail;
6379 }
6380 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6381 if (ret) {
6382 goto fail;
6383 }
6384 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6385 if (ret) {
6386 goto fail;
6387 }
6388
6389 /*
6390 * This takes a timespec, and not a timeval, so we cannot
6391 * use the do_select() helper ...
6392 */
6393 if (ts_addr) {
6394 if (target_to_host_timespec(&ts, ts_addr)) {
6395 goto efault;
6396 }
6397 ts_ptr = &ts;
6398 } else {
6399 ts_ptr = NULL;
6400 }
6401
6402 /* Extract the two packed args for the sigset */
6403 if (arg6) {
6404 sig_ptr = &sig;
6405 sig.size = _NSIG / 8;
6406
6407 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6408 if (!arg7) {
6409 goto efault;
6410 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006411 arg_sigset = tswapal(arg7[0]);
6412 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006413 unlock_user(arg7, arg6, 0);
6414
6415 if (arg_sigset) {
6416 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006417 if (arg_sigsize != sizeof(*target_sigset)) {
6418 /* Like the kernel, we enforce correct size sigsets */
6419 ret = -TARGET_EINVAL;
6420 goto fail;
6421 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006422 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6423 sizeof(*target_sigset), 1);
6424 if (!target_sigset) {
6425 goto efault;
6426 }
6427 target_to_host_sigset(&set, target_sigset);
6428 unlock_user(target_sigset, arg_sigset, 0);
6429 } else {
6430 sig.set = NULL;
6431 }
6432 } else {
6433 sig_ptr = NULL;
6434 }
6435
6436 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6437 ts_ptr, sig_ptr));
6438
6439 if (!is_error(ret)) {
6440 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6441 goto efault;
6442 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6443 goto efault;
6444 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6445 goto efault;
6446
6447 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6448 goto efault;
6449 }
6450 }
6451 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006452#endif
bellard31e31b82003-02-18 22:55:36 +00006453 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006454 {
6455 void *p2;
6456 p = lock_user_string(arg1);
6457 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006458 if (!p || !p2)
6459 ret = -TARGET_EFAULT;
6460 else
6461 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006462 unlock_user(p2, arg2, 0);
6463 unlock_user(p, arg1, 0);
6464 }
bellard31e31b82003-02-18 22:55:36 +00006465 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006466#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00006467 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006468 {
bellard579a97f2007-11-11 14:26:47 +00006469 void *p2;
thsf0b62432007-09-24 09:25:40 +00006470 p = lock_user_string(arg1);
6471 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006472 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006473 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006474 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006475 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006476 unlock_user(p2, arg3, 0);
6477 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006478 }
6479 break;
6480#endif
bellardebc05482003-09-30 21:08:41 +00006481#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006482 case TARGET_NR_oldlstat:
6483 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006484#endif
bellard31e31b82003-02-18 22:55:36 +00006485 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006486 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01006487 void *p2;
pbrook53a59602006-03-25 19:31:22 +00006488 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006489 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006490 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00006491 ret = -TARGET_EFAULT;
Andreas Schwab463d8e72013-07-02 14:04:12 +01006492 } else if (is_proc_myself((const char *)p, "exe")) {
6493 char real[PATH_MAX], *temp;
6494 temp = realpath(exec_path, real);
6495 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6496 snprintf((char *)p2, arg3, "%s", real);
6497 } else {
6498 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006499 }
pbrook53a59602006-03-25 19:31:22 +00006500 unlock_user(p2, arg2, ret);
6501 unlock_user(p, arg1, 0);
6502 }
bellard31e31b82003-02-18 22:55:36 +00006503 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006504#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00006505 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006506 {
bellard579a97f2007-11-11 14:26:47 +00006507 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006508 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006509 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006510 if (!p || !p2) {
6511 ret = -TARGET_EFAULT;
6512 } else if (is_proc_myself((const char *)p, "exe")) {
6513 char real[PATH_MAX], *temp;
6514 temp = realpath(exec_path, real);
6515 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6516 snprintf((char *)p2, arg4, "%s", real);
6517 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01006518 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01006519 }
bellard579a97f2007-11-11 14:26:47 +00006520 unlock_user(p2, arg3, ret);
6521 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006522 }
6523 break;
6524#endif
thse5febef2007-04-01 18:31:35 +00006525#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006526 case TARGET_NR_uselib:
6527 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006528#endif
6529#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006530 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006531 if (!(p = lock_user_string(arg1)))
6532 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006533 ret = get_errno(swapon(p, arg2));
6534 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006535 break;
thse5febef2007-04-01 18:31:35 +00006536#endif
bellard31e31b82003-02-18 22:55:36 +00006537 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006538 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6539 /* arg4 must be ignored in all other cases */
6540 p = lock_user_string(arg4);
6541 if (!p) {
6542 goto efault;
6543 }
6544 ret = get_errno(reboot(arg1, arg2, arg3, p));
6545 unlock_user(p, arg4, 0);
6546 } else {
6547 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6548 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006549 break;
thse5febef2007-04-01 18:31:35 +00006550#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006551 case TARGET_NR_readdir:
6552 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006553#endif
6554#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006555 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01006556#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6557 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006558 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6559 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006560 {
blueswir1992f48a2007-10-14 16:27:31 +00006561 abi_ulong *v;
6562 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006563 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6564 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006565 v1 = tswapal(v[0]);
6566 v2 = tswapal(v[1]);
6567 v3 = tswapal(v[2]);
6568 v4 = tswapal(v[3]);
6569 v5 = tswapal(v[4]);
6570 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006571 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006572 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006573 target_to_host_bitmask(v4, mmap_flags_tbl),
6574 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006575 }
bellard31e31b82003-02-18 22:55:36 +00006576#else
ths5fafdf22007-09-16 21:08:06 +00006577 ret = get_errno(target_mmap(arg1, arg2, arg3,
6578 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006579 arg5,
6580 arg6));
bellard31e31b82003-02-18 22:55:36 +00006581#endif
bellard6fb883e2003-07-09 17:12:39 +00006582 break;
thse5febef2007-04-01 18:31:35 +00006583#endif
bellarda315a142005-01-30 22:59:18 +00006584#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006585 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006586#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006587#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006588#endif
ths5fafdf22007-09-16 21:08:06 +00006589 ret = get_errno(target_mmap(arg1, arg2, arg3,
6590 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006591 arg5,
bellardc573ff62004-01-04 15:51:36 +00006592 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006593 break;
bellarda315a142005-01-30 22:59:18 +00006594#endif
bellard31e31b82003-02-18 22:55:36 +00006595 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006596 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006597 break;
bellard9de5e442003-03-23 16:49:39 +00006598 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006599 {
Andreas Färber0429a972013-08-26 18:14:44 +02006600 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006601 /* Special hack to detect libc making the stack executable. */
6602 if ((arg3 & PROT_GROWSDOWN)
6603 && arg1 >= ts->info->stack_limit
6604 && arg1 <= ts->info->start_stack) {
6605 arg3 &= ~PROT_GROWSDOWN;
6606 arg2 = arg2 + arg1 - ts->info->stack_limit;
6607 arg1 = ts->info->stack_limit;
6608 }
6609 }
bellard54936002003-05-13 00:25:15 +00006610 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006611 break;
thse5febef2007-04-01 18:31:35 +00006612#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006613 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006614 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006615 break;
thse5febef2007-04-01 18:31:35 +00006616#endif
pbrook53a59602006-03-25 19:31:22 +00006617 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006618#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006619 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006620 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006621 break;
thse5febef2007-04-01 18:31:35 +00006622#endif
6623#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006624 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006625 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006626 break;
thse5febef2007-04-01 18:31:35 +00006627#endif
6628#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006629 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006630 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006631 break;
thse5febef2007-04-01 18:31:35 +00006632#endif
6633#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006634 case TARGET_NR_mlockall:
6635 ret = get_errno(mlockall(arg1));
6636 break;
thse5febef2007-04-01 18:31:35 +00006637#endif
6638#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006639 case TARGET_NR_munlockall:
6640 ret = get_errno(munlockall());
6641 break;
thse5febef2007-04-01 18:31:35 +00006642#endif
bellard31e31b82003-02-18 22:55:36 +00006643 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006644 if (!(p = lock_user_string(arg1)))
6645 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006646 ret = get_errno(truncate(p, arg2));
6647 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006648 break;
6649 case TARGET_NR_ftruncate:
6650 ret = get_errno(ftruncate(arg1, arg2));
6651 break;
6652 case TARGET_NR_fchmod:
6653 ret = get_errno(fchmod(arg1, arg2));
6654 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006655#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00006656 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006657 if (!(p = lock_user_string(arg2)))
6658 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006659 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006660 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006661 break;
6662#endif
bellard31e31b82003-02-18 22:55:36 +00006663 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006664 /* Note that negative values are valid for getpriority, so we must
6665 differentiate based on errno settings. */
6666 errno = 0;
6667 ret = getpriority(arg1, arg2);
6668 if (ret == -1 && errno != 0) {
6669 ret = -host_to_target_errno(errno);
6670 break;
6671 }
6672#ifdef TARGET_ALPHA
6673 /* Return value is the unbiased priority. Signal no error. */
6674 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6675#else
6676 /* Return value is a biased priority to avoid negative numbers. */
6677 ret = 20 - ret;
6678#endif
bellard31e31b82003-02-18 22:55:36 +00006679 break;
6680 case TARGET_NR_setpriority:
6681 ret = get_errno(setpriority(arg1, arg2, arg3));
6682 break;
bellardebc05482003-09-30 21:08:41 +00006683#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006684 case TARGET_NR_profil:
6685 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006686#endif
bellard31e31b82003-02-18 22:55:36 +00006687 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006688 if (!(p = lock_user_string(arg1)))
6689 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006690 ret = get_errno(statfs(path(p), &stfs));
6691 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006692 convert_statfs:
6693 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006694 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006695
bellard579a97f2007-11-11 14:26:47 +00006696 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6697 goto efault;
6698 __put_user(stfs.f_type, &target_stfs->f_type);
6699 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6700 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6701 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6702 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6703 __put_user(stfs.f_files, &target_stfs->f_files);
6704 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6705 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6706 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6707 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006708 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6709 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006710 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006711 }
6712 break;
6713 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006714 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006715 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006716#ifdef TARGET_NR_statfs64
6717 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006718 if (!(p = lock_user_string(arg1)))
6719 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006720 ret = get_errno(statfs(path(p), &stfs));
6721 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006722 convert_statfs64:
6723 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006724 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006725
bellard579a97f2007-11-11 14:26:47 +00006726 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6727 goto efault;
6728 __put_user(stfs.f_type, &target_stfs->f_type);
6729 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6730 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6731 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6732 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6733 __put_user(stfs.f_files, &target_stfs->f_files);
6734 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6735 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6736 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6737 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006738 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6739 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00006740 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006741 }
6742 break;
6743 case TARGET_NR_fstatfs64:
6744 ret = get_errno(fstatfs(arg1, &stfs));
6745 goto convert_statfs64;
6746#endif
bellardebc05482003-09-30 21:08:41 +00006747#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006748 case TARGET_NR_ioperm:
6749 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006750#endif
thse5febef2007-04-01 18:31:35 +00006751#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006752 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006753 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006754 break;
thse5febef2007-04-01 18:31:35 +00006755#endif
bellard3532fa72006-06-24 15:06:03 +00006756#ifdef TARGET_NR_accept
6757 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00006758 ret = do_accept4(arg1, arg2, arg3, 0);
6759 break;
6760#endif
6761#ifdef TARGET_NR_accept4
6762 case TARGET_NR_accept4:
6763#ifdef CONFIG_ACCEPT4
6764 ret = do_accept4(arg1, arg2, arg3, arg4);
6765#else
6766 goto unimplemented;
6767#endif
bellard3532fa72006-06-24 15:06:03 +00006768 break;
6769#endif
6770#ifdef TARGET_NR_bind
6771 case TARGET_NR_bind:
6772 ret = do_bind(arg1, arg2, arg3);
6773 break;
6774#endif
6775#ifdef TARGET_NR_connect
6776 case TARGET_NR_connect:
6777 ret = do_connect(arg1, arg2, arg3);
6778 break;
6779#endif
6780#ifdef TARGET_NR_getpeername
6781 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006782 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006783 break;
6784#endif
6785#ifdef TARGET_NR_getsockname
6786 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006787 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006788 break;
6789#endif
6790#ifdef TARGET_NR_getsockopt
6791 case TARGET_NR_getsockopt:
6792 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6793 break;
6794#endif
6795#ifdef TARGET_NR_listen
6796 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006797 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006798 break;
6799#endif
6800#ifdef TARGET_NR_recv
6801 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006802 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006803 break;
6804#endif
6805#ifdef TARGET_NR_recvfrom
6806 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006807 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006808 break;
6809#endif
6810#ifdef TARGET_NR_recvmsg
6811 case TARGET_NR_recvmsg:
6812 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6813 break;
6814#endif
6815#ifdef TARGET_NR_send
6816 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006817 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006818 break;
6819#endif
6820#ifdef TARGET_NR_sendmsg
6821 case TARGET_NR_sendmsg:
6822 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6823 break;
6824#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00006825#ifdef TARGET_NR_sendmmsg
6826 case TARGET_NR_sendmmsg:
6827 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
6828 break;
6829 case TARGET_NR_recvmmsg:
6830 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
6831 break;
6832#endif
bellard3532fa72006-06-24 15:06:03 +00006833#ifdef TARGET_NR_sendto
6834 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006835 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006836 break;
6837#endif
6838#ifdef TARGET_NR_shutdown
6839 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006840 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006841 break;
6842#endif
6843#ifdef TARGET_NR_socket
6844 case TARGET_NR_socket:
6845 ret = do_socket(arg1, arg2, arg3);
6846 break;
6847#endif
6848#ifdef TARGET_NR_socketpair
6849 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006850 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006851 break;
6852#endif
6853#ifdef TARGET_NR_setsockopt
6854 case TARGET_NR_setsockopt:
6855 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6856 break;
6857#endif
ths7494b0f2007-02-11 18:26:53 +00006858
bellard31e31b82003-02-18 22:55:36 +00006859 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006860 if (!(p = lock_user_string(arg2)))
6861 goto efault;
thse5574482007-02-11 20:03:13 +00006862 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6863 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006864 break;
6865
bellard31e31b82003-02-18 22:55:36 +00006866 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006867 {
bellard66fb9762003-03-23 01:06:05 +00006868 struct itimerval value, ovalue, *pvalue;
6869
pbrook53a59602006-03-25 19:31:22 +00006870 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006871 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006872 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6873 || copy_from_user_timeval(&pvalue->it_value,
6874 arg2 + sizeof(struct target_timeval)))
6875 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006876 } else {
6877 pvalue = NULL;
6878 }
6879 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006880 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006881 if (copy_to_user_timeval(arg3,
6882 &ovalue.it_interval)
6883 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6884 &ovalue.it_value))
6885 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006886 }
6887 }
6888 break;
bellard31e31b82003-02-18 22:55:36 +00006889 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006890 {
bellard66fb9762003-03-23 01:06:05 +00006891 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006892
bellard66fb9762003-03-23 01:06:05 +00006893 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006894 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006895 if (copy_to_user_timeval(arg2,
6896 &value.it_interval)
6897 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6898 &value.it_value))
6899 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006900 }
6901 }
6902 break;
bellard31e31b82003-02-18 22:55:36 +00006903 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006904 if (!(p = lock_user_string(arg1)))
6905 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006906 ret = get_errno(stat(path(p), &st));
6907 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006908 goto do_stat;
6909 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006910 if (!(p = lock_user_string(arg1)))
6911 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006912 ret = get_errno(lstat(path(p), &st));
6913 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006914 goto do_stat;
6915 case TARGET_NR_fstat:
6916 {
6917 ret = get_errno(fstat(arg1, &st));
6918 do_stat:
6919 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006920 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006921
bellard579a97f2007-11-11 14:26:47 +00006922 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6923 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006924 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006925 __put_user(st.st_dev, &target_st->st_dev);
6926 __put_user(st.st_ino, &target_st->st_ino);
6927 __put_user(st.st_mode, &target_st->st_mode);
6928 __put_user(st.st_uid, &target_st->st_uid);
6929 __put_user(st.st_gid, &target_st->st_gid);
6930 __put_user(st.st_nlink, &target_st->st_nlink);
6931 __put_user(st.st_rdev, &target_st->st_rdev);
6932 __put_user(st.st_size, &target_st->st_size);
6933 __put_user(st.st_blksize, &target_st->st_blksize);
6934 __put_user(st.st_blocks, &target_st->st_blocks);
6935 __put_user(st.st_atime, &target_st->target_st_atime);
6936 __put_user(st.st_mtime, &target_st->target_st_mtime);
6937 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006938 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006939 }
6940 }
6941 break;
bellardebc05482003-09-30 21:08:41 +00006942#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006943 case TARGET_NR_olduname:
6944 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006945#endif
6946#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006947 case TARGET_NR_iopl:
6948 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006949#endif
bellard31e31b82003-02-18 22:55:36 +00006950 case TARGET_NR_vhangup:
6951 ret = get_errno(vhangup());
6952 break;
bellardebc05482003-09-30 21:08:41 +00006953#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006954 case TARGET_NR_idle:
6955 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006956#endif
bellard42ad6ae2005-01-03 22:48:11 +00006957#ifdef TARGET_NR_syscall
6958 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006959 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6960 arg6, arg7, arg8, 0);
6961 break;
bellard42ad6ae2005-01-03 22:48:11 +00006962#endif
bellard31e31b82003-02-18 22:55:36 +00006963 case TARGET_NR_wait4:
6964 {
6965 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006966 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006967 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006968 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00006969 if (target_rusage)
6970 rusage_ptr = &rusage;
6971 else
6972 rusage_ptr = NULL;
6973 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6974 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01006975 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00006976 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006977 if (put_user_s32(status, status_ptr))
6978 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006979 }
bellard2f619692007-11-16 10:46:05 +00006980 if (target_rusage)
6981 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00006982 }
6983 }
6984 break;
thse5febef2007-04-01 18:31:35 +00006985#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006986 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006987 if (!(p = lock_user_string(arg1)))
6988 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006989 ret = get_errno(swapoff(p));
6990 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006991 break;
thse5febef2007-04-01 18:31:35 +00006992#endif
bellard31e31b82003-02-18 22:55:36 +00006993 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006994 {
pbrook53a59602006-03-25 19:31:22 +00006995 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006996 struct sysinfo value;
6997 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006998 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006999 {
bellard579a97f2007-11-11 14:26:47 +00007000 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
7001 goto efault;
bellarda5448a72004-06-19 16:59:03 +00007002 __put_user(value.uptime, &target_value->uptime);
7003 __put_user(value.loads[0], &target_value->loads[0]);
7004 __put_user(value.loads[1], &target_value->loads[1]);
7005 __put_user(value.loads[2], &target_value->loads[2]);
7006 __put_user(value.totalram, &target_value->totalram);
7007 __put_user(value.freeram, &target_value->freeram);
7008 __put_user(value.sharedram, &target_value->sharedram);
7009 __put_user(value.bufferram, &target_value->bufferram);
7010 __put_user(value.totalswap, &target_value->totalswap);
7011 __put_user(value.freeswap, &target_value->freeswap);
7012 __put_user(value.procs, &target_value->procs);
7013 __put_user(value.totalhigh, &target_value->totalhigh);
7014 __put_user(value.freehigh, &target_value->freehigh);
7015 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00007016 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00007017 }
7018 }
7019 break;
thse5febef2007-04-01 18:31:35 +00007020#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00007021 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00007022 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
7023 break;
thse5febef2007-04-01 18:31:35 +00007024#endif
aurel32e5289082009-04-18 16:16:12 +00007025#ifdef TARGET_NR_semget
7026 case TARGET_NR_semget:
7027 ret = get_errno(semget(arg1, arg2, arg3));
7028 break;
7029#endif
7030#ifdef TARGET_NR_semop
7031 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00007032 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00007033 break;
7034#endif
7035#ifdef TARGET_NR_semctl
7036 case TARGET_NR_semctl:
7037 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
7038 break;
7039#endif
aurel32eeb438c2008-10-13 21:08:55 +00007040#ifdef TARGET_NR_msgctl
7041 case TARGET_NR_msgctl:
7042 ret = do_msgctl(arg1, arg2, arg3);
7043 break;
7044#endif
7045#ifdef TARGET_NR_msgget
7046 case TARGET_NR_msgget:
7047 ret = get_errno(msgget(arg1, arg2));
7048 break;
7049#endif
7050#ifdef TARGET_NR_msgrcv
7051 case TARGET_NR_msgrcv:
7052 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7053 break;
7054#endif
7055#ifdef TARGET_NR_msgsnd
7056 case TARGET_NR_msgsnd:
7057 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7058 break;
7059#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007060#ifdef TARGET_NR_shmget
7061 case TARGET_NR_shmget:
7062 ret = get_errno(shmget(arg1, arg2, arg3));
7063 break;
7064#endif
7065#ifdef TARGET_NR_shmctl
7066 case TARGET_NR_shmctl:
7067 ret = do_shmctl(arg1, arg2, arg3);
7068 break;
7069#endif
7070#ifdef TARGET_NR_shmat
7071 case TARGET_NR_shmat:
7072 ret = do_shmat(arg1, arg2, arg3);
7073 break;
7074#endif
7075#ifdef TARGET_NR_shmdt
7076 case TARGET_NR_shmdt:
7077 ret = do_shmdt(arg1);
7078 break;
7079#endif
bellard31e31b82003-02-18 22:55:36 +00007080 case TARGET_NR_fsync:
7081 ret = get_errno(fsync(arg1));
7082 break;
bellard31e31b82003-02-18 22:55:36 +00007083 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007084 /* Linux manages to have three different orderings for its
7085 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7086 * match the kernel's CONFIG_CLONE_* settings.
7087 * Microblaze is further special in that it uses a sixth
7088 * implicit argument to clone for the TLS pointer.
7089 */
7090#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007091 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007092#elif defined(TARGET_CLONE_BACKWARDS)
7093 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7094#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007095 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007096#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007097 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007098#endif
bellard1b6b0292003-03-22 17:31:38 +00007099 break;
bellardec86b0f2003-04-11 00:15:04 +00007100#ifdef __NR_exit_group
7101 /* new thread calls */
7102 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007103#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007104 _mcleanup();
7105#endif
bellarde9009672005-04-26 20:42:36 +00007106 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007107 ret = get_errno(exit_group(arg1));
7108 break;
7109#endif
bellard31e31b82003-02-18 22:55:36 +00007110 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007111 if (!(p = lock_user_string(arg1)))
7112 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007113 ret = get_errno(setdomainname(p, arg2));
7114 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007115 break;
7116 case TARGET_NR_uname:
7117 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007118 {
7119 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007120
bellard579a97f2007-11-11 14:26:47 +00007121 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7122 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007123 ret = get_errno(sys_uname(buf));
7124 if (!is_error(ret)) {
7125 /* Overrite the native machine name with whatever is being
7126 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007127 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007128 /* Allow the user to override the reported release. */
7129 if (qemu_uname_release && *qemu_uname_release)
7130 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007131 }
pbrook53a59602006-03-25 19:31:22 +00007132 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007133 }
bellard31e31b82003-02-18 22:55:36 +00007134 break;
bellard6dbad632003-03-16 18:05:05 +00007135#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007136 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007137 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007138 break;
j_mayer84409dd2007-04-06 08:56:50 +00007139#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007140 case TARGET_NR_vm86old:
7141 goto unimplemented;
7142 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007143 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007144 break;
7145#endif
j_mayer84409dd2007-04-06 08:56:50 +00007146#endif
bellard31e31b82003-02-18 22:55:36 +00007147 case TARGET_NR_adjtimex:
7148 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007149#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007150 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007151#endif
bellard31e31b82003-02-18 22:55:36 +00007152 case TARGET_NR_init_module:
7153 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007154#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007155 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007156#endif
bellard31e31b82003-02-18 22:55:36 +00007157 goto unimplemented;
7158 case TARGET_NR_quotactl:
7159 goto unimplemented;
7160 case TARGET_NR_getpgid:
7161 ret = get_errno(getpgid(arg1));
7162 break;
7163 case TARGET_NR_fchdir:
7164 ret = get_errno(fchdir(arg1));
7165 break;
j_mayer84409dd2007-04-06 08:56:50 +00007166#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007167 case TARGET_NR_bdflush:
7168 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007169#endif
thse5febef2007-04-01 18:31:35 +00007170#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007171 case TARGET_NR_sysfs:
7172 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007173#endif
bellard31e31b82003-02-18 22:55:36 +00007174 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007175 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007176 break;
thse5febef2007-04-01 18:31:35 +00007177#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007178 case TARGET_NR_afs_syscall:
7179 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007180#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007181#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007182 case TARGET_NR__llseek:
7183 {
7184 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007185#if !defined(__NR_llseek)
7186 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7187 if (res == -1) {
7188 ret = get_errno(res);
7189 } else {
7190 ret = 0;
7191 }
7192#else
bellard31e31b82003-02-18 22:55:36 +00007193 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007194#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007195 if ((ret == 0) && put_user_s64(res, arg4)) {
7196 goto efault;
7197 }
bellard31e31b82003-02-18 22:55:36 +00007198 }
7199 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007200#endif
bellard31e31b82003-02-18 22:55:36 +00007201 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01007202#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007203#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007204 {
pbrook53a59602006-03-25 19:31:22 +00007205 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007206 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007207 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007208
7209 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00007210 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007211 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007212 goto fail;
7213 }
ths3b46e622007-09-17 08:09:54 +00007214
bellard4add45b2003-06-05 01:52:59 +00007215 ret = get_errno(sys_getdents(arg1, dirp, count));
7216 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007217 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007218 struct target_dirent *tde;
7219 int len = ret;
7220 int reclen, treclen;
7221 int count1, tnamelen;
7222
7223 count1 = 0;
7224 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007225 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7226 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007227 tde = target_dirp;
7228 while (len > 0) {
7229 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007230 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7231 assert(tnamelen >= 0);
7232 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7233 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007234 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007235 tde->d_ino = tswapal(de->d_ino);
7236 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007237 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007238 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007239 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007240 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007241 count1 += treclen;
7242 }
7243 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007244 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007245 }
7246 free(dirp);
7247 }
7248#else
bellard31e31b82003-02-18 22:55:36 +00007249 {
aurel326556a832008-10-13 21:08:17 +00007250 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007251 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007252
bellard579a97f2007-11-11 14:26:47 +00007253 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7254 goto efault;
bellard72f03902003-02-18 23:33:18 +00007255 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007256 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007257 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007258 int len = ret;
7259 int reclen;
7260 de = dirp;
7261 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007262 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007263 if (reclen > len)
7264 break;
bellard8083a3e2003-03-24 23:12:16 +00007265 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007266 tswapls(&de->d_ino);
7267 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007268 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007269 len -= reclen;
7270 }
7271 }
pbrook53a59602006-03-25 19:31:22 +00007272 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007273 }
bellard4add45b2003-06-05 01:52:59 +00007274#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007275#else
7276 /* Implement getdents in terms of getdents64 */
7277 {
7278 struct linux_dirent64 *dirp;
7279 abi_long count = arg3;
7280
7281 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7282 if (!dirp) {
7283 goto efault;
7284 }
7285 ret = get_errno(sys_getdents64(arg1, dirp, count));
7286 if (!is_error(ret)) {
7287 /* Convert the dirent64 structs to target dirent. We do this
7288 * in-place, since we can guarantee that a target_dirent is no
7289 * larger than a dirent64; however this means we have to be
7290 * careful to read everything before writing in the new format.
7291 */
7292 struct linux_dirent64 *de;
7293 struct target_dirent *tde;
7294 int len = ret;
7295 int tlen = 0;
7296
7297 de = dirp;
7298 tde = (struct target_dirent *)dirp;
7299 while (len > 0) {
7300 int namelen, treclen;
7301 int reclen = de->d_reclen;
7302 uint64_t ino = de->d_ino;
7303 int64_t off = de->d_off;
7304 uint8_t type = de->d_type;
7305
7306 namelen = strlen(de->d_name);
7307 treclen = offsetof(struct target_dirent, d_name)
7308 + namelen + 2;
7309 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
7310
7311 memmove(tde->d_name, de->d_name, namelen + 1);
7312 tde->d_ino = tswapal(ino);
7313 tde->d_off = tswapal(off);
7314 tde->d_reclen = tswap16(treclen);
7315 /* The target_dirent type is in what was formerly a padding
7316 * byte at the end of the structure:
7317 */
7318 *(((char *)tde) + treclen - 1) = type;
7319
7320 de = (struct linux_dirent64 *)((char *)de + reclen);
7321 tde = (struct target_dirent *)((char *)tde + treclen);
7322 len -= reclen;
7323 tlen += treclen;
7324 }
7325 ret = tlen;
7326 }
7327 unlock_user(dirp, arg2, ret);
7328 }
7329#endif
bellard31e31b82003-02-18 22:55:36 +00007330 break;
ths3ae43202007-09-16 21:39:48 +00007331#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007332 case TARGET_NR_getdents64:
7333 {
aurel326556a832008-10-13 21:08:17 +00007334 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007335 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007336 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7337 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007338 ret = get_errno(sys_getdents64(arg1, dirp, count));
7339 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007340 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007341 int len = ret;
7342 int reclen;
7343 de = dirp;
7344 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007345 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007346 if (reclen > len)
7347 break;
bellard8083a3e2003-03-24 23:12:16 +00007348 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007349 tswap64s((uint64_t *)&de->d_ino);
7350 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007351 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007352 len -= reclen;
7353 }
7354 }
pbrook53a59602006-03-25 19:31:22 +00007355 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007356 }
7357 break;
bellarda541f292004-04-12 20:39:29 +00007358#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007359#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007360 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007361 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007362 break;
thse5febef2007-04-01 18:31:35 +00007363#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007364#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7365# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007366 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007367# endif
7368# ifdef TARGET_NR_ppoll
7369 case TARGET_NR_ppoll:
7370# endif
bellard9de5e442003-03-23 16:49:39 +00007371 {
pbrook53a59602006-03-25 19:31:22 +00007372 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007373 unsigned int nfds = arg2;
7374 int timeout = arg3;
7375 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007376 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007377
bellard579a97f2007-11-11 14:26:47 +00007378 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7379 if (!target_pfd)
7380 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007381
bellard9de5e442003-03-23 16:49:39 +00007382 pfd = alloca(sizeof(struct pollfd) * nfds);
7383 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007384 pfd[i].fd = tswap32(target_pfd[i].fd);
7385 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007386 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007387
7388# ifdef TARGET_NR_ppoll
7389 if (num == TARGET_NR_ppoll) {
7390 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7391 target_sigset_t *target_set;
7392 sigset_t _set, *set = &_set;
7393
7394 if (arg3) {
7395 if (target_to_host_timespec(timeout_ts, arg3)) {
7396 unlock_user(target_pfd, arg1, 0);
7397 goto efault;
7398 }
7399 } else {
7400 timeout_ts = NULL;
7401 }
7402
7403 if (arg4) {
7404 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7405 if (!target_set) {
7406 unlock_user(target_pfd, arg1, 0);
7407 goto efault;
7408 }
7409 target_to_host_sigset(set, target_set);
7410 } else {
7411 set = NULL;
7412 }
7413
7414 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7415
7416 if (!is_error(ret) && arg3) {
7417 host_to_target_timespec(arg3, timeout_ts);
7418 }
7419 if (arg4) {
7420 unlock_user(target_set, arg4, 0);
7421 }
7422 } else
7423# endif
7424 ret = get_errno(poll(pfd, nfds, timeout));
7425
bellard9de5e442003-03-23 16:49:39 +00007426 if (!is_error(ret)) {
7427 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007428 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007429 }
7430 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007431 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007432 }
7433 break;
thse5febef2007-04-01 18:31:35 +00007434#endif
bellard31e31b82003-02-18 22:55:36 +00007435 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007436 /* NOTE: the flock constant seems to be the same for every
7437 Linux platform */
7438 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007439 break;
7440 case TARGET_NR_readv:
7441 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007442 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7443 if (vec != NULL) {
7444 ret = get_errno(readv(arg1, vec, arg3));
7445 unlock_iovec(vec, arg2, arg3, 1);
7446 } else {
7447 ret = -host_to_target_errno(errno);
7448 }
bellard31e31b82003-02-18 22:55:36 +00007449 }
7450 break;
7451 case TARGET_NR_writev:
7452 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007453 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7454 if (vec != NULL) {
7455 ret = get_errno(writev(arg1, vec, arg3));
7456 unlock_iovec(vec, arg2, arg3, 0);
7457 } else {
7458 ret = -host_to_target_errno(errno);
7459 }
bellard31e31b82003-02-18 22:55:36 +00007460 }
7461 break;
7462 case TARGET_NR_getsid:
7463 ret = get_errno(getsid(arg1));
7464 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007465#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007466 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007467 ret = get_errno(fdatasync(arg1));
7468 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007469#endif
bellard31e31b82003-02-18 22:55:36 +00007470 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007471 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007472 return value. */
ths0da46a62007-10-20 20:23:07 +00007473 ret = -TARGET_ENOTDIR;
7474 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007475 case TARGET_NR_sched_getaffinity:
7476 {
7477 unsigned int mask_size;
7478 unsigned long *mask;
7479
7480 /*
7481 * sched_getaffinity needs multiples of ulong, so need to take
7482 * care of mismatches between target ulong and host ulong sizes.
7483 */
7484 if (arg2 & (sizeof(abi_ulong) - 1)) {
7485 ret = -TARGET_EINVAL;
7486 break;
7487 }
7488 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7489
7490 mask = alloca(mask_size);
7491 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7492
7493 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09007494 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007495 goto efault;
7496 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007497 }
7498 }
7499 break;
7500 case TARGET_NR_sched_setaffinity:
7501 {
7502 unsigned int mask_size;
7503 unsigned long *mask;
7504
7505 /*
7506 * sched_setaffinity needs multiples of ulong, so need to take
7507 * care of mismatches between target ulong and host ulong sizes.
7508 */
7509 if (arg2 & (sizeof(abi_ulong) - 1)) {
7510 ret = -TARGET_EINVAL;
7511 break;
7512 }
7513 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7514
7515 mask = alloca(mask_size);
7516 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7517 goto efault;
7518 }
7519 memcpy(mask, p, arg2);
7520 unlock_user_struct(p, arg2, 0);
7521
7522 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7523 }
7524 break;
bellard31e31b82003-02-18 22:55:36 +00007525 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007526 {
pbrook53a59602006-03-25 19:31:22 +00007527 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007528 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007529
bellard579a97f2007-11-11 14:26:47 +00007530 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7531 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007532 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007533 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007534 ret = get_errno(sched_setparam(arg1, &schp));
7535 }
7536 break;
bellard31e31b82003-02-18 22:55:36 +00007537 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007538 {
pbrook53a59602006-03-25 19:31:22 +00007539 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007540 struct sched_param schp;
7541 ret = get_errno(sched_getparam(arg1, &schp));
7542 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007543 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7544 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007545 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007546 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007547 }
7548 }
7549 break;
bellard31e31b82003-02-18 22:55:36 +00007550 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007551 {
pbrook53a59602006-03-25 19:31:22 +00007552 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007553 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007554 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7555 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007556 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007557 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007558 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7559 }
7560 break;
bellard31e31b82003-02-18 22:55:36 +00007561 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007562 ret = get_errno(sched_getscheduler(arg1));
7563 break;
bellard31e31b82003-02-18 22:55:36 +00007564 case TARGET_NR_sched_yield:
7565 ret = get_errno(sched_yield());
7566 break;
7567 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007568 ret = get_errno(sched_get_priority_max(arg1));
7569 break;
bellard31e31b82003-02-18 22:55:36 +00007570 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007571 ret = get_errno(sched_get_priority_min(arg1));
7572 break;
bellard31e31b82003-02-18 22:55:36 +00007573 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007574 {
bellard5cd43932003-03-29 16:54:36 +00007575 struct timespec ts;
7576 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7577 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007578 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007579 }
7580 }
7581 break;
bellard31e31b82003-02-18 22:55:36 +00007582 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007583 {
bellard1b6b0292003-03-22 17:31:38 +00007584 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007585 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007586 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007587 if (is_error(ret) && arg2) {
7588 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007589 }
7590 }
7591 break;
thse5febef2007-04-01 18:31:35 +00007592#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007593 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007594 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007595#endif
7596#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007597 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007598 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007599#endif
bellard31e31b82003-02-18 22:55:36 +00007600 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007601 switch (arg1) {
7602 case PR_GET_PDEATHSIG:
7603 {
7604 int deathsig;
7605 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7606 if (!is_error(ret) && arg2
7607 && put_user_ual(deathsig, arg2)) {
7608 goto efault;
thse5574482007-02-11 20:03:13 +00007609 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007610 break;
7611 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007612#ifdef PR_GET_NAME
7613 case PR_GET_NAME:
7614 {
7615 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7616 if (!name) {
7617 goto efault;
7618 }
7619 ret = get_errno(prctl(arg1, (unsigned long)name,
7620 arg3, arg4, arg5));
7621 unlock_user(name, arg2, 16);
7622 break;
7623 }
7624 case PR_SET_NAME:
7625 {
7626 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7627 if (!name) {
7628 goto efault;
7629 }
7630 ret = get_errno(prctl(arg1, (unsigned long)name,
7631 arg3, arg4, arg5));
7632 unlock_user(name, arg2, 0);
7633 break;
7634 }
7635#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007636 default:
7637 /* Most prctl options have no pointer arguments */
7638 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7639 break;
7640 }
ths39b9aae2007-02-11 18:36:44 +00007641 break;
bellardd2fd1af2007-11-14 18:08:56 +00007642#ifdef TARGET_NR_arch_prctl
7643 case TARGET_NR_arch_prctl:
7644#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7645 ret = do_arch_prctl(cpu_env, arg1, arg2);
7646 break;
7647#else
7648 goto unimplemented;
7649#endif
7650#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007651#ifdef TARGET_NR_pread64
7652 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007653 if (regpairs_aligned(cpu_env)) {
7654 arg4 = arg5;
7655 arg5 = arg6;
7656 }
aurel32f2c7ba12008-03-28 22:32:06 +00007657 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7658 goto efault;
7659 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7660 unlock_user(p, arg2, ret);
7661 break;
7662 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00007663 if (regpairs_aligned(cpu_env)) {
7664 arg4 = arg5;
7665 arg5 = arg6;
7666 }
aurel32f2c7ba12008-03-28 22:32:06 +00007667 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7668 goto efault;
7669 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7670 unlock_user(p, arg2, 0);
7671 break;
7672#endif
bellard31e31b82003-02-18 22:55:36 +00007673 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007674 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7675 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007676 ret = get_errno(sys_getcwd1(p, arg2));
7677 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007678 break;
7679 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00007680 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007681 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00007682 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007683 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007684#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007685 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08007686 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007687 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007688 break;
7689#else
bellard5cd43932003-03-29 16:54:36 +00007690 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007691#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007692
7693#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00007694 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007695 {
7696 off_t *offp = NULL;
7697 off_t off;
7698 if (arg3) {
7699 ret = get_user_sal(off, arg3);
7700 if (is_error(ret)) {
7701 break;
7702 }
7703 offp = &off;
7704 }
7705 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7706 if (!is_error(ret) && arg3) {
7707 abi_long ret2 = put_user_sal(off, arg3);
7708 if (is_error(ret2)) {
7709 ret = ret2;
7710 }
7711 }
7712 break;
7713 }
7714#ifdef TARGET_NR_sendfile64
7715 case TARGET_NR_sendfile64:
7716 {
7717 off_t *offp = NULL;
7718 off_t off;
7719 if (arg3) {
7720 ret = get_user_s64(off, arg3);
7721 if (is_error(ret)) {
7722 break;
7723 }
7724 offp = &off;
7725 }
7726 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7727 if (!is_error(ret) && arg3) {
7728 abi_long ret2 = put_user_s64(off, arg3);
7729 if (is_error(ret2)) {
7730 ret = ret2;
7731 }
7732 }
7733 break;
7734 }
7735#endif
7736#else
7737 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01007738#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007739 case TARGET_NR_sendfile64:
7740#endif
bellard5cd43932003-03-29 16:54:36 +00007741 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007742#endif
7743
bellardebc05482003-09-30 21:08:41 +00007744#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007745 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007746 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007747#endif
7748#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007749 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007750 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007751#endif
bellard048f6b42005-11-26 18:47:20 +00007752#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007753 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007754 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7755 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007756 break;
bellard048f6b42005-11-26 18:47:20 +00007757#endif
bellardebc05482003-09-30 21:08:41 +00007758#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007759 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007760 {
7761 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007762 int resource = target_to_host_resource(arg1);
7763 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007764 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007765 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007766 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7767 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007768 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7769 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007770 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007771 }
7772 break;
7773 }
bellardebc05482003-09-30 21:08:41 +00007774#endif
bellarda315a142005-01-30 22:59:18 +00007775#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007776 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007777 if (!(p = lock_user_string(arg1)))
7778 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007779 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7780 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007781 break;
bellarda315a142005-01-30 22:59:18 +00007782#endif
7783#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00007784 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00007785 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00007786 break;
bellarda315a142005-01-30 22:59:18 +00007787#endif
7788#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00007789 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00007790 if (!(p = lock_user_string(arg1)))
7791 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007792 ret = get_errno(stat(path(p), &st));
7793 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007794 if (!is_error(ret))
7795 ret = host_to_target_stat64(cpu_env, arg2, &st);
7796 break;
bellarda315a142005-01-30 22:59:18 +00007797#endif
7798#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00007799 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00007800 if (!(p = lock_user_string(arg1)))
7801 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007802 ret = get_errno(lstat(path(p), &st));
7803 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007804 if (!is_error(ret))
7805 ret = host_to_target_stat64(cpu_env, arg2, &st);
7806 break;
bellarda315a142005-01-30 22:59:18 +00007807#endif
7808#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00007809 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00007810 ret = get_errno(fstat(arg1, &st));
7811 if (!is_error(ret))
7812 ret = host_to_target_stat64(cpu_env, arg2, &st);
7813 break;
bellardec86b0f2003-04-11 00:15:04 +00007814#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007815#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00007816#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007817 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007818#endif
7819#ifdef TARGET_NR_newfstatat
7820 case TARGET_NR_newfstatat:
7821#endif
balrog6a24a772008-09-20 02:23:36 +00007822 if (!(p = lock_user_string(arg2)))
7823 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007824 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00007825 if (!is_error(ret))
7826 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007827 break;
bellarda315a142005-01-30 22:59:18 +00007828#endif
bellard67867302003-11-23 17:05:30 +00007829 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007830 if (!(p = lock_user_string(arg1)))
7831 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007832 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7833 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007834 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007835#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007836 case TARGET_NR_getuid:
7837 ret = get_errno(high2lowuid(getuid()));
7838 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007839#endif
7840#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007841 case TARGET_NR_getgid:
7842 ret = get_errno(high2lowgid(getgid()));
7843 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007844#endif
7845#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007846 case TARGET_NR_geteuid:
7847 ret = get_errno(high2lowuid(geteuid()));
7848 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007849#endif
7850#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007851 case TARGET_NR_getegid:
7852 ret = get_errno(high2lowgid(getegid()));
7853 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007854#endif
bellard67867302003-11-23 17:05:30 +00007855 case TARGET_NR_setreuid:
7856 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7857 break;
7858 case TARGET_NR_setregid:
7859 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7860 break;
7861 case TARGET_NR_getgroups:
7862 {
7863 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007864 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007865 gid_t *grouplist;
7866 int i;
7867
7868 grouplist = alloca(gidsetsize * sizeof(gid_t));
7869 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007870 if (gidsetsize == 0)
7871 break;
bellard67867302003-11-23 17:05:30 +00007872 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00007873 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00007874 if (!target_grouplist)
7875 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007876 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007877 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007878 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00007879 }
7880 }
7881 break;
7882 case TARGET_NR_setgroups:
7883 {
7884 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007885 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007886 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00007887 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007888 if (gidsetsize) {
7889 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007890 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007891 if (!target_grouplist) {
7892 ret = -TARGET_EFAULT;
7893 goto fail;
7894 }
7895 for (i = 0; i < gidsetsize; i++) {
7896 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
7897 }
7898 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007899 }
bellard67867302003-11-23 17:05:30 +00007900 ret = get_errno(setgroups(gidsetsize, grouplist));
7901 }
7902 break;
7903 case TARGET_NR_fchown:
7904 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7905 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007906#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00007907 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007908 if (!(p = lock_user_string(arg2)))
7909 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007910 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
7911 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00007912 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007913 break;
7914#endif
bellard67867302003-11-23 17:05:30 +00007915#ifdef TARGET_NR_setresuid
7916 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007917 ret = get_errno(setresuid(low2highuid(arg1),
7918 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007919 low2highuid(arg3)));
7920 break;
7921#endif
7922#ifdef TARGET_NR_getresuid
7923 case TARGET_NR_getresuid:
7924 {
pbrook53a59602006-03-25 19:31:22 +00007925 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007926 ret = get_errno(getresuid(&ruid, &euid, &suid));
7927 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00007928 if (put_user_id(high2lowuid(ruid), arg1)
7929 || put_user_id(high2lowuid(euid), arg2)
7930 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00007931 goto efault;
bellard67867302003-11-23 17:05:30 +00007932 }
7933 }
7934 break;
7935#endif
7936#ifdef TARGET_NR_getresgid
7937 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007938 ret = get_errno(setresgid(low2highgid(arg1),
7939 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007940 low2highgid(arg3)));
7941 break;
7942#endif
7943#ifdef TARGET_NR_getresgid
7944 case TARGET_NR_getresgid:
7945 {
pbrook53a59602006-03-25 19:31:22 +00007946 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007947 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7948 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00007949 if (put_user_id(high2lowgid(rgid), arg1)
7950 || put_user_id(high2lowgid(egid), arg2)
7951 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00007952 goto efault;
bellard67867302003-11-23 17:05:30 +00007953 }
7954 }
7955 break;
7956#endif
7957 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007958 if (!(p = lock_user_string(arg1)))
7959 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007960 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7961 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007962 break;
7963 case TARGET_NR_setuid:
7964 ret = get_errno(setuid(low2highuid(arg1)));
7965 break;
7966 case TARGET_NR_setgid:
7967 ret = get_errno(setgid(low2highgid(arg1)));
7968 break;
7969 case TARGET_NR_setfsuid:
7970 ret = get_errno(setfsuid(arg1));
7971 break;
7972 case TARGET_NR_setfsgid:
7973 ret = get_errno(setfsgid(arg1));
7974 break;
bellard67867302003-11-23 17:05:30 +00007975
bellarda315a142005-01-30 22:59:18 +00007976#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00007977 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00007978 if (!(p = lock_user_string(arg1)))
7979 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007980 ret = get_errno(lchown(p, arg2, arg3));
7981 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007982 break;
bellarda315a142005-01-30 22:59:18 +00007983#endif
7984#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00007985 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00007986 ret = get_errno(getuid());
7987 break;
bellarda315a142005-01-30 22:59:18 +00007988#endif
aurel3264b4d282008-11-14 17:20:15 +00007989
7990#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
7991 /* Alpha specific */
7992 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007993 {
7994 uid_t euid;
7995 euid=geteuid();
7996 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
7997 }
aurel3264b4d282008-11-14 17:20:15 +00007998 ret = get_errno(getuid());
7999 break;
8000#endif
8001#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8002 /* Alpha specific */
8003 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008004 {
8005 uid_t egid;
8006 egid=getegid();
8007 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8008 }
aurel3264b4d282008-11-14 17:20:15 +00008009 ret = get_errno(getgid());
8010 break;
8011#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008012#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8013 /* Alpha specific */
8014 case TARGET_NR_osf_getsysinfo:
8015 ret = -TARGET_EOPNOTSUPP;
8016 switch (arg1) {
8017 case TARGET_GSI_IEEE_FP_CONTROL:
8018 {
8019 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8020
8021 /* Copied from linux ieee_fpcr_to_swcr. */
8022 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8023 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8024 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8025 | SWCR_TRAP_ENABLE_DZE
8026 | SWCR_TRAP_ENABLE_OVF);
8027 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8028 | SWCR_TRAP_ENABLE_INE);
8029 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8030 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8031
8032 if (put_user_u64 (swcr, arg2))
8033 goto efault;
8034 ret = 0;
8035 }
8036 break;
8037
8038 /* case GSI_IEEE_STATE_AT_SIGNAL:
8039 -- Not implemented in linux kernel.
8040 case GSI_UACPROC:
8041 -- Retrieves current unaligned access state; not much used.
8042 case GSI_PROC_TYPE:
8043 -- Retrieves implver information; surely not used.
8044 case GSI_GET_HWRPB:
8045 -- Grabs a copy of the HWRPB; surely not used.
8046 */
8047 }
8048 break;
8049#endif
8050#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8051 /* Alpha specific */
8052 case TARGET_NR_osf_setsysinfo:
8053 ret = -TARGET_EOPNOTSUPP;
8054 switch (arg1) {
8055 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008056 {
8057 uint64_t swcr, fpcr, orig_fpcr;
8058
Richard Henderson6e06d512012-06-01 09:08:21 -07008059 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008060 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008061 }
8062 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008063 fpcr = orig_fpcr & FPCR_DYN_MASK;
8064
8065 /* Copied from linux ieee_swcr_to_fpcr. */
8066 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8067 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8068 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8069 | SWCR_TRAP_ENABLE_DZE
8070 | SWCR_TRAP_ENABLE_OVF)) << 48;
8071 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8072 | SWCR_TRAP_ENABLE_INE)) << 57;
8073 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8074 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8075
Richard Henderson6e06d512012-06-01 09:08:21 -07008076 cpu_alpha_store_fpcr(cpu_env, fpcr);
8077 ret = 0;
8078 }
8079 break;
8080
8081 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8082 {
8083 uint64_t exc, fpcr, orig_fpcr;
8084 int si_code;
8085
8086 if (get_user_u64(exc, arg2)) {
8087 goto efault;
8088 }
8089
8090 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
8091
8092 /* We only add to the exception status here. */
8093 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
8094
8095 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008096 ret = 0;
8097
Richard Henderson6e06d512012-06-01 09:08:21 -07008098 /* Old exceptions are not signaled. */
8099 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008100
Richard Henderson6e06d512012-06-01 09:08:21 -07008101 /* If any exceptions set by this call,
8102 and are unmasked, send a signal. */
8103 si_code = 0;
8104 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
8105 si_code = TARGET_FPE_FLTRES;
8106 }
8107 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
8108 si_code = TARGET_FPE_FLTUND;
8109 }
8110 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
8111 si_code = TARGET_FPE_FLTOVF;
8112 }
8113 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
8114 si_code = TARGET_FPE_FLTDIV;
8115 }
8116 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
8117 si_code = TARGET_FPE_FLTINV;
8118 }
8119 if (si_code != 0) {
8120 target_siginfo_t info;
8121 info.si_signo = SIGFPE;
8122 info.si_errno = 0;
8123 info.si_code = si_code;
8124 info._sifields._sigfault._addr
8125 = ((CPUArchState *)cpu_env)->pc;
8126 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008127 }
8128 }
8129 break;
8130
8131 /* case SSI_NVPAIRS:
8132 -- Used with SSIN_UACPROC to enable unaligned accesses.
8133 case SSI_IEEE_STATE_AT_SIGNAL:
8134 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8135 -- Not implemented in linux kernel
8136 */
8137 }
8138 break;
8139#endif
8140#ifdef TARGET_NR_osf_sigprocmask
8141 /* Alpha specific. */
8142 case TARGET_NR_osf_sigprocmask:
8143 {
8144 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008145 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008146 sigset_t set, oldset;
8147
8148 switch(arg1) {
8149 case TARGET_SIG_BLOCK:
8150 how = SIG_BLOCK;
8151 break;
8152 case TARGET_SIG_UNBLOCK:
8153 how = SIG_UNBLOCK;
8154 break;
8155 case TARGET_SIG_SETMASK:
8156 how = SIG_SETMASK;
8157 break;
8158 default:
8159 ret = -TARGET_EINVAL;
8160 goto fail;
8161 }
8162 mask = arg2;
8163 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00008164 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008165 host_to_target_old_sigset(&mask, &oldset);
8166 ret = mask;
8167 }
8168 break;
8169#endif
aurel3264b4d282008-11-14 17:20:15 +00008170
bellarda315a142005-01-30 22:59:18 +00008171#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008172 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008173 ret = get_errno(getgid());
8174 break;
bellarda315a142005-01-30 22:59:18 +00008175#endif
8176#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00008177 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00008178 ret = get_errno(geteuid());
8179 break;
bellarda315a142005-01-30 22:59:18 +00008180#endif
8181#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00008182 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00008183 ret = get_errno(getegid());
8184 break;
bellarda315a142005-01-30 22:59:18 +00008185#endif
8186#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00008187 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00008188 ret = get_errno(setreuid(arg1, arg2));
8189 break;
bellarda315a142005-01-30 22:59:18 +00008190#endif
8191#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00008192 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00008193 ret = get_errno(setregid(arg1, arg2));
8194 break;
bellarda315a142005-01-30 22:59:18 +00008195#endif
8196#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00008197 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00008198 {
8199 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008200 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008201 gid_t *grouplist;
8202 int i;
8203
8204 grouplist = alloca(gidsetsize * sizeof(gid_t));
8205 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008206 if (gidsetsize == 0)
8207 break;
bellard99c475a2005-01-31 20:45:13 +00008208 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008209 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
8210 if (!target_grouplist) {
8211 ret = -TARGET_EFAULT;
8212 goto fail;
8213 }
balroga2155fc2008-09-20 02:12:08 +00008214 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00008215 target_grouplist[i] = tswap32(grouplist[i]);
8216 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00008217 }
8218 }
8219 break;
bellarda315a142005-01-30 22:59:18 +00008220#endif
8221#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00008222 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00008223 {
8224 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008225 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008226 gid_t *grouplist;
8227 int i;
ths3b46e622007-09-17 08:09:54 +00008228
bellard99c475a2005-01-31 20:45:13 +00008229 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00008230 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
8231 if (!target_grouplist) {
8232 ret = -TARGET_EFAULT;
8233 goto fail;
8234 }
bellard99c475a2005-01-31 20:45:13 +00008235 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00008236 grouplist[i] = tswap32(target_grouplist[i]);
8237 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00008238 ret = get_errno(setgroups(gidsetsize, grouplist));
8239 }
8240 break;
bellarda315a142005-01-30 22:59:18 +00008241#endif
8242#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00008243 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008244 ret = get_errno(fchown(arg1, arg2, arg3));
8245 break;
bellarda315a142005-01-30 22:59:18 +00008246#endif
8247#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008248 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008249 ret = get_errno(setresuid(arg1, arg2, arg3));
8250 break;
bellarda315a142005-01-30 22:59:18 +00008251#endif
8252#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008253 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008254 {
pbrook53a59602006-03-25 19:31:22 +00008255 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008256 ret = get_errno(getresuid(&ruid, &euid, &suid));
8257 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008258 if (put_user_u32(ruid, arg1)
8259 || put_user_u32(euid, arg2)
8260 || put_user_u32(suid, arg3))
8261 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008262 }
8263 }
8264 break;
bellarda315a142005-01-30 22:59:18 +00008265#endif
8266#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008267 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008268 ret = get_errno(setresgid(arg1, arg2, arg3));
8269 break;
bellarda315a142005-01-30 22:59:18 +00008270#endif
8271#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008272 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008273 {
pbrook53a59602006-03-25 19:31:22 +00008274 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008275 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8276 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008277 if (put_user_u32(rgid, arg1)
8278 || put_user_u32(egid, arg2)
8279 || put_user_u32(sgid, arg3))
8280 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008281 }
8282 }
8283 break;
bellarda315a142005-01-30 22:59:18 +00008284#endif
8285#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008286 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008287 if (!(p = lock_user_string(arg1)))
8288 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008289 ret = get_errno(chown(p, arg2, arg3));
8290 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008291 break;
bellarda315a142005-01-30 22:59:18 +00008292#endif
8293#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008294 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008295 ret = get_errno(setuid(arg1));
8296 break;
bellarda315a142005-01-30 22:59:18 +00008297#endif
8298#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008299 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008300 ret = get_errno(setgid(arg1));
8301 break;
bellarda315a142005-01-30 22:59:18 +00008302#endif
8303#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008304 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008305 ret = get_errno(setfsuid(arg1));
8306 break;
bellarda315a142005-01-30 22:59:18 +00008307#endif
8308#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008309 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008310 ret = get_errno(setfsgid(arg1));
8311 break;
bellarda315a142005-01-30 22:59:18 +00008312#endif
bellard67867302003-11-23 17:05:30 +00008313
bellard31e31b82003-02-18 22:55:36 +00008314 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008315 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008316#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008317 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008318 {
8319 void *a;
8320 ret = -TARGET_EFAULT;
8321 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8322 goto efault;
8323 if (!(p = lock_user_string(arg3)))
8324 goto mincore_fail;
8325 ret = get_errno(mincore(a, arg2, p));
8326 unlock_user(p, arg3, ret);
8327 mincore_fail:
8328 unlock_user(a, arg1, 0);
8329 }
8330 break;
bellardffa65c32004-01-04 23:57:22 +00008331#endif
aurel32408321b2008-10-01 21:46:32 +00008332#ifdef TARGET_NR_arm_fadvise64_64
8333 case TARGET_NR_arm_fadvise64_64:
8334 {
8335 /*
8336 * arm_fadvise64_64 looks like fadvise64_64 but
8337 * with different argument order
8338 */
8339 abi_long temp;
8340 temp = arg3;
8341 arg3 = arg4;
8342 arg4 = temp;
8343 }
8344#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008345#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008346#ifdef TARGET_NR_fadvise64_64
8347 case TARGET_NR_fadvise64_64:
8348#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008349#ifdef TARGET_NR_fadvise64
8350 case TARGET_NR_fadvise64:
8351#endif
8352#ifdef TARGET_S390X
8353 switch (arg4) {
8354 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8355 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8356 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8357 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8358 default: break;
8359 }
8360#endif
8361 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008362 break;
8363#endif
bellardffa65c32004-01-04 23:57:22 +00008364#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008365 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008366 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08008367 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00008368 This will break MADV_DONTNEED.
8369 This is a hint, so ignoring and returning success is ok. */
8370 ret = get_errno(0);
8371 break;
bellardffa65c32004-01-04 23:57:22 +00008372#endif
blueswir1992f48a2007-10-14 16:27:31 +00008373#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008374 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008375 {
thsb1e341e2007-03-20 21:50:52 +00008376 int cmd;
bellard77e46722003-04-29 20:39:06 +00008377 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008378 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008379#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008380 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008381#endif
bellard77e46722003-04-29 20:39:06 +00008382
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008383 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008384 if (cmd == -TARGET_EINVAL) {
8385 ret = cmd;
8386 break;
8387 }
thsb1e341e2007-03-20 21:50:52 +00008388
bellard60cd49d2003-03-16 22:53:56 +00008389 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008390 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008391#ifdef TARGET_ARM
8392 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008393 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8394 goto efault;
ths58134272007-03-31 18:59:32 +00008395 fl.l_type = tswap16(target_efl->l_type);
8396 fl.l_whence = tswap16(target_efl->l_whence);
8397 fl.l_start = tswap64(target_efl->l_start);
8398 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008399 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008400 unlock_user_struct(target_efl, arg3, 0);
8401 } else
8402#endif
8403 {
bellard9ee1fa22007-11-11 15:11:19 +00008404 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8405 goto efault;
ths58134272007-03-31 18:59:32 +00008406 fl.l_type = tswap16(target_fl->l_type);
8407 fl.l_whence = tswap16(target_fl->l_whence);
8408 fl.l_start = tswap64(target_fl->l_start);
8409 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008410 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008411 unlock_user_struct(target_fl, arg3, 0);
8412 }
thsb1e341e2007-03-20 21:50:52 +00008413 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008414 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008415#ifdef TARGET_ARM
8416 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008417 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8418 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008419 target_efl->l_type = tswap16(fl.l_type);
8420 target_efl->l_whence = tswap16(fl.l_whence);
8421 target_efl->l_start = tswap64(fl.l_start);
8422 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008423 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008424 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008425 } else
8426#endif
8427 {
bellard9ee1fa22007-11-11 15:11:19 +00008428 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8429 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008430 target_fl->l_type = tswap16(fl.l_type);
8431 target_fl->l_whence = tswap16(fl.l_whence);
8432 target_fl->l_start = tswap64(fl.l_start);
8433 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008434 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008435 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008436 }
bellard77e46722003-04-29 20:39:06 +00008437 }
8438 break;
8439
thsb1e341e2007-03-20 21:50:52 +00008440 case TARGET_F_SETLK64:
8441 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008442#ifdef TARGET_ARM
8443 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008444 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8445 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008446 fl.l_type = tswap16(target_efl->l_type);
8447 fl.l_whence = tswap16(target_efl->l_whence);
8448 fl.l_start = tswap64(target_efl->l_start);
8449 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008450 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008451 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008452 } else
8453#endif
8454 {
bellard9ee1fa22007-11-11 15:11:19 +00008455 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8456 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008457 fl.l_type = tswap16(target_fl->l_type);
8458 fl.l_whence = tswap16(target_fl->l_whence);
8459 fl.l_start = tswap64(target_fl->l_start);
8460 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008461 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008462 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008463 }
thsb1e341e2007-03-20 21:50:52 +00008464 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008465 break;
bellard60cd49d2003-03-16 22:53:56 +00008466 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008467 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008468 break;
8469 }
bellard77e46722003-04-29 20:39:06 +00008470 break;
8471 }
bellard60cd49d2003-03-16 22:53:56 +00008472#endif
ths7d600c82006-12-08 01:32:58 +00008473#ifdef TARGET_NR_cacheflush
8474 case TARGET_NR_cacheflush:
8475 /* self-modifying code is handled automatically, so nothing needed */
8476 ret = 0;
8477 break;
8478#endif
bellardebc05482003-09-30 21:08:41 +00008479#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008480 case TARGET_NR_security:
8481 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008482#endif
bellardc573ff62004-01-04 15:51:36 +00008483#ifdef TARGET_NR_getpagesize
8484 case TARGET_NR_getpagesize:
8485 ret = TARGET_PAGE_SIZE;
8486 break;
8487#endif
bellard31e31b82003-02-18 22:55:36 +00008488 case TARGET_NR_gettid:
8489 ret = get_errno(gettid());
8490 break;
thse5febef2007-04-01 18:31:35 +00008491#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008492 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008493#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008494 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008495 arg2 = arg3;
8496 arg3 = arg4;
8497 arg4 = arg5;
8498 }
aurel322054ac92008-10-13 21:08:07 +00008499 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8500#else
8501 ret = get_errno(readahead(arg1, arg2, arg3));
8502#endif
8503 break;
thse5febef2007-04-01 18:31:35 +00008504#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008505#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008506#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008507 case TARGET_NR_listxattr:
8508 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008509 {
8510 void *p, *b = 0;
8511 if (arg2) {
8512 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8513 if (!b) {
8514 ret = -TARGET_EFAULT;
8515 break;
8516 }
8517 }
8518 p = lock_user_string(arg1);
8519 if (p) {
8520 if (num == TARGET_NR_listxattr) {
8521 ret = get_errno(listxattr(p, b, arg3));
8522 } else {
8523 ret = get_errno(llistxattr(p, b, arg3));
8524 }
8525 } else {
8526 ret = -TARGET_EFAULT;
8527 }
8528 unlock_user(p, arg1, 0);
8529 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008530 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008531 }
8532 case TARGET_NR_flistxattr:
8533 {
8534 void *b = 0;
8535 if (arg2) {
8536 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8537 if (!b) {
8538 ret = -TARGET_EFAULT;
8539 break;
8540 }
8541 }
8542 ret = get_errno(flistxattr(arg1, b, arg3));
8543 unlock_user(b, arg2, arg3);
8544 break;
8545 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008546 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008547 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008548 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008549 void *p, *n, *v = 0;
8550 if (arg3) {
8551 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8552 if (!v) {
8553 ret = -TARGET_EFAULT;
8554 break;
8555 }
8556 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008557 p = lock_user_string(arg1);
8558 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008559 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008560 if (num == TARGET_NR_setxattr) {
8561 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8562 } else {
8563 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8564 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008565 } else {
8566 ret = -TARGET_EFAULT;
8567 }
8568 unlock_user(p, arg1, 0);
8569 unlock_user(n, arg2, 0);
8570 unlock_user(v, arg3, 0);
8571 }
8572 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008573 case TARGET_NR_fsetxattr:
8574 {
8575 void *n, *v = 0;
8576 if (arg3) {
8577 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8578 if (!v) {
8579 ret = -TARGET_EFAULT;
8580 break;
8581 }
8582 }
8583 n = lock_user_string(arg2);
8584 if (n) {
8585 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8586 } else {
8587 ret = -TARGET_EFAULT;
8588 }
8589 unlock_user(n, arg2, 0);
8590 unlock_user(v, arg3, 0);
8591 }
8592 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008593 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008594 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008595 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008596 void *p, *n, *v = 0;
8597 if (arg3) {
8598 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8599 if (!v) {
8600 ret = -TARGET_EFAULT;
8601 break;
8602 }
8603 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008604 p = lock_user_string(arg1);
8605 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008606 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008607 if (num == TARGET_NR_getxattr) {
8608 ret = get_errno(getxattr(p, n, v, arg4));
8609 } else {
8610 ret = get_errno(lgetxattr(p, n, v, arg4));
8611 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008612 } else {
8613 ret = -TARGET_EFAULT;
8614 }
8615 unlock_user(p, arg1, 0);
8616 unlock_user(n, arg2, 0);
8617 unlock_user(v, arg3, arg4);
8618 }
8619 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008620 case TARGET_NR_fgetxattr:
8621 {
8622 void *n, *v = 0;
8623 if (arg3) {
8624 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8625 if (!v) {
8626 ret = -TARGET_EFAULT;
8627 break;
8628 }
8629 }
8630 n = lock_user_string(arg2);
8631 if (n) {
8632 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8633 } else {
8634 ret = -TARGET_EFAULT;
8635 }
8636 unlock_user(n, arg2, 0);
8637 unlock_user(v, arg3, arg4);
8638 }
8639 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008640 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008641 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008642 {
8643 void *p, *n;
8644 p = lock_user_string(arg1);
8645 n = lock_user_string(arg2);
8646 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008647 if (num == TARGET_NR_removexattr) {
8648 ret = get_errno(removexattr(p, n));
8649 } else {
8650 ret = get_errno(lremovexattr(p, n));
8651 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008652 } else {
8653 ret = -TARGET_EFAULT;
8654 }
8655 unlock_user(p, arg1, 0);
8656 unlock_user(n, arg2, 0);
8657 }
8658 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008659 case TARGET_NR_fremovexattr:
8660 {
8661 void *n;
8662 n = lock_user_string(arg2);
8663 if (n) {
8664 ret = get_errno(fremovexattr(arg1, n));
8665 } else {
8666 ret = -TARGET_EFAULT;
8667 }
8668 unlock_user(n, arg2, 0);
8669 }
8670 break;
bellardebc05482003-09-30 21:08:41 +00008671#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008672#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008673#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008674 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008675#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00008676 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
8677 ret = 0;
8678 break;
edgar_iglef967792009-01-07 14:19:38 +00008679#elif defined(TARGET_CRIS)
8680 if (arg1 & 0xff)
8681 ret = -TARGET_EINVAL;
8682 else {
8683 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8684 ret = 0;
8685 }
8686 break;
bellard8d18e892007-11-14 15:18:40 +00008687#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8688 ret = do_set_thread_area(cpu_env, arg1);
8689 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008690#elif defined(TARGET_M68K)
8691 {
Andreas Färber0429a972013-08-26 18:14:44 +02008692 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008693 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01008694 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008695 break;
8696 }
ths6f5b89a2007-03-02 20:48:00 +00008697#else
8698 goto unimplemented_nowarn;
8699#endif
8700#endif
8701#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008702 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008703#if defined(TARGET_I386) && defined(TARGET_ABI32)
8704 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01008705 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008706#elif defined(TARGET_M68K)
8707 {
Andreas Färber0429a972013-08-26 18:14:44 +02008708 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008709 ret = ts->tp_value;
8710 break;
8711 }
bellard8d18e892007-11-14 15:18:40 +00008712#else
bellard5cd43932003-03-29 16:54:36 +00008713 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008714#endif
bellard8d18e892007-11-14 15:18:40 +00008715#endif
bellard48dc41e2006-06-21 18:15:50 +00008716#ifdef TARGET_NR_getdomainname
8717 case TARGET_NR_getdomainname:
8718 goto unimplemented_nowarn;
8719#endif
ths6f5b89a2007-03-02 20:48:00 +00008720
thsb5906f92007-03-19 13:32:45 +00008721#ifdef TARGET_NR_clock_gettime
8722 case TARGET_NR_clock_gettime:
8723 {
8724 struct timespec ts;
8725 ret = get_errno(clock_gettime(arg1, &ts));
8726 if (!is_error(ret)) {
8727 host_to_target_timespec(arg2, &ts);
8728 }
8729 break;
8730 }
8731#endif
8732#ifdef TARGET_NR_clock_getres
8733 case TARGET_NR_clock_getres:
8734 {
8735 struct timespec ts;
8736 ret = get_errno(clock_getres(arg1, &ts));
8737 if (!is_error(ret)) {
8738 host_to_target_timespec(arg2, &ts);
8739 }
8740 break;
8741 }
8742#endif
pbrook63d76512008-05-29 13:43:29 +00008743#ifdef TARGET_NR_clock_nanosleep
8744 case TARGET_NR_clock_nanosleep:
8745 {
8746 struct timespec ts;
8747 target_to_host_timespec(&ts, arg3);
8748 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8749 if (arg4)
8750 host_to_target_timespec(arg4, &ts);
8751 break;
8752 }
8753#endif
thsb5906f92007-03-19 13:32:45 +00008754
ths6f5b89a2007-03-02 20:48:00 +00008755#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8756 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008757 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8758 break;
ths6f5b89a2007-03-02 20:48:00 +00008759#endif
8760
ths3ae43202007-09-16 21:39:48 +00008761#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008762 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008763 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008764 break;
8765#endif
8766
ths3ae43202007-09-16 21:39:48 +00008767#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008768 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008769 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8770 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008771 break;
8772#endif
8773
ths4f2b1fe2007-06-21 21:57:12 +00008774#ifdef TARGET_NR_set_robust_list
8775 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00008776 case TARGET_NR_get_robust_list:
8777 /* The ABI for supporting robust futexes has userspace pass
8778 * the kernel a pointer to a linked list which is updated by
8779 * userspace after the syscall; the list is walked by the kernel
8780 * when the thread exits. Since the linked list in QEMU guest
8781 * memory isn't a valid linked list for the host and we have
8782 * no way to reliably intercept the thread-death event, we can't
8783 * support these. Silently return ENOSYS so that guest userspace
8784 * falls back to a non-robust futex implementation (which should
8785 * be OK except in the corner case of the guest crashing while
8786 * holding a mutex that is shared with another process via
8787 * shared memory).
8788 */
8789 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00008790#endif
8791
Peter Maydell1acae9f2013-07-02 14:04:12 +01008792#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00008793 case TARGET_NR_utimensat:
8794 {
Riku Voipioebc996f2009-04-21 15:01:51 +03008795 struct timespec *tsp, ts[2];
8796 if (!arg3) {
8797 tsp = NULL;
8798 } else {
8799 target_to_host_timespec(ts, arg3);
8800 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
8801 tsp = ts;
8802 }
ths9007f0e2007-09-25 17:50:37 +00008803 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03008804 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00008805 else {
bellard579a97f2007-11-11 14:26:47 +00008806 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00008807 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008808 goto fail;
8809 }
Riku Voipioebc996f2009-04-21 15:01:51 +03008810 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00008811 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00008812 }
8813 }
8814 break;
8815#endif
pbrookbd0c5662008-05-29 14:34:11 +00008816 case TARGET_NR_futex:
8817 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
8818 break;
aurel32dbfe4c32009-04-08 21:29:30 +00008819#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00008820 case TARGET_NR_inotify_init:
8821 ret = get_errno(sys_inotify_init());
8822 break;
8823#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008824#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00008825#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
8826 case TARGET_NR_inotify_init1:
8827 ret = get_errno(sys_inotify_init1(arg1));
8828 break;
8829#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008830#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008831#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00008832 case TARGET_NR_inotify_add_watch:
8833 p = lock_user_string(arg2);
8834 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
8835 unlock_user(p, arg2, 0);
8836 break;
8837#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008838#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00008839 case TARGET_NR_inotify_rm_watch:
8840 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
8841 break;
8842#endif
ths9007f0e2007-09-25 17:50:37 +00008843
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07008844#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00008845 case TARGET_NR_mq_open:
8846 {
8847 struct mq_attr posix_mq_attr;
8848
8849 p = lock_user_string(arg1 - 1);
8850 if (arg4 != 0)
8851 copy_from_user_mq_attr (&posix_mq_attr, arg4);
8852 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
8853 unlock_user (p, arg1, 0);
8854 }
8855 break;
8856
8857 case TARGET_NR_mq_unlink:
8858 p = lock_user_string(arg1 - 1);
8859 ret = get_errno(mq_unlink(p));
8860 unlock_user (p, arg1, 0);
8861 break;
8862
8863 case TARGET_NR_mq_timedsend:
8864 {
8865 struct timespec ts;
8866
8867 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8868 if (arg5 != 0) {
8869 target_to_host_timespec(&ts, arg5);
8870 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
8871 host_to_target_timespec(arg5, &ts);
8872 }
8873 else
8874 ret = get_errno(mq_send(arg1, p, arg3, arg4));
8875 unlock_user (p, arg2, arg3);
8876 }
8877 break;
8878
8879 case TARGET_NR_mq_timedreceive:
8880 {
8881 struct timespec ts;
8882 unsigned int prio;
8883
8884 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8885 if (arg5 != 0) {
8886 target_to_host_timespec(&ts, arg5);
8887 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
8888 host_to_target_timespec(arg5, &ts);
8889 }
8890 else
8891 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
8892 unlock_user (p, arg2, arg3);
8893 if (arg4 != 0)
8894 put_user_u32(prio, arg4);
8895 }
8896 break;
8897
8898 /* Not implemented for now... */
8899/* case TARGET_NR_mq_notify: */
8900/* break; */
8901
8902 case TARGET_NR_mq_getsetattr:
8903 {
8904 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
8905 ret = 0;
8906 if (arg3 != 0) {
8907 ret = mq_getattr(arg1, &posix_mq_attr_out);
8908 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
8909 }
8910 if (arg2 != 0) {
8911 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
8912 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
8913 }
8914
8915 }
8916 break;
8917#endif
8918
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308919#ifdef CONFIG_SPLICE
8920#ifdef TARGET_NR_tee
8921 case TARGET_NR_tee:
8922 {
8923 ret = get_errno(tee(arg1,arg2,arg3,arg4));
8924 }
8925 break;
8926#endif
8927#ifdef TARGET_NR_splice
8928 case TARGET_NR_splice:
8929 {
8930 loff_t loff_in, loff_out;
8931 loff_t *ploff_in = NULL, *ploff_out = NULL;
8932 if(arg2) {
8933 get_user_u64(loff_in, arg2);
8934 ploff_in = &loff_in;
8935 }
8936 if(arg4) {
8937 get_user_u64(loff_out, arg2);
8938 ploff_out = &loff_out;
8939 }
8940 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
8941 }
8942 break;
8943#endif
8944#ifdef TARGET_NR_vmsplice
8945 case TARGET_NR_vmsplice:
8946 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008947 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
8948 if (vec != NULL) {
8949 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
8950 unlock_iovec(vec, arg2, arg3, 0);
8951 } else {
8952 ret = -host_to_target_errno(errno);
8953 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308954 }
8955 break;
8956#endif
8957#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03008958#ifdef CONFIG_EVENTFD
8959#if defined(TARGET_NR_eventfd)
8960 case TARGET_NR_eventfd:
8961 ret = get_errno(eventfd(arg1, 0));
8962 break;
8963#endif
8964#if defined(TARGET_NR_eventfd2)
8965 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02008966 {
8967 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
8968 if (arg2 & TARGET_O_NONBLOCK) {
8969 host_flags |= O_NONBLOCK;
8970 }
8971 if (arg2 & TARGET_O_CLOEXEC) {
8972 host_flags |= O_CLOEXEC;
8973 }
8974 ret = get_errno(eventfd(arg1, host_flags));
Riku Voipioc2882b92009-08-12 15:08:24 +03008975 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02008976 }
Riku Voipioc2882b92009-08-12 15:08:24 +03008977#endif
8978#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03008979#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
8980 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01008981#if TARGET_ABI_BITS == 32
8982 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
8983 target_offset64(arg5, arg6)));
8984#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03008985 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01008986#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008987 break;
8988#endif
Peter Maydellc727f472011-01-06 11:05:10 +00008989#if defined(CONFIG_SYNC_FILE_RANGE)
8990#if defined(TARGET_NR_sync_file_range)
8991 case TARGET_NR_sync_file_range:
8992#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03008993#if defined(TARGET_MIPS)
8994 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8995 target_offset64(arg5, arg6), arg7));
8996#else
Peter Maydellc727f472011-01-06 11:05:10 +00008997 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
8998 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03008999#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009000#else
9001 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9002#endif
9003 break;
9004#endif
9005#if defined(TARGET_NR_sync_file_range2)
9006 case TARGET_NR_sync_file_range2:
9007 /* This is like sync_file_range but the arguments are reordered */
9008#if TARGET_ABI_BITS == 32
9009 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9010 target_offset64(arg5, arg6), arg2));
9011#else
9012 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9013#endif
9014 break;
9015#endif
9016#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009017#if defined(CONFIG_EPOLL)
9018#if defined(TARGET_NR_epoll_create)
9019 case TARGET_NR_epoll_create:
9020 ret = get_errno(epoll_create(arg1));
9021 break;
9022#endif
9023#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9024 case TARGET_NR_epoll_create1:
9025 ret = get_errno(epoll_create1(arg1));
9026 break;
9027#endif
9028#if defined(TARGET_NR_epoll_ctl)
9029 case TARGET_NR_epoll_ctl:
9030 {
9031 struct epoll_event ep;
9032 struct epoll_event *epp = 0;
9033 if (arg4) {
9034 struct target_epoll_event *target_ep;
9035 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9036 goto efault;
9037 }
9038 ep.events = tswap32(target_ep->events);
9039 /* The epoll_data_t union is just opaque data to the kernel,
9040 * so we transfer all 64 bits across and need not worry what
9041 * actual data type it is.
9042 */
9043 ep.data.u64 = tswap64(target_ep->data.u64);
9044 unlock_user_struct(target_ep, arg4, 0);
9045 epp = &ep;
9046 }
9047 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9048 break;
9049 }
9050#endif
9051
9052#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
9053#define IMPLEMENT_EPOLL_PWAIT
9054#endif
9055#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
9056#if defined(TARGET_NR_epoll_wait)
9057 case TARGET_NR_epoll_wait:
9058#endif
9059#if defined(IMPLEMENT_EPOLL_PWAIT)
9060 case TARGET_NR_epoll_pwait:
9061#endif
9062 {
9063 struct target_epoll_event *target_ep;
9064 struct epoll_event *ep;
9065 int epfd = arg1;
9066 int maxevents = arg3;
9067 int timeout = arg4;
9068
9069 target_ep = lock_user(VERIFY_WRITE, arg2,
9070 maxevents * sizeof(struct target_epoll_event), 1);
9071 if (!target_ep) {
9072 goto efault;
9073 }
9074
9075 ep = alloca(maxevents * sizeof(struct epoll_event));
9076
9077 switch (num) {
9078#if defined(IMPLEMENT_EPOLL_PWAIT)
9079 case TARGET_NR_epoll_pwait:
9080 {
9081 target_sigset_t *target_set;
9082 sigset_t _set, *set = &_set;
9083
9084 if (arg5) {
9085 target_set = lock_user(VERIFY_READ, arg5,
9086 sizeof(target_sigset_t), 1);
9087 if (!target_set) {
9088 unlock_user(target_ep, arg2, 0);
9089 goto efault;
9090 }
9091 target_to_host_sigset(set, target_set);
9092 unlock_user(target_set, arg5, 0);
9093 } else {
9094 set = NULL;
9095 }
9096
9097 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
9098 break;
9099 }
9100#endif
9101#if defined(TARGET_NR_epoll_wait)
9102 case TARGET_NR_epoll_wait:
9103 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
9104 break;
9105#endif
9106 default:
9107 ret = -TARGET_ENOSYS;
9108 }
9109 if (!is_error(ret)) {
9110 int i;
9111 for (i = 0; i < ret; i++) {
9112 target_ep[i].events = tswap32(ep[i].events);
9113 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
9114 }
9115 }
9116 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
9117 break;
9118 }
9119#endif
9120#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01009121#ifdef TARGET_NR_prlimit64
9122 case TARGET_NR_prlimit64:
9123 {
9124 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
9125 struct target_rlimit64 *target_rnew, *target_rold;
9126 struct host_rlimit64 rnew, rold, *rnewp = 0;
9127 if (arg3) {
9128 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
9129 goto efault;
9130 }
9131 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
9132 rnew.rlim_max = tswap64(target_rnew->rlim_max);
9133 unlock_user_struct(target_rnew, arg3, 0);
9134 rnewp = &rnew;
9135 }
9136
9137 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
9138 if (!is_error(ret) && arg4) {
9139 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
9140 goto efault;
9141 }
9142 target_rold->rlim_cur = tswap64(rold.rlim_cur);
9143 target_rold->rlim_max = tswap64(rold.rlim_max);
9144 unlock_user_struct(target_rold, arg4, 1);
9145 }
9146 break;
9147 }
9148#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07009149#ifdef TARGET_NR_gethostname
9150 case TARGET_NR_gethostname:
9151 {
9152 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9153 if (name) {
9154 ret = get_errno(gethostname(name, arg2));
9155 unlock_user(name, arg1, arg2);
9156 } else {
9157 ret = -TARGET_EFAULT;
9158 }
9159 break;
9160 }
9161#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009162#ifdef TARGET_NR_atomic_cmpxchg_32
9163 case TARGET_NR_atomic_cmpxchg_32:
9164 {
9165 /* should use start_exclusive from main.c */
9166 abi_ulong mem_value;
9167 if (get_user_u32(mem_value, arg6)) {
9168 target_siginfo_t info;
9169 info.si_signo = SIGSEGV;
9170 info.si_errno = 0;
9171 info.si_code = TARGET_SEGV_MAPERR;
9172 info._sifields._sigfault._addr = arg6;
9173 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
9174 ret = 0xdeadbeef;
9175
9176 }
9177 if (mem_value == arg2)
9178 put_user_u32(arg1, arg6);
9179 ret = mem_value;
9180 break;
9181 }
9182#endif
9183#ifdef TARGET_NR_atomic_barrier
9184 case TARGET_NR_atomic_barrier:
9185 {
9186 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +00009187 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009188 break;
9189 }
9190#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009191
9192#ifdef TARGET_NR_timer_create
9193 case TARGET_NR_timer_create:
9194 {
9195 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
9196
9197 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
9198 struct target_sigevent *ptarget_sevp;
9199 struct target_timer_t *ptarget_timer;
9200
9201 int clkid = arg1;
9202 int timer_index = next_free_host_timer();
9203
9204 if (timer_index < 0) {
9205 ret = -TARGET_EAGAIN;
9206 } else {
9207 timer_t *phtimer = g_posix_timers + timer_index;
9208
9209 if (arg2) {
9210 if (!lock_user_struct(VERIFY_READ, ptarget_sevp, arg2, 1)) {
9211 goto efault;
9212 }
9213
9214 host_sevp.sigev_signo = tswap32(ptarget_sevp->sigev_signo);
9215 host_sevp.sigev_notify = tswap32(ptarget_sevp->sigev_notify);
9216
9217 phost_sevp = &host_sevp;
9218 }
9219
9220 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
9221 if (ret) {
9222 phtimer = NULL;
9223 } else {
9224 if (!lock_user_struct(VERIFY_WRITE, ptarget_timer, arg3, 1)) {
9225 goto efault;
9226 }
9227 ptarget_timer->ptr = tswap32(0xcafe0000 | timer_index);
9228 unlock_user_struct(ptarget_timer, arg3, 1);
9229 }
9230 }
9231 break;
9232 }
9233#endif
9234
9235#ifdef TARGET_NR_timer_settime
9236 case TARGET_NR_timer_settime:
9237 {
9238 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
9239 * struct itimerspec * old_value */
9240 arg1 &= 0xffff;
9241 if (arg3 == 0 || arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9242 ret = -TARGET_EINVAL;
9243 } else {
9244 timer_t htimer = g_posix_timers[arg1];
9245 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
9246
9247 target_to_host_itimerspec(&hspec_new, arg3);
9248 ret = get_errno(
9249 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
9250 host_to_target_itimerspec(arg2, &hspec_old);
9251 }
9252 break;
9253 }
9254#endif
9255
9256#ifdef TARGET_NR_timer_gettime
9257 case TARGET_NR_timer_gettime:
9258 {
9259 /* args: timer_t timerid, struct itimerspec *curr_value */
9260 arg1 &= 0xffff;
9261 if (!arg2) {
9262 return -TARGET_EFAULT;
9263 } else if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9264 ret = -TARGET_EINVAL;
9265 } else {
9266 timer_t htimer = g_posix_timers[arg1];
9267 struct itimerspec hspec;
9268 ret = get_errno(timer_gettime(htimer, &hspec));
9269
9270 if (host_to_target_itimerspec(arg2, &hspec)) {
9271 ret = -TARGET_EFAULT;
9272 }
9273 }
9274 break;
9275 }
9276#endif
9277
9278#ifdef TARGET_NR_timer_getoverrun
9279 case TARGET_NR_timer_getoverrun:
9280 {
9281 /* args: timer_t timerid */
9282 arg1 &= 0xffff;
9283 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9284 ret = -TARGET_EINVAL;
9285 } else {
9286 timer_t htimer = g_posix_timers[arg1];
9287 ret = get_errno(timer_getoverrun(htimer));
9288 }
9289 break;
9290 }
9291#endif
9292
9293#ifdef TARGET_NR_timer_delete
9294 case TARGET_NR_timer_delete:
9295 {
9296 /* args: timer_t timerid */
9297 arg1 &= 0xffff;
9298 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9299 ret = -TARGET_EINVAL;
9300 } else {
9301 timer_t htimer = g_posix_timers[arg1];
9302 ret = get_errno(timer_delete(htimer));
9303 g_posix_timers[arg1] = 0;
9304 }
9305 break;
9306 }
9307#endif
9308
bellard31e31b82003-02-18 22:55:36 +00009309 default:
9310 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00009311 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00009312#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 +00009313 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00009314#endif
ths0da46a62007-10-20 20:23:07 +00009315 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00009316 break;
9317 }
bellard579a97f2007-11-11 14:26:47 +00009318fail:
bellardc573ff62004-01-04 15:51:36 +00009319#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00009320 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00009321#endif
thsb92c47c2007-11-01 00:07:38 +00009322 if(do_strace)
9323 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00009324 return ret;
bellard579a97f2007-11-11 14:26:47 +00009325efault:
9326 ret = -TARGET_EFAULT;
9327 goto fail;
bellard31e31b82003-02-18 22:55:36 +00009328}