blob: e0c832d2700d9e41ccd3282dffde057beaae2920 [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>
pbrookd7e40362008-05-23 16:06:43 +0000110#include "linux_loop.h"
Loïc Minierda790302009-12-29 22:06:13 +0100111#include "cpu-uname.h"
bellard31e31b82003-02-18 22:55:36 +0000112
bellard3ef693a2003-03-23 20:17:16 +0000113#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000114
pbrookd865bab2008-06-07 22:12:17 +0000115#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
116 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000117
bellard72f03902003-02-18 23:33:18 +0000118//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000119
bellard1a9353d2003-03-16 20:28:50 +0000120//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000121#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
122#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000123
bellard70a194b2003-08-11 22:20:16 +0000124
bellard70a194b2003-08-11 22:20:16 +0000125#undef _syscall0
126#undef _syscall1
127#undef _syscall2
128#undef _syscall3
129#undef _syscall4
130#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000131#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000132
bellard83fcb512006-06-14 13:37:16 +0000133#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000134static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000135{ \
136 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000137}
138
bellard83fcb512006-06-14 13:37:16 +0000139#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000140static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000141{ \
142 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000143}
144
bellard83fcb512006-06-14 13:37:16 +0000145#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000146static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000147{ \
148 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000149}
150
bellard83fcb512006-06-14 13:37:16 +0000151#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000152static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000153{ \
154 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000155}
156
bellard83fcb512006-06-14 13:37:16 +0000157#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000158static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000159{ \
160 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000161}
162
bellard83fcb512006-06-14 13:37:16 +0000163#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
164 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000165static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000166{ \
167 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000168}
bellard83fcb512006-06-14 13:37:16 +0000169
170
171#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
172 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000173static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
174 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000175{ \
176 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
177}
178
bellard70a194b2003-08-11 22:20:16 +0000179
bellard31e31b82003-02-18 22:55:36 +0000180#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000181#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000182#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000183#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000184#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000185#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000186#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000187#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000188#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000189#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000190#define __NR_sys_inotify_init __NR_inotify_init
191#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
192#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000193
Alexander Graf42a39fb2011-04-15 17:32:45 +0200194#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
195 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000196#define __NR__llseek __NR_lseek
197#endif
198
bellard72f03902003-02-18 23:33:18 +0000199#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000200_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000201#else
ths0da46a62007-10-20 20:23:07 +0000202/* This is a replacement for the host gettid() and must return a host
203 errno. */
bellard72f03902003-02-18 23:33:18 +0000204static int gettid(void) {
205 return -ENOSYS;
206}
207#endif
Peter Maydell3307e232013-06-12 16:20:21 +0100208#ifdef __NR_getdents
aurel323b3f24a2009-04-15 16:12:13 +0000209_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100210#endif
211#if !defined(__NR_getdents) || \
212 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000213_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
214#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700215#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000216_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
217 loff_t *, res, uint, wh);
218#endif
219_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
220_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
221#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
222_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
223#endif
224#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
225_syscall2(int,sys_tkill,int,tid,int,sig)
226#endif
227#ifdef __NR_exit_group
228_syscall1(int,exit_group,int,error_code)
229#endif
230#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
231_syscall1(int,set_tid_address,int *,tidptr)
232#endif
aurel323b3f24a2009-04-15 16:12:13 +0000233#if defined(TARGET_NR_futex) && defined(__NR_futex)
234_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
235 const struct timespec *,timeout,int *,uaddr2,int,val3)
236#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500237#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
238_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
239 unsigned long *, user_mask_ptr);
240#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
241_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
242 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200243_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
244 void *, arg);
aurel323b3f24a2009-04-15 16:12:13 +0000245
246static bitmask_transtbl fcntl_flags_tbl[] = {
247 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
248 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
249 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
250 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
251 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
252 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
253 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
254 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700255 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000256 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
257 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
258 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
259 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000260#if defined(O_DIRECT)
261 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
262#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700263#if defined(O_NOATIME)
264 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
265#endif
266#if defined(O_CLOEXEC)
267 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
268#endif
269#if defined(O_PATH)
270 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
271#endif
272 /* Don't terminate the list prematurely on 64-bit host+guest. */
273#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
274 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
275#endif
aurel323b3f24a2009-04-15 16:12:13 +0000276 { 0, 0, 0, 0 }
277};
278
279#define COPY_UTSNAME_FIELD(dest, src) \
280 do { \
281 /* __NEW_UTS_LEN doesn't include terminating null */ \
282 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
283 (dest)[__NEW_UTS_LEN] = '\0'; \
284 } while (0)
285
286static int sys_uname(struct new_utsname *buf)
287{
288 struct utsname uts_buf;
289
290 if (uname(&uts_buf) < 0)
291 return (-1);
292
293 /*
294 * Just in case these have some differences, we
295 * translate utsname to new_utsname (which is the
296 * struct linux kernel uses).
297 */
298
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200299 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000300 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
301 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
302 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
303 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
304 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
305#ifdef _GNU_SOURCE
306 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
307#endif
308 return (0);
309
310#undef COPY_UTSNAME_FIELD
311}
312
313static int sys_getcwd1(char *buf, size_t size)
314{
315 if (getcwd(buf, size) == NULL) {
316 /* getcwd() sets errno */
317 return (-1);
318 }
aurel32aaf4ad32009-04-16 14:17:14 +0000319 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000320}
321
aurel323b3f24a2009-04-15 16:12:13 +0000322#ifdef TARGET_NR_openat
Alexander Graff4c69012011-09-25 06:25:35 +0200323static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000324{
325 /*
326 * open(2) has extra parameter 'mode' when called with
327 * flag O_CREAT.
328 */
329 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000330 return (openat(dirfd, pathname, flags, mode));
331 }
332 return (openat(dirfd, pathname, flags));
333}
334#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300335
Peter Maydell1acae9f2013-07-02 14:04:12 +0100336#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300337#ifdef CONFIG_UTIMENSAT
338static int sys_utimensat(int dirfd, const char *pathname,
339 const struct timespec times[2], int flags)
340{
341 if (pathname == NULL)
342 return futimens(dirfd, times);
343 else
344 return utimensat(dirfd, pathname, times, flags);
345}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100346#elif defined(__NR_utimensat)
347#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000348_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
349 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100350#else
351static int sys_utimensat(int dirfd, const char *pathname,
352 const struct timespec times[2], int flags)
353{
354 errno = ENOSYS;
355 return -1;
356}
ths9007f0e2007-09-25 17:50:37 +0000357#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100358#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000359
360#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000361#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000362
aurel3239b59762008-10-01 21:46:50 +0000363#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000364static int sys_inotify_init(void)
365{
366 return (inotify_init());
367}
aurel3239b59762008-10-01 21:46:50 +0000368#endif
369#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000370static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
371{
372 return (inotify_add_watch(fd, pathname, mask));
373}
aurel3239b59762008-10-01 21:46:50 +0000374#endif
375#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000376static int sys_inotify_rm_watch(int fd, int32_t wd)
377{
aurel328690e422009-04-17 13:50:32 +0000378 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000379}
aurel3239b59762008-10-01 21:46:50 +0000380#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000381#ifdef CONFIG_INOTIFY1
382#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
383static int sys_inotify_init1(int flags)
384{
385 return (inotify_init1(flags));
386}
387#endif
388#endif
aurel323b3f24a2009-04-15 16:12:13 +0000389#else
390/* Userspace can usually survive runtime without inotify */
391#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000392#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000393#undef TARGET_NR_inotify_add_watch
394#undef TARGET_NR_inotify_rm_watch
395#endif /* CONFIG_INOTIFY */
396
Mike Frysingerd8035d42011-02-07 01:05:51 -0500397#if defined(TARGET_NR_ppoll)
398#ifndef __NR_ppoll
399# define __NR_ppoll -1
400#endif
401#define __NR_sys_ppoll __NR_ppoll
402_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
403 struct timespec *, timeout, const __sigset_t *, sigmask,
404 size_t, sigsetsize)
405#endif
bellard66fb9762003-03-23 01:06:05 +0000406
Mike Frysinger055e0902011-06-03 17:01:49 -0400407#if defined(TARGET_NR_pselect6)
408#ifndef __NR_pselect6
409# define __NR_pselect6 -1
410#endif
411#define __NR_sys_pselect6 __NR_pselect6
412_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
413 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
414#endif
415
Peter Maydell163a05a2011-06-27 17:44:52 +0100416#if defined(TARGET_NR_prlimit64)
417#ifndef __NR_prlimit64
418# define __NR_prlimit64 -1
419#endif
420#define __NR_sys_prlimit64 __NR_prlimit64
421/* The glibc rlimit structure may not be that used by the underlying syscall */
422struct host_rlimit64 {
423 uint64_t rlim_cur;
424 uint64_t rlim_max;
425};
426_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
427 const struct host_rlimit64 *, new_limit,
428 struct host_rlimit64 *, old_limit)
429#endif
430
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100431
432#if defined(TARGET_NR_timer_create)
433/* Maxiumum of 32 active POSIX timers allowed at any one time. */
434static timer_t g_posix_timers[32] = { 0, } ;
435
436static inline int next_free_host_timer(void)
437{
438 int k ;
439 /* FIXME: Does finding the next free slot require a lock? */
440 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
441 if (g_posix_timers[k] == 0) {
442 g_posix_timers[k] = (timer_t) 1;
443 return k;
444 }
445 }
446 return -1;
447}
448#endif
449
Riku Voipio48e515d2011-07-12 15:40:51 +0300450/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000451#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300452static inline int regpairs_aligned(void *cpu_env) {
453 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
454}
455#elif defined(TARGET_MIPS)
456static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000457#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
458/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
459 * of registers which translates to the same as ARM/MIPS, because we start with
460 * r3 as arg1 */
461static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300462#else
463static inline int regpairs_aligned(void *cpu_env) { return 0; }
464#endif
465
thsb92c47c2007-11-01 00:07:38 +0000466#define ERRNO_TABLE_SIZE 1200
467
468/* target_to_host_errno_table[] is initialized from
469 * host_to_target_errno_table[] in syscall_init(). */
470static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
471};
472
ths637947f2007-06-01 12:09:19 +0000473/*
thsfe8f0962007-07-12 10:59:21 +0000474 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000475 * minus the errnos that are not actually generic to all archs.
476 */
thsb92c47c2007-11-01 00:07:38 +0000477static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000478 [EIDRM] = TARGET_EIDRM,
479 [ECHRNG] = TARGET_ECHRNG,
480 [EL2NSYNC] = TARGET_EL2NSYNC,
481 [EL3HLT] = TARGET_EL3HLT,
482 [EL3RST] = TARGET_EL3RST,
483 [ELNRNG] = TARGET_ELNRNG,
484 [EUNATCH] = TARGET_EUNATCH,
485 [ENOCSI] = TARGET_ENOCSI,
486 [EL2HLT] = TARGET_EL2HLT,
487 [EDEADLK] = TARGET_EDEADLK,
488 [ENOLCK] = TARGET_ENOLCK,
489 [EBADE] = TARGET_EBADE,
490 [EBADR] = TARGET_EBADR,
491 [EXFULL] = TARGET_EXFULL,
492 [ENOANO] = TARGET_ENOANO,
493 [EBADRQC] = TARGET_EBADRQC,
494 [EBADSLT] = TARGET_EBADSLT,
495 [EBFONT] = TARGET_EBFONT,
496 [ENOSTR] = TARGET_ENOSTR,
497 [ENODATA] = TARGET_ENODATA,
498 [ETIME] = TARGET_ETIME,
499 [ENOSR] = TARGET_ENOSR,
500 [ENONET] = TARGET_ENONET,
501 [ENOPKG] = TARGET_ENOPKG,
502 [EREMOTE] = TARGET_EREMOTE,
503 [ENOLINK] = TARGET_ENOLINK,
504 [EADV] = TARGET_EADV,
505 [ESRMNT] = TARGET_ESRMNT,
506 [ECOMM] = TARGET_ECOMM,
507 [EPROTO] = TARGET_EPROTO,
508 [EDOTDOT] = TARGET_EDOTDOT,
509 [EMULTIHOP] = TARGET_EMULTIHOP,
510 [EBADMSG] = TARGET_EBADMSG,
511 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
512 [EOVERFLOW] = TARGET_EOVERFLOW,
513 [ENOTUNIQ] = TARGET_ENOTUNIQ,
514 [EBADFD] = TARGET_EBADFD,
515 [EREMCHG] = TARGET_EREMCHG,
516 [ELIBACC] = TARGET_ELIBACC,
517 [ELIBBAD] = TARGET_ELIBBAD,
518 [ELIBSCN] = TARGET_ELIBSCN,
519 [ELIBMAX] = TARGET_ELIBMAX,
520 [ELIBEXEC] = TARGET_ELIBEXEC,
521 [EILSEQ] = TARGET_EILSEQ,
522 [ENOSYS] = TARGET_ENOSYS,
523 [ELOOP] = TARGET_ELOOP,
524 [ERESTART] = TARGET_ERESTART,
525 [ESTRPIPE] = TARGET_ESTRPIPE,
526 [ENOTEMPTY] = TARGET_ENOTEMPTY,
527 [EUSERS] = TARGET_EUSERS,
528 [ENOTSOCK] = TARGET_ENOTSOCK,
529 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
530 [EMSGSIZE] = TARGET_EMSGSIZE,
531 [EPROTOTYPE] = TARGET_EPROTOTYPE,
532 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
533 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
534 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
535 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
536 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
537 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
538 [EADDRINUSE] = TARGET_EADDRINUSE,
539 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
540 [ENETDOWN] = TARGET_ENETDOWN,
541 [ENETUNREACH] = TARGET_ENETUNREACH,
542 [ENETRESET] = TARGET_ENETRESET,
543 [ECONNABORTED] = TARGET_ECONNABORTED,
544 [ECONNRESET] = TARGET_ECONNRESET,
545 [ENOBUFS] = TARGET_ENOBUFS,
546 [EISCONN] = TARGET_EISCONN,
547 [ENOTCONN] = TARGET_ENOTCONN,
548 [EUCLEAN] = TARGET_EUCLEAN,
549 [ENOTNAM] = TARGET_ENOTNAM,
550 [ENAVAIL] = TARGET_ENAVAIL,
551 [EISNAM] = TARGET_EISNAM,
552 [EREMOTEIO] = TARGET_EREMOTEIO,
553 [ESHUTDOWN] = TARGET_ESHUTDOWN,
554 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
555 [ETIMEDOUT] = TARGET_ETIMEDOUT,
556 [ECONNREFUSED] = TARGET_ECONNREFUSED,
557 [EHOSTDOWN] = TARGET_EHOSTDOWN,
558 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
559 [EALREADY] = TARGET_EALREADY,
560 [EINPROGRESS] = TARGET_EINPROGRESS,
561 [ESTALE] = TARGET_ESTALE,
562 [ECANCELED] = TARGET_ECANCELED,
563 [ENOMEDIUM] = TARGET_ENOMEDIUM,
564 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000565#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000566 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000567#endif
568#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000569 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000570#endif
571#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000572 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000573#endif
574#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000575 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000576#endif
577#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000578 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000579#endif
580#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000581 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000582#endif
thsb92c47c2007-11-01 00:07:38 +0000583};
ths637947f2007-06-01 12:09:19 +0000584
585static inline int host_to_target_errno(int err)
586{
587 if(host_to_target_errno_table[err])
588 return host_to_target_errno_table[err];
589 return err;
590}
591
thsb92c47c2007-11-01 00:07:38 +0000592static inline int target_to_host_errno(int err)
593{
594 if (target_to_host_errno_table[err])
595 return target_to_host_errno_table[err];
596 return err;
597}
598
blueswir1992f48a2007-10-14 16:27:31 +0000599static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000600{
601 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000602 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000603 else
604 return ret;
605}
606
blueswir1992f48a2007-10-14 16:27:31 +0000607static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000608{
blueswir1992f48a2007-10-14 16:27:31 +0000609 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000610}
611
thsb92c47c2007-11-01 00:07:38 +0000612char *target_strerror(int err)
613{
Alexander Graf962b2892011-11-21 12:04:07 +0100614 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
615 return NULL;
616 }
thsb92c47c2007-11-01 00:07:38 +0000617 return strerror(target_to_host_errno(err));
618}
619
blueswir1992f48a2007-10-14 16:27:31 +0000620static abi_ulong target_brk;
621static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000622static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000623
blueswir1992f48a2007-10-14 16:27:31 +0000624void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000625{
blueswir14c1de732007-07-07 20:45:44 +0000626 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000627 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000628}
629
vincent4d1de872011-06-14 21:56:33 +0000630//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
631#define DEBUGF_BRK(message, args...)
632
ths0da46a62007-10-20 20:23:07 +0000633/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000634abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000635{
blueswir1992f48a2007-10-14 16:27:31 +0000636 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000637 int new_alloc_size;
638
Paul Brook3a0c6c42012-02-09 19:04:27 +0000639 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000640
vincent4d1de872011-06-14 21:56:33 +0000641 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000642 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000643 return target_brk;
644 }
645 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000646 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
647 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000648 return target_brk;
649 }
bellard31e31b82003-02-18 22:55:36 +0000650
vincent4d1de872011-06-14 21:56:33 +0000651 /* If the new brk is less than the highest page reserved to the
652 * target heap allocation, set it and we're almost done... */
653 if (new_brk <= brk_page) {
654 /* Heap contents are initialized to zero, as for anonymous
655 * mapped pages. */
656 if (new_brk > target_brk) {
657 memset(g2h(target_brk), 0, new_brk - target_brk);
658 }
bellard31e31b82003-02-18 22:55:36 +0000659 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000660 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000661 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000662 }
663
Peter Maydell00faf082011-04-18 16:34:24 +0100664 /* We need to allocate more memory after the brk... Note that
665 * we don't use MAP_FIXED because that will map over the top of
666 * any existing mapping (like the one with the host libc or qemu
667 * itself); instead we treat "mapped but at wrong address" as
668 * a failure and unmap again.
669 */
vincent4d1de872011-06-14 21:56:33 +0000670 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000671 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000672 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100673 MAP_ANON|MAP_PRIVATE, 0, 0));
674
675 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200676 /* Heap contents are initialized to zero, as for anonymous
677 * mapped pages. Technically the new pages are already
678 * initialized to zero since they *are* anonymous mapped
679 * pages, however we have to take care with the contents that
680 * come from the remaining part of the previous page: it may
681 * contains garbage data due to a previous heap usage (grown
682 * then shrunken). */
683 memset(g2h(target_brk), 0, brk_page - target_brk);
684
Peter Maydell00faf082011-04-18 16:34:24 +0100685 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000686 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000687 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
688 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100689 return target_brk;
690 } else if (mapped_addr != -1) {
691 /* Mapped but at wrong address, meaning there wasn't actually
692 * enough space for this brk.
693 */
694 target_munmap(mapped_addr, new_alloc_size);
695 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000696 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000697 }
698 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000699 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100700 }
balrog7ab240a2008-04-26 12:17:34 +0000701
Richard Henderson7dd46c02010-05-03 10:07:49 -0700702#if defined(TARGET_ALPHA)
703 /* We (partially) emulate OSF/1 on Alpha, which requires we
704 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100705 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700706#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100707 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000708 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000709}
710
ths26edcf42007-12-09 02:25:24 +0000711static inline abi_long copy_from_user_fdset(fd_set *fds,
712 abi_ulong target_fds_addr,
713 int n)
bellard31e31b82003-02-18 22:55:36 +0000714{
ths26edcf42007-12-09 02:25:24 +0000715 int i, nw, j, k;
716 abi_ulong b, *target_fds;
717
718 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
719 if (!(target_fds = lock_user(VERIFY_READ,
720 target_fds_addr,
721 sizeof(abi_ulong) * nw,
722 1)))
723 return -TARGET_EFAULT;
724
725 FD_ZERO(fds);
726 k = 0;
727 for (i = 0; i < nw; i++) {
728 /* grab the abi_ulong */
729 __get_user(b, &target_fds[i]);
730 for (j = 0; j < TARGET_ABI_BITS; j++) {
731 /* check the bit inside the abi_ulong */
732 if ((b >> j) & 1)
733 FD_SET(k, fds);
734 k++;
bellard31e31b82003-02-18 22:55:36 +0000735 }
bellard31e31b82003-02-18 22:55:36 +0000736 }
ths26edcf42007-12-09 02:25:24 +0000737
738 unlock_user(target_fds, target_fds_addr, 0);
739
740 return 0;
bellard31e31b82003-02-18 22:55:36 +0000741}
742
Mike Frysinger055e0902011-06-03 17:01:49 -0400743static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
744 abi_ulong target_fds_addr,
745 int n)
746{
747 if (target_fds_addr) {
748 if (copy_from_user_fdset(fds, target_fds_addr, n))
749 return -TARGET_EFAULT;
750 *fds_ptr = fds;
751 } else {
752 *fds_ptr = NULL;
753 }
754 return 0;
755}
756
ths26edcf42007-12-09 02:25:24 +0000757static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
758 const fd_set *fds,
759 int n)
bellard31e31b82003-02-18 22:55:36 +0000760{
bellard31e31b82003-02-18 22:55:36 +0000761 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000762 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000763 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000764
ths26edcf42007-12-09 02:25:24 +0000765 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
766 if (!(target_fds = lock_user(VERIFY_WRITE,
767 target_fds_addr,
768 sizeof(abi_ulong) * nw,
769 0)))
770 return -TARGET_EFAULT;
771
772 k = 0;
773 for (i = 0; i < nw; i++) {
774 v = 0;
775 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000776 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000777 k++;
bellard31e31b82003-02-18 22:55:36 +0000778 }
ths26edcf42007-12-09 02:25:24 +0000779 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000780 }
ths26edcf42007-12-09 02:25:24 +0000781
782 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
783
784 return 0;
bellard31e31b82003-02-18 22:55:36 +0000785}
786
bellardc596ed12003-07-13 17:32:31 +0000787#if defined(__alpha__)
788#define HOST_HZ 1024
789#else
790#define HOST_HZ 100
791#endif
792
blueswir1992f48a2007-10-14 16:27:31 +0000793static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000794{
795#if HOST_HZ == TARGET_HZ
796 return ticks;
797#else
798 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
799#endif
800}
801
bellard579a97f2007-11-11 14:26:47 +0000802static inline abi_long host_to_target_rusage(abi_ulong target_addr,
803 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000804{
pbrook53a59602006-03-25 19:31:22 +0000805 struct target_rusage *target_rusage;
806
bellard579a97f2007-11-11 14:26:47 +0000807 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
808 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200809 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
810 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
811 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
812 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
813 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
814 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
815 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
816 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
817 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
818 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
819 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
820 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
821 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
822 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
823 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
824 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
825 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
826 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000827 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000828
829 return 0;
bellardb4091862003-05-16 15:39:34 +0000830}
831
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200832static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900833{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200834 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300835 rlim_t result;
836
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200837 target_rlim_swap = tswapal(target_rlim);
838 if (target_rlim_swap == TARGET_RLIM_INFINITY)
839 return RLIM_INFINITY;
840
841 result = target_rlim_swap;
842 if (target_rlim_swap != (rlim_t)result)
843 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300844
845 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900846}
847
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200848static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900849{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200850 abi_ulong target_rlim_swap;
851 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300852
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200853 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300854 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900855 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300856 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200857 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300858
859 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900860}
861
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300862static inline int target_to_host_resource(int code)
863{
864 switch (code) {
865 case TARGET_RLIMIT_AS:
866 return RLIMIT_AS;
867 case TARGET_RLIMIT_CORE:
868 return RLIMIT_CORE;
869 case TARGET_RLIMIT_CPU:
870 return RLIMIT_CPU;
871 case TARGET_RLIMIT_DATA:
872 return RLIMIT_DATA;
873 case TARGET_RLIMIT_FSIZE:
874 return RLIMIT_FSIZE;
875 case TARGET_RLIMIT_LOCKS:
876 return RLIMIT_LOCKS;
877 case TARGET_RLIMIT_MEMLOCK:
878 return RLIMIT_MEMLOCK;
879 case TARGET_RLIMIT_MSGQUEUE:
880 return RLIMIT_MSGQUEUE;
881 case TARGET_RLIMIT_NICE:
882 return RLIMIT_NICE;
883 case TARGET_RLIMIT_NOFILE:
884 return RLIMIT_NOFILE;
885 case TARGET_RLIMIT_NPROC:
886 return RLIMIT_NPROC;
887 case TARGET_RLIMIT_RSS:
888 return RLIMIT_RSS;
889 case TARGET_RLIMIT_RTPRIO:
890 return RLIMIT_RTPRIO;
891 case TARGET_RLIMIT_SIGPENDING:
892 return RLIMIT_SIGPENDING;
893 case TARGET_RLIMIT_STACK:
894 return RLIMIT_STACK;
895 default:
896 return code;
897 }
898}
899
ths788f5ec2007-12-09 02:37:05 +0000900static inline abi_long copy_from_user_timeval(struct timeval *tv,
901 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000902{
pbrook53a59602006-03-25 19:31:22 +0000903 struct target_timeval *target_tv;
904
ths788f5ec2007-12-09 02:37:05 +0000905 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000906 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000907
908 __get_user(tv->tv_sec, &target_tv->tv_sec);
909 __get_user(tv->tv_usec, &target_tv->tv_usec);
910
911 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000912
913 return 0;
bellard31e31b82003-02-18 22:55:36 +0000914}
915
ths788f5ec2007-12-09 02:37:05 +0000916static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
917 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000918{
pbrook53a59602006-03-25 19:31:22 +0000919 struct target_timeval *target_tv;
920
ths788f5ec2007-12-09 02:37:05 +0000921 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000922 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000923
924 __put_user(tv->tv_sec, &target_tv->tv_sec);
925 __put_user(tv->tv_usec, &target_tv->tv_usec);
926
927 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000928
929 return 0;
bellard31e31b82003-02-18 22:55:36 +0000930}
931
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700932#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
933#include <mqueue.h>
934
aurel3224e10032009-04-15 16:11:43 +0000935static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
936 abi_ulong target_mq_attr_addr)
937{
938 struct target_mq_attr *target_mq_attr;
939
940 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
941 target_mq_attr_addr, 1))
942 return -TARGET_EFAULT;
943
944 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
945 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
946 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
947 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
948
949 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
950
951 return 0;
952}
953
954static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
955 const struct mq_attr *attr)
956{
957 struct target_mq_attr *target_mq_attr;
958
959 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
960 target_mq_attr_addr, 0))
961 return -TARGET_EFAULT;
962
963 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
964 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
965 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
966 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
967
968 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
969
970 return 0;
971}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700972#endif
bellard31e31b82003-02-18 22:55:36 +0000973
Mike Frysinger055e0902011-06-03 17:01:49 -0400974#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +0000975/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000976static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +0000977 abi_ulong rfd_addr, abi_ulong wfd_addr,
978 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000979{
980 fd_set rfds, wfds, efds;
981 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
982 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +0000983 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +0000984
Mike Frysinger055e0902011-06-03 17:01:49 -0400985 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
986 if (ret) {
987 return ret;
pbrook53a59602006-03-25 19:31:22 +0000988 }
Mike Frysinger055e0902011-06-03 17:01:49 -0400989 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
990 if (ret) {
991 return ret;
pbrook53a59602006-03-25 19:31:22 +0000992 }
Mike Frysinger055e0902011-06-03 17:01:49 -0400993 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
994 if (ret) {
995 return ret;
pbrook53a59602006-03-25 19:31:22 +0000996 }
ths3b46e622007-09-17 08:09:54 +0000997
ths26edcf42007-12-09 02:25:24 +0000998 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +0000999 if (copy_from_user_timeval(&tv, target_tv_addr))
1000 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001001 tv_ptr = &tv;
1002 } else {
1003 tv_ptr = NULL;
1004 }
ths26edcf42007-12-09 02:25:24 +00001005
bellard31e31b82003-02-18 22:55:36 +00001006 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001007
ths26edcf42007-12-09 02:25:24 +00001008 if (!is_error(ret)) {
1009 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1010 return -TARGET_EFAULT;
1011 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1012 return -TARGET_EFAULT;
1013 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1014 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001015
ths788f5ec2007-12-09 02:37:05 +00001016 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1017 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001018 }
bellard579a97f2007-11-11 14:26:47 +00001019
bellard31e31b82003-02-18 22:55:36 +00001020 return ret;
1021}
Mike Frysinger055e0902011-06-03 17:01:49 -04001022#endif
bellard31e31b82003-02-18 22:55:36 +00001023
Riku Voipio099d6b02009-05-05 12:10:04 +03001024static abi_long do_pipe2(int host_pipe[], int flags)
1025{
1026#ifdef CONFIG_PIPE2
1027 return pipe2(host_pipe, flags);
1028#else
1029 return -ENOSYS;
1030#endif
1031}
1032
Richard Hendersonfb41a662010-05-03 10:07:52 -07001033static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1034 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001035{
1036 int host_pipe[2];
1037 abi_long ret;
1038 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1039
1040 if (is_error(ret))
1041 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001042
1043 /* Several targets have special calling conventions for the original
1044 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1045 if (!is_pipe2) {
1046#if defined(TARGET_ALPHA)
1047 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1048 return host_pipe[0];
1049#elif defined(TARGET_MIPS)
1050 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1051 return host_pipe[0];
1052#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001053 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001054 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001055#elif defined(TARGET_SPARC)
1056 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1057 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001058#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001059 }
1060
Riku Voipio099d6b02009-05-05 12:10:04 +03001061 if (put_user_s32(host_pipe[0], pipedes)
1062 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1063 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001064 return get_errno(ret);
1065}
1066
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001067static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1068 abi_ulong target_addr,
1069 socklen_t len)
1070{
1071 struct target_ip_mreqn *target_smreqn;
1072
1073 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1074 if (!target_smreqn)
1075 return -TARGET_EFAULT;
1076 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1077 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1078 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001079 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001080 unlock_user(target_smreqn, target_addr, 0);
1081
1082 return 0;
1083}
1084
bellard579a97f2007-11-11 14:26:47 +00001085static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1086 abi_ulong target_addr,
1087 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001088{
aurel32607175e2009-04-15 16:11:59 +00001089 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1090 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001091 struct target_sockaddr *target_saddr;
1092
bellard579a97f2007-11-11 14:26:47 +00001093 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1094 if (!target_saddr)
1095 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001096
1097 sa_family = tswap16(target_saddr->sa_family);
1098
1099 /* Oops. The caller might send a incomplete sun_path; sun_path
1100 * must be terminated by \0 (see the manual page), but
1101 * unfortunately it is quite common to specify sockaddr_un
1102 * length as "strlen(x->sun_path)" while it should be
1103 * "strlen(...) + 1". We'll fix that here if needed.
1104 * Linux kernel has a similar feature.
1105 */
1106
1107 if (sa_family == AF_UNIX) {
1108 if (len < unix_maxlen && len > 0) {
1109 char *cp = (char*)target_saddr;
1110
1111 if ( cp[len-1] && !cp[len] )
1112 len++;
1113 }
1114 if (len > unix_maxlen)
1115 len = unix_maxlen;
1116 }
1117
pbrook53a59602006-03-25 19:31:22 +00001118 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001119 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001120 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001121
1122 return 0;
bellard7854b052003-03-29 17:22:23 +00001123}
1124
bellard579a97f2007-11-11 14:26:47 +00001125static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1126 struct sockaddr *addr,
1127 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001128{
pbrook53a59602006-03-25 19:31:22 +00001129 struct target_sockaddr *target_saddr;
1130
bellard579a97f2007-11-11 14:26:47 +00001131 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1132 if (!target_saddr)
1133 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001134 memcpy(target_saddr, addr, len);
1135 target_saddr->sa_family = tswap16(addr->sa_family);
1136 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001137
1138 return 0;
bellard7854b052003-03-29 17:22:23 +00001139}
1140
bellard5a4a8982007-11-11 17:39:18 +00001141static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1142 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001143{
1144 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001145 abi_long msg_controllen;
1146 abi_ulong target_cmsg_addr;
1147 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001148 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001149
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001150 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001151 if (msg_controllen < sizeof (struct target_cmsghdr))
1152 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001153 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001154 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1155 if (!target_cmsg)
1156 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001157
1158 while (cmsg && target_cmsg) {
1159 void *data = CMSG_DATA(cmsg);
1160 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1161
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001162 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001163 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1164
1165 space += CMSG_SPACE(len);
1166 if (space > msgh->msg_controllen) {
1167 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001168 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001169 break;
1170 }
1171
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001172 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1173 cmsg->cmsg_level = SOL_SOCKET;
1174 } else {
1175 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1176 }
bellard7854b052003-03-29 17:22:23 +00001177 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1178 cmsg->cmsg_len = CMSG_LEN(len);
1179
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001180 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001181 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1182 memcpy(data, target_data, len);
1183 } else {
1184 int *fd = (int *)data;
1185 int *target_fd = (int *)target_data;
1186 int i, numfds = len / sizeof(int);
1187
1188 for (i = 0; i < numfds; i++)
1189 fd[i] = tswap32(target_fd[i]);
1190 }
1191
1192 cmsg = CMSG_NXTHDR(msgh, cmsg);
1193 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1194 }
bellard5a4a8982007-11-11 17:39:18 +00001195 unlock_user(target_cmsg, target_cmsg_addr, 0);
1196 the_end:
bellard7854b052003-03-29 17:22:23 +00001197 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001198 return 0;
bellard7854b052003-03-29 17:22:23 +00001199}
1200
bellard5a4a8982007-11-11 17:39:18 +00001201static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1202 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001203{
1204 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001205 abi_long msg_controllen;
1206 abi_ulong target_cmsg_addr;
1207 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001208 socklen_t space = 0;
1209
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001210 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001211 if (msg_controllen < sizeof (struct target_cmsghdr))
1212 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001213 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001214 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1215 if (!target_cmsg)
1216 return -TARGET_EFAULT;
1217
bellard7854b052003-03-29 17:22:23 +00001218 while (cmsg && target_cmsg) {
1219 void *data = CMSG_DATA(cmsg);
1220 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1221
1222 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1223
1224 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001225 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001226 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001227 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001228 break;
1229 }
1230
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001231 if (cmsg->cmsg_level == SOL_SOCKET) {
1232 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1233 } else {
1234 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1235 }
bellard7854b052003-03-29 17:22:23 +00001236 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001237 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001238
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001239 if ((cmsg->cmsg_level == SOL_SOCKET) &&
Jing Huangaebf5bc2012-07-24 14:01:42 +00001240 (cmsg->cmsg_type == SCM_RIGHTS)) {
bellard7854b052003-03-29 17:22:23 +00001241 int *fd = (int *)data;
1242 int *target_fd = (int *)target_data;
1243 int i, numfds = len / sizeof(int);
1244
1245 for (i = 0; i < numfds; i++)
1246 target_fd[i] = tswap32(fd[i]);
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001247 } else if ((cmsg->cmsg_level == SOL_SOCKET) &&
Jing Huangaebf5bc2012-07-24 14:01:42 +00001248 (cmsg->cmsg_type == SO_TIMESTAMP) &&
1249 (len == sizeof(struct timeval))) {
1250 /* copy struct timeval to target */
1251 struct timeval *tv = (struct timeval *)data;
1252 struct target_timeval *target_tv =
1253 (struct target_timeval *)target_data;
1254
1255 target_tv->tv_sec = tswapal(tv->tv_sec);
1256 target_tv->tv_usec = tswapal(tv->tv_usec);
1257 } else {
1258 gemu_log("Unsupported ancillary data: %d/%d\n",
1259 cmsg->cmsg_level, cmsg->cmsg_type);
1260 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001261 }
1262
1263 cmsg = CMSG_NXTHDR(msgh, cmsg);
1264 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1265 }
bellard5a4a8982007-11-11 17:39:18 +00001266 unlock_user(target_cmsg, target_cmsg_addr, space);
1267 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001268 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001269 return 0;
bellard7854b052003-03-29 17:22:23 +00001270}
1271
ths0da46a62007-10-20 20:23:07 +00001272/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001273static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001274 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001275{
blueswir1992f48a2007-10-14 16:27:31 +00001276 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001277 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001278 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001279 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001280
bellard8853f862004-02-22 14:57:26 +00001281 switch(level) {
1282 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001283 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001284 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001285 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001286
bellard2f619692007-11-16 10:46:05 +00001287 if (get_user_u32(val, optval_addr))
1288 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001289 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1290 break;
1291 case SOL_IP:
1292 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001293 case IP_TOS:
1294 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001295 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001296 case IP_ROUTER_ALERT:
1297 case IP_RECVOPTS:
1298 case IP_RETOPTS:
1299 case IP_PKTINFO:
1300 case IP_MTU_DISCOVER:
1301 case IP_RECVERR:
1302 case IP_RECVTOS:
1303#ifdef IP_FREEBIND
1304 case IP_FREEBIND:
1305#endif
1306 case IP_MULTICAST_TTL:
1307 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001308 val = 0;
1309 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001310 if (get_user_u32(val, optval_addr))
1311 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001312 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001313 if (get_user_u8(val, optval_addr))
1314 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001315 }
1316 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1317 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001318 case IP_ADD_MEMBERSHIP:
1319 case IP_DROP_MEMBERSHIP:
1320 if (optlen < sizeof (struct target_ip_mreq) ||
1321 optlen > sizeof (struct target_ip_mreqn))
1322 return -TARGET_EINVAL;
1323
1324 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1325 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1326 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1327 break;
1328
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001329 case IP_BLOCK_SOURCE:
1330 case IP_UNBLOCK_SOURCE:
1331 case IP_ADD_SOURCE_MEMBERSHIP:
1332 case IP_DROP_SOURCE_MEMBERSHIP:
1333 if (optlen != sizeof (struct target_ip_mreq_source))
1334 return -TARGET_EINVAL;
1335
1336 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1337 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1338 unlock_user (ip_mreq_source, optval_addr, 0);
1339 break;
1340
bellard8853f862004-02-22 14:57:26 +00001341 default:
1342 goto unimplemented;
1343 }
1344 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001345 case SOL_IPV6:
1346 switch (optname) {
1347 case IPV6_MTU_DISCOVER:
1348 case IPV6_MTU:
1349 case IPV6_V6ONLY:
1350 case IPV6_RECVPKTINFO:
1351 val = 0;
1352 if (optlen < sizeof(uint32_t)) {
1353 return -TARGET_EINVAL;
1354 }
1355 if (get_user_u32(val, optval_addr)) {
1356 return -TARGET_EFAULT;
1357 }
1358 ret = get_errno(setsockopt(sockfd, level, optname,
1359 &val, sizeof(val)));
1360 break;
1361 default:
1362 goto unimplemented;
1363 }
1364 break;
Jing Huang920394d2012-07-24 13:59:23 +00001365 case SOL_RAW:
1366 switch (optname) {
1367 case ICMP_FILTER:
1368 /* struct icmp_filter takes an u32 value */
1369 if (optlen < sizeof(uint32_t)) {
1370 return -TARGET_EINVAL;
1371 }
1372
1373 if (get_user_u32(val, optval_addr)) {
1374 return -TARGET_EFAULT;
1375 }
1376 ret = get_errno(setsockopt(sockfd, level, optname,
1377 &val, sizeof(val)));
1378 break;
1379
1380 default:
1381 goto unimplemented;
1382 }
1383 break;
bellard3532fa72006-06-24 15:06:03 +00001384 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001385 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001386 case TARGET_SO_RCVTIMEO:
1387 {
1388 struct timeval tv;
1389
1390 optname = SO_RCVTIMEO;
1391
1392set_timeout:
1393 if (optlen != sizeof(struct target_timeval)) {
1394 return -TARGET_EINVAL;
1395 }
1396
1397 if (copy_from_user_timeval(&tv, optval_addr)) {
1398 return -TARGET_EFAULT;
1399 }
1400
1401 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1402 &tv, sizeof(tv)));
1403 return ret;
1404 }
1405 case TARGET_SO_SNDTIMEO:
1406 optname = SO_SNDTIMEO;
1407 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001408 case TARGET_SO_ATTACH_FILTER:
1409 {
1410 struct target_sock_fprog *tfprog;
1411 struct target_sock_filter *tfilter;
1412 struct sock_fprog fprog;
1413 struct sock_filter *filter;
1414 int i;
1415
1416 if (optlen != sizeof(*tfprog)) {
1417 return -TARGET_EINVAL;
1418 }
1419 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
1420 return -TARGET_EFAULT;
1421 }
1422 if (!lock_user_struct(VERIFY_READ, tfilter,
1423 tswapal(tfprog->filter), 0)) {
1424 unlock_user_struct(tfprog, optval_addr, 1);
1425 return -TARGET_EFAULT;
1426 }
1427
1428 fprog.len = tswap16(tfprog->len);
1429 filter = malloc(fprog.len * sizeof(*filter));
1430 if (filter == NULL) {
1431 unlock_user_struct(tfilter, tfprog->filter, 1);
1432 unlock_user_struct(tfprog, optval_addr, 1);
1433 return -TARGET_ENOMEM;
1434 }
1435 for (i = 0; i < fprog.len; i++) {
1436 filter[i].code = tswap16(tfilter[i].code);
1437 filter[i].jt = tfilter[i].jt;
1438 filter[i].jf = tfilter[i].jf;
1439 filter[i].k = tswap32(tfilter[i].k);
1440 }
1441 fprog.filter = filter;
1442
1443 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
1444 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
1445 free(filter);
1446
1447 unlock_user_struct(tfilter, tfprog->filter, 1);
1448 unlock_user_struct(tfprog, optval_addr, 1);
1449 return ret;
1450 }
bellard8853f862004-02-22 14:57:26 +00001451 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001452 case TARGET_SO_DEBUG:
1453 optname = SO_DEBUG;
1454 break;
1455 case TARGET_SO_REUSEADDR:
1456 optname = SO_REUSEADDR;
1457 break;
1458 case TARGET_SO_TYPE:
1459 optname = SO_TYPE;
1460 break;
1461 case TARGET_SO_ERROR:
1462 optname = SO_ERROR;
1463 break;
1464 case TARGET_SO_DONTROUTE:
1465 optname = SO_DONTROUTE;
1466 break;
1467 case TARGET_SO_BROADCAST:
1468 optname = SO_BROADCAST;
1469 break;
1470 case TARGET_SO_SNDBUF:
1471 optname = SO_SNDBUF;
1472 break;
1473 case TARGET_SO_RCVBUF:
1474 optname = SO_RCVBUF;
1475 break;
1476 case TARGET_SO_KEEPALIVE:
1477 optname = SO_KEEPALIVE;
1478 break;
1479 case TARGET_SO_OOBINLINE:
1480 optname = SO_OOBINLINE;
1481 break;
1482 case TARGET_SO_NO_CHECK:
1483 optname = SO_NO_CHECK;
1484 break;
1485 case TARGET_SO_PRIORITY:
1486 optname = SO_PRIORITY;
1487 break;
bellard5e83e8e2005-03-01 22:32:06 +00001488#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001489 case TARGET_SO_BSDCOMPAT:
1490 optname = SO_BSDCOMPAT;
1491 break;
bellard5e83e8e2005-03-01 22:32:06 +00001492#endif
bellard3532fa72006-06-24 15:06:03 +00001493 case TARGET_SO_PASSCRED:
1494 optname = SO_PASSCRED;
1495 break;
1496 case TARGET_SO_TIMESTAMP:
1497 optname = SO_TIMESTAMP;
1498 break;
1499 case TARGET_SO_RCVLOWAT:
1500 optname = SO_RCVLOWAT;
1501 break;
bellard8853f862004-02-22 14:57:26 +00001502 break;
1503 default:
1504 goto unimplemented;
1505 }
bellard3532fa72006-06-24 15:06:03 +00001506 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001507 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001508
bellard2f619692007-11-16 10:46:05 +00001509 if (get_user_u32(val, optval_addr))
1510 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001511 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001512 break;
bellard7854b052003-03-29 17:22:23 +00001513 default:
bellard8853f862004-02-22 14:57:26 +00001514 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001515 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001516 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001517 }
bellard8853f862004-02-22 14:57:26 +00001518 return ret;
bellard7854b052003-03-29 17:22:23 +00001519}
1520
ths0da46a62007-10-20 20:23:07 +00001521/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001522static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001523 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001524{
blueswir1992f48a2007-10-14 16:27:31 +00001525 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001526 int len, val;
1527 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001528
1529 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001530 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001531 level = SOL_SOCKET;
1532 switch (optname) {
1533 /* These don't just return a single integer */
1534 case TARGET_SO_LINGER:
1535 case TARGET_SO_RCVTIMEO:
1536 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001537 case TARGET_SO_PEERNAME:
1538 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001539 case TARGET_SO_PEERCRED: {
1540 struct ucred cr;
1541 socklen_t crlen;
1542 struct target_ucred *tcr;
1543
1544 if (get_user_u32(len, optlen)) {
1545 return -TARGET_EFAULT;
1546 }
1547 if (len < 0) {
1548 return -TARGET_EINVAL;
1549 }
1550
1551 crlen = sizeof(cr);
1552 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1553 &cr, &crlen));
1554 if (ret < 0) {
1555 return ret;
1556 }
1557 if (len > crlen) {
1558 len = crlen;
1559 }
1560 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1561 return -TARGET_EFAULT;
1562 }
1563 __put_user(cr.pid, &tcr->pid);
1564 __put_user(cr.uid, &tcr->uid);
1565 __put_user(cr.gid, &tcr->gid);
1566 unlock_user_struct(tcr, optval_addr, 1);
1567 if (put_user_u32(len, optlen)) {
1568 return -TARGET_EFAULT;
1569 }
1570 break;
1571 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001572 /* Options with 'int' argument. */
1573 case TARGET_SO_DEBUG:
1574 optname = SO_DEBUG;
1575 goto int_case;
1576 case TARGET_SO_REUSEADDR:
1577 optname = SO_REUSEADDR;
1578 goto int_case;
1579 case TARGET_SO_TYPE:
1580 optname = SO_TYPE;
1581 goto int_case;
1582 case TARGET_SO_ERROR:
1583 optname = SO_ERROR;
1584 goto int_case;
1585 case TARGET_SO_DONTROUTE:
1586 optname = SO_DONTROUTE;
1587 goto int_case;
1588 case TARGET_SO_BROADCAST:
1589 optname = SO_BROADCAST;
1590 goto int_case;
1591 case TARGET_SO_SNDBUF:
1592 optname = SO_SNDBUF;
1593 goto int_case;
1594 case TARGET_SO_RCVBUF:
1595 optname = SO_RCVBUF;
1596 goto int_case;
1597 case TARGET_SO_KEEPALIVE:
1598 optname = SO_KEEPALIVE;
1599 goto int_case;
1600 case TARGET_SO_OOBINLINE:
1601 optname = SO_OOBINLINE;
1602 goto int_case;
1603 case TARGET_SO_NO_CHECK:
1604 optname = SO_NO_CHECK;
1605 goto int_case;
1606 case TARGET_SO_PRIORITY:
1607 optname = SO_PRIORITY;
1608 goto int_case;
1609#ifdef SO_BSDCOMPAT
1610 case TARGET_SO_BSDCOMPAT:
1611 optname = SO_BSDCOMPAT;
1612 goto int_case;
1613#endif
1614 case TARGET_SO_PASSCRED:
1615 optname = SO_PASSCRED;
1616 goto int_case;
1617 case TARGET_SO_TIMESTAMP:
1618 optname = SO_TIMESTAMP;
1619 goto int_case;
1620 case TARGET_SO_RCVLOWAT:
1621 optname = SO_RCVLOWAT;
1622 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001623 default:
bellard2efbe912005-07-23 15:10:20 +00001624 goto int_case;
1625 }
1626 break;
1627 case SOL_TCP:
1628 /* TCP options all take an 'int' value. */
1629 int_case:
bellard2f619692007-11-16 10:46:05 +00001630 if (get_user_u32(len, optlen))
1631 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001632 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001633 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001634 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001635 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1636 if (ret < 0)
1637 return ret;
bellard2efbe912005-07-23 15:10:20 +00001638 if (len > lv)
1639 len = lv;
bellard2f619692007-11-16 10:46:05 +00001640 if (len == 4) {
1641 if (put_user_u32(val, optval_addr))
1642 return -TARGET_EFAULT;
1643 } else {
1644 if (put_user_u8(val, optval_addr))
1645 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001646 }
bellard2f619692007-11-16 10:46:05 +00001647 if (put_user_u32(len, optlen))
1648 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001649 break;
1650 case SOL_IP:
1651 switch(optname) {
1652 case IP_TOS:
1653 case IP_TTL:
1654 case IP_HDRINCL:
1655 case IP_ROUTER_ALERT:
1656 case IP_RECVOPTS:
1657 case IP_RETOPTS:
1658 case IP_PKTINFO:
1659 case IP_MTU_DISCOVER:
1660 case IP_RECVERR:
1661 case IP_RECVTOS:
1662#ifdef IP_FREEBIND
1663 case IP_FREEBIND:
1664#endif
1665 case IP_MULTICAST_TTL:
1666 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001667 if (get_user_u32(len, optlen))
1668 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001669 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001670 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001671 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001672 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1673 if (ret < 0)
1674 return ret;
bellard2efbe912005-07-23 15:10:20 +00001675 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001676 len = 1;
bellard2f619692007-11-16 10:46:05 +00001677 if (put_user_u32(len, optlen)
1678 || put_user_u8(val, optval_addr))
1679 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001680 } else {
bellard2efbe912005-07-23 15:10:20 +00001681 if (len > sizeof(int))
1682 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001683 if (put_user_u32(len, optlen)
1684 || put_user_u32(val, optval_addr))
1685 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001686 }
bellard8853f862004-02-22 14:57:26 +00001687 break;
bellard2efbe912005-07-23 15:10:20 +00001688 default:
thsc02f4992007-12-18 02:39:59 +00001689 ret = -TARGET_ENOPROTOOPT;
1690 break;
bellard8853f862004-02-22 14:57:26 +00001691 }
1692 break;
1693 default:
1694 unimplemented:
1695 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1696 level, optname);
thsc02f4992007-12-18 02:39:59 +00001697 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001698 break;
1699 }
1700 return ret;
bellard7854b052003-03-29 17:22:23 +00001701}
1702
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001703static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1704 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001705{
1706 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001707 struct iovec *vec;
1708 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001709 int i;
pbrook53a59602006-03-25 19:31:22 +00001710
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001711 if (count == 0) {
1712 errno = 0;
1713 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001714 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001715 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001716 errno = EINVAL;
1717 return NULL;
1718 }
1719
1720 vec = calloc(count, sizeof(struct iovec));
1721 if (vec == NULL) {
1722 errno = ENOMEM;
1723 return NULL;
1724 }
1725
1726 target_vec = lock_user(VERIFY_READ, target_addr,
1727 count * sizeof(struct target_iovec), 1);
1728 if (target_vec == NULL) {
1729 errno = EFAULT;
1730 goto fail2;
1731 }
1732
1733 /* ??? If host page size > target page size, this will result in a
1734 value larger than what we can actually support. */
1735 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1736 total_len = 0;
1737
1738 for (i = 0; i < count; i++) {
1739 abi_ulong base = tswapal(target_vec[i].iov_base);
1740 abi_long len = tswapal(target_vec[i].iov_len);
1741
1742 if (len < 0) {
1743 errno = EINVAL;
1744 goto fail;
1745 } else if (len == 0) {
1746 /* Zero length pointer is ignored. */
1747 vec[i].iov_base = 0;
1748 } else {
1749 vec[i].iov_base = lock_user(type, base, len, copy);
1750 if (!vec[i].iov_base) {
1751 errno = EFAULT;
1752 goto fail;
1753 }
1754 if (len > max_len - total_len) {
1755 len = max_len - total_len;
1756 }
1757 }
1758 vec[i].iov_len = len;
1759 total_len += len;
1760 }
1761
1762 unlock_user(target_vec, target_addr, 0);
1763 return vec;
1764
1765 fail:
1766 free(vec);
1767 fail2:
1768 unlock_user(target_vec, target_addr, 0);
1769 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001770}
1771
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001772static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1773 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001774{
1775 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00001776 int i;
1777
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001778 target_vec = lock_user(VERIFY_READ, target_addr,
1779 count * sizeof(struct target_iovec), 1);
1780 if (target_vec) {
1781 for (i = 0; i < count; i++) {
1782 abi_ulong base = tswapal(target_vec[i].iov_base);
1783 abi_long len = tswapal(target_vec[i].iov_base);
1784 if (len < 0) {
1785 break;
1786 }
balrogd732dcb2008-10-28 10:21:03 +00001787 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1788 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001789 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00001790 }
bellard579a97f2007-11-11 14:26:47 +00001791
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001792 free(vec);
pbrook53a59602006-03-25 19:31:22 +00001793}
1794
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001795static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001796{
1797 int host_type = 0;
1798 int target_type = *type;
1799
1800 switch (target_type & TARGET_SOCK_TYPE_MASK) {
1801 case TARGET_SOCK_DGRAM:
1802 host_type = SOCK_DGRAM;
1803 break;
1804 case TARGET_SOCK_STREAM:
1805 host_type = SOCK_STREAM;
1806 break;
1807 default:
1808 host_type = target_type & TARGET_SOCK_TYPE_MASK;
1809 break;
1810 }
1811 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001812#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001813 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001814#else
1815 return -TARGET_EINVAL;
1816#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001817 }
1818 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001819#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001820 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001821#elif !defined(O_NONBLOCK)
1822 return -TARGET_EINVAL;
1823#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001824 }
1825 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001826 return 0;
1827}
1828
1829/* Try to emulate socket type flags after socket creation. */
1830static int sock_flags_fixup(int fd, int target_type)
1831{
1832#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
1833 if (target_type & TARGET_SOCK_NONBLOCK) {
1834 int flags = fcntl(fd, F_GETFL);
1835 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
1836 close(fd);
1837 return -TARGET_EINVAL;
1838 }
1839 }
1840#endif
1841 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001842}
1843
ths0da46a62007-10-20 20:23:07 +00001844/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001845static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001846{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001847 int target_type = type;
1848 int ret;
1849
1850 ret = target_to_host_sock_type(&type);
1851 if (ret) {
1852 return ret;
1853 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001854
balrog12bc92a2007-10-30 21:06:14 +00001855 if (domain == PF_NETLINK)
1856 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001857 ret = get_errno(socket(domain, type, protocol));
1858 if (ret >= 0) {
1859 ret = sock_flags_fixup(ret, target_type);
1860 }
1861 return ret;
bellard3532fa72006-06-24 15:06:03 +00001862}
1863
ths0da46a62007-10-20 20:23:07 +00001864/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001865static abi_long do_bind(int sockfd, abi_ulong target_addr,
1866 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001867{
aurel328f7aeaf2009-01-30 19:47:57 +00001868 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001869 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001870
Blue Swirl38724252010-09-18 05:53:14 +00001871 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001872 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001873 }
aurel328f7aeaf2009-01-30 19:47:57 +00001874
aurel32607175e2009-04-15 16:11:59 +00001875 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001876
Arnaud Patard917507b2009-06-19 10:44:45 +03001877 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1878 if (ret)
1879 return ret;
1880
bellard3532fa72006-06-24 15:06:03 +00001881 return get_errno(bind(sockfd, addr, addrlen));
1882}
1883
ths0da46a62007-10-20 20:23:07 +00001884/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001885static abi_long do_connect(int sockfd, abi_ulong target_addr,
1886 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001887{
aurel328f7aeaf2009-01-30 19:47:57 +00001888 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001889 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001890
Blue Swirl38724252010-09-18 05:53:14 +00001891 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001892 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001893 }
aurel328f7aeaf2009-01-30 19:47:57 +00001894
1895 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001896
Arnaud Patard917507b2009-06-19 10:44:45 +03001897 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1898 if (ret)
1899 return ret;
1900
bellard3532fa72006-06-24 15:06:03 +00001901 return get_errno(connect(sockfd, addr, addrlen));
1902}
1903
ths0da46a62007-10-20 20:23:07 +00001904/* do_sendrecvmsg() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001905static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1906 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001907{
balrog6de645c2008-10-28 10:26:29 +00001908 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001909 struct target_msghdr *msgp;
1910 struct msghdr msg;
1911 int count;
1912 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001913 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001914
bellard579a97f2007-11-11 14:26:47 +00001915 /* FIXME */
1916 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1917 msgp,
1918 target_msg,
1919 send ? 1 : 0))
1920 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001921 if (msgp->msg_name) {
1922 msg.msg_namelen = tswap32(msgp->msg_namelen);
1923 msg.msg_name = alloca(msg.msg_namelen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001924 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001925 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001926 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001927 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03001928 }
bellard3532fa72006-06-24 15:06:03 +00001929 } else {
1930 msg.msg_name = NULL;
1931 msg.msg_namelen = 0;
1932 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001933 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00001934 msg.msg_control = alloca(msg.msg_controllen);
1935 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001936
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001937 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001938 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001939 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
1940 target_vec, count, send);
1941 if (vec == NULL) {
1942 ret = -host_to_target_errno(errno);
1943 goto out2;
1944 }
bellard3532fa72006-06-24 15:06:03 +00001945 msg.msg_iovlen = count;
1946 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001947
bellard3532fa72006-06-24 15:06:03 +00001948 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001949 ret = target_to_host_cmsg(&msg, msgp);
1950 if (ret == 0)
1951 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001952 } else {
1953 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001954 if (!is_error(ret)) {
1955 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001956 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00001957 if (!is_error(ret)) {
1958 msgp->msg_namelen = tswap32(msg.msg_namelen);
1959 if (msg.msg_name != NULL) {
1960 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
1961 msg.msg_name, msg.msg_namelen);
1962 if (ret) {
1963 goto out;
1964 }
1965 }
1966
balrog6de645c2008-10-28 10:26:29 +00001967 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00001968 }
balrog6de645c2008-10-28 10:26:29 +00001969 }
bellard3532fa72006-06-24 15:06:03 +00001970 }
Jing Huangca619062012-07-24 13:58:02 +00001971
1972out:
bellard3532fa72006-06-24 15:06:03 +00001973 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001974out2:
bellard579a97f2007-11-11 14:26:47 +00001975 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001976 return ret;
1977}
1978
Peter Maydella94b4982013-02-08 04:35:04 +00001979/* If we don't have a system accept4() then just call accept.
1980 * The callsites to do_accept4() will ensure that they don't
1981 * pass a non-zero flags argument in this config.
1982 */
1983#ifndef CONFIG_ACCEPT4
1984static inline int accept4(int sockfd, struct sockaddr *addr,
1985 socklen_t *addrlen, int flags)
1986{
1987 assert(flags == 0);
1988 return accept(sockfd, addr, addrlen);
1989}
1990#endif
1991
1992/* do_accept4() Must return target values and target errnos. */
1993static abi_long do_accept4(int fd, abi_ulong target_addr,
1994 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00001995{
bellard2f619692007-11-16 10:46:05 +00001996 socklen_t addrlen;
1997 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001998 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001999
Peter Maydella94b4982013-02-08 04:35:04 +00002000 if (target_addr == 0) {
2001 return get_errno(accept4(fd, NULL, NULL, flags));
2002 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002003
2004 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002005 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002006 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002007
Blue Swirl38724252010-09-18 05:53:14 +00002008 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002009 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002010 }
aurel328f7aeaf2009-01-30 19:47:57 +00002011
Arnaud Patard917507b2009-06-19 10:44:45 +03002012 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2013 return -TARGET_EINVAL;
2014
bellard2f619692007-11-16 10:46:05 +00002015 addr = alloca(addrlen);
2016
Peter Maydella94b4982013-02-08 04:35:04 +00002017 ret = get_errno(accept4(fd, addr, &addrlen, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002018 if (!is_error(ret)) {
2019 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002020 if (put_user_u32(addrlen, target_addrlen_addr))
2021 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002022 }
2023 return ret;
2024}
2025
ths0da46a62007-10-20 20:23:07 +00002026/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002027static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002028 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002029{
bellard2f619692007-11-16 10:46:05 +00002030 socklen_t addrlen;
2031 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002032 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002033
bellard2f619692007-11-16 10:46:05 +00002034 if (get_user_u32(addrlen, target_addrlen_addr))
2035 return -TARGET_EFAULT;
2036
Blue Swirl38724252010-09-18 05:53:14 +00002037 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002038 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002039 }
aurel328f7aeaf2009-01-30 19:47:57 +00002040
Arnaud Patard917507b2009-06-19 10:44:45 +03002041 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2042 return -TARGET_EFAULT;
2043
bellard2f619692007-11-16 10:46:05 +00002044 addr = alloca(addrlen);
2045
pbrook1be9e1d2006-11-19 15:26:04 +00002046 ret = get_errno(getpeername(fd, addr, &addrlen));
2047 if (!is_error(ret)) {
2048 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002049 if (put_user_u32(addrlen, target_addrlen_addr))
2050 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002051 }
2052 return ret;
2053}
2054
ths0da46a62007-10-20 20:23:07 +00002055/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002056static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002057 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002058{
bellard2f619692007-11-16 10:46:05 +00002059 socklen_t addrlen;
2060 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002061 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002062
bellard2f619692007-11-16 10:46:05 +00002063 if (get_user_u32(addrlen, target_addrlen_addr))
2064 return -TARGET_EFAULT;
2065
Blue Swirl38724252010-09-18 05:53:14 +00002066 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002067 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002068 }
aurel328f7aeaf2009-01-30 19:47:57 +00002069
Arnaud Patard917507b2009-06-19 10:44:45 +03002070 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2071 return -TARGET_EFAULT;
2072
bellard2f619692007-11-16 10:46:05 +00002073 addr = alloca(addrlen);
2074
pbrook1be9e1d2006-11-19 15:26:04 +00002075 ret = get_errno(getsockname(fd, addr, &addrlen));
2076 if (!is_error(ret)) {
2077 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002078 if (put_user_u32(addrlen, target_addrlen_addr))
2079 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002080 }
2081 return ret;
2082}
2083
ths0da46a62007-10-20 20:23:07 +00002084/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002085static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002086 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002087{
2088 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002089 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002090
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002091 target_to_host_sock_type(&type);
2092
pbrook1be9e1d2006-11-19 15:26:04 +00002093 ret = get_errno(socketpair(domain, type, protocol, tab));
2094 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002095 if (put_user_s32(tab[0], target_tab_addr)
2096 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2097 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002098 }
2099 return ret;
2100}
2101
ths0da46a62007-10-20 20:23:07 +00002102/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002103static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2104 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002105{
2106 void *addr;
2107 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002108 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002109
Blue Swirl38724252010-09-18 05:53:14 +00002110 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002111 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002112 }
aurel328f7aeaf2009-01-30 19:47:57 +00002113
bellard579a97f2007-11-11 14:26:47 +00002114 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2115 if (!host_msg)
2116 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002117 if (target_addr) {
2118 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002119 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2120 if (ret) {
2121 unlock_user(host_msg, msg, 0);
2122 return ret;
2123 }
pbrook1be9e1d2006-11-19 15:26:04 +00002124 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2125 } else {
2126 ret = get_errno(send(fd, host_msg, len, flags));
2127 }
2128 unlock_user(host_msg, msg, 0);
2129 return ret;
2130}
2131
ths0da46a62007-10-20 20:23:07 +00002132/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002133static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2134 abi_ulong target_addr,
2135 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002136{
2137 socklen_t addrlen;
2138 void *addr;
2139 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002140 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002141
bellard579a97f2007-11-11 14:26:47 +00002142 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2143 if (!host_msg)
2144 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002145 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002146 if (get_user_u32(addrlen, target_addrlen)) {
2147 ret = -TARGET_EFAULT;
2148 goto fail;
2149 }
Blue Swirl38724252010-09-18 05:53:14 +00002150 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002151 ret = -TARGET_EINVAL;
2152 goto fail;
2153 }
pbrook1be9e1d2006-11-19 15:26:04 +00002154 addr = alloca(addrlen);
2155 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2156 } else {
2157 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002158 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002159 }
2160 if (!is_error(ret)) {
2161 if (target_addr) {
2162 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002163 if (put_user_u32(addrlen, target_addrlen)) {
2164 ret = -TARGET_EFAULT;
2165 goto fail;
2166 }
pbrook1be9e1d2006-11-19 15:26:04 +00002167 }
2168 unlock_user(host_msg, msg, len);
2169 } else {
bellard2f619692007-11-16 10:46:05 +00002170fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002171 unlock_user(host_msg, msg, 0);
2172 }
2173 return ret;
2174}
2175
j_mayer32407102007-09-26 23:01:49 +00002176#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002177/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002178static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002179{
blueswir1992f48a2007-10-14 16:27:31 +00002180 abi_long ret;
2181 const int n = sizeof(abi_ulong);
bellard31e31b82003-02-18 22:55:36 +00002182
2183 switch(num) {
2184 case SOCKOP_socket:
bellard7854b052003-03-29 17:22:23 +00002185 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002186 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002187
Ulrich Hecht98818182009-07-03 17:09:28 +02002188 if (get_user_ual(domain, vptr)
2189 || get_user_ual(type, vptr + n)
2190 || get_user_ual(protocol, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002191 return -TARGET_EFAULT;
2192
bellard3532fa72006-06-24 15:06:03 +00002193 ret = do_socket(domain, type, protocol);
bellard7854b052003-03-29 17:22:23 +00002194 }
bellard31e31b82003-02-18 22:55:36 +00002195 break;
2196 case SOCKOP_bind:
bellard7854b052003-03-29 17:22:23 +00002197 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002198 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002199 abi_ulong target_addr;
2200 socklen_t addrlen;
2201
Ulrich Hecht98818182009-07-03 17:09:28 +02002202 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002203 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002204 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002205 return -TARGET_EFAULT;
2206
bellard3532fa72006-06-24 15:06:03 +00002207 ret = do_bind(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002208 }
bellard31e31b82003-02-18 22:55:36 +00002209 break;
2210 case SOCKOP_connect:
bellard7854b052003-03-29 17:22:23 +00002211 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002212 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002213 abi_ulong target_addr;
2214 socklen_t addrlen;
2215
Ulrich Hecht98818182009-07-03 17:09:28 +02002216 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002217 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002218 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002219 return -TARGET_EFAULT;
2220
bellard3532fa72006-06-24 15:06:03 +00002221 ret = do_connect(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002222 }
bellard31e31b82003-02-18 22:55:36 +00002223 break;
2224 case SOCKOP_listen:
bellard7854b052003-03-29 17:22:23 +00002225 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002226 abi_ulong sockfd, backlog;
bellard2f619692007-11-16 10:46:05 +00002227
Ulrich Hecht98818182009-07-03 17:09:28 +02002228 if (get_user_ual(sockfd, vptr)
2229 || get_user_ual(backlog, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002230 return -TARGET_EFAULT;
2231
bellard7854b052003-03-29 17:22:23 +00002232 ret = get_errno(listen(sockfd, backlog));
2233 }
bellard31e31b82003-02-18 22:55:36 +00002234 break;
2235 case SOCKOP_accept:
2236 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002237 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002238 abi_ulong target_addr, target_addrlen;
2239
Ulrich Hecht98818182009-07-03 17:09:28 +02002240 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002241 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002242 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002243 return -TARGET_EFAULT;
2244
Peter Maydella94b4982013-02-08 04:35:04 +00002245 ret = do_accept4(sockfd, target_addr, target_addrlen, 0);
bellard31e31b82003-02-18 22:55:36 +00002246 }
2247 break;
2248 case SOCKOP_getsockname:
2249 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002250 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002251 abi_ulong target_addr, target_addrlen;
2252
Ulrich Hecht98818182009-07-03 17:09:28 +02002253 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002254 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002255 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002256 return -TARGET_EFAULT;
2257
pbrook1be9e1d2006-11-19 15:26:04 +00002258 ret = do_getsockname(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002259 }
2260 break;
2261 case SOCKOP_getpeername:
2262 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002263 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002264 abi_ulong target_addr, target_addrlen;
2265
Ulrich Hecht98818182009-07-03 17:09:28 +02002266 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002267 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002268 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002269 return -TARGET_EFAULT;
2270
pbrook1be9e1d2006-11-19 15:26:04 +00002271 ret = do_getpeername(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002272 }
2273 break;
2274 case SOCKOP_socketpair:
2275 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002276 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002277 abi_ulong tab;
2278
Ulrich Hecht98818182009-07-03 17:09:28 +02002279 if (get_user_ual(domain, vptr)
2280 || get_user_ual(type, vptr + n)
2281 || get_user_ual(protocol, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002282 || get_user_ual(tab, vptr + 3 * n))
2283 return -TARGET_EFAULT;
2284
pbrook1be9e1d2006-11-19 15:26:04 +00002285 ret = do_socketpair(domain, type, protocol, tab);
bellard31e31b82003-02-18 22:55:36 +00002286 }
2287 break;
2288 case SOCKOP_send:
bellard7854b052003-03-29 17:22:23 +00002289 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002290 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002291 abi_ulong msg;
2292 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002293 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002294
Ulrich Hecht98818182009-07-03 17:09:28 +02002295 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002296 || get_user_ual(msg, vptr + n)
2297 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002298 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002299 return -TARGET_EFAULT;
2300
pbrook1be9e1d2006-11-19 15:26:04 +00002301 ret = do_sendto(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002302 }
bellard31e31b82003-02-18 22:55:36 +00002303 break;
2304 case SOCKOP_recv:
bellard7854b052003-03-29 17:22:23 +00002305 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002306 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002307 abi_ulong msg;
2308 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002309 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002310
Ulrich Hecht98818182009-07-03 17:09:28 +02002311 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002312 || get_user_ual(msg, vptr + n)
2313 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002314 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002315 return -TARGET_EFAULT;
2316
pbrook1be9e1d2006-11-19 15:26:04 +00002317 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002318 }
bellard31e31b82003-02-18 22:55:36 +00002319 break;
2320 case SOCKOP_sendto:
bellard7854b052003-03-29 17:22:23 +00002321 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002322 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002323 abi_ulong msg;
2324 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002325 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002326 abi_ulong addr;
2327 socklen_t addrlen;
2328
Ulrich Hecht98818182009-07-03 17:09:28 +02002329 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002330 || get_user_ual(msg, vptr + n)
2331 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002332 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002333 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002334 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002335 return -TARGET_EFAULT;
2336
pbrook1be9e1d2006-11-19 15:26:04 +00002337 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002338 }
bellard31e31b82003-02-18 22:55:36 +00002339 break;
2340 case SOCKOP_recvfrom:
2341 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002342 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002343 abi_ulong msg;
2344 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002345 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002346 abi_ulong addr;
2347 socklen_t addrlen;
2348
Ulrich Hecht98818182009-07-03 17:09:28 +02002349 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002350 || get_user_ual(msg, vptr + n)
2351 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002352 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002353 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002354 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002355 return -TARGET_EFAULT;
2356
pbrook1be9e1d2006-11-19 15:26:04 +00002357 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
bellard31e31b82003-02-18 22:55:36 +00002358 }
2359 break;
2360 case SOCKOP_shutdown:
bellard7854b052003-03-29 17:22:23 +00002361 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002362 abi_ulong sockfd, how;
bellard2f619692007-11-16 10:46:05 +00002363
Ulrich Hecht98818182009-07-03 17:09:28 +02002364 if (get_user_ual(sockfd, vptr)
2365 || get_user_ual(how, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002366 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002367
2368 ret = get_errno(shutdown(sockfd, how));
2369 }
bellard31e31b82003-02-18 22:55:36 +00002370 break;
2371 case SOCKOP_sendmsg:
2372 case SOCKOP_recvmsg:
bellard1a9353d2003-03-16 20:28:50 +00002373 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002374 abi_ulong fd;
blueswir1992f48a2007-10-14 16:27:31 +00002375 abi_ulong target_msg;
Ulrich Hecht98818182009-07-03 17:09:28 +02002376 abi_ulong flags;
bellard1a9353d2003-03-16 20:28:50 +00002377
Ulrich Hecht98818182009-07-03 17:09:28 +02002378 if (get_user_ual(fd, vptr)
bellard2f619692007-11-16 10:46:05 +00002379 || get_user_ual(target_msg, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002380 || get_user_ual(flags, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002381 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002382
ths5fafdf22007-09-16 21:08:06 +00002383 ret = do_sendrecvmsg(fd, target_msg, flags,
bellard3532fa72006-06-24 15:06:03 +00002384 (num == SOCKOP_sendmsg));
bellard1a9353d2003-03-16 20:28:50 +00002385 }
2386 break;
bellard31e31b82003-02-18 22:55:36 +00002387 case SOCKOP_setsockopt:
bellard7854b052003-03-29 17:22:23 +00002388 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002389 abi_ulong sockfd;
2390 abi_ulong level;
2391 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002392 abi_ulong optval;
2393 socklen_t optlen;
2394
Ulrich Hecht98818182009-07-03 17:09:28 +02002395 if (get_user_ual(sockfd, vptr)
2396 || get_user_ual(level, vptr + n)
2397 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002398 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002399 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002400 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002401
2402 ret = do_setsockopt(sockfd, level, optname, optval, optlen);
2403 }
2404 break;
bellard31e31b82003-02-18 22:55:36 +00002405 case SOCKOP_getsockopt:
bellard7854b052003-03-29 17:22:23 +00002406 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002407 abi_ulong sockfd;
2408 abi_ulong level;
2409 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002410 abi_ulong optval;
2411 socklen_t optlen;
bellard7854b052003-03-29 17:22:23 +00002412
Ulrich Hecht98818182009-07-03 17:09:28 +02002413 if (get_user_ual(sockfd, vptr)
2414 || get_user_ual(level, vptr + n)
2415 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002416 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002417 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002418 return -TARGET_EFAULT;
2419
2420 ret = do_getsockopt(sockfd, level, optname, optval, optlen);
bellard7854b052003-03-29 17:22:23 +00002421 }
2422 break;
bellard31e31b82003-02-18 22:55:36 +00002423 default:
2424 gemu_log("Unsupported socketcall: %d\n", num);
ths0da46a62007-10-20 20:23:07 +00002425 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002426 break;
2427 }
2428 return ret;
2429}
j_mayer32407102007-09-26 23:01:49 +00002430#endif
bellard31e31b82003-02-18 22:55:36 +00002431
bellard8853f862004-02-22 14:57:26 +00002432#define N_SHM_REGIONS 32
2433
2434static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002435 abi_ulong start;
2436 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002437} shm_regions[N_SHM_REGIONS];
2438
ths3eb6b042007-06-03 14:26:27 +00002439struct target_ipc_perm
2440{
blueswir1992f48a2007-10-14 16:27:31 +00002441 abi_long __key;
2442 abi_ulong uid;
2443 abi_ulong gid;
2444 abi_ulong cuid;
2445 abi_ulong cgid;
ths3eb6b042007-06-03 14:26:27 +00002446 unsigned short int mode;
2447 unsigned short int __pad1;
2448 unsigned short int __seq;
2449 unsigned short int __pad2;
blueswir1992f48a2007-10-14 16:27:31 +00002450 abi_ulong __unused1;
2451 abi_ulong __unused2;
ths3eb6b042007-06-03 14:26:27 +00002452};
2453
2454struct target_semid_ds
2455{
2456 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002457 abi_ulong sem_otime;
2458 abi_ulong __unused1;
2459 abi_ulong sem_ctime;
2460 abi_ulong __unused2;
2461 abi_ulong sem_nsems;
2462 abi_ulong __unused3;
2463 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002464};
2465
bellard579a97f2007-11-11 14:26:47 +00002466static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2467 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002468{
2469 struct target_ipc_perm *target_ip;
2470 struct target_semid_ds *target_sd;
2471
bellard579a97f2007-11-11 14:26:47 +00002472 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2473 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002474 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002475 host_ip->__key = tswapal(target_ip->__key);
2476 host_ip->uid = tswapal(target_ip->uid);
2477 host_ip->gid = tswapal(target_ip->gid);
2478 host_ip->cuid = tswapal(target_ip->cuid);
2479 host_ip->cgid = tswapal(target_ip->cgid);
2480 host_ip->mode = tswap16(target_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002481 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002482 return 0;
ths3eb6b042007-06-03 14:26:27 +00002483}
2484
bellard579a97f2007-11-11 14:26:47 +00002485static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2486 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002487{
2488 struct target_ipc_perm *target_ip;
2489 struct target_semid_ds *target_sd;
2490
bellard579a97f2007-11-11 14:26:47 +00002491 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2492 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002493 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002494 target_ip->__key = tswapal(host_ip->__key);
2495 target_ip->uid = tswapal(host_ip->uid);
2496 target_ip->gid = tswapal(host_ip->gid);
2497 target_ip->cuid = tswapal(host_ip->cuid);
2498 target_ip->cgid = tswapal(host_ip->cgid);
2499 target_ip->mode = tswap16(host_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002500 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002501 return 0;
ths3eb6b042007-06-03 14:26:27 +00002502}
2503
bellard579a97f2007-11-11 14:26:47 +00002504static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2505 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002506{
2507 struct target_semid_ds *target_sd;
2508
bellard579a97f2007-11-11 14:26:47 +00002509 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2510 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002511 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2512 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002513 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2514 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2515 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002516 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002517 return 0;
ths3eb6b042007-06-03 14:26:27 +00002518}
2519
bellard579a97f2007-11-11 14:26:47 +00002520static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2521 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002522{
2523 struct target_semid_ds *target_sd;
2524
bellard579a97f2007-11-11 14:26:47 +00002525 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2526 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002527 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002528 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002529 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2530 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2531 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002532 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002533 return 0;
ths3eb6b042007-06-03 14:26:27 +00002534}
2535
aurel32e5289082009-04-18 16:16:12 +00002536struct target_seminfo {
2537 int semmap;
2538 int semmni;
2539 int semmns;
2540 int semmnu;
2541 int semmsl;
2542 int semopm;
2543 int semume;
2544 int semusz;
2545 int semvmx;
2546 int semaem;
2547};
2548
2549static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2550 struct seminfo *host_seminfo)
2551{
2552 struct target_seminfo *target_seminfo;
2553 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2554 return -TARGET_EFAULT;
2555 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2556 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2557 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2558 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2559 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2560 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2561 __put_user(host_seminfo->semume, &target_seminfo->semume);
2562 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2563 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2564 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2565 unlock_user_struct(target_seminfo, target_addr, 1);
2566 return 0;
2567}
2568
thsfa294812007-02-02 22:05:00 +00002569union semun {
2570 int val;
ths3eb6b042007-06-03 14:26:27 +00002571 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002572 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002573 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002574};
2575
ths3eb6b042007-06-03 14:26:27 +00002576union target_semun {
2577 int val;
aurel32e5289082009-04-18 16:16:12 +00002578 abi_ulong buf;
2579 abi_ulong array;
2580 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002581};
2582
aurel32e5289082009-04-18 16:16:12 +00002583static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2584 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002585{
aurel32e5289082009-04-18 16:16:12 +00002586 int nsems;
2587 unsigned short *array;
2588 union semun semun;
2589 struct semid_ds semid_ds;
2590 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002591
aurel32e5289082009-04-18 16:16:12 +00002592 semun.buf = &semid_ds;
2593
2594 ret = semctl(semid, 0, IPC_STAT, semun);
2595 if (ret == -1)
2596 return get_errno(ret);
2597
2598 nsems = semid_ds.sem_nsems;
2599
2600 *host_array = malloc(nsems*sizeof(unsigned short));
2601 array = lock_user(VERIFY_READ, target_addr,
2602 nsems*sizeof(unsigned short), 1);
2603 if (!array)
2604 return -TARGET_EFAULT;
2605
2606 for(i=0; i<nsems; i++) {
2607 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002608 }
aurel32e5289082009-04-18 16:16:12 +00002609 unlock_user(array, target_addr, 0);
2610
bellard579a97f2007-11-11 14:26:47 +00002611 return 0;
ths3eb6b042007-06-03 14:26:27 +00002612}
2613
aurel32e5289082009-04-18 16:16:12 +00002614static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2615 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002616{
aurel32e5289082009-04-18 16:16:12 +00002617 int nsems;
2618 unsigned short *array;
2619 union semun semun;
2620 struct semid_ds semid_ds;
2621 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002622
aurel32e5289082009-04-18 16:16:12 +00002623 semun.buf = &semid_ds;
2624
2625 ret = semctl(semid, 0, IPC_STAT, semun);
2626 if (ret == -1)
2627 return get_errno(ret);
2628
2629 nsems = semid_ds.sem_nsems;
2630
2631 array = lock_user(VERIFY_WRITE, target_addr,
2632 nsems*sizeof(unsigned short), 0);
2633 if (!array)
2634 return -TARGET_EFAULT;
2635
2636 for(i=0; i<nsems; i++) {
2637 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002638 }
aurel32e5289082009-04-18 16:16:12 +00002639 free(*host_array);
2640 unlock_user(array, target_addr, 1);
2641
bellard579a97f2007-11-11 14:26:47 +00002642 return 0;
ths3eb6b042007-06-03 14:26:27 +00002643}
2644
aurel32e5289082009-04-18 16:16:12 +00002645static inline abi_long do_semctl(int semid, int semnum, int cmd,
2646 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002647{
2648 union semun arg;
2649 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302650 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002651 struct seminfo seminfo;
2652 abi_long ret = -TARGET_EINVAL;
2653 abi_long err;
2654 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002655
2656 switch( cmd ) {
2657 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002658 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002659 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002660 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002661 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002662 break;
2663 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002664 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002665 err = target_to_host_semarray(semid, &array, target_su.array);
2666 if (err)
2667 return err;
2668 arg.array = array;
2669 ret = get_errno(semctl(semid, semnum, cmd, arg));
2670 err = host_to_target_semarray(semid, target_su.array, &array);
2671 if (err)
2672 return err;
ths3eb6b042007-06-03 14:26:27 +00002673 break;
2674 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002675 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002676 case SEM_STAT:
2677 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2678 if (err)
2679 return err;
2680 arg.buf = &dsarg;
2681 ret = get_errno(semctl(semid, semnum, cmd, arg));
2682 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2683 if (err)
2684 return err;
ths3eb6b042007-06-03 14:26:27 +00002685 break;
aurel32e5289082009-04-18 16:16:12 +00002686 case IPC_INFO:
2687 case SEM_INFO:
2688 arg.__buf = &seminfo;
2689 ret = get_errno(semctl(semid, semnum, cmd, arg));
2690 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2691 if (err)
2692 return err;
2693 break;
2694 case IPC_RMID:
2695 case GETPID:
2696 case GETNCNT:
2697 case GETZCNT:
2698 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2699 break;
ths3eb6b042007-06-03 14:26:27 +00002700 }
2701
2702 return ret;
2703}
2704
aurel32e5289082009-04-18 16:16:12 +00002705struct target_sembuf {
2706 unsigned short sem_num;
2707 short sem_op;
2708 short sem_flg;
2709};
2710
2711static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2712 abi_ulong target_addr,
2713 unsigned nsops)
2714{
2715 struct target_sembuf *target_sembuf;
2716 int i;
2717
2718 target_sembuf = lock_user(VERIFY_READ, target_addr,
2719 nsops*sizeof(struct target_sembuf), 1);
2720 if (!target_sembuf)
2721 return -TARGET_EFAULT;
2722
2723 for(i=0; i<nsops; i++) {
2724 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2725 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2726 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2727 }
2728
2729 unlock_user(target_sembuf, target_addr, 0);
2730
2731 return 0;
2732}
2733
2734static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2735{
2736 struct sembuf sops[nsops];
2737
2738 if (target_to_host_sembuf(sops, ptr, nsops))
2739 return -TARGET_EFAULT;
2740
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002741 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002742}
2743
ths1bc012f2007-06-03 14:27:49 +00002744struct target_msqid_ds
2745{
aurel321c54ff92008-10-13 21:08:44 +00002746 struct target_ipc_perm msg_perm;
2747 abi_ulong msg_stime;
2748#if TARGET_ABI_BITS == 32
2749 abi_ulong __unused1;
2750#endif
2751 abi_ulong msg_rtime;
2752#if TARGET_ABI_BITS == 32
2753 abi_ulong __unused2;
2754#endif
2755 abi_ulong msg_ctime;
2756#if TARGET_ABI_BITS == 32
2757 abi_ulong __unused3;
2758#endif
2759 abi_ulong __msg_cbytes;
2760 abi_ulong msg_qnum;
2761 abi_ulong msg_qbytes;
2762 abi_ulong msg_lspid;
2763 abi_ulong msg_lrpid;
2764 abi_ulong __unused4;
2765 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002766};
2767
bellard579a97f2007-11-11 14:26:47 +00002768static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2769 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002770{
2771 struct target_msqid_ds *target_md;
2772
bellard579a97f2007-11-11 14:26:47 +00002773 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2774 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002775 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2776 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002777 host_md->msg_stime = tswapal(target_md->msg_stime);
2778 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2779 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2780 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2781 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2782 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2783 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2784 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002785 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002786 return 0;
ths1bc012f2007-06-03 14:27:49 +00002787}
2788
bellard579a97f2007-11-11 14:26:47 +00002789static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2790 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002791{
2792 struct target_msqid_ds *target_md;
2793
bellard579a97f2007-11-11 14:26:47 +00002794 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2795 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002796 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2797 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002798 target_md->msg_stime = tswapal(host_md->msg_stime);
2799 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2800 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2801 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2802 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2803 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2804 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2805 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002806 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002807 return 0;
ths1bc012f2007-06-03 14:27:49 +00002808}
2809
aurel321c54ff92008-10-13 21:08:44 +00002810struct target_msginfo {
2811 int msgpool;
2812 int msgmap;
2813 int msgmax;
2814 int msgmnb;
2815 int msgmni;
2816 int msgssz;
2817 int msgtql;
2818 unsigned short int msgseg;
2819};
2820
2821static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2822 struct msginfo *host_msginfo)
2823{
2824 struct target_msginfo *target_msginfo;
2825 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2826 return -TARGET_EFAULT;
2827 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2828 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2829 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2830 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2831 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2832 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2833 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2834 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2835 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002836 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002837}
2838
2839static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002840{
2841 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002842 struct msginfo msginfo;
2843 abi_long ret = -TARGET_EINVAL;
2844
2845 cmd &= 0xff;
2846
2847 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002848 case IPC_STAT:
2849 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002850 case MSG_STAT:
2851 if (target_to_host_msqid_ds(&dsarg,ptr))
2852 return -TARGET_EFAULT;
2853 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2854 if (host_to_target_msqid_ds(ptr,&dsarg))
2855 return -TARGET_EFAULT;
2856 break;
2857 case IPC_RMID:
2858 ret = get_errno(msgctl(msgid, cmd, NULL));
2859 break;
2860 case IPC_INFO:
2861 case MSG_INFO:
2862 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2863 if (host_to_target_msginfo(ptr, &msginfo))
2864 return -TARGET_EFAULT;
2865 break;
ths1bc012f2007-06-03 14:27:49 +00002866 }
aurel321c54ff92008-10-13 21:08:44 +00002867
ths1bc012f2007-06-03 14:27:49 +00002868 return ret;
2869}
2870
2871struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002872 abi_long mtype;
2873 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002874};
2875
blueswir1992f48a2007-10-14 16:27:31 +00002876static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2877 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002878{
2879 struct target_msgbuf *target_mb;
2880 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002881 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002882
bellard579a97f2007-11-11 14:26:47 +00002883 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2884 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002885 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002886 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002887 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002888 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2889 free(host_mb);
2890 unlock_user_struct(target_mb, msgp, 0);
2891
2892 return ret;
2893}
2894
blueswir1992f48a2007-10-14 16:27:31 +00002895static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002896 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002897 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002898{
2899 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002900 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002901 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002902 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002903
bellard579a97f2007-11-11 14:26:47 +00002904 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2905 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002906
Jim Meyering0d07fe42012-08-22 13:55:53 +02002907 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00002908 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002909
bellard579a97f2007-11-11 14:26:47 +00002910 if (ret > 0) {
2911 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2912 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2913 if (!target_mtext) {
2914 ret = -TARGET_EFAULT;
2915 goto end;
2916 }
aurel321c54ff92008-10-13 21:08:44 +00002917 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002918 unlock_user(target_mtext, target_mtext_addr, ret);
2919 }
aurel321c54ff92008-10-13 21:08:44 +00002920
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002921 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002922
bellard579a97f2007-11-11 14:26:47 +00002923end:
2924 if (target_mb)
2925 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02002926 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002927 return ret;
2928}
2929
Riku Voipio88a8c982009-04-03 10:42:00 +03002930struct target_shmid_ds
2931{
2932 struct target_ipc_perm shm_perm;
2933 abi_ulong shm_segsz;
2934 abi_ulong shm_atime;
2935#if TARGET_ABI_BITS == 32
2936 abi_ulong __unused1;
2937#endif
2938 abi_ulong shm_dtime;
2939#if TARGET_ABI_BITS == 32
2940 abi_ulong __unused2;
2941#endif
2942 abi_ulong shm_ctime;
2943#if TARGET_ABI_BITS == 32
2944 abi_ulong __unused3;
2945#endif
2946 int shm_cpid;
2947 int shm_lpid;
2948 abi_ulong shm_nattch;
2949 unsigned long int __unused4;
2950 unsigned long int __unused5;
2951};
2952
2953static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2954 abi_ulong target_addr)
2955{
2956 struct target_shmid_ds *target_sd;
2957
2958 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2959 return -TARGET_EFAULT;
2960 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2961 return -TARGET_EFAULT;
2962 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2963 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2964 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2965 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2966 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2967 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2968 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2969 unlock_user_struct(target_sd, target_addr, 0);
2970 return 0;
2971}
2972
2973static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2974 struct shmid_ds *host_sd)
2975{
2976 struct target_shmid_ds *target_sd;
2977
2978 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2979 return -TARGET_EFAULT;
2980 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2981 return -TARGET_EFAULT;
2982 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2983 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2984 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2985 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2986 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2987 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2988 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2989 unlock_user_struct(target_sd, target_addr, 1);
2990 return 0;
2991}
2992
2993struct target_shminfo {
2994 abi_ulong shmmax;
2995 abi_ulong shmmin;
2996 abi_ulong shmmni;
2997 abi_ulong shmseg;
2998 abi_ulong shmall;
2999};
3000
3001static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3002 struct shminfo *host_shminfo)
3003{
3004 struct target_shminfo *target_shminfo;
3005 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3006 return -TARGET_EFAULT;
3007 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3008 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3009 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3010 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3011 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3012 unlock_user_struct(target_shminfo, target_addr, 1);
3013 return 0;
3014}
3015
3016struct target_shm_info {
3017 int used_ids;
3018 abi_ulong shm_tot;
3019 abi_ulong shm_rss;
3020 abi_ulong shm_swp;
3021 abi_ulong swap_attempts;
3022 abi_ulong swap_successes;
3023};
3024
3025static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3026 struct shm_info *host_shm_info)
3027{
3028 struct target_shm_info *target_shm_info;
3029 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3030 return -TARGET_EFAULT;
3031 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3032 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3033 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3034 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3035 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3036 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3037 unlock_user_struct(target_shm_info, target_addr, 1);
3038 return 0;
3039}
3040
3041static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3042{
3043 struct shmid_ds dsarg;
3044 struct shminfo shminfo;
3045 struct shm_info shm_info;
3046 abi_long ret = -TARGET_EINVAL;
3047
3048 cmd &= 0xff;
3049
3050 switch(cmd) {
3051 case IPC_STAT:
3052 case IPC_SET:
3053 case SHM_STAT:
3054 if (target_to_host_shmid_ds(&dsarg, buf))
3055 return -TARGET_EFAULT;
3056 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3057 if (host_to_target_shmid_ds(buf, &dsarg))
3058 return -TARGET_EFAULT;
3059 break;
3060 case IPC_INFO:
3061 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3062 if (host_to_target_shminfo(buf, &shminfo))
3063 return -TARGET_EFAULT;
3064 break;
3065 case SHM_INFO:
3066 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3067 if (host_to_target_shm_info(buf, &shm_info))
3068 return -TARGET_EFAULT;
3069 break;
3070 case IPC_RMID:
3071 case SHM_LOCK:
3072 case SHM_UNLOCK:
3073 ret = get_errno(shmctl(shmid, cmd, NULL));
3074 break;
3075 }
3076
3077 return ret;
3078}
3079
3080static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3081{
3082 abi_long raddr;
3083 void *host_raddr;
3084 struct shmid_ds shm_info;
3085 int i,ret;
3086
3087 /* find out the length of the shared memory segment */
3088 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3089 if (is_error(ret)) {
3090 /* can't get length, bail out */
3091 return ret;
3092 }
3093
3094 mmap_lock();
3095
3096 if (shmaddr)
3097 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3098 else {
3099 abi_ulong mmap_start;
3100
3101 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3102
3103 if (mmap_start == -1) {
3104 errno = ENOMEM;
3105 host_raddr = (void *)-1;
3106 } else
3107 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3108 }
3109
3110 if (host_raddr == (void *)-1) {
3111 mmap_unlock();
3112 return get_errno((long)host_raddr);
3113 }
3114 raddr=h2g((unsigned long)host_raddr);
3115
3116 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3117 PAGE_VALID | PAGE_READ |
3118 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3119
3120 for (i = 0; i < N_SHM_REGIONS; i++) {
3121 if (shm_regions[i].start == 0) {
3122 shm_regions[i].start = raddr;
3123 shm_regions[i].size = shm_info.shm_segsz;
3124 break;
3125 }
3126 }
3127
3128 mmap_unlock();
3129 return raddr;
3130
3131}
3132
3133static inline abi_long do_shmdt(abi_ulong shmaddr)
3134{
3135 int i;
3136
3137 for (i = 0; i < N_SHM_REGIONS; ++i) {
3138 if (shm_regions[i].start == shmaddr) {
3139 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003140 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003141 break;
3142 }
3143 }
3144
3145 return get_errno(shmdt(g2h(shmaddr)));
3146}
3147
aurel321c54ff92008-10-13 21:08:44 +00003148#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003149/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003150/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003151static abi_long do_ipc(unsigned int call, int first,
3152 int second, int third,
3153 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003154{
3155 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003156 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003157
3158 version = call >> 16;
3159 call &= 0xffff;
3160
3161 switch (call) {
thsfa294812007-02-02 22:05:00 +00003162 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003163 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003164 break;
3165
3166 case IPCOP_semget:
3167 ret = get_errno(semget(first, second, third));
3168 break;
3169
3170 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003171 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003172 break;
thsd96372e2007-02-02 22:05:44 +00003173
aurel321c54ff92008-10-13 21:08:44 +00003174 case IPCOP_msgget:
3175 ret = get_errno(msgget(first, second));
3176 break;
thsd96372e2007-02-02 22:05:44 +00003177
aurel321c54ff92008-10-13 21:08:44 +00003178 case IPCOP_msgsnd:
3179 ret = do_msgsnd(first, ptr, second, third);
3180 break;
thsd96372e2007-02-02 22:05:44 +00003181
aurel321c54ff92008-10-13 21:08:44 +00003182 case IPCOP_msgctl:
3183 ret = do_msgctl(first, second, ptr);
3184 break;
thsd96372e2007-02-02 22:05:44 +00003185
aurel321c54ff92008-10-13 21:08:44 +00003186 case IPCOP_msgrcv:
3187 switch (version) {
3188 case 0:
3189 {
3190 struct target_ipc_kludge {
3191 abi_long msgp;
3192 abi_long msgtyp;
3193 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003194
aurel321c54ff92008-10-13 21:08:44 +00003195 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3196 ret = -TARGET_EFAULT;
3197 break;
ths1bc012f2007-06-03 14:27:49 +00003198 }
aurel321c54ff92008-10-13 21:08:44 +00003199
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003200 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003201
3202 unlock_user_struct(tmp, ptr, 0);
3203 break;
3204 }
3205 default:
3206 ret = do_msgrcv(first, ptr, second, fifth, third);
3207 }
3208 break;
thsd96372e2007-02-02 22:05:44 +00003209
bellard8853f862004-02-22 14:57:26 +00003210 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003211 switch (version) {
3212 default:
bellard5a4a8982007-11-11 17:39:18 +00003213 {
3214 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003215 raddr = do_shmat(first, ptr, second);
3216 if (is_error(raddr))
3217 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003218 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003219 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003220 break;
3221 }
3222 case 1:
3223 ret = -TARGET_EINVAL;
3224 break;
bellard5a4a8982007-11-11 17:39:18 +00003225 }
bellard8853f862004-02-22 14:57:26 +00003226 break;
3227 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003228 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003229 break;
3230
3231 case IPCOP_shmget:
3232 /* IPC_* flag values are the same on all linux platforms */
3233 ret = get_errno(shmget(first, second, third));
3234 break;
3235
3236 /* IPC_* and SHM_* command values are the same on all linux platforms */
3237 case IPCOP_shmctl:
Riku Voipio88a8c982009-04-03 10:42:00 +03003238 ret = do_shmctl(first, second, third);
bellard8853f862004-02-22 14:57:26 +00003239 break;
3240 default:
j_mayer32407102007-09-26 23:01:49 +00003241 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003242 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003243 break;
3244 }
3245 return ret;
3246}
j_mayer32407102007-09-26 23:01:49 +00003247#endif
bellard8853f862004-02-22 14:57:26 +00003248
bellard31e31b82003-02-18 22:55:36 +00003249/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003250
Blue Swirl001faf32009-05-13 17:53:17 +00003251#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003252#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3253enum {
3254#include "syscall_types.h"
3255};
3256#undef STRUCT
3257#undef STRUCT_SPECIAL
3258
Blue Swirl001faf32009-05-13 17:53:17 +00003259#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003260#define STRUCT_SPECIAL(name)
3261#include "syscall_types.h"
3262#undef STRUCT
3263#undef STRUCT_SPECIAL
3264
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003265typedef struct IOCTLEntry IOCTLEntry;
3266
3267typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3268 int fd, abi_long cmd, abi_long arg);
3269
3270struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003271 unsigned int target_cmd;
3272 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003273 const char *name;
3274 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003275 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003276 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003277};
bellard31e31b82003-02-18 22:55:36 +00003278
3279#define IOC_R 0x0001
3280#define IOC_W 0x0002
3281#define IOC_RW (IOC_R | IOC_W)
3282
3283#define MAX_STRUCT_SIZE 4096
3284
Peter Maydelldace20d2011-01-10 13:11:24 +00003285#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003286/* So fiemap access checks don't overflow on 32 bit systems.
3287 * This is very slightly smaller than the limit imposed by
3288 * the underlying kernel.
3289 */
3290#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3291 / sizeof(struct fiemap_extent))
3292
3293static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3294 int fd, abi_long cmd, abi_long arg)
3295{
3296 /* The parameter for this ioctl is a struct fiemap followed
3297 * by an array of struct fiemap_extent whose size is set
3298 * in fiemap->fm_extent_count. The array is filled in by the
3299 * ioctl.
3300 */
3301 int target_size_in, target_size_out;
3302 struct fiemap *fm;
3303 const argtype *arg_type = ie->arg_type;
3304 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3305 void *argptr, *p;
3306 abi_long ret;
3307 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3308 uint32_t outbufsz;
3309 int free_fm = 0;
3310
3311 assert(arg_type[0] == TYPE_PTR);
3312 assert(ie->access == IOC_RW);
3313 arg_type++;
3314 target_size_in = thunk_type_size(arg_type, 0);
3315 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3316 if (!argptr) {
3317 return -TARGET_EFAULT;
3318 }
3319 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3320 unlock_user(argptr, arg, 0);
3321 fm = (struct fiemap *)buf_temp;
3322 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3323 return -TARGET_EINVAL;
3324 }
3325
3326 outbufsz = sizeof (*fm) +
3327 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3328
3329 if (outbufsz > MAX_STRUCT_SIZE) {
3330 /* We can't fit all the extents into the fixed size buffer.
3331 * Allocate one that is large enough and use it instead.
3332 */
3333 fm = malloc(outbufsz);
3334 if (!fm) {
3335 return -TARGET_ENOMEM;
3336 }
3337 memcpy(fm, buf_temp, sizeof(struct fiemap));
3338 free_fm = 1;
3339 }
3340 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3341 if (!is_error(ret)) {
3342 target_size_out = target_size_in;
3343 /* An extent_count of 0 means we were only counting the extents
3344 * so there are no structs to copy
3345 */
3346 if (fm->fm_extent_count != 0) {
3347 target_size_out += fm->fm_mapped_extents * extent_size;
3348 }
3349 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3350 if (!argptr) {
3351 ret = -TARGET_EFAULT;
3352 } else {
3353 /* Convert the struct fiemap */
3354 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3355 if (fm->fm_extent_count != 0) {
3356 p = argptr + target_size_in;
3357 /* ...and then all the struct fiemap_extents */
3358 for (i = 0; i < fm->fm_mapped_extents; i++) {
3359 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3360 THUNK_TARGET);
3361 p += extent_size;
3362 }
3363 }
3364 unlock_user(argptr, arg, target_size_out);
3365 }
3366 }
3367 if (free_fm) {
3368 free(fm);
3369 }
3370 return ret;
3371}
Peter Maydelldace20d2011-01-10 13:11:24 +00003372#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003373
Laurent Vivier059c2f22011-03-30 00:12:12 +02003374static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3375 int fd, abi_long cmd, abi_long arg)
3376{
3377 const argtype *arg_type = ie->arg_type;
3378 int target_size;
3379 void *argptr;
3380 int ret;
3381 struct ifconf *host_ifconf;
3382 uint32_t outbufsz;
3383 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3384 int target_ifreq_size;
3385 int nb_ifreq;
3386 int free_buf = 0;
3387 int i;
3388 int target_ifc_len;
3389 abi_long target_ifc_buf;
3390 int host_ifc_len;
3391 char *host_ifc_buf;
3392
3393 assert(arg_type[0] == TYPE_PTR);
3394 assert(ie->access == IOC_RW);
3395
3396 arg_type++;
3397 target_size = thunk_type_size(arg_type, 0);
3398
3399 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3400 if (!argptr)
3401 return -TARGET_EFAULT;
3402 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3403 unlock_user(argptr, arg, 0);
3404
3405 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3406 target_ifc_len = host_ifconf->ifc_len;
3407 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3408
3409 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3410 nb_ifreq = target_ifc_len / target_ifreq_size;
3411 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3412
3413 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3414 if (outbufsz > MAX_STRUCT_SIZE) {
3415 /* We can't fit all the extents into the fixed size buffer.
3416 * Allocate one that is large enough and use it instead.
3417 */
3418 host_ifconf = malloc(outbufsz);
3419 if (!host_ifconf) {
3420 return -TARGET_ENOMEM;
3421 }
3422 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3423 free_buf = 1;
3424 }
3425 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3426
3427 host_ifconf->ifc_len = host_ifc_len;
3428 host_ifconf->ifc_buf = host_ifc_buf;
3429
3430 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3431 if (!is_error(ret)) {
3432 /* convert host ifc_len to target ifc_len */
3433
3434 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3435 target_ifc_len = nb_ifreq * target_ifreq_size;
3436 host_ifconf->ifc_len = target_ifc_len;
3437
3438 /* restore target ifc_buf */
3439
3440 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3441
3442 /* copy struct ifconf to target user */
3443
3444 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3445 if (!argptr)
3446 return -TARGET_EFAULT;
3447 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3448 unlock_user(argptr, arg, target_size);
3449
3450 /* copy ifreq[] to target user */
3451
3452 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3453 for (i = 0; i < nb_ifreq ; i++) {
3454 thunk_convert(argptr + i * target_ifreq_size,
3455 host_ifc_buf + i * sizeof(struct ifreq),
3456 ifreq_arg_type, THUNK_TARGET);
3457 }
3458 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3459 }
3460
3461 if (free_buf) {
3462 free(host_ifconf);
3463 }
3464
3465 return ret;
3466}
3467
Alexander Graf56e904e2012-01-31 18:42:06 +01003468static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3469 abi_long cmd, abi_long arg)
3470{
3471 void *argptr;
3472 struct dm_ioctl *host_dm;
3473 abi_long guest_data;
3474 uint32_t guest_data_size;
3475 int target_size;
3476 const argtype *arg_type = ie->arg_type;
3477 abi_long ret;
3478 void *big_buf = NULL;
3479 char *host_data;
3480
3481 arg_type++;
3482 target_size = thunk_type_size(arg_type, 0);
3483 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3484 if (!argptr) {
3485 ret = -TARGET_EFAULT;
3486 goto out;
3487 }
3488 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3489 unlock_user(argptr, arg, 0);
3490
3491 /* buf_temp is too small, so fetch things into a bigger buffer */
3492 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3493 memcpy(big_buf, buf_temp, target_size);
3494 buf_temp = big_buf;
3495 host_dm = big_buf;
3496
3497 guest_data = arg + host_dm->data_start;
3498 if ((guest_data - arg) < 0) {
3499 ret = -EINVAL;
3500 goto out;
3501 }
3502 guest_data_size = host_dm->data_size - host_dm->data_start;
3503 host_data = (char*)host_dm + host_dm->data_start;
3504
3505 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3506 switch (ie->host_cmd) {
3507 case DM_REMOVE_ALL:
3508 case DM_LIST_DEVICES:
3509 case DM_DEV_CREATE:
3510 case DM_DEV_REMOVE:
3511 case DM_DEV_SUSPEND:
3512 case DM_DEV_STATUS:
3513 case DM_DEV_WAIT:
3514 case DM_TABLE_STATUS:
3515 case DM_TABLE_CLEAR:
3516 case DM_TABLE_DEPS:
3517 case DM_LIST_VERSIONS:
3518 /* no input data */
3519 break;
3520 case DM_DEV_RENAME:
3521 case DM_DEV_SET_GEOMETRY:
3522 /* data contains only strings */
3523 memcpy(host_data, argptr, guest_data_size);
3524 break;
3525 case DM_TARGET_MSG:
3526 memcpy(host_data, argptr, guest_data_size);
3527 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3528 break;
3529 case DM_TABLE_LOAD:
3530 {
3531 void *gspec = argptr;
3532 void *cur_data = host_data;
3533 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3534 int spec_size = thunk_type_size(arg_type, 0);
3535 int i;
3536
3537 for (i = 0; i < host_dm->target_count; i++) {
3538 struct dm_target_spec *spec = cur_data;
3539 uint32_t next;
3540 int slen;
3541
3542 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3543 slen = strlen((char*)gspec + spec_size) + 1;
3544 next = spec->next;
3545 spec->next = sizeof(*spec) + slen;
3546 strcpy((char*)&spec[1], gspec + spec_size);
3547 gspec += next;
3548 cur_data += spec->next;
3549 }
3550 break;
3551 }
3552 default:
3553 ret = -TARGET_EINVAL;
3554 goto out;
3555 }
3556 unlock_user(argptr, guest_data, 0);
3557
3558 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3559 if (!is_error(ret)) {
3560 guest_data = arg + host_dm->data_start;
3561 guest_data_size = host_dm->data_size - host_dm->data_start;
3562 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3563 switch (ie->host_cmd) {
3564 case DM_REMOVE_ALL:
3565 case DM_DEV_CREATE:
3566 case DM_DEV_REMOVE:
3567 case DM_DEV_RENAME:
3568 case DM_DEV_SUSPEND:
3569 case DM_DEV_STATUS:
3570 case DM_TABLE_LOAD:
3571 case DM_TABLE_CLEAR:
3572 case DM_TARGET_MSG:
3573 case DM_DEV_SET_GEOMETRY:
3574 /* no return data */
3575 break;
3576 case DM_LIST_DEVICES:
3577 {
3578 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3579 uint32_t remaining_data = guest_data_size;
3580 void *cur_data = argptr;
3581 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3582 int nl_size = 12; /* can't use thunk_size due to alignment */
3583
3584 while (1) {
3585 uint32_t next = nl->next;
3586 if (next) {
3587 nl->next = nl_size + (strlen(nl->name) + 1);
3588 }
3589 if (remaining_data < nl->next) {
3590 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3591 break;
3592 }
3593 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3594 strcpy(cur_data + nl_size, nl->name);
3595 cur_data += nl->next;
3596 remaining_data -= nl->next;
3597 if (!next) {
3598 break;
3599 }
3600 nl = (void*)nl + next;
3601 }
3602 break;
3603 }
3604 case DM_DEV_WAIT:
3605 case DM_TABLE_STATUS:
3606 {
3607 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3608 void *cur_data = argptr;
3609 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3610 int spec_size = thunk_type_size(arg_type, 0);
3611 int i;
3612
3613 for (i = 0; i < host_dm->target_count; i++) {
3614 uint32_t next = spec->next;
3615 int slen = strlen((char*)&spec[1]) + 1;
3616 spec->next = (cur_data - argptr) + spec_size + slen;
3617 if (guest_data_size < spec->next) {
3618 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3619 break;
3620 }
3621 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3622 strcpy(cur_data + spec_size, (char*)&spec[1]);
3623 cur_data = argptr + spec->next;
3624 spec = (void*)host_dm + host_dm->data_start + next;
3625 }
3626 break;
3627 }
3628 case DM_TABLE_DEPS:
3629 {
3630 void *hdata = (void*)host_dm + host_dm->data_start;
3631 int count = *(uint32_t*)hdata;
3632 uint64_t *hdev = hdata + 8;
3633 uint64_t *gdev = argptr + 8;
3634 int i;
3635
3636 *(uint32_t*)argptr = tswap32(count);
3637 for (i = 0; i < count; i++) {
3638 *gdev = tswap64(*hdev);
3639 gdev++;
3640 hdev++;
3641 }
3642 break;
3643 }
3644 case DM_LIST_VERSIONS:
3645 {
3646 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3647 uint32_t remaining_data = guest_data_size;
3648 void *cur_data = argptr;
3649 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3650 int vers_size = thunk_type_size(arg_type, 0);
3651
3652 while (1) {
3653 uint32_t next = vers->next;
3654 if (next) {
3655 vers->next = vers_size + (strlen(vers->name) + 1);
3656 }
3657 if (remaining_data < vers->next) {
3658 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3659 break;
3660 }
3661 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3662 strcpy(cur_data + vers_size, vers->name);
3663 cur_data += vers->next;
3664 remaining_data -= vers->next;
3665 if (!next) {
3666 break;
3667 }
3668 vers = (void*)vers + next;
3669 }
3670 break;
3671 }
3672 default:
3673 ret = -TARGET_EINVAL;
3674 goto out;
3675 }
3676 unlock_user(argptr, guest_data, guest_data_size);
3677
3678 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3679 if (!argptr) {
3680 ret = -TARGET_EFAULT;
3681 goto out;
3682 }
3683 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3684 unlock_user(argptr, arg, target_size);
3685 }
3686out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003687 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003688 return ret;
3689}
3690
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003691static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
3692 int fd, abi_long cmd, abi_long arg)
3693{
3694 const argtype *arg_type = ie->arg_type;
3695 const StructEntry *se;
3696 const argtype *field_types;
3697 const int *dst_offsets, *src_offsets;
3698 int target_size;
3699 void *argptr;
3700 abi_ulong *target_rt_dev_ptr;
3701 unsigned long *host_rt_dev_ptr;
3702 abi_long ret;
3703 int i;
3704
3705 assert(ie->access == IOC_W);
3706 assert(*arg_type == TYPE_PTR);
3707 arg_type++;
3708 assert(*arg_type == TYPE_STRUCT);
3709 target_size = thunk_type_size(arg_type, 0);
3710 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3711 if (!argptr) {
3712 return -TARGET_EFAULT;
3713 }
3714 arg_type++;
3715 assert(*arg_type == (int)STRUCT_rtentry);
3716 se = struct_entries + *arg_type++;
3717 assert(se->convert[0] == NULL);
3718 /* convert struct here to be able to catch rt_dev string */
3719 field_types = se->field_types;
3720 dst_offsets = se->field_offsets[THUNK_HOST];
3721 src_offsets = se->field_offsets[THUNK_TARGET];
3722 for (i = 0; i < se->nb_fields; i++) {
3723 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
3724 assert(*field_types == TYPE_PTRVOID);
3725 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
3726 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
3727 if (*target_rt_dev_ptr != 0) {
3728 *host_rt_dev_ptr = (unsigned long)lock_user_string(
3729 tswapal(*target_rt_dev_ptr));
3730 if (!*host_rt_dev_ptr) {
3731 unlock_user(argptr, arg, 0);
3732 return -TARGET_EFAULT;
3733 }
3734 } else {
3735 *host_rt_dev_ptr = 0;
3736 }
3737 field_types++;
3738 continue;
3739 }
3740 field_types = thunk_convert(buf_temp + dst_offsets[i],
3741 argptr + src_offsets[i],
3742 field_types, THUNK_HOST);
3743 }
3744 unlock_user(argptr, arg, 0);
3745
3746 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3747 if (*host_rt_dev_ptr != 0) {
3748 unlock_user((void *)*host_rt_dev_ptr,
3749 *target_rt_dev_ptr, 0);
3750 }
3751 return ret;
3752}
3753
blueswir19f106a72008-10-05 10:52:52 +00003754static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003755#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003756 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3757#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3758 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003759#include "ioctls.h"
3760 { 0, 0, },
3761};
3762
pbrook53a59602006-03-25 19:31:22 +00003763/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003764/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003765static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003766{
3767 const IOCTLEntry *ie;
3768 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003769 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003770 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003771 int target_size;
3772 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003773
3774 ie = ioctl_entries;
3775 for(;;) {
3776 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003777 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003778 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003779 }
3780 if (ie->target_cmd == cmd)
3781 break;
3782 ie++;
3783 }
3784 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003785#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003786 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003787#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003788 if (ie->do_ioctl) {
3789 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3790 }
3791
bellard31e31b82003-02-18 22:55:36 +00003792 switch(arg_type[0]) {
3793 case TYPE_NULL:
3794 /* no argument */
3795 ret = get_errno(ioctl(fd, ie->host_cmd));
3796 break;
3797 case TYPE_PTRVOID:
3798 case TYPE_INT:
3799 /* int argment */
3800 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3801 break;
3802 case TYPE_PTR:
3803 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003804 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003805 switch(ie->access) {
3806 case IOC_R:
3807 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3808 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003809 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3810 if (!argptr)
3811 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003812 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3813 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003814 }
3815 break;
3816 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003817 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3818 if (!argptr)
3819 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003820 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3821 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003822 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3823 break;
3824 default:
3825 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003826 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3827 if (!argptr)
3828 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003829 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3830 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003831 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3832 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003833 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3834 if (!argptr)
3835 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003836 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3837 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003838 }
3839 break;
3840 }
3841 break;
3842 default:
j_mayer32407102007-09-26 23:01:49 +00003843 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3844 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003845 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003846 break;
3847 }
3848 return ret;
3849}
3850
blueswir1b39bc502008-10-05 10:51:10 +00003851static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003852 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3853 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3854 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3855 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3856 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3857 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3858 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3859 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3860 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3861 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3862 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3863 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3864 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3865 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3866 { 0, 0, 0, 0 }
3867};
3868
blueswir1b39bc502008-10-05 10:51:10 +00003869static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003870 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3871 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3872 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3873 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3874 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3875 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3876 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3877 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3878 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3879 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3880 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3881 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3882 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3883 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3884 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3885 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3886 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3887 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3888 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3889 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3890 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3891 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3892 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3893 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3894 { 0, 0, 0, 0 }
3895};
3896
blueswir1b39bc502008-10-05 10:51:10 +00003897static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003898 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3899 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3900 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3901 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3902 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3903 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3904 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3905 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3906 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3907 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3908 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3909 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3910 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3911 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3912 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3913 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3914 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3915 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3916 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3917 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3918 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3919 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3920 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3921 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3922 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3923 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3924 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3925 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3926 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3927 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3928 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3929 { 0, 0, 0, 0 }
3930};
3931
blueswir1b39bc502008-10-05 10:51:10 +00003932static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003933 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3934 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3935 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3936 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3937 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3938 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3939 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3940 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3941 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3942 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3943 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3944 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3945 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3946 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3947 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3948 { 0, 0, 0, 0 }
3949};
3950
3951static void target_to_host_termios (void *dst, const void *src)
3952{
3953 struct host_termios *host = dst;
3954 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003955
ths5fafdf22007-09-16 21:08:06 +00003956 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003957 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003958 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003959 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003960 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003961 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003962 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003963 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3964 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003965
Arnaud Patard44607122009-04-21 17:39:08 +03003966 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003967 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3968 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003969 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003970 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003971 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003972 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003973 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003974 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003975 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003976 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3977 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003978 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3979 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3980 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3981 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3982 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003983 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003984}
ths3b46e622007-09-17 08:09:54 +00003985
bellard31e31b82003-02-18 22:55:36 +00003986static void host_to_target_termios (void *dst, const void *src)
3987{
3988 struct target_termios *target = dst;
3989 const struct host_termios *host = src;
3990
ths5fafdf22007-09-16 21:08:06 +00003991 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003992 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003993 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003994 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003995 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003996 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003997 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003998 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3999 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00004000
Arnaud Patard44607122009-04-21 17:39:08 +03004001 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00004002 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
4003 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
4004 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
4005 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
4006 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
4007 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
4008 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
4009 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
4010 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
4011 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
4012 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
4013 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
4014 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
4015 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
4016 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
4017 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
4018 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
4019}
4020
blueswir18e853dc2008-10-05 10:49:32 +00004021static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00004022 .convert = { host_to_target_termios, target_to_host_termios },
4023 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
4024 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
4025};
4026
bellard5286db72003-06-05 00:57:30 +00004027static bitmask_transtbl mmap_flags_tbl[] = {
4028 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
4029 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
4030 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
4031 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
4032 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
4033 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
4034 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
4035 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
4036 { 0, 0, 0, 0 }
4037};
4038
bellard2ab83ea2003-06-15 19:56:46 +00004039#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00004040
4041/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00004042static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00004043
bellard03acab62007-11-11 14:57:14 +00004044static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004045{
4046 int size;
pbrook53a59602006-03-25 19:31:22 +00004047 void *p;
bellard6dbad632003-03-16 18:05:05 +00004048
4049 if (!ldt_table)
4050 return 0;
4051 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
4052 if (size > bytecount)
4053 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00004054 p = lock_user(VERIFY_WRITE, ptr, size, 0);
4055 if (!p)
bellard03acab62007-11-11 14:57:14 +00004056 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00004057 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00004058 memcpy(p, ldt_table, size);
4059 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00004060 return size;
4061}
4062
4063/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00004064static abi_long write_ldt(CPUX86State *env,
4065 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00004066{
4067 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00004068 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00004069 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00004070 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00004071 uint32_t *lp, entry_1, entry_2;
4072
4073 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00004074 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00004075 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00004076 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004077 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004078 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00004079 ldt_info.limit = tswap32(target_ldt_info->limit);
4080 ldt_info.flags = tswap32(target_ldt_info->flags);
4081 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00004082
bellard6dbad632003-03-16 18:05:05 +00004083 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00004084 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004085 seg_32bit = ldt_info.flags & 1;
4086 contents = (ldt_info.flags >> 1) & 3;
4087 read_exec_only = (ldt_info.flags >> 3) & 1;
4088 limit_in_pages = (ldt_info.flags >> 4) & 1;
4089 seg_not_present = (ldt_info.flags >> 5) & 1;
4090 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00004091#ifdef TARGET_ABI32
4092 lm = 0;
4093#else
4094 lm = (ldt_info.flags >> 7) & 1;
4095#endif
bellard6dbad632003-03-16 18:05:05 +00004096 if (contents == 3) {
4097 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00004098 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004099 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00004100 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004101 }
4102 /* allocate the LDT */
4103 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00004104 env->ldt.base = target_mmap(0,
4105 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
4106 PROT_READ|PROT_WRITE,
4107 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4108 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00004109 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00004110 memset(g2h(env->ldt.base), 0,
4111 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00004112 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00004113 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00004114 }
4115
4116 /* NOTE: same code as Linux kernel */
4117 /* Allow LDTs to be cleared by the user. */
4118 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4119 if (oldmode ||
4120 (contents == 0 &&
4121 read_exec_only == 1 &&
4122 seg_32bit == 0 &&
4123 limit_in_pages == 0 &&
4124 seg_not_present == 1 &&
4125 useable == 0 )) {
4126 entry_1 = 0;
4127 entry_2 = 0;
4128 goto install;
4129 }
4130 }
ths3b46e622007-09-17 08:09:54 +00004131
bellard6dbad632003-03-16 18:05:05 +00004132 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4133 (ldt_info.limit & 0x0ffff);
4134 entry_2 = (ldt_info.base_addr & 0xff000000) |
4135 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4136 (ldt_info.limit & 0xf0000) |
4137 ((read_exec_only ^ 1) << 9) |
4138 (contents << 10) |
4139 ((seg_not_present ^ 1) << 15) |
4140 (seg_32bit << 22) |
4141 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004142 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004143 0x7000;
4144 if (!oldmode)
4145 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004146
bellard6dbad632003-03-16 18:05:05 +00004147 /* Install the new entry ... */
4148install:
4149 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4150 lp[0] = tswap32(entry_1);
4151 lp[1] = tswap32(entry_2);
4152 return 0;
4153}
4154
4155/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004156static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4157 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004158{
bellard03acab62007-11-11 14:57:14 +00004159 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004160
bellard6dbad632003-03-16 18:05:05 +00004161 switch (func) {
4162 case 0:
4163 ret = read_ldt(ptr, bytecount);
4164 break;
4165 case 1:
4166 ret = write_ldt(env, ptr, bytecount, 1);
4167 break;
4168 case 0x11:
4169 ret = write_ldt(env, ptr, bytecount, 0);
4170 break;
bellard03acab62007-11-11 14:57:14 +00004171 default:
4172 ret = -TARGET_ENOSYS;
4173 break;
bellard6dbad632003-03-16 18:05:05 +00004174 }
4175 return ret;
4176}
bellard1b6b0292003-03-22 17:31:38 +00004177
blueswir14583f582008-08-24 10:35:55 +00004178#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004179abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004180{
4181 uint64_t *gdt_table = g2h(env->gdt.base);
4182 struct target_modify_ldt_ldt_s ldt_info;
4183 struct target_modify_ldt_ldt_s *target_ldt_info;
4184 int seg_32bit, contents, read_exec_only, limit_in_pages;
4185 int seg_not_present, useable, lm;
4186 uint32_t *lp, entry_1, entry_2;
4187 int i;
4188
4189 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4190 if (!target_ldt_info)
4191 return -TARGET_EFAULT;
4192 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004193 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004194 ldt_info.limit = tswap32(target_ldt_info->limit);
4195 ldt_info.flags = tswap32(target_ldt_info->flags);
4196 if (ldt_info.entry_number == -1) {
4197 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4198 if (gdt_table[i] == 0) {
4199 ldt_info.entry_number = i;
4200 target_ldt_info->entry_number = tswap32(i);
4201 break;
4202 }
4203 }
4204 }
4205 unlock_user_struct(target_ldt_info, ptr, 1);
4206
4207 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4208 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4209 return -TARGET_EINVAL;
4210 seg_32bit = ldt_info.flags & 1;
4211 contents = (ldt_info.flags >> 1) & 3;
4212 read_exec_only = (ldt_info.flags >> 3) & 1;
4213 limit_in_pages = (ldt_info.flags >> 4) & 1;
4214 seg_not_present = (ldt_info.flags >> 5) & 1;
4215 useable = (ldt_info.flags >> 6) & 1;
4216#ifdef TARGET_ABI32
4217 lm = 0;
4218#else
4219 lm = (ldt_info.flags >> 7) & 1;
4220#endif
4221
4222 if (contents == 3) {
4223 if (seg_not_present == 0)
4224 return -TARGET_EINVAL;
4225 }
4226
4227 /* NOTE: same code as Linux kernel */
4228 /* Allow LDTs to be cleared by the user. */
4229 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4230 if ((contents == 0 &&
4231 read_exec_only == 1 &&
4232 seg_32bit == 0 &&
4233 limit_in_pages == 0 &&
4234 seg_not_present == 1 &&
4235 useable == 0 )) {
4236 entry_1 = 0;
4237 entry_2 = 0;
4238 goto install;
4239 }
4240 }
4241
4242 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4243 (ldt_info.limit & 0x0ffff);
4244 entry_2 = (ldt_info.base_addr & 0xff000000) |
4245 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4246 (ldt_info.limit & 0xf0000) |
4247 ((read_exec_only ^ 1) << 9) |
4248 (contents << 10) |
4249 ((seg_not_present ^ 1) << 15) |
4250 (seg_32bit << 22) |
4251 (limit_in_pages << 23) |
4252 (useable << 20) |
4253 (lm << 21) |
4254 0x7000;
4255
4256 /* Install the new entry ... */
4257install:
4258 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4259 lp[0] = tswap32(entry_1);
4260 lp[1] = tswap32(entry_2);
4261 return 0;
4262}
4263
blueswir18fcd3692008-08-17 20:26:25 +00004264static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004265{
4266 struct target_modify_ldt_ldt_s *target_ldt_info;
4267 uint64_t *gdt_table = g2h(env->gdt.base);
4268 uint32_t base_addr, limit, flags;
4269 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4270 int seg_not_present, useable, lm;
4271 uint32_t *lp, entry_1, entry_2;
4272
4273 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4274 if (!target_ldt_info)
4275 return -TARGET_EFAULT;
4276 idx = tswap32(target_ldt_info->entry_number);
4277 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4278 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4279 unlock_user_struct(target_ldt_info, ptr, 1);
4280 return -TARGET_EINVAL;
4281 }
4282 lp = (uint32_t *)(gdt_table + idx);
4283 entry_1 = tswap32(lp[0]);
4284 entry_2 = tswap32(lp[1]);
4285
4286 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4287 contents = (entry_2 >> 10) & 3;
4288 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4289 seg_32bit = (entry_2 >> 22) & 1;
4290 limit_in_pages = (entry_2 >> 23) & 1;
4291 useable = (entry_2 >> 20) & 1;
4292#ifdef TARGET_ABI32
4293 lm = 0;
4294#else
4295 lm = (entry_2 >> 21) & 1;
4296#endif
4297 flags = (seg_32bit << 0) | (contents << 1) |
4298 (read_exec_only << 3) | (limit_in_pages << 4) |
4299 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4300 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4301 base_addr = (entry_1 >> 16) |
4302 (entry_2 & 0xff000000) |
4303 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004304 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004305 target_ldt_info->limit = tswap32(limit);
4306 target_ldt_info->flags = tswap32(flags);
4307 unlock_user_struct(target_ldt_info, ptr, 1);
4308 return 0;
4309}
blueswir14583f582008-08-24 10:35:55 +00004310#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004311
bellardd2fd1af2007-11-14 18:08:56 +00004312#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004313abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004314{
Juan Quintela1add8692011-06-16 17:37:09 +01004315 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004316 abi_ulong val;
4317 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004318
bellardd2fd1af2007-11-14 18:08:56 +00004319 switch(code) {
4320 case TARGET_ARCH_SET_GS:
4321 case TARGET_ARCH_SET_FS:
4322 if (code == TARGET_ARCH_SET_GS)
4323 idx = R_GS;
4324 else
4325 idx = R_FS;
4326 cpu_x86_load_seg(env, idx, 0);
4327 env->segs[idx].base = addr;
4328 break;
4329 case TARGET_ARCH_GET_GS:
4330 case TARGET_ARCH_GET_FS:
4331 if (code == TARGET_ARCH_GET_GS)
4332 idx = R_GS;
4333 else
4334 idx = R_FS;
4335 val = env->segs[idx].base;
4336 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004337 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004338 break;
4339 default:
4340 ret = -TARGET_EINVAL;
4341 break;
4342 }
Juan Quintela1add8692011-06-16 17:37:09 +01004343 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004344}
4345#endif
4346
bellard2ab83ea2003-06-15 19:56:46 +00004347#endif /* defined(TARGET_I386) */
4348
Riku Voipio05098a92011-03-04 15:27:29 +02004349#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004350
pbrookd865bab2008-06-07 22:12:17 +00004351
4352static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4353typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004354 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004355 pthread_mutex_t mutex;
4356 pthread_cond_t cond;
4357 pthread_t thread;
4358 uint32_t tid;
4359 abi_ulong child_tidptr;
4360 abi_ulong parent_tidptr;
4361 sigset_t sigmask;
4362} new_thread_info;
4363
4364static void *clone_func(void *arg)
4365{
4366 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004367 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004368 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004369 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004370
4371 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004372 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004373 thread_cpu = cpu;
4374 ts = (TaskState *)env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004375 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004376 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004377 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004378 if (info->child_tidptr)
4379 put_user_u32(info->tid, info->child_tidptr);
4380 if (info->parent_tidptr)
4381 put_user_u32(info->tid, info->parent_tidptr);
4382 /* Enable signals. */
4383 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4384 /* Signal to the parent that we're ready. */
4385 pthread_mutex_lock(&info->mutex);
4386 pthread_cond_broadcast(&info->cond);
4387 pthread_mutex_unlock(&info->mutex);
4388 /* Wait until the parent has finshed initializing the tls state. */
4389 pthread_mutex_lock(&clone_lock);
4390 pthread_mutex_unlock(&clone_lock);
4391 cpu_loop(env);
4392 /* never exits */
4393 return NULL;
4394}
bellard1b6b0292003-03-22 17:31:38 +00004395
ths0da46a62007-10-20 20:23:07 +00004396/* do_fork() Must return host values and target errnos (unlike most
4397 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004398static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004399 abi_ulong parent_tidptr, target_ulong newtls,
4400 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004401{
4402 int ret;
bellard5cd43932003-03-29 16:54:36 +00004403 TaskState *ts;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004404 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004405 unsigned int nptl_flags;
4406 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004407
balrog436d1242008-09-21 02:39:45 +00004408 /* Emulate vfork() with fork() */
4409 if (flags & CLONE_VFORK)
4410 flags &= ~(CLONE_VFORK | CLONE_VM);
4411
bellard1b6b0292003-03-22 17:31:38 +00004412 if (flags & CLONE_VM) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004413 TaskState *parent_ts = (TaskState *)env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004414 new_thread_info info;
4415 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004416
Anthony Liguori7267c092011-08-20 22:09:37 -05004417 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004418 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004419 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004420 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004421 /* Init regs that differ from the parent. */
4422 cpu_clone_regs(new_env, newsp);
bellard5cd43932003-03-29 16:54:36 +00004423 new_env->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004424 ts->bprm = parent_ts->bprm;
4425 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004426 nptl_flags = flags;
4427 flags &= ~CLONE_NPTL_FLAGS2;
4428
pbrookc2764712009-03-07 15:24:59 +00004429 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4430 ts->child_tidptr = child_tidptr;
4431 }
4432
pbrookd865bab2008-06-07 22:12:17 +00004433 if (nptl_flags & CLONE_SETTLS)
4434 cpu_set_tls (new_env, newtls);
4435
4436 /* Grab a mutex so that thread setup appears atomic. */
4437 pthread_mutex_lock(&clone_lock);
4438
4439 memset(&info, 0, sizeof(info));
4440 pthread_mutex_init(&info.mutex, NULL);
4441 pthread_mutex_lock(&info.mutex);
4442 pthread_cond_init(&info.cond, NULL);
4443 info.env = new_env;
4444 if (nptl_flags & CLONE_CHILD_SETTID)
4445 info.child_tidptr = child_tidptr;
4446 if (nptl_flags & CLONE_PARENT_SETTID)
4447 info.parent_tidptr = parent_tidptr;
4448
4449 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004450 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4451 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004452 /* It is not safe to deliver signals until the child has finished
4453 initializing, so temporarily block all signals. */
4454 sigfillset(&sigmask);
4455 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4456
4457 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004458 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004459
4460 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4461 pthread_attr_destroy(&attr);
4462 if (ret == 0) {
4463 /* Wait for the child to initialize. */
4464 pthread_cond_wait(&info.cond, &info.mutex);
4465 ret = info.tid;
4466 if (flags & CLONE_PARENT_SETTID)
4467 put_user_u32(ret, parent_tidptr);
4468 } else {
4469 ret = -1;
4470 }
4471 pthread_mutex_unlock(&info.mutex);
4472 pthread_cond_destroy(&info.cond);
4473 pthread_mutex_destroy(&info.mutex);
4474 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004475 } else {
4476 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004477 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004478 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004479 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004480 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004481 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004482 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004483 cpu_clone_regs(env, newsp);
4484 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004485 /* There is a race condition here. The parent process could
4486 theoretically read the TID in the child process before the child
4487 tid is set. This would require using either ptrace
4488 (not implemented) or having *_tidptr to point at a shared memory
4489 mapping. We can't repeat the spinlock hack used above because
4490 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004491 if (flags & CLONE_CHILD_SETTID)
4492 put_user_u32(gettid(), child_tidptr);
4493 if (flags & CLONE_PARENT_SETTID)
4494 put_user_u32(gettid(), parent_tidptr);
4495 ts = (TaskState *)env->opaque;
4496 if (flags & CLONE_SETTLS)
4497 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004498 if (flags & CLONE_CHILD_CLEARTID)
4499 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004500 } else {
4501 fork_end(0);
4502 }
bellard1b6b0292003-03-22 17:31:38 +00004503 }
4504 return ret;
4505}
4506
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004507/* warning : doesn't handle linux specific flags... */
4508static int target_to_host_fcntl_cmd(int cmd)
4509{
4510 switch(cmd) {
4511 case TARGET_F_DUPFD:
4512 case TARGET_F_GETFD:
4513 case TARGET_F_SETFD:
4514 case TARGET_F_GETFL:
4515 case TARGET_F_SETFL:
4516 return cmd;
4517 case TARGET_F_GETLK:
4518 return F_GETLK;
4519 case TARGET_F_SETLK:
4520 return F_SETLK;
4521 case TARGET_F_SETLKW:
4522 return F_SETLKW;
4523 case TARGET_F_GETOWN:
4524 return F_GETOWN;
4525 case TARGET_F_SETOWN:
4526 return F_SETOWN;
4527 case TARGET_F_GETSIG:
4528 return F_GETSIG;
4529 case TARGET_F_SETSIG:
4530 return F_SETSIG;
4531#if TARGET_ABI_BITS == 32
4532 case TARGET_F_GETLK64:
4533 return F_GETLK64;
4534 case TARGET_F_SETLK64:
4535 return F_SETLK64;
4536 case TARGET_F_SETLKW64:
4537 return F_SETLKW64;
4538#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004539 case TARGET_F_SETLEASE:
4540 return F_SETLEASE;
4541 case TARGET_F_GETLEASE:
4542 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004543#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004544 case TARGET_F_DUPFD_CLOEXEC:
4545 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004546#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004547 case TARGET_F_NOTIFY:
4548 return F_NOTIFY;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004549 default:
4550 return -TARGET_EINVAL;
4551 }
4552 return -TARGET_EINVAL;
4553}
4554
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004555#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4556static const bitmask_transtbl flock_tbl[] = {
4557 TRANSTBL_CONVERT(F_RDLCK),
4558 TRANSTBL_CONVERT(F_WRLCK),
4559 TRANSTBL_CONVERT(F_UNLCK),
4560 TRANSTBL_CONVERT(F_EXLCK),
4561 TRANSTBL_CONVERT(F_SHLCK),
4562 { 0, 0, 0, 0 }
4563};
4564
blueswir1992f48a2007-10-14 16:27:31 +00004565static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004566{
4567 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004568 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004569 struct flock64 fl64;
4570 struct target_flock64 *target_fl64;
blueswir1992f48a2007-10-14 16:27:31 +00004571 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004572 int host_cmd = target_to_host_fcntl_cmd(cmd);
4573
4574 if (host_cmd == -TARGET_EINVAL)
4575 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004576
bellard7775e9e2003-05-14 22:46:48 +00004577 switch(cmd) {
4578 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004579 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4580 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004581 fl.l_type =
4582 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004583 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004584 fl.l_start = tswapal(target_fl->l_start);
4585 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004586 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004587 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004588 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004589 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004590 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4591 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004592 target_fl->l_type =
4593 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004594 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004595 target_fl->l_start = tswapal(fl.l_start);
4596 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004597 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004598 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004599 }
4600 break;
ths3b46e622007-09-17 08:09:54 +00004601
bellard7775e9e2003-05-14 22:46:48 +00004602 case TARGET_F_SETLK:
4603 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004604 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4605 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004606 fl.l_type =
4607 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004608 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004609 fl.l_start = tswapal(target_fl->l_start);
4610 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004611 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004612 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004613 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004614 break;
ths3b46e622007-09-17 08:09:54 +00004615
bellard7775e9e2003-05-14 22:46:48 +00004616 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004617 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4618 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004619 fl64.l_type =
4620 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004621 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004622 fl64.l_start = tswap64(target_fl64->l_start);
4623 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004624 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004625 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004626 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004627 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004628 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4629 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004630 target_fl64->l_type =
4631 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004632 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004633 target_fl64->l_start = tswap64(fl64.l_start);
4634 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004635 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004636 unlock_user_struct(target_fl64, arg, 1);
4637 }
bellard9ee1fa22007-11-11 15:11:19 +00004638 break;
bellard7775e9e2003-05-14 22:46:48 +00004639 case TARGET_F_SETLK64:
4640 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004641 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4642 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004643 fl64.l_type =
4644 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004645 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004646 fl64.l_start = tswap64(target_fl64->l_start);
4647 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004648 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004649 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004650 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004651 break;
4652
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004653 case TARGET_F_GETFL:
4654 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004655 if (ret >= 0) {
4656 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4657 }
bellardffa65c32004-01-04 23:57:22 +00004658 break;
4659
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004660 case TARGET_F_SETFL:
4661 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4662 break;
4663
4664 case TARGET_F_SETOWN:
4665 case TARGET_F_GETOWN:
4666 case TARGET_F_SETSIG:
4667 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004668 case TARGET_F_SETLEASE:
4669 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004670 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004671 break;
4672
bellard7775e9e2003-05-14 22:46:48 +00004673 default:
bellard9ee1fa22007-11-11 15:11:19 +00004674 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004675 break;
4676 }
4677 return ret;
4678}
4679
bellard67867302003-11-23 17:05:30 +00004680#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004681
bellard67867302003-11-23 17:05:30 +00004682static inline int high2lowuid(int uid)
4683{
4684 if (uid > 65535)
4685 return 65534;
4686 else
4687 return uid;
4688}
4689
4690static inline int high2lowgid(int gid)
4691{
4692 if (gid > 65535)
4693 return 65534;
4694 else
4695 return gid;
4696}
4697
4698static inline int low2highuid(int uid)
4699{
4700 if ((int16_t)uid == -1)
4701 return -1;
4702 else
4703 return uid;
4704}
4705
4706static inline int low2highgid(int gid)
4707{
4708 if ((int16_t)gid == -1)
4709 return -1;
4710 else
4711 return gid;
4712}
Riku Voipio0c866a72011-04-18 15:23:06 +03004713static inline int tswapid(int id)
4714{
4715 return tswap16(id);
4716}
4717#else /* !USE_UID16 */
4718static inline int high2lowuid(int uid)
4719{
4720 return uid;
4721}
4722static inline int high2lowgid(int gid)
4723{
4724 return gid;
4725}
4726static inline int low2highuid(int uid)
4727{
4728 return uid;
4729}
4730static inline int low2highgid(int gid)
4731{
4732 return gid;
4733}
4734static inline int tswapid(int id)
4735{
4736 return tswap32(id);
4737}
bellard67867302003-11-23 17:05:30 +00004738#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004739
bellard31e31b82003-02-18 22:55:36 +00004740void syscall_init(void)
4741{
bellard2ab83ea2003-06-15 19:56:46 +00004742 IOCTLEntry *ie;
4743 const argtype *arg_type;
4744 int size;
thsb92c47c2007-11-01 00:07:38 +00004745 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004746
Blue Swirl001faf32009-05-13 17:53:17 +00004747#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004748#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004749#include "syscall_types.h"
4750#undef STRUCT
4751#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004752
Peter Maydelldd6e9572012-07-23 08:07:22 +00004753 /* Build target_to_host_errno_table[] table from
4754 * host_to_target_errno_table[]. */
4755 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4756 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4757 }
4758
bellard2ab83ea2003-06-15 19:56:46 +00004759 /* we patch the ioctl size if necessary. We rely on the fact that
4760 no ioctl has all the bits at '1' in the size field */
4761 ie = ioctl_entries;
4762 while (ie->target_cmd != 0) {
4763 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4764 TARGET_IOC_SIZEMASK) {
4765 arg_type = ie->arg_type;
4766 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004767 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004768 ie->target_cmd);
4769 exit(1);
4770 }
4771 arg_type++;
4772 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004773 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004774 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4775 (size << TARGET_IOC_SIZESHIFT);
4776 }
thsb92c47c2007-11-01 00:07:38 +00004777
bellard2ab83ea2003-06-15 19:56:46 +00004778 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004779#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4780 (defined(__x86_64__) && defined(TARGET_X86_64))
4781 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4782 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4783 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004784 }
4785#endif
4786 ie++;
4787 }
bellard31e31b82003-02-18 22:55:36 +00004788}
bellardc573ff62004-01-04 15:51:36 +00004789
blueswir1992f48a2007-10-14 16:27:31 +00004790#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004791static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4792{
thsaf325d32008-06-10 15:29:15 +00004793#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004794 return ((uint64_t)word0 << 32) | word1;
4795#else
4796 return ((uint64_t)word1 << 32) | word0;
4797#endif
4798}
blueswir1992f48a2007-10-14 16:27:31 +00004799#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004800static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4801{
4802 return word0;
4803}
blueswir1992f48a2007-10-14 16:27:31 +00004804#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004805
4806#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004807static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4808 abi_long arg2,
4809 abi_long arg3,
4810 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004811{
Riku Voipio48e515d2011-07-12 15:40:51 +03004812 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004813 arg2 = arg3;
4814 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004815 }
pbrookce4defa2006-02-09 16:49:55 +00004816 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4817}
4818#endif
4819
4820#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004821static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4822 abi_long arg2,
4823 abi_long arg3,
4824 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004825{
Riku Voipio48e515d2011-07-12 15:40:51 +03004826 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004827 arg2 = arg3;
4828 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004829 }
pbrookce4defa2006-02-09 16:49:55 +00004830 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4831}
4832#endif
4833
bellard579a97f2007-11-11 14:26:47 +00004834static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4835 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004836{
4837 struct target_timespec *target_ts;
4838
bellard579a97f2007-11-11 14:26:47 +00004839 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4840 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004841 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4842 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004843 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004844 return 0;
pbrook53a59602006-03-25 19:31:22 +00004845}
4846
bellard579a97f2007-11-11 14:26:47 +00004847static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4848 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004849{
4850 struct target_timespec *target_ts;
4851
bellard579a97f2007-11-11 14:26:47 +00004852 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4853 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004854 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4855 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004856 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004857 return 0;
pbrook53a59602006-03-25 19:31:22 +00004858}
4859
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11004860static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
4861 abi_ulong target_addr)
4862{
4863 struct target_itimerspec *target_itspec;
4864
4865 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
4866 return -TARGET_EFAULT;
4867 }
4868
4869 host_itspec->it_interval.tv_sec =
4870 tswapal(target_itspec->it_interval.tv_sec);
4871 host_itspec->it_interval.tv_nsec =
4872 tswapal(target_itspec->it_interval.tv_nsec);
4873 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
4874 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
4875
4876 unlock_user_struct(target_itspec, target_addr, 1);
4877 return 0;
4878}
4879
4880static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
4881 struct itimerspec *host_its)
4882{
4883 struct target_itimerspec *target_itspec;
4884
4885 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
4886 return -TARGET_EFAULT;
4887 }
4888
4889 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
4890 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
4891
4892 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
4893 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
4894
4895 unlock_user_struct(target_itspec, target_addr, 0);
4896 return 0;
4897}
4898
aurel329d33b762009-04-08 23:07:05 +00004899#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004900static inline abi_long host_to_target_stat64(void *cpu_env,
4901 abi_ulong target_addr,
4902 struct stat *host_st)
4903{
Alexander Graf09701192013-09-03 20:12:15 +01004904#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00004905 if (((CPUARMState *)cpu_env)->eabi) {
4906 struct target_eabi_stat64 *target_st;
4907
4908 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4909 return -TARGET_EFAULT;
4910 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4911 __put_user(host_st->st_dev, &target_st->st_dev);
4912 __put_user(host_st->st_ino, &target_st->st_ino);
4913#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4914 __put_user(host_st->st_ino, &target_st->__st_ino);
4915#endif
4916 __put_user(host_st->st_mode, &target_st->st_mode);
4917 __put_user(host_st->st_nlink, &target_st->st_nlink);
4918 __put_user(host_st->st_uid, &target_st->st_uid);
4919 __put_user(host_st->st_gid, &target_st->st_gid);
4920 __put_user(host_st->st_rdev, &target_st->st_rdev);
4921 __put_user(host_st->st_size, &target_st->st_size);
4922 __put_user(host_st->st_blksize, &target_st->st_blksize);
4923 __put_user(host_st->st_blocks, &target_st->st_blocks);
4924 __put_user(host_st->st_atime, &target_st->target_st_atime);
4925 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4926 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4927 unlock_user_struct(target_st, target_addr, 1);
4928 } else
4929#endif
4930 {
Stefan Weil20d155b2013-10-30 22:52:24 +01004931#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00004932 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01004933#else
4934 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00004935#endif
balrog6a24a772008-09-20 02:23:36 +00004936
4937 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4938 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004939 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004940 __put_user(host_st->st_dev, &target_st->st_dev);
4941 __put_user(host_st->st_ino, &target_st->st_ino);
4942#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4943 __put_user(host_st->st_ino, &target_st->__st_ino);
4944#endif
4945 __put_user(host_st->st_mode, &target_st->st_mode);
4946 __put_user(host_st->st_nlink, &target_st->st_nlink);
4947 __put_user(host_st->st_uid, &target_st->st_uid);
4948 __put_user(host_st->st_gid, &target_st->st_gid);
4949 __put_user(host_st->st_rdev, &target_st->st_rdev);
4950 /* XXX: better use of kernel struct */
4951 __put_user(host_st->st_size, &target_st->st_size);
4952 __put_user(host_st->st_blksize, &target_st->st_blksize);
4953 __put_user(host_st->st_blocks, &target_st->st_blocks);
4954 __put_user(host_st->st_atime, &target_st->target_st_atime);
4955 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4956 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4957 unlock_user_struct(target_st, target_addr, 1);
4958 }
4959
4960 return 0;
4961}
4962#endif
4963
pbrookbd0c5662008-05-29 14:34:11 +00004964/* ??? Using host futex calls even when target atomic operations
4965 are not really atomic probably breaks things. However implementing
4966 futexes locally would make futexes shared between multiple processes
4967 tricky. However they're probably useless because guest atomic
4968 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004969static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4970 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004971{
4972 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004973 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004974
4975 /* ??? We assume FUTEX_* constants are the same on both host
4976 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004977#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004978 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004979#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004980 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004981#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004982 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004983 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07004984 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00004985 if (timeout) {
4986 pts = &ts;
4987 target_to_host_timespec(pts, timeout);
4988 } else {
4989 pts = NULL;
4990 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004991 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07004992 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00004993 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004994 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004995 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004996 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004997 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004998 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004999 case FUTEX_WAKE_OP:
5000 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
5001 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
5002 But the prototype takes a `struct timespec *'; insert casts
5003 to satisfy the compiler. We do not need to tswap TIMEOUT
5004 since it's not compared to guest memory. */
5005 pts = (struct timespec *)(uintptr_t) timeout;
5006 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
5007 g2h(uaddr2),
5008 (base_op == FUTEX_CMP_REQUEUE
5009 ? tswap32(val3)
5010 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00005011 default:
5012 return -TARGET_ENOSYS;
5013 }
5014}
pbrookbd0c5662008-05-29 14:34:11 +00005015
pbrook1d9d8b52009-04-16 15:17:02 +00005016/* Map host to target signal numbers for the wait family of syscalls.
5017 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07005018int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00005019{
5020 if (WIFSIGNALED(status)) {
5021 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
5022 }
5023 if (WIFSTOPPED(status)) {
5024 return (host_to_target_signal(WSTOPSIG(status)) << 8)
5025 | (status & 0xff);
5026 }
5027 return status;
5028}
5029
Peter Maydell4a24a752013-09-03 20:12:20 +01005030static int relstr_to_int(const char *s)
pbrooka745ec62008-05-06 15:36:17 +00005031{
Peter Maydell4a24a752013-09-03 20:12:20 +01005032 /* Convert a uname release string like "2.6.18" to an integer
5033 * of the form 0x020612. (Beware that 0x020612 is *not* 2.6.12.)
5034 */
pbrooka745ec62008-05-06 15:36:17 +00005035 int i, n, tmp;
Peter Maydell4a24a752013-09-03 20:12:20 +01005036
pbrooka745ec62008-05-06 15:36:17 +00005037 tmp = 0;
5038 for (i = 0; i < 3; i++) {
5039 n = 0;
5040 while (*s >= '0' && *s <= '9') {
5041 n *= 10;
5042 n += *s - '0';
5043 s++;
5044 }
5045 tmp = (tmp << 8) + n;
Peter Maydell4a24a752013-09-03 20:12:20 +01005046 if (*s == '.') {
pbrooka745ec62008-05-06 15:36:17 +00005047 s++;
Peter Maydell4a24a752013-09-03 20:12:20 +01005048 }
pbrooka745ec62008-05-06 15:36:17 +00005049 }
Peter Maydell4a24a752013-09-03 20:12:20 +01005050 return tmp;
5051}
5052
5053int get_osversion(void)
5054{
5055 static int osversion;
5056 struct new_utsname buf;
5057 const char *s;
5058
5059 if (osversion)
5060 return osversion;
5061 if (qemu_uname_release && *qemu_uname_release) {
5062 s = qemu_uname_release;
5063 } else {
5064 if (sys_uname(&buf))
5065 return 0;
5066 s = buf.release;
5067 }
5068 osversion = relstr_to_int(s);
pbrooka745ec62008-05-06 15:36:17 +00005069 return osversion;
5070}
5071
Peter Maydell4a24a752013-09-03 20:12:20 +01005072void init_qemu_uname_release(void)
5073{
5074 /* Initialize qemu_uname_release for later use.
5075 * If the host kernel is too old and the user hasn't asked for
5076 * a specific fake version number, we might want to fake a minimum
5077 * target kernel version.
5078 */
5079#ifdef UNAME_MINIMUM_RELEASE
5080 struct new_utsname buf;
5081
5082 if (qemu_uname_release && *qemu_uname_release) {
5083 return;
5084 }
5085
5086 if (sys_uname(&buf)) {
5087 return;
5088 }
5089
5090 if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) {
5091 qemu_uname_release = UNAME_MINIMUM_RELEASE;
5092 }
5093#endif
5094}
Alexander Graf36c08d42011-11-02 20:23:24 +01005095
5096static int open_self_maps(void *cpu_env, int fd)
5097{
Alexander Graf1a49ef22012-05-01 16:30:28 +01005098#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Andreas Färber9349b4f2012-03-14 01:38:32 +01005099 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005100#endif
5101 FILE *fp;
5102 char *line = NULL;
5103 size_t len = 0;
5104 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005105
Alexander Graf1a49ef22012-05-01 16:30:28 +01005106 fp = fopen("/proc/self/maps", "r");
5107 if (fp == NULL) {
5108 return -EACCES;
5109 }
5110
5111 while ((read = getline(&line, &len, fp)) != -1) {
5112 int fields, dev_maj, dev_min, inode;
5113 uint64_t min, max, offset;
5114 char flag_r, flag_w, flag_x, flag_p;
5115 char path[512] = "";
5116 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5117 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5118 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5119
5120 if ((fields < 10) || (fields > 11)) {
5121 continue;
5122 }
5123 if (!strncmp(path, "[stack]", 7)) {
5124 continue;
5125 }
5126 if (h2g_valid(min) && h2g_valid(max)) {
5127 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02005128 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Alexander Graf1a49ef22012-05-01 16:30:28 +01005129 h2g(min), h2g(max), flag_r, flag_w,
5130 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02005131 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01005132 }
5133 }
5134
5135 free(line);
5136 fclose(fp);
5137
5138#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Alexander Graf36c08d42011-11-02 20:23:24 +01005139 dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
5140 (unsigned long long)ts->info->stack_limit,
Alexander Graf1bdd7c72012-05-30 14:45:21 +02005141 (unsigned long long)(ts->info->start_stack +
5142 (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005143 (unsigned long long)0);
5144#endif
Alexander Graf36c08d42011-11-02 20:23:24 +01005145
5146 return 0;
5147}
5148
Alexander Graf480b8e72011-11-02 20:23:25 +01005149static int open_self_stat(void *cpu_env, int fd)
5150{
Andreas Färber9349b4f2012-03-14 01:38:32 +01005151 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005152 abi_ulong start_stack = ts->info->start_stack;
5153 int i;
5154
5155 for (i = 0; i < 44; i++) {
5156 char buf[128];
5157 int len;
5158 uint64_t val = 0;
5159
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005160 if (i == 0) {
5161 /* pid */
5162 val = getpid();
5163 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5164 } else if (i == 1) {
5165 /* app name */
5166 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5167 } else if (i == 27) {
5168 /* stack bottom */
5169 val = start_stack;
5170 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5171 } else {
5172 /* for the rest, there is MasterCard */
5173 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005174 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005175
Alexander Graf480b8e72011-11-02 20:23:25 +01005176 len = strlen(buf);
5177 if (write(fd, buf, len) != len) {
5178 return -1;
5179 }
5180 }
5181
5182 return 0;
5183}
5184
Alexander Graf257450e2011-11-02 20:23:26 +01005185static int open_self_auxv(void *cpu_env, int fd)
5186{
Andreas Färber9349b4f2012-03-14 01:38:32 +01005187 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005188 abi_ulong auxv = ts->info->saved_auxv;
5189 abi_ulong len = ts->info->auxv_len;
5190 char *ptr;
5191
5192 /*
5193 * Auxiliary vector is stored in target process stack.
5194 * read in whole auxv vector and copy it to file
5195 */
5196 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5197 if (ptr != NULL) {
5198 while (len > 0) {
5199 ssize_t r;
5200 r = write(fd, ptr, len);
5201 if (r <= 0) {
5202 break;
5203 }
5204 len -= r;
5205 ptr += r;
5206 }
5207 lseek(fd, 0, SEEK_SET);
5208 unlock_user(ptr, auxv, len);
5209 }
5210
5211 return 0;
5212}
5213
Andreas Schwab463d8e72013-07-02 14:04:12 +01005214static int is_proc_myself(const char *filename, const char *entry)
5215{
5216 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5217 filename += strlen("/proc/");
5218 if (!strncmp(filename, "self/", strlen("self/"))) {
5219 filename += strlen("self/");
5220 } else if (*filename >= '1' && *filename <= '9') {
5221 char myself[80];
5222 snprintf(myself, sizeof(myself), "%d/", getpid());
5223 if (!strncmp(filename, myself, strlen(myself))) {
5224 filename += strlen(myself);
5225 } else {
5226 return 0;
5227 }
5228 } else {
5229 return 0;
5230 }
5231 if (!strcmp(filename, entry)) {
5232 return 1;
5233 }
5234 }
5235 return 0;
5236}
5237
Laurent Vivierde6b9932013-08-30 01:46:40 +02005238#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5239static int is_proc(const char *filename, const char *entry)
5240{
5241 return strcmp(filename, entry) == 0;
5242}
5243
5244static int open_net_route(void *cpu_env, int fd)
5245{
5246 FILE *fp;
5247 char *line = NULL;
5248 size_t len = 0;
5249 ssize_t read;
5250
5251 fp = fopen("/proc/net/route", "r");
5252 if (fp == NULL) {
5253 return -EACCES;
5254 }
5255
5256 /* read header */
5257
5258 read = getline(&line, &len, fp);
5259 dprintf(fd, "%s", line);
5260
5261 /* read routes */
5262
5263 while ((read = getline(&line, &len, fp)) != -1) {
5264 char iface[16];
5265 uint32_t dest, gw, mask;
5266 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5267 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5268 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5269 &mask, &mtu, &window, &irtt);
5270 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5271 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5272 metric, tswap32(mask), mtu, window, irtt);
5273 }
5274
5275 free(line);
5276 fclose(fp);
5277
5278 return 0;
5279}
5280#endif
5281
Alexander Graf3be14d02011-11-02 20:23:23 +01005282static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
5283{
5284 struct fake_open {
5285 const char *filename;
5286 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005287 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005288 };
5289 const struct fake_open *fake_open;
5290 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005291 { "maps", open_self_maps, is_proc_myself },
5292 { "stat", open_self_stat, is_proc_myself },
5293 { "auxv", open_self_auxv, is_proc_myself },
5294#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5295 { "/proc/net/route", open_net_route, is_proc },
5296#endif
5297 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005298 };
5299
5300 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005301 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005302 break;
5303 }
5304 }
5305
5306 if (fake_open->filename) {
5307 const char *tmpdir;
5308 char filename[PATH_MAX];
5309 int fd, r;
5310
5311 /* create temporary file to map stat to */
5312 tmpdir = getenv("TMPDIR");
5313 if (!tmpdir)
5314 tmpdir = "/tmp";
5315 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5316 fd = mkstemp(filename);
5317 if (fd < 0) {
5318 return fd;
5319 }
5320 unlink(filename);
5321
5322 if ((r = fake_open->fill(cpu_env, fd))) {
5323 close(fd);
5324 return r;
5325 }
5326 lseek(fd, 0, SEEK_SET);
5327
5328 return fd;
5329 }
5330
5331 return get_errno(open(path(pathname), flags, mode));
5332}
5333
ths0da46a62007-10-20 20:23:07 +00005334/* do_syscall() should always have a single exit point at the end so
5335 that actions, such as logging of syscall results, can be performed.
5336 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005337abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5338 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005339 abi_long arg5, abi_long arg6, abi_long arg7,
5340 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005341{
Andreas Färber182735e2013-05-29 22:29:20 +02005342 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005343 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005344 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005345 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005346 void *p;
ths3b46e622007-09-17 08:09:54 +00005347
bellard72f03902003-02-18 23:33:18 +00005348#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005349 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005350#endif
thsb92c47c2007-11-01 00:07:38 +00005351 if(do_strace)
5352 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5353
bellard31e31b82003-02-18 22:55:36 +00005354 switch(num) {
5355 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005356 /* In old applications this may be used to implement _exit(2).
5357 However in threaded applictions it is used for thread termination,
5358 and _exit_group is used for application termination.
5359 Do thread termination if we have more then one thread. */
5360 /* FIXME: This probably breaks if a signal arrives. We should probably
5361 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005362 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005363 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005364
Andreas Färber9b056fc2013-06-24 23:53:10 +02005365 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005366 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005367 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005368 cpu_list_unlock();
5369 ts = ((CPUArchState *)cpu_env)->opaque;
5370 if (ts->child_tidptr) {
5371 put_user_u32(0, ts->child_tidptr);
5372 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5373 NULL, NULL, 0);
5374 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005375 thread_cpu = NULL;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005376 object_unref(OBJECT(ENV_GET_CPU(cpu_env)));
5377 g_free(ts);
5378 pthread_exit(NULL);
5379 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005380#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005381 _mcleanup();
5382#endif
bellarde9009672005-04-26 20:42:36 +00005383 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005384 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005385 ret = 0; /* avoid warning */
5386 break;
5387 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005388 if (arg3 == 0)
5389 ret = 0;
5390 else {
5391 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5392 goto efault;
5393 ret = get_errno(read(arg1, p, arg3));
5394 unlock_user(p, arg2, ret);
5395 }
bellard31e31b82003-02-18 22:55:36 +00005396 break;
5397 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005398 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5399 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005400 ret = get_errno(write(arg1, p, arg3));
5401 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005402 break;
5403 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005404 if (!(p = lock_user_string(arg1)))
5405 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005406 ret = get_errno(do_open(cpu_env, p,
5407 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5408 arg3));
pbrook53a59602006-03-25 19:31:22 +00005409 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005410 break;
ths82424832007-09-24 09:21:55 +00005411#if defined(TARGET_NR_openat) && defined(__NR_openat)
5412 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005413 if (!(p = lock_user_string(arg2)))
5414 goto efault;
5415 ret = get_errno(sys_openat(arg1,
5416 path(p),
5417 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5418 arg4));
5419 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005420 break;
5421#endif
bellard31e31b82003-02-18 22:55:36 +00005422 case TARGET_NR_close:
5423 ret = get_errno(close(arg1));
5424 break;
5425 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005426 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005427 break;
5428 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005429 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005430 break;
thse5febef2007-04-01 18:31:35 +00005431#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005432 case TARGET_NR_waitpid:
5433 {
pbrook53a59602006-03-25 19:31:22 +00005434 int status;
5435 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005436 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005437 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005438 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005439 }
5440 break;
thse5febef2007-04-01 18:31:35 +00005441#endif
pbrookf0cbb612008-05-30 18:20:05 +00005442#ifdef TARGET_NR_waitid
5443 case TARGET_NR_waitid:
5444 {
5445 siginfo_t info;
5446 info.si_pid = 0;
5447 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5448 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005449 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005450 goto efault;
5451 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005452 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005453 }
5454 }
5455 break;
5456#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005457#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005458 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005459 if (!(p = lock_user_string(arg1)))
5460 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005461 ret = get_errno(creat(p, arg2));
5462 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005463 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005464#endif
bellard31e31b82003-02-18 22:55:36 +00005465 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005466 {
5467 void * p2;
5468 p = lock_user_string(arg1);
5469 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005470 if (!p || !p2)
5471 ret = -TARGET_EFAULT;
5472 else
5473 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005474 unlock_user(p2, arg2, 0);
5475 unlock_user(p, arg1, 0);
5476 }
bellard31e31b82003-02-18 22:55:36 +00005477 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005478#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00005479 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005480 {
5481 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005482 if (!arg2 || !arg4)
5483 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005484 p = lock_user_string(arg2);
5485 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005486 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005487 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005488 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005489 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005490 unlock_user(p, arg2, 0);
5491 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005492 }
5493 break;
5494#endif
bellard31e31b82003-02-18 22:55:36 +00005495 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005496 if (!(p = lock_user_string(arg1)))
5497 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005498 ret = get_errno(unlink(p));
5499 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005500 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005501#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00005502 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005503 if (!(p = lock_user_string(arg2)))
5504 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005505 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005506 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005507 break;
balrogb7d35e62007-12-12 00:40:24 +00005508#endif
bellard31e31b82003-02-18 22:55:36 +00005509 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005510 {
5511 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005512 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005513 abi_ulong gp;
5514 abi_ulong guest_argp;
5515 abi_ulong guest_envp;
5516 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005517 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005518 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005519
bellardf7341ff2003-03-30 21:00:25 +00005520 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005521 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005522 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005523 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005524 goto efault;
ths03aa1972007-12-02 06:28:08 +00005525 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005526 break;
bellard7854b052003-03-29 17:22:23 +00005527 argc++;
bellard2f619692007-11-16 10:46:05 +00005528 }
bellardf7341ff2003-03-30 21:00:25 +00005529 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005530 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005531 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005532 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005533 goto efault;
ths03aa1972007-12-02 06:28:08 +00005534 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005535 break;
bellard7854b052003-03-29 17:22:23 +00005536 envc++;
bellard2f619692007-11-16 10:46:05 +00005537 }
bellard7854b052003-03-29 17:22:23 +00005538
bellardf7341ff2003-03-30 21:00:25 +00005539 argp = alloca((argc + 1) * sizeof(void *));
5540 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005541
pbrookda94d262008-05-30 18:24:00 +00005542 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005543 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005544 if (get_user_ual(addr, gp))
5545 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005546 if (!addr)
5547 break;
bellard2f619692007-11-16 10:46:05 +00005548 if (!(*q = lock_user_string(addr)))
5549 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005550 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005551 }
bellardf7341ff2003-03-30 21:00:25 +00005552 *q = NULL;
5553
pbrookda94d262008-05-30 18:24:00 +00005554 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005555 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005556 if (get_user_ual(addr, gp))
5557 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005558 if (!addr)
5559 break;
bellard2f619692007-11-16 10:46:05 +00005560 if (!(*q = lock_user_string(addr)))
5561 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005562 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005563 }
bellardf7341ff2003-03-30 21:00:25 +00005564 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005565
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005566 /* This case will not be caught by the host's execve() if its
5567 page size is bigger than the target's. */
5568 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5569 ret = -TARGET_E2BIG;
5570 goto execve_end;
5571 }
bellard2f619692007-11-16 10:46:05 +00005572 if (!(p = lock_user_string(arg1)))
5573 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005574 ret = get_errno(execve(p, argp, envp));
5575 unlock_user(p, arg1, 0);
5576
bellard2f619692007-11-16 10:46:05 +00005577 goto execve_end;
5578
5579 execve_efault:
5580 ret = -TARGET_EFAULT;
5581
5582 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005583 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005584 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005585 if (get_user_ual(addr, gp)
5586 || !addr)
5587 break;
pbrook53a59602006-03-25 19:31:22 +00005588 unlock_user(*q, addr, 0);
5589 }
5590 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005591 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005592 if (get_user_ual(addr, gp)
5593 || !addr)
5594 break;
pbrook53a59602006-03-25 19:31:22 +00005595 unlock_user(*q, addr, 0);
5596 }
bellard7854b052003-03-29 17:22:23 +00005597 }
bellard31e31b82003-02-18 22:55:36 +00005598 break;
5599 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005600 if (!(p = lock_user_string(arg1)))
5601 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005602 ret = get_errno(chdir(p));
5603 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005604 break;
bellarda315a142005-01-30 22:59:18 +00005605#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005606 case TARGET_NR_time:
5607 {
pbrook53a59602006-03-25 19:31:22 +00005608 time_t host_time;
5609 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005610 if (!is_error(ret)
5611 && arg1
5612 && put_user_sal(host_time, arg1))
5613 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005614 }
5615 break;
bellarda315a142005-01-30 22:59:18 +00005616#endif
bellard31e31b82003-02-18 22:55:36 +00005617 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005618 if (!(p = lock_user_string(arg1)))
5619 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005620 ret = get_errno(mknod(p, arg2, arg3));
5621 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005622 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005623#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00005624 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005625 if (!(p = lock_user_string(arg2)))
5626 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005627 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00005628 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005629 break;
5630#endif
bellard31e31b82003-02-18 22:55:36 +00005631 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005632 if (!(p = lock_user_string(arg1)))
5633 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005634 ret = get_errno(chmod(p, arg2));
5635 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005636 break;
bellardebc05482003-09-30 21:08:41 +00005637#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005638 case TARGET_NR_break:
5639 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005640#endif
5641#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005642 case TARGET_NR_oldstat:
5643 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005644#endif
bellard31e31b82003-02-18 22:55:36 +00005645 case TARGET_NR_lseek:
5646 ret = get_errno(lseek(arg1, arg2, arg3));
5647 break;
Richard Henderson92317332010-05-03 10:07:53 -07005648#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5649 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005650 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005651 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005652 ret = get_errno(getpid());
5653 break;
Richard Henderson92317332010-05-03 10:07:53 -07005654#endif
5655#ifdef TARGET_NR_getpid
5656 case TARGET_NR_getpid:
5657 ret = get_errno(getpid());
5658 break;
5659#endif
bellard31e31b82003-02-18 22:55:36 +00005660 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00005661 {
5662 /* need to look at the data field */
5663 void *p2, *p3;
5664 p = lock_user_string(arg1);
5665 p2 = lock_user_string(arg2);
5666 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005667 if (!p || !p2 || !p3)
5668 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005669 else {
bellard579a97f2007-11-11 14:26:47 +00005670 /* FIXME - arg5 should be locked, but it isn't clear how to
5671 * do that since it's not guaranteed to be a NULL-terminated
5672 * string.
5673 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005674 if ( ! arg5 )
5675 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
5676 else
5677 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
5678 }
bellard579a97f2007-11-11 14:26:47 +00005679 unlock_user(p, arg1, 0);
5680 unlock_user(p2, arg2, 0);
5681 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00005682 break;
5683 }
thse5febef2007-04-01 18:31:35 +00005684#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005685 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005686 if (!(p = lock_user_string(arg1)))
5687 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005688 ret = get_errno(umount(p));
5689 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005690 break;
thse5febef2007-04-01 18:31:35 +00005691#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005692#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005693 case TARGET_NR_stime:
5694 {
pbrook53a59602006-03-25 19:31:22 +00005695 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005696 if (get_user_sal(host_time, arg1))
5697 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005698 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005699 }
5700 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005701#endif
bellard31e31b82003-02-18 22:55:36 +00005702 case TARGET_NR_ptrace:
5703 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005704#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005705 case TARGET_NR_alarm:
5706 ret = alarm(arg1);
5707 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005708#endif
bellardebc05482003-09-30 21:08:41 +00005709#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005710 case TARGET_NR_oldfstat:
5711 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005712#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005713#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005714 case TARGET_NR_pause:
5715 ret = get_errno(pause());
5716 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005717#endif
thse5febef2007-04-01 18:31:35 +00005718#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005719 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005720 {
pbrook53a59602006-03-25 19:31:22 +00005721 struct utimbuf tbuf, *host_tbuf;
5722 struct target_utimbuf *target_tbuf;
5723 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005724 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5725 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005726 tbuf.actime = tswapal(target_tbuf->actime);
5727 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005728 unlock_user_struct(target_tbuf, arg2, 0);
5729 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005730 } else {
pbrook53a59602006-03-25 19:31:22 +00005731 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005732 }
bellard579a97f2007-11-11 14:26:47 +00005733 if (!(p = lock_user_string(arg1)))
5734 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005735 ret = get_errno(utime(p, host_tbuf));
5736 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005737 }
5738 break;
thse5febef2007-04-01 18:31:35 +00005739#endif
bellard978a66f2004-12-06 22:58:05 +00005740 case TARGET_NR_utimes:
5741 {
bellard978a66f2004-12-06 22:58:05 +00005742 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005743 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005744 if (copy_from_user_timeval(&tv[0], arg2)
5745 || copy_from_user_timeval(&tv[1],
5746 arg2 + sizeof(struct target_timeval)))
5747 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005748 tvp = tv;
5749 } else {
5750 tvp = NULL;
5751 }
bellard579a97f2007-11-11 14:26:47 +00005752 if (!(p = lock_user_string(arg1)))
5753 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005754 ret = get_errno(utimes(p, tvp));
5755 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005756 }
5757 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005758#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00005759 case TARGET_NR_futimesat:
5760 {
5761 struct timeval *tvp, tv[2];
5762 if (arg3) {
5763 if (copy_from_user_timeval(&tv[0], arg3)
5764 || copy_from_user_timeval(&tv[1],
5765 arg3 + sizeof(struct target_timeval)))
5766 goto efault;
5767 tvp = tv;
5768 } else {
5769 tvp = NULL;
5770 }
5771 if (!(p = lock_user_string(arg2)))
5772 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005773 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00005774 unlock_user(p, arg2, 0);
5775 }
5776 break;
5777#endif
bellardebc05482003-09-30 21:08:41 +00005778#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005779 case TARGET_NR_stty:
5780 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005781#endif
5782#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005783 case TARGET_NR_gtty:
5784 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005785#endif
bellard31e31b82003-02-18 22:55:36 +00005786 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005787 if (!(p = lock_user_string(arg1)))
5788 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005789 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005790 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005791 break;
ths92a34c12007-09-24 09:27:49 +00005792#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5793 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005794 if (!(p = lock_user_string(arg2)))
5795 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005796 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00005797 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005798 break;
5799#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005800#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005801 case TARGET_NR_nice:
5802 ret = get_errno(nice(arg1));
5803 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005804#endif
bellardebc05482003-09-30 21:08:41 +00005805#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005806 case TARGET_NR_ftime:
5807 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005808#endif
bellard31e31b82003-02-18 22:55:36 +00005809 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005810 sync();
5811 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005812 break;
5813 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005814 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005815 break;
5816 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005817 {
5818 void *p2;
5819 p = lock_user_string(arg1);
5820 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005821 if (!p || !p2)
5822 ret = -TARGET_EFAULT;
5823 else
5824 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005825 unlock_user(p2, arg2, 0);
5826 unlock_user(p, arg1, 0);
5827 }
bellard31e31b82003-02-18 22:55:36 +00005828 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005829#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00005830 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005831 {
bellard579a97f2007-11-11 14:26:47 +00005832 void *p2;
ths722183f2007-09-24 09:24:37 +00005833 p = lock_user_string(arg2);
5834 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005835 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005836 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005837 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005838 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005839 unlock_user(p2, arg4, 0);
5840 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005841 }
5842 break;
5843#endif
bellard31e31b82003-02-18 22:55:36 +00005844 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005845 if (!(p = lock_user_string(arg1)))
5846 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005847 ret = get_errno(mkdir(p, arg2));
5848 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005849 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005850#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00005851 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005852 if (!(p = lock_user_string(arg2)))
5853 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005854 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005855 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005856 break;
5857#endif
bellard31e31b82003-02-18 22:55:36 +00005858 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005859 if (!(p = lock_user_string(arg1)))
5860 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005861 ret = get_errno(rmdir(p));
5862 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005863 break;
5864 case TARGET_NR_dup:
5865 ret = get_errno(dup(arg1));
5866 break;
5867 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005868 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005869 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005870#ifdef TARGET_NR_pipe2
5871 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07005872 ret = do_pipe(cpu_env, arg1,
5873 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005874 break;
5875#endif
bellard31e31b82003-02-18 22:55:36 +00005876 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005877 {
pbrook53a59602006-03-25 19:31:22 +00005878 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005879 struct tms tms;
5880 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005881 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005882 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5883 if (!tmsp)
5884 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005885 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5886 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5887 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5888 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005889 }
bellardc596ed12003-07-13 17:32:31 +00005890 if (!is_error(ret))
5891 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005892 }
5893 break;
bellardebc05482003-09-30 21:08:41 +00005894#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005895 case TARGET_NR_prof:
5896 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005897#endif
thse5febef2007-04-01 18:31:35 +00005898#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005899 case TARGET_NR_signal:
5900 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005901#endif
bellard31e31b82003-02-18 22:55:36 +00005902 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005903 if (arg1 == 0) {
5904 ret = get_errno(acct(NULL));
5905 } else {
5906 if (!(p = lock_user_string(arg1)))
5907 goto efault;
5908 ret = get_errno(acct(path(p)));
5909 unlock_user(p, arg1, 0);
5910 }
pbrook24836682006-04-16 14:14:53 +00005911 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10005912#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00005913 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005914 if (!(p = lock_user_string(arg1)))
5915 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005916 ret = get_errno(umount2(p, arg2));
5917 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005918 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005919#endif
bellardebc05482003-09-30 21:08:41 +00005920#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005921 case TARGET_NR_lock:
5922 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005923#endif
bellard31e31b82003-02-18 22:55:36 +00005924 case TARGET_NR_ioctl:
5925 ret = do_ioctl(arg1, arg2, arg3);
5926 break;
5927 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005928 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005929 break;
bellardebc05482003-09-30 21:08:41 +00005930#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005931 case TARGET_NR_mpx:
5932 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005933#endif
bellard31e31b82003-02-18 22:55:36 +00005934 case TARGET_NR_setpgid:
5935 ret = get_errno(setpgid(arg1, arg2));
5936 break;
bellardebc05482003-09-30 21:08:41 +00005937#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005938 case TARGET_NR_ulimit:
5939 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005940#endif
5941#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005942 case TARGET_NR_oldolduname:
5943 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005944#endif
bellard31e31b82003-02-18 22:55:36 +00005945 case TARGET_NR_umask:
5946 ret = get_errno(umask(arg1));
5947 break;
5948 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005949 if (!(p = lock_user_string(arg1)))
5950 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005951 ret = get_errno(chroot(p));
5952 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005953 break;
5954 case TARGET_NR_ustat:
5955 goto unimplemented;
5956 case TARGET_NR_dup2:
5957 ret = get_errno(dup2(arg1, arg2));
5958 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005959#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5960 case TARGET_NR_dup3:
5961 ret = get_errno(dup3(arg1, arg2, arg3));
5962 break;
5963#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005964#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005965 case TARGET_NR_getppid:
5966 ret = get_errno(getppid());
5967 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005968#endif
bellard31e31b82003-02-18 22:55:36 +00005969 case TARGET_NR_getpgrp:
5970 ret = get_errno(getpgrp());
5971 break;
5972 case TARGET_NR_setsid:
5973 ret = get_errno(setsid());
5974 break;
thse5febef2007-04-01 18:31:35 +00005975#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005976 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005977 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005978#if defined(TARGET_ALPHA)
5979 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005980 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005981 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005982 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5983 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005984 act._sa_handler = old_act->_sa_handler;
5985 target_siginitset(&act.sa_mask, old_act->sa_mask);
5986 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005987 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005988 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005989 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005990 }
5991 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005992 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005993 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5994 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005995 old_act->_sa_handler = oact._sa_handler;
5996 old_act->sa_mask = oact.sa_mask.sig[0];
5997 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005998 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005999 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006000#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00006001 struct target_sigaction act, oact, *pact, *old_act;
6002
6003 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006004 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6005 goto efault;
bellard106ec872006-06-27 21:08:10 +00006006 act._sa_handler = old_act->_sa_handler;
6007 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
6008 act.sa_flags = old_act->sa_flags;
6009 unlock_user_struct(old_act, arg2, 0);
6010 pact = &act;
6011 } else {
6012 pact = NULL;
6013 }
6014
6015 ret = get_errno(do_sigaction(arg1, pact, &oact));
6016
6017 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006018 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6019 goto efault;
bellard106ec872006-06-27 21:08:10 +00006020 old_act->_sa_handler = oact._sa_handler;
6021 old_act->sa_flags = oact.sa_flags;
6022 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
6023 old_act->sa_mask.sig[1] = 0;
6024 old_act->sa_mask.sig[2] = 0;
6025 old_act->sa_mask.sig[3] = 0;
6026 unlock_user_struct(old_act, arg3, 1);
6027 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006028#else
6029 struct target_old_sigaction *old_act;
6030 struct target_sigaction act, oact, *pact;
6031 if (arg2) {
6032 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6033 goto efault;
6034 act._sa_handler = old_act->_sa_handler;
6035 target_siginitset(&act.sa_mask, old_act->sa_mask);
6036 act.sa_flags = old_act->sa_flags;
6037 act.sa_restorer = old_act->sa_restorer;
6038 unlock_user_struct(old_act, arg2, 0);
6039 pact = &act;
6040 } else {
6041 pact = NULL;
6042 }
6043 ret = get_errno(do_sigaction(arg1, pact, &oact));
6044 if (!is_error(ret) && arg3) {
6045 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6046 goto efault;
6047 old_act->_sa_handler = oact._sa_handler;
6048 old_act->sa_mask = oact.sa_mask.sig[0];
6049 old_act->sa_flags = oact.sa_flags;
6050 old_act->sa_restorer = oact.sa_restorer;
6051 unlock_user_struct(old_act, arg3, 1);
6052 }
ths388bb212007-05-13 13:58:00 +00006053#endif
bellard31e31b82003-02-18 22:55:36 +00006054 }
6055 break;
thse5febef2007-04-01 18:31:35 +00006056#endif
bellard66fb9762003-03-23 01:06:05 +00006057 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00006058 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006059#if defined(TARGET_ALPHA)
6060 struct target_sigaction act, oact, *pact = 0;
6061 struct target_rt_sigaction *rt_act;
6062 /* ??? arg4 == sizeof(sigset_t). */
6063 if (arg2) {
6064 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
6065 goto efault;
6066 act._sa_handler = rt_act->_sa_handler;
6067 act.sa_mask = rt_act->sa_mask;
6068 act.sa_flags = rt_act->sa_flags;
6069 act.sa_restorer = arg5;
6070 unlock_user_struct(rt_act, arg2, 0);
6071 pact = &act;
6072 }
6073 ret = get_errno(do_sigaction(arg1, pact, &oact));
6074 if (!is_error(ret) && arg3) {
6075 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
6076 goto efault;
6077 rt_act->_sa_handler = oact._sa_handler;
6078 rt_act->sa_mask = oact.sa_mask;
6079 rt_act->sa_flags = oact.sa_flags;
6080 unlock_user_struct(rt_act, arg3, 1);
6081 }
6082#else
pbrook53a59602006-03-25 19:31:22 +00006083 struct target_sigaction *act;
6084 struct target_sigaction *oact;
6085
bellard579a97f2007-11-11 14:26:47 +00006086 if (arg2) {
6087 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
6088 goto efault;
6089 } else
pbrook53a59602006-03-25 19:31:22 +00006090 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00006091 if (arg3) {
6092 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
6093 ret = -TARGET_EFAULT;
6094 goto rt_sigaction_fail;
6095 }
6096 } else
pbrook53a59602006-03-25 19:31:22 +00006097 oact = NULL;
6098 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00006099 rt_sigaction_fail:
6100 if (act)
pbrook53a59602006-03-25 19:31:22 +00006101 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00006102 if (oact)
pbrook53a59602006-03-25 19:31:22 +00006103 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08006104#endif
pbrook53a59602006-03-25 19:31:22 +00006105 }
bellard66fb9762003-03-23 01:06:05 +00006106 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006107#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006108 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00006109 {
6110 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006111 abi_ulong target_set;
bellard66fb9762003-03-23 01:06:05 +00006112 sigprocmask(0, NULL, &cur_set);
6113 host_to_target_old_sigset(&target_set, &cur_set);
6114 ret = target_set;
6115 }
6116 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006117#endif
6118#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006119 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00006120 {
6121 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006122 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00006123 sigprocmask(0, NULL, &cur_set);
6124 target_to_host_old_sigset(&set, &target_set);
6125 sigorset(&set, &set, &cur_set);
6126 sigprocmask(SIG_SETMASK, &set, &oset);
6127 host_to_target_old_sigset(&target_set, &oset);
6128 ret = target_set;
6129 }
6130 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006131#endif
thse5febef2007-04-01 18:31:35 +00006132#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006133 case TARGET_NR_sigprocmask:
6134 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006135#if defined(TARGET_ALPHA)
6136 sigset_t set, oldset;
6137 abi_ulong mask;
6138 int how;
6139
6140 switch (arg1) {
6141 case TARGET_SIG_BLOCK:
6142 how = SIG_BLOCK;
6143 break;
6144 case TARGET_SIG_UNBLOCK:
6145 how = SIG_UNBLOCK;
6146 break;
6147 case TARGET_SIG_SETMASK:
6148 how = SIG_SETMASK;
6149 break;
6150 default:
6151 ret = -TARGET_EINVAL;
6152 goto fail;
6153 }
6154 mask = arg2;
6155 target_to_host_old_sigset(&set, &mask);
6156
6157 ret = get_errno(sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006158 if (!is_error(ret)) {
6159 host_to_target_old_sigset(&mask, &oldset);
6160 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006161 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006162 }
6163#else
bellard66fb9762003-03-23 01:06:05 +00006164 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006165 int how;
ths3b46e622007-09-17 08:09:54 +00006166
pbrook53a59602006-03-25 19:31:22 +00006167 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006168 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006169 case TARGET_SIG_BLOCK:
6170 how = SIG_BLOCK;
6171 break;
6172 case TARGET_SIG_UNBLOCK:
6173 how = SIG_UNBLOCK;
6174 break;
6175 case TARGET_SIG_SETMASK:
6176 how = SIG_SETMASK;
6177 break;
6178 default:
ths0da46a62007-10-20 20:23:07 +00006179 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006180 goto fail;
6181 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006182 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006183 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006184 target_to_host_old_sigset(&set, p);
6185 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006186 set_ptr = &set;
6187 } else {
6188 how = 0;
6189 set_ptr = NULL;
6190 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006191 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006192 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006193 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006194 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006195 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006196 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006197 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006198#endif
bellard66fb9762003-03-23 01:06:05 +00006199 }
6200 break;
thse5febef2007-04-01 18:31:35 +00006201#endif
bellard66fb9762003-03-23 01:06:05 +00006202 case TARGET_NR_rt_sigprocmask:
6203 {
6204 int how = arg1;
6205 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006206
pbrook53a59602006-03-25 19:31:22 +00006207 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006208 switch(how) {
6209 case TARGET_SIG_BLOCK:
6210 how = SIG_BLOCK;
6211 break;
6212 case TARGET_SIG_UNBLOCK:
6213 how = SIG_UNBLOCK;
6214 break;
6215 case TARGET_SIG_SETMASK:
6216 how = SIG_SETMASK;
6217 break;
6218 default:
ths0da46a62007-10-20 20:23:07 +00006219 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006220 goto fail;
6221 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006222 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006223 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006224 target_to_host_sigset(&set, p);
6225 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006226 set_ptr = &set;
6227 } else {
6228 how = 0;
6229 set_ptr = NULL;
6230 }
6231 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006232 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006233 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006234 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006235 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006236 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006237 }
6238 }
6239 break;
thse5febef2007-04-01 18:31:35 +00006240#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006241 case TARGET_NR_sigpending:
6242 {
6243 sigset_t set;
6244 ret = get_errno(sigpending(&set));
6245 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006246 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006247 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006248 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006249 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006250 }
6251 }
6252 break;
thse5febef2007-04-01 18:31:35 +00006253#endif
bellard66fb9762003-03-23 01:06:05 +00006254 case TARGET_NR_rt_sigpending:
6255 {
6256 sigset_t set;
6257 ret = get_errno(sigpending(&set));
6258 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006259 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006260 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006261 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006262 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006263 }
6264 }
6265 break;
thse5febef2007-04-01 18:31:35 +00006266#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006267 case TARGET_NR_sigsuspend:
6268 {
6269 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006270#if defined(TARGET_ALPHA)
6271 abi_ulong mask = arg1;
6272 target_to_host_old_sigset(&set, &mask);
6273#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006274 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006275 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006276 target_to_host_old_sigset(&set, p);
6277 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006278#endif
bellard66fb9762003-03-23 01:06:05 +00006279 ret = get_errno(sigsuspend(&set));
6280 }
6281 break;
thse5febef2007-04-01 18:31:35 +00006282#endif
bellard66fb9762003-03-23 01:06:05 +00006283 case TARGET_NR_rt_sigsuspend:
6284 {
6285 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006286 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006287 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006288 target_to_host_sigset(&set, p);
6289 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006290 ret = get_errno(sigsuspend(&set));
6291 }
6292 break;
6293 case TARGET_NR_rt_sigtimedwait:
6294 {
bellard66fb9762003-03-23 01:06:05 +00006295 sigset_t set;
6296 struct timespec uts, *puts;
6297 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006298
Anthony Liguoric227f092009-10-01 16:12:16 -05006299 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006300 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006301 target_to_host_sigset(&set, p);
6302 unlock_user(p, arg1, 0);
6303 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006304 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006305 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006306 } else {
6307 puts = NULL;
6308 }
6309 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
pbrook53a59602006-03-25 19:31:22 +00006310 if (!is_error(ret) && arg2) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006311 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006312 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006313 host_to_target_siginfo(p, &uinfo);
Anthony Liguoric227f092009-10-01 16:12:16 -05006314 unlock_user(p, arg2, sizeof(target_siginfo_t));
bellard66fb9762003-03-23 01:06:05 +00006315 }
6316 }
6317 break;
6318 case TARGET_NR_rt_sigqueueinfo:
6319 {
6320 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006321 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006322 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006323 target_to_host_siginfo(&uinfo, p);
6324 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006325 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6326 }
6327 break;
thse5febef2007-04-01 18:31:35 +00006328#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006329 case TARGET_NR_sigreturn:
6330 /* NOTE: ret is eax, so not transcoding must be done */
6331 ret = do_sigreturn(cpu_env);
6332 break;
thse5febef2007-04-01 18:31:35 +00006333#endif
bellard66fb9762003-03-23 01:06:05 +00006334 case TARGET_NR_rt_sigreturn:
6335 /* NOTE: ret is eax, so not transcoding must be done */
6336 ret = do_rt_sigreturn(cpu_env);
6337 break;
bellard31e31b82003-02-18 22:55:36 +00006338 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006339 if (!(p = lock_user_string(arg1)))
6340 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006341 ret = get_errno(sethostname(p, arg2));
6342 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006343 break;
6344 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006345 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006346 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006347 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006348 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006349 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6350 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006351 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6352 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006353 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006354 ret = get_errno(setrlimit(resource, &rlim));
6355 }
6356 break;
bellard31e31b82003-02-18 22:55:36 +00006357 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006358 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006359 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006360 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006361 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006362
bellard9de5e442003-03-23 16:49:39 +00006363 ret = get_errno(getrlimit(resource, &rlim));
6364 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006365 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6366 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006367 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6368 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006369 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006370 }
6371 }
6372 break;
bellard31e31b82003-02-18 22:55:36 +00006373 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006374 {
6375 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006376 ret = get_errno(getrusage(arg1, &rusage));
6377 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006378 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006379 }
6380 }
6381 break;
bellard31e31b82003-02-18 22:55:36 +00006382 case TARGET_NR_gettimeofday:
6383 {
bellard31e31b82003-02-18 22:55:36 +00006384 struct timeval tv;
6385 ret = get_errno(gettimeofday(&tv, NULL));
6386 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006387 if (copy_to_user_timeval(arg1, &tv))
6388 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006389 }
6390 }
6391 break;
6392 case TARGET_NR_settimeofday:
6393 {
bellard31e31b82003-02-18 22:55:36 +00006394 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00006395 if (copy_from_user_timeval(&tv, arg1))
6396 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006397 ret = get_errno(settimeofday(&tv, NULL));
6398 }
6399 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006400#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006401 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006402#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6403 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6404#else
bellardf2674e32003-07-09 12:26:09 +00006405 {
pbrook53a59602006-03-25 19:31:22 +00006406 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006407 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006408 long nsel;
6409
bellard579a97f2007-11-11 14:26:47 +00006410 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6411 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006412 nsel = tswapal(sel->n);
6413 inp = tswapal(sel->inp);
6414 outp = tswapal(sel->outp);
6415 exp = tswapal(sel->exp);
6416 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006417 unlock_user_struct(sel, arg1, 0);
6418 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006419 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006420#endif
bellardf2674e32003-07-09 12:26:09 +00006421 break;
bellard048f6b42005-11-26 18:47:20 +00006422#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006423#ifdef TARGET_NR_pselect6
6424 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006425 {
6426 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6427 fd_set rfds, wfds, efds;
6428 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6429 struct timespec ts, *ts_ptr;
6430
6431 /*
6432 * The 6th arg is actually two args smashed together,
6433 * so we cannot use the C library.
6434 */
6435 sigset_t set;
6436 struct {
6437 sigset_t *set;
6438 size_t size;
6439 } sig, *sig_ptr;
6440
6441 abi_ulong arg_sigset, arg_sigsize, *arg7;
6442 target_sigset_t *target_sigset;
6443
6444 n = arg1;
6445 rfd_addr = arg2;
6446 wfd_addr = arg3;
6447 efd_addr = arg4;
6448 ts_addr = arg5;
6449
6450 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6451 if (ret) {
6452 goto fail;
6453 }
6454 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6455 if (ret) {
6456 goto fail;
6457 }
6458 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6459 if (ret) {
6460 goto fail;
6461 }
6462
6463 /*
6464 * This takes a timespec, and not a timeval, so we cannot
6465 * use the do_select() helper ...
6466 */
6467 if (ts_addr) {
6468 if (target_to_host_timespec(&ts, ts_addr)) {
6469 goto efault;
6470 }
6471 ts_ptr = &ts;
6472 } else {
6473 ts_ptr = NULL;
6474 }
6475
6476 /* Extract the two packed args for the sigset */
6477 if (arg6) {
6478 sig_ptr = &sig;
6479 sig.size = _NSIG / 8;
6480
6481 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6482 if (!arg7) {
6483 goto efault;
6484 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006485 arg_sigset = tswapal(arg7[0]);
6486 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006487 unlock_user(arg7, arg6, 0);
6488
6489 if (arg_sigset) {
6490 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006491 if (arg_sigsize != sizeof(*target_sigset)) {
6492 /* Like the kernel, we enforce correct size sigsets */
6493 ret = -TARGET_EINVAL;
6494 goto fail;
6495 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006496 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6497 sizeof(*target_sigset), 1);
6498 if (!target_sigset) {
6499 goto efault;
6500 }
6501 target_to_host_sigset(&set, target_sigset);
6502 unlock_user(target_sigset, arg_sigset, 0);
6503 } else {
6504 sig.set = NULL;
6505 }
6506 } else {
6507 sig_ptr = NULL;
6508 }
6509
6510 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6511 ts_ptr, sig_ptr));
6512
6513 if (!is_error(ret)) {
6514 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6515 goto efault;
6516 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6517 goto efault;
6518 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6519 goto efault;
6520
6521 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6522 goto efault;
6523 }
6524 }
6525 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006526#endif
bellard31e31b82003-02-18 22:55:36 +00006527 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006528 {
6529 void *p2;
6530 p = lock_user_string(arg1);
6531 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006532 if (!p || !p2)
6533 ret = -TARGET_EFAULT;
6534 else
6535 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006536 unlock_user(p2, arg2, 0);
6537 unlock_user(p, arg1, 0);
6538 }
bellard31e31b82003-02-18 22:55:36 +00006539 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006540#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00006541 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006542 {
bellard579a97f2007-11-11 14:26:47 +00006543 void *p2;
thsf0b62432007-09-24 09:25:40 +00006544 p = lock_user_string(arg1);
6545 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006546 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006547 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006548 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006549 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006550 unlock_user(p2, arg3, 0);
6551 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006552 }
6553 break;
6554#endif
bellardebc05482003-09-30 21:08:41 +00006555#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006556 case TARGET_NR_oldlstat:
6557 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006558#endif
bellard31e31b82003-02-18 22:55:36 +00006559 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006560 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01006561 void *p2;
pbrook53a59602006-03-25 19:31:22 +00006562 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006563 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006564 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00006565 ret = -TARGET_EFAULT;
Andreas Schwab463d8e72013-07-02 14:04:12 +01006566 } else if (is_proc_myself((const char *)p, "exe")) {
6567 char real[PATH_MAX], *temp;
6568 temp = realpath(exec_path, real);
6569 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6570 snprintf((char *)p2, arg3, "%s", real);
6571 } else {
6572 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006573 }
pbrook53a59602006-03-25 19:31:22 +00006574 unlock_user(p2, arg2, ret);
6575 unlock_user(p, arg1, 0);
6576 }
bellard31e31b82003-02-18 22:55:36 +00006577 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006578#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00006579 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006580 {
bellard579a97f2007-11-11 14:26:47 +00006581 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006582 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006583 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006584 if (!p || !p2) {
6585 ret = -TARGET_EFAULT;
6586 } else if (is_proc_myself((const char *)p, "exe")) {
6587 char real[PATH_MAX], *temp;
6588 temp = realpath(exec_path, real);
6589 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6590 snprintf((char *)p2, arg4, "%s", real);
6591 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01006592 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01006593 }
bellard579a97f2007-11-11 14:26:47 +00006594 unlock_user(p2, arg3, ret);
6595 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006596 }
6597 break;
6598#endif
thse5febef2007-04-01 18:31:35 +00006599#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006600 case TARGET_NR_uselib:
6601 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006602#endif
6603#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006604 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006605 if (!(p = lock_user_string(arg1)))
6606 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006607 ret = get_errno(swapon(p, arg2));
6608 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006609 break;
thse5febef2007-04-01 18:31:35 +00006610#endif
bellard31e31b82003-02-18 22:55:36 +00006611 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006612 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6613 /* arg4 must be ignored in all other cases */
6614 p = lock_user_string(arg4);
6615 if (!p) {
6616 goto efault;
6617 }
6618 ret = get_errno(reboot(arg1, arg2, arg3, p));
6619 unlock_user(p, arg4, 0);
6620 } else {
6621 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6622 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006623 break;
thse5febef2007-04-01 18:31:35 +00006624#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006625 case TARGET_NR_readdir:
6626 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006627#endif
6628#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006629 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01006630#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6631 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006632 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6633 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006634 {
blueswir1992f48a2007-10-14 16:27:31 +00006635 abi_ulong *v;
6636 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006637 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6638 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006639 v1 = tswapal(v[0]);
6640 v2 = tswapal(v[1]);
6641 v3 = tswapal(v[2]);
6642 v4 = tswapal(v[3]);
6643 v5 = tswapal(v[4]);
6644 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006645 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006646 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006647 target_to_host_bitmask(v4, mmap_flags_tbl),
6648 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006649 }
bellard31e31b82003-02-18 22:55:36 +00006650#else
ths5fafdf22007-09-16 21:08:06 +00006651 ret = get_errno(target_mmap(arg1, arg2, arg3,
6652 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006653 arg5,
6654 arg6));
bellard31e31b82003-02-18 22:55:36 +00006655#endif
bellard6fb883e2003-07-09 17:12:39 +00006656 break;
thse5febef2007-04-01 18:31:35 +00006657#endif
bellarda315a142005-01-30 22:59:18 +00006658#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006659 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006660#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006661#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006662#endif
ths5fafdf22007-09-16 21:08:06 +00006663 ret = get_errno(target_mmap(arg1, arg2, arg3,
6664 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006665 arg5,
bellardc573ff62004-01-04 15:51:36 +00006666 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006667 break;
bellarda315a142005-01-30 22:59:18 +00006668#endif
bellard31e31b82003-02-18 22:55:36 +00006669 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006670 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006671 break;
bellard9de5e442003-03-23 16:49:39 +00006672 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006673 {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006674 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006675 /* Special hack to detect libc making the stack executable. */
6676 if ((arg3 & PROT_GROWSDOWN)
6677 && arg1 >= ts->info->stack_limit
6678 && arg1 <= ts->info->start_stack) {
6679 arg3 &= ~PROT_GROWSDOWN;
6680 arg2 = arg2 + arg1 - ts->info->stack_limit;
6681 arg1 = ts->info->stack_limit;
6682 }
6683 }
bellard54936002003-05-13 00:25:15 +00006684 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006685 break;
thse5febef2007-04-01 18:31:35 +00006686#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006687 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006688 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006689 break;
thse5febef2007-04-01 18:31:35 +00006690#endif
pbrook53a59602006-03-25 19:31:22 +00006691 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006692#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006693 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006694 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006695 break;
thse5febef2007-04-01 18:31:35 +00006696#endif
6697#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006698 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006699 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006700 break;
thse5febef2007-04-01 18:31:35 +00006701#endif
6702#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006703 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006704 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006705 break;
thse5febef2007-04-01 18:31:35 +00006706#endif
6707#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006708 case TARGET_NR_mlockall:
6709 ret = get_errno(mlockall(arg1));
6710 break;
thse5febef2007-04-01 18:31:35 +00006711#endif
6712#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006713 case TARGET_NR_munlockall:
6714 ret = get_errno(munlockall());
6715 break;
thse5febef2007-04-01 18:31:35 +00006716#endif
bellard31e31b82003-02-18 22:55:36 +00006717 case TARGET_NR_truncate:
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(truncate(p, arg2));
6721 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006722 break;
6723 case TARGET_NR_ftruncate:
6724 ret = get_errno(ftruncate(arg1, arg2));
6725 break;
6726 case TARGET_NR_fchmod:
6727 ret = get_errno(fchmod(arg1, arg2));
6728 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006729#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00006730 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006731 if (!(p = lock_user_string(arg2)))
6732 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006733 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006734 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006735 break;
6736#endif
bellard31e31b82003-02-18 22:55:36 +00006737 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006738 /* Note that negative values are valid for getpriority, so we must
6739 differentiate based on errno settings. */
6740 errno = 0;
6741 ret = getpriority(arg1, arg2);
6742 if (ret == -1 && errno != 0) {
6743 ret = -host_to_target_errno(errno);
6744 break;
6745 }
6746#ifdef TARGET_ALPHA
6747 /* Return value is the unbiased priority. Signal no error. */
6748 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6749#else
6750 /* Return value is a biased priority to avoid negative numbers. */
6751 ret = 20 - ret;
6752#endif
bellard31e31b82003-02-18 22:55:36 +00006753 break;
6754 case TARGET_NR_setpriority:
6755 ret = get_errno(setpriority(arg1, arg2, arg3));
6756 break;
bellardebc05482003-09-30 21:08:41 +00006757#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006758 case TARGET_NR_profil:
6759 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006760#endif
bellard31e31b82003-02-18 22:55:36 +00006761 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006762 if (!(p = lock_user_string(arg1)))
6763 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006764 ret = get_errno(statfs(path(p), &stfs));
6765 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006766 convert_statfs:
6767 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006768 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006769
bellard579a97f2007-11-11 14:26:47 +00006770 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6771 goto efault;
6772 __put_user(stfs.f_type, &target_stfs->f_type);
6773 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6774 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6775 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6776 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6777 __put_user(stfs.f_files, &target_stfs->f_files);
6778 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6779 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6780 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6781 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006782 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6783 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006784 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006785 }
6786 break;
6787 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006788 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006789 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006790#ifdef TARGET_NR_statfs64
6791 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006792 if (!(p = lock_user_string(arg1)))
6793 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006794 ret = get_errno(statfs(path(p), &stfs));
6795 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006796 convert_statfs64:
6797 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006798 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006799
bellard579a97f2007-11-11 14:26:47 +00006800 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6801 goto efault;
6802 __put_user(stfs.f_type, &target_stfs->f_type);
6803 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6804 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6805 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6806 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6807 __put_user(stfs.f_files, &target_stfs->f_files);
6808 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6809 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6810 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6811 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006812 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6813 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00006814 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006815 }
6816 break;
6817 case TARGET_NR_fstatfs64:
6818 ret = get_errno(fstatfs(arg1, &stfs));
6819 goto convert_statfs64;
6820#endif
bellardebc05482003-09-30 21:08:41 +00006821#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006822 case TARGET_NR_ioperm:
6823 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006824#endif
thse5febef2007-04-01 18:31:35 +00006825#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006826 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006827 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006828 break;
thse5febef2007-04-01 18:31:35 +00006829#endif
bellard3532fa72006-06-24 15:06:03 +00006830#ifdef TARGET_NR_accept
6831 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00006832 ret = do_accept4(arg1, arg2, arg3, 0);
6833 break;
6834#endif
6835#ifdef TARGET_NR_accept4
6836 case TARGET_NR_accept4:
6837#ifdef CONFIG_ACCEPT4
6838 ret = do_accept4(arg1, arg2, arg3, arg4);
6839#else
6840 goto unimplemented;
6841#endif
bellard3532fa72006-06-24 15:06:03 +00006842 break;
6843#endif
6844#ifdef TARGET_NR_bind
6845 case TARGET_NR_bind:
6846 ret = do_bind(arg1, arg2, arg3);
6847 break;
6848#endif
6849#ifdef TARGET_NR_connect
6850 case TARGET_NR_connect:
6851 ret = do_connect(arg1, arg2, arg3);
6852 break;
6853#endif
6854#ifdef TARGET_NR_getpeername
6855 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006856 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006857 break;
6858#endif
6859#ifdef TARGET_NR_getsockname
6860 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006861 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006862 break;
6863#endif
6864#ifdef TARGET_NR_getsockopt
6865 case TARGET_NR_getsockopt:
6866 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6867 break;
6868#endif
6869#ifdef TARGET_NR_listen
6870 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006871 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006872 break;
6873#endif
6874#ifdef TARGET_NR_recv
6875 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006876 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006877 break;
6878#endif
6879#ifdef TARGET_NR_recvfrom
6880 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006881 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006882 break;
6883#endif
6884#ifdef TARGET_NR_recvmsg
6885 case TARGET_NR_recvmsg:
6886 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6887 break;
6888#endif
6889#ifdef TARGET_NR_send
6890 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006891 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006892 break;
6893#endif
6894#ifdef TARGET_NR_sendmsg
6895 case TARGET_NR_sendmsg:
6896 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6897 break;
6898#endif
6899#ifdef TARGET_NR_sendto
6900 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006901 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006902 break;
6903#endif
6904#ifdef TARGET_NR_shutdown
6905 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006906 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006907 break;
6908#endif
6909#ifdef TARGET_NR_socket
6910 case TARGET_NR_socket:
6911 ret = do_socket(arg1, arg2, arg3);
6912 break;
6913#endif
6914#ifdef TARGET_NR_socketpair
6915 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006916 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006917 break;
6918#endif
6919#ifdef TARGET_NR_setsockopt
6920 case TARGET_NR_setsockopt:
6921 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6922 break;
6923#endif
ths7494b0f2007-02-11 18:26:53 +00006924
bellard31e31b82003-02-18 22:55:36 +00006925 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006926 if (!(p = lock_user_string(arg2)))
6927 goto efault;
thse5574482007-02-11 20:03:13 +00006928 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6929 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006930 break;
6931
bellard31e31b82003-02-18 22:55:36 +00006932 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006933 {
bellard66fb9762003-03-23 01:06:05 +00006934 struct itimerval value, ovalue, *pvalue;
6935
pbrook53a59602006-03-25 19:31:22 +00006936 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006937 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006938 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6939 || copy_from_user_timeval(&pvalue->it_value,
6940 arg2 + sizeof(struct target_timeval)))
6941 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006942 } else {
6943 pvalue = NULL;
6944 }
6945 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006946 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006947 if (copy_to_user_timeval(arg3,
6948 &ovalue.it_interval)
6949 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6950 &ovalue.it_value))
6951 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006952 }
6953 }
6954 break;
bellard31e31b82003-02-18 22:55:36 +00006955 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006956 {
bellard66fb9762003-03-23 01:06:05 +00006957 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006958
bellard66fb9762003-03-23 01:06:05 +00006959 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006960 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006961 if (copy_to_user_timeval(arg2,
6962 &value.it_interval)
6963 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6964 &value.it_value))
6965 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006966 }
6967 }
6968 break;
bellard31e31b82003-02-18 22:55:36 +00006969 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006970 if (!(p = lock_user_string(arg1)))
6971 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006972 ret = get_errno(stat(path(p), &st));
6973 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006974 goto do_stat;
6975 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006976 if (!(p = lock_user_string(arg1)))
6977 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006978 ret = get_errno(lstat(path(p), &st));
6979 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006980 goto do_stat;
6981 case TARGET_NR_fstat:
6982 {
6983 ret = get_errno(fstat(arg1, &st));
6984 do_stat:
6985 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006986 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006987
bellard579a97f2007-11-11 14:26:47 +00006988 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6989 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006990 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006991 __put_user(st.st_dev, &target_st->st_dev);
6992 __put_user(st.st_ino, &target_st->st_ino);
6993 __put_user(st.st_mode, &target_st->st_mode);
6994 __put_user(st.st_uid, &target_st->st_uid);
6995 __put_user(st.st_gid, &target_st->st_gid);
6996 __put_user(st.st_nlink, &target_st->st_nlink);
6997 __put_user(st.st_rdev, &target_st->st_rdev);
6998 __put_user(st.st_size, &target_st->st_size);
6999 __put_user(st.st_blksize, &target_st->st_blksize);
7000 __put_user(st.st_blocks, &target_st->st_blocks);
7001 __put_user(st.st_atime, &target_st->target_st_atime);
7002 __put_user(st.st_mtime, &target_st->target_st_mtime);
7003 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00007004 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007005 }
7006 }
7007 break;
bellardebc05482003-09-30 21:08:41 +00007008#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00007009 case TARGET_NR_olduname:
7010 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007011#endif
7012#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00007013 case TARGET_NR_iopl:
7014 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007015#endif
bellard31e31b82003-02-18 22:55:36 +00007016 case TARGET_NR_vhangup:
7017 ret = get_errno(vhangup());
7018 break;
bellardebc05482003-09-30 21:08:41 +00007019#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00007020 case TARGET_NR_idle:
7021 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007022#endif
bellard42ad6ae2005-01-03 22:48:11 +00007023#ifdef TARGET_NR_syscall
7024 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01007025 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
7026 arg6, arg7, arg8, 0);
7027 break;
bellard42ad6ae2005-01-03 22:48:11 +00007028#endif
bellard31e31b82003-02-18 22:55:36 +00007029 case TARGET_NR_wait4:
7030 {
7031 int status;
blueswir1992f48a2007-10-14 16:27:31 +00007032 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00007033 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00007034 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00007035 if (target_rusage)
7036 rusage_ptr = &rusage;
7037 else
7038 rusage_ptr = NULL;
7039 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
7040 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01007041 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00007042 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00007043 if (put_user_s32(status, status_ptr))
7044 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007045 }
bellard2f619692007-11-16 10:46:05 +00007046 if (target_rusage)
7047 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00007048 }
7049 }
7050 break;
thse5febef2007-04-01 18:31:35 +00007051#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00007052 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00007053 if (!(p = lock_user_string(arg1)))
7054 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007055 ret = get_errno(swapoff(p));
7056 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007057 break;
thse5febef2007-04-01 18:31:35 +00007058#endif
bellard31e31b82003-02-18 22:55:36 +00007059 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00007060 {
pbrook53a59602006-03-25 19:31:22 +00007061 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00007062 struct sysinfo value;
7063 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00007064 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00007065 {
bellard579a97f2007-11-11 14:26:47 +00007066 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
7067 goto efault;
bellarda5448a72004-06-19 16:59:03 +00007068 __put_user(value.uptime, &target_value->uptime);
7069 __put_user(value.loads[0], &target_value->loads[0]);
7070 __put_user(value.loads[1], &target_value->loads[1]);
7071 __put_user(value.loads[2], &target_value->loads[2]);
7072 __put_user(value.totalram, &target_value->totalram);
7073 __put_user(value.freeram, &target_value->freeram);
7074 __put_user(value.sharedram, &target_value->sharedram);
7075 __put_user(value.bufferram, &target_value->bufferram);
7076 __put_user(value.totalswap, &target_value->totalswap);
7077 __put_user(value.freeswap, &target_value->freeswap);
7078 __put_user(value.procs, &target_value->procs);
7079 __put_user(value.totalhigh, &target_value->totalhigh);
7080 __put_user(value.freehigh, &target_value->freehigh);
7081 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00007082 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00007083 }
7084 }
7085 break;
thse5febef2007-04-01 18:31:35 +00007086#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00007087 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00007088 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
7089 break;
thse5febef2007-04-01 18:31:35 +00007090#endif
aurel32e5289082009-04-18 16:16:12 +00007091#ifdef TARGET_NR_semget
7092 case TARGET_NR_semget:
7093 ret = get_errno(semget(arg1, arg2, arg3));
7094 break;
7095#endif
7096#ifdef TARGET_NR_semop
7097 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00007098 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00007099 break;
7100#endif
7101#ifdef TARGET_NR_semctl
7102 case TARGET_NR_semctl:
7103 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
7104 break;
7105#endif
aurel32eeb438c2008-10-13 21:08:55 +00007106#ifdef TARGET_NR_msgctl
7107 case TARGET_NR_msgctl:
7108 ret = do_msgctl(arg1, arg2, arg3);
7109 break;
7110#endif
7111#ifdef TARGET_NR_msgget
7112 case TARGET_NR_msgget:
7113 ret = get_errno(msgget(arg1, arg2));
7114 break;
7115#endif
7116#ifdef TARGET_NR_msgrcv
7117 case TARGET_NR_msgrcv:
7118 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7119 break;
7120#endif
7121#ifdef TARGET_NR_msgsnd
7122 case TARGET_NR_msgsnd:
7123 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7124 break;
7125#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007126#ifdef TARGET_NR_shmget
7127 case TARGET_NR_shmget:
7128 ret = get_errno(shmget(arg1, arg2, arg3));
7129 break;
7130#endif
7131#ifdef TARGET_NR_shmctl
7132 case TARGET_NR_shmctl:
7133 ret = do_shmctl(arg1, arg2, arg3);
7134 break;
7135#endif
7136#ifdef TARGET_NR_shmat
7137 case TARGET_NR_shmat:
7138 ret = do_shmat(arg1, arg2, arg3);
7139 break;
7140#endif
7141#ifdef TARGET_NR_shmdt
7142 case TARGET_NR_shmdt:
7143 ret = do_shmdt(arg1);
7144 break;
7145#endif
bellard31e31b82003-02-18 22:55:36 +00007146 case TARGET_NR_fsync:
7147 ret = get_errno(fsync(arg1));
7148 break;
bellard31e31b82003-02-18 22:55:36 +00007149 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007150 /* Linux manages to have three different orderings for its
7151 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7152 * match the kernel's CONFIG_CLONE_* settings.
7153 * Microblaze is further special in that it uses a sixth
7154 * implicit argument to clone for the TLS pointer.
7155 */
7156#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007157 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007158#elif defined(TARGET_CLONE_BACKWARDS)
7159 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7160#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007161 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007162#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007163 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007164#endif
bellard1b6b0292003-03-22 17:31:38 +00007165 break;
bellardec86b0f2003-04-11 00:15:04 +00007166#ifdef __NR_exit_group
7167 /* new thread calls */
7168 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007169#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007170 _mcleanup();
7171#endif
bellarde9009672005-04-26 20:42:36 +00007172 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007173 ret = get_errno(exit_group(arg1));
7174 break;
7175#endif
bellard31e31b82003-02-18 22:55:36 +00007176 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007177 if (!(p = lock_user_string(arg1)))
7178 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007179 ret = get_errno(setdomainname(p, arg2));
7180 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007181 break;
7182 case TARGET_NR_uname:
7183 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007184 {
7185 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007186
bellard579a97f2007-11-11 14:26:47 +00007187 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7188 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007189 ret = get_errno(sys_uname(buf));
7190 if (!is_error(ret)) {
7191 /* Overrite the native machine name with whatever is being
7192 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007193 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007194 /* Allow the user to override the reported release. */
7195 if (qemu_uname_release && *qemu_uname_release)
7196 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007197 }
pbrook53a59602006-03-25 19:31:22 +00007198 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007199 }
bellard31e31b82003-02-18 22:55:36 +00007200 break;
bellard6dbad632003-03-16 18:05:05 +00007201#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007202 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007203 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007204 break;
j_mayer84409dd2007-04-06 08:56:50 +00007205#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007206 case TARGET_NR_vm86old:
7207 goto unimplemented;
7208 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007209 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007210 break;
7211#endif
j_mayer84409dd2007-04-06 08:56:50 +00007212#endif
bellard31e31b82003-02-18 22:55:36 +00007213 case TARGET_NR_adjtimex:
7214 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007215#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007216 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007217#endif
bellard31e31b82003-02-18 22:55:36 +00007218 case TARGET_NR_init_module:
7219 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007220#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007221 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007222#endif
bellard31e31b82003-02-18 22:55:36 +00007223 goto unimplemented;
7224 case TARGET_NR_quotactl:
7225 goto unimplemented;
7226 case TARGET_NR_getpgid:
7227 ret = get_errno(getpgid(arg1));
7228 break;
7229 case TARGET_NR_fchdir:
7230 ret = get_errno(fchdir(arg1));
7231 break;
j_mayer84409dd2007-04-06 08:56:50 +00007232#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007233 case TARGET_NR_bdflush:
7234 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007235#endif
thse5febef2007-04-01 18:31:35 +00007236#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007237 case TARGET_NR_sysfs:
7238 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007239#endif
bellard31e31b82003-02-18 22:55:36 +00007240 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007241 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007242 break;
thse5febef2007-04-01 18:31:35 +00007243#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007244 case TARGET_NR_afs_syscall:
7245 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007246#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007247#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007248 case TARGET_NR__llseek:
7249 {
7250 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007251#if !defined(__NR_llseek)
7252 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7253 if (res == -1) {
7254 ret = get_errno(res);
7255 } else {
7256 ret = 0;
7257 }
7258#else
bellard31e31b82003-02-18 22:55:36 +00007259 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007260#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007261 if ((ret == 0) && put_user_s64(res, arg4)) {
7262 goto efault;
7263 }
bellard31e31b82003-02-18 22:55:36 +00007264 }
7265 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007266#endif
bellard31e31b82003-02-18 22:55:36 +00007267 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01007268#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007269#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007270 {
pbrook53a59602006-03-25 19:31:22 +00007271 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007272 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007273 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007274
7275 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00007276 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007277 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007278 goto fail;
7279 }
ths3b46e622007-09-17 08:09:54 +00007280
bellard4add45b2003-06-05 01:52:59 +00007281 ret = get_errno(sys_getdents(arg1, dirp, count));
7282 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007283 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007284 struct target_dirent *tde;
7285 int len = ret;
7286 int reclen, treclen;
7287 int count1, tnamelen;
7288
7289 count1 = 0;
7290 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007291 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7292 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007293 tde = target_dirp;
7294 while (len > 0) {
7295 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007296 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7297 assert(tnamelen >= 0);
7298 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7299 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007300 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007301 tde->d_ino = tswapal(de->d_ino);
7302 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007303 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007304 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007305 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007306 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007307 count1 += treclen;
7308 }
7309 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007310 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007311 }
7312 free(dirp);
7313 }
7314#else
bellard31e31b82003-02-18 22:55:36 +00007315 {
aurel326556a832008-10-13 21:08:17 +00007316 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007317 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007318
bellard579a97f2007-11-11 14:26:47 +00007319 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7320 goto efault;
bellard72f03902003-02-18 23:33:18 +00007321 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007322 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007323 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007324 int len = ret;
7325 int reclen;
7326 de = dirp;
7327 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007328 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007329 if (reclen > len)
7330 break;
bellard8083a3e2003-03-24 23:12:16 +00007331 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007332 tswapls(&de->d_ino);
7333 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007334 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007335 len -= reclen;
7336 }
7337 }
pbrook53a59602006-03-25 19:31:22 +00007338 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007339 }
bellard4add45b2003-06-05 01:52:59 +00007340#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007341#else
7342 /* Implement getdents in terms of getdents64 */
7343 {
7344 struct linux_dirent64 *dirp;
7345 abi_long count = arg3;
7346
7347 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7348 if (!dirp) {
7349 goto efault;
7350 }
7351 ret = get_errno(sys_getdents64(arg1, dirp, count));
7352 if (!is_error(ret)) {
7353 /* Convert the dirent64 structs to target dirent. We do this
7354 * in-place, since we can guarantee that a target_dirent is no
7355 * larger than a dirent64; however this means we have to be
7356 * careful to read everything before writing in the new format.
7357 */
7358 struct linux_dirent64 *de;
7359 struct target_dirent *tde;
7360 int len = ret;
7361 int tlen = 0;
7362
7363 de = dirp;
7364 tde = (struct target_dirent *)dirp;
7365 while (len > 0) {
7366 int namelen, treclen;
7367 int reclen = de->d_reclen;
7368 uint64_t ino = de->d_ino;
7369 int64_t off = de->d_off;
7370 uint8_t type = de->d_type;
7371
7372 namelen = strlen(de->d_name);
7373 treclen = offsetof(struct target_dirent, d_name)
7374 + namelen + 2;
7375 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
7376
7377 memmove(tde->d_name, de->d_name, namelen + 1);
7378 tde->d_ino = tswapal(ino);
7379 tde->d_off = tswapal(off);
7380 tde->d_reclen = tswap16(treclen);
7381 /* The target_dirent type is in what was formerly a padding
7382 * byte at the end of the structure:
7383 */
7384 *(((char *)tde) + treclen - 1) = type;
7385
7386 de = (struct linux_dirent64 *)((char *)de + reclen);
7387 tde = (struct target_dirent *)((char *)tde + treclen);
7388 len -= reclen;
7389 tlen += treclen;
7390 }
7391 ret = tlen;
7392 }
7393 unlock_user(dirp, arg2, ret);
7394 }
7395#endif
bellard31e31b82003-02-18 22:55:36 +00007396 break;
ths3ae43202007-09-16 21:39:48 +00007397#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007398 case TARGET_NR_getdents64:
7399 {
aurel326556a832008-10-13 21:08:17 +00007400 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007401 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007402 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7403 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007404 ret = get_errno(sys_getdents64(arg1, dirp, count));
7405 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007406 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007407 int len = ret;
7408 int reclen;
7409 de = dirp;
7410 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007411 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007412 if (reclen > len)
7413 break;
bellard8083a3e2003-03-24 23:12:16 +00007414 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007415 tswap64s((uint64_t *)&de->d_ino);
7416 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007417 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007418 len -= reclen;
7419 }
7420 }
pbrook53a59602006-03-25 19:31:22 +00007421 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007422 }
7423 break;
bellarda541f292004-04-12 20:39:29 +00007424#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007425#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007426 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007427 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007428 break;
thse5febef2007-04-01 18:31:35 +00007429#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007430#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7431# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007432 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007433# endif
7434# ifdef TARGET_NR_ppoll
7435 case TARGET_NR_ppoll:
7436# endif
bellard9de5e442003-03-23 16:49:39 +00007437 {
pbrook53a59602006-03-25 19:31:22 +00007438 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007439 unsigned int nfds = arg2;
7440 int timeout = arg3;
7441 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007442 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007443
bellard579a97f2007-11-11 14:26:47 +00007444 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7445 if (!target_pfd)
7446 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007447
bellard9de5e442003-03-23 16:49:39 +00007448 pfd = alloca(sizeof(struct pollfd) * nfds);
7449 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007450 pfd[i].fd = tswap32(target_pfd[i].fd);
7451 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007452 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007453
7454# ifdef TARGET_NR_ppoll
7455 if (num == TARGET_NR_ppoll) {
7456 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7457 target_sigset_t *target_set;
7458 sigset_t _set, *set = &_set;
7459
7460 if (arg3) {
7461 if (target_to_host_timespec(timeout_ts, arg3)) {
7462 unlock_user(target_pfd, arg1, 0);
7463 goto efault;
7464 }
7465 } else {
7466 timeout_ts = NULL;
7467 }
7468
7469 if (arg4) {
7470 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7471 if (!target_set) {
7472 unlock_user(target_pfd, arg1, 0);
7473 goto efault;
7474 }
7475 target_to_host_sigset(set, target_set);
7476 } else {
7477 set = NULL;
7478 }
7479
7480 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7481
7482 if (!is_error(ret) && arg3) {
7483 host_to_target_timespec(arg3, timeout_ts);
7484 }
7485 if (arg4) {
7486 unlock_user(target_set, arg4, 0);
7487 }
7488 } else
7489# endif
7490 ret = get_errno(poll(pfd, nfds, timeout));
7491
bellard9de5e442003-03-23 16:49:39 +00007492 if (!is_error(ret)) {
7493 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007494 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007495 }
7496 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007497 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007498 }
7499 break;
thse5febef2007-04-01 18:31:35 +00007500#endif
bellard31e31b82003-02-18 22:55:36 +00007501 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007502 /* NOTE: the flock constant seems to be the same for every
7503 Linux platform */
7504 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007505 break;
7506 case TARGET_NR_readv:
7507 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007508 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7509 if (vec != NULL) {
7510 ret = get_errno(readv(arg1, vec, arg3));
7511 unlock_iovec(vec, arg2, arg3, 1);
7512 } else {
7513 ret = -host_to_target_errno(errno);
7514 }
bellard31e31b82003-02-18 22:55:36 +00007515 }
7516 break;
7517 case TARGET_NR_writev:
7518 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007519 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7520 if (vec != NULL) {
7521 ret = get_errno(writev(arg1, vec, arg3));
7522 unlock_iovec(vec, arg2, arg3, 0);
7523 } else {
7524 ret = -host_to_target_errno(errno);
7525 }
bellard31e31b82003-02-18 22:55:36 +00007526 }
7527 break;
7528 case TARGET_NR_getsid:
7529 ret = get_errno(getsid(arg1));
7530 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007531#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007532 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007533 ret = get_errno(fdatasync(arg1));
7534 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007535#endif
bellard31e31b82003-02-18 22:55:36 +00007536 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007537 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007538 return value. */
ths0da46a62007-10-20 20:23:07 +00007539 ret = -TARGET_ENOTDIR;
7540 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007541 case TARGET_NR_sched_getaffinity:
7542 {
7543 unsigned int mask_size;
7544 unsigned long *mask;
7545
7546 /*
7547 * sched_getaffinity needs multiples of ulong, so need to take
7548 * care of mismatches between target ulong and host ulong sizes.
7549 */
7550 if (arg2 & (sizeof(abi_ulong) - 1)) {
7551 ret = -TARGET_EINVAL;
7552 break;
7553 }
7554 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7555
7556 mask = alloca(mask_size);
7557 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7558
7559 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09007560 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007561 goto efault;
7562 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007563 }
7564 }
7565 break;
7566 case TARGET_NR_sched_setaffinity:
7567 {
7568 unsigned int mask_size;
7569 unsigned long *mask;
7570
7571 /*
7572 * sched_setaffinity needs multiples of ulong, so need to take
7573 * care of mismatches between target ulong and host ulong sizes.
7574 */
7575 if (arg2 & (sizeof(abi_ulong) - 1)) {
7576 ret = -TARGET_EINVAL;
7577 break;
7578 }
7579 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7580
7581 mask = alloca(mask_size);
7582 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7583 goto efault;
7584 }
7585 memcpy(mask, p, arg2);
7586 unlock_user_struct(p, arg2, 0);
7587
7588 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7589 }
7590 break;
bellard31e31b82003-02-18 22:55:36 +00007591 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007592 {
pbrook53a59602006-03-25 19:31:22 +00007593 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007594 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007595
bellard579a97f2007-11-11 14:26:47 +00007596 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7597 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007598 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007599 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007600 ret = get_errno(sched_setparam(arg1, &schp));
7601 }
7602 break;
bellard31e31b82003-02-18 22:55:36 +00007603 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007604 {
pbrook53a59602006-03-25 19:31:22 +00007605 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007606 struct sched_param schp;
7607 ret = get_errno(sched_getparam(arg1, &schp));
7608 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007609 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7610 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007611 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007612 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007613 }
7614 }
7615 break;
bellard31e31b82003-02-18 22:55:36 +00007616 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007617 {
pbrook53a59602006-03-25 19:31:22 +00007618 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007619 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007620 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7621 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007622 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007623 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007624 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7625 }
7626 break;
bellard31e31b82003-02-18 22:55:36 +00007627 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007628 ret = get_errno(sched_getscheduler(arg1));
7629 break;
bellard31e31b82003-02-18 22:55:36 +00007630 case TARGET_NR_sched_yield:
7631 ret = get_errno(sched_yield());
7632 break;
7633 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007634 ret = get_errno(sched_get_priority_max(arg1));
7635 break;
bellard31e31b82003-02-18 22:55:36 +00007636 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007637 ret = get_errno(sched_get_priority_min(arg1));
7638 break;
bellard31e31b82003-02-18 22:55:36 +00007639 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007640 {
bellard5cd43932003-03-29 16:54:36 +00007641 struct timespec ts;
7642 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7643 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007644 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007645 }
7646 }
7647 break;
bellard31e31b82003-02-18 22:55:36 +00007648 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007649 {
bellard1b6b0292003-03-22 17:31:38 +00007650 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007651 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007652 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007653 if (is_error(ret) && arg2) {
7654 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007655 }
7656 }
7657 break;
thse5febef2007-04-01 18:31:35 +00007658#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007659 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007660 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007661#endif
7662#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007663 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007664 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007665#endif
bellard31e31b82003-02-18 22:55:36 +00007666 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007667 switch (arg1) {
7668 case PR_GET_PDEATHSIG:
7669 {
7670 int deathsig;
7671 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7672 if (!is_error(ret) && arg2
7673 && put_user_ual(deathsig, arg2)) {
7674 goto efault;
thse5574482007-02-11 20:03:13 +00007675 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007676 break;
7677 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007678#ifdef PR_GET_NAME
7679 case PR_GET_NAME:
7680 {
7681 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7682 if (!name) {
7683 goto efault;
7684 }
7685 ret = get_errno(prctl(arg1, (unsigned long)name,
7686 arg3, arg4, arg5));
7687 unlock_user(name, arg2, 16);
7688 break;
7689 }
7690 case PR_SET_NAME:
7691 {
7692 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7693 if (!name) {
7694 goto efault;
7695 }
7696 ret = get_errno(prctl(arg1, (unsigned long)name,
7697 arg3, arg4, arg5));
7698 unlock_user(name, arg2, 0);
7699 break;
7700 }
7701#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007702 default:
7703 /* Most prctl options have no pointer arguments */
7704 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7705 break;
7706 }
ths39b9aae2007-02-11 18:36:44 +00007707 break;
bellardd2fd1af2007-11-14 18:08:56 +00007708#ifdef TARGET_NR_arch_prctl
7709 case TARGET_NR_arch_prctl:
7710#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7711 ret = do_arch_prctl(cpu_env, arg1, arg2);
7712 break;
7713#else
7714 goto unimplemented;
7715#endif
7716#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007717#ifdef TARGET_NR_pread64
7718 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007719 if (regpairs_aligned(cpu_env)) {
7720 arg4 = arg5;
7721 arg5 = arg6;
7722 }
aurel32f2c7ba12008-03-28 22:32:06 +00007723 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7724 goto efault;
7725 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7726 unlock_user(p, arg2, ret);
7727 break;
7728 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00007729 if (regpairs_aligned(cpu_env)) {
7730 arg4 = arg5;
7731 arg5 = arg6;
7732 }
aurel32f2c7ba12008-03-28 22:32:06 +00007733 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7734 goto efault;
7735 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7736 unlock_user(p, arg2, 0);
7737 break;
7738#endif
bellard31e31b82003-02-18 22:55:36 +00007739 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007740 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7741 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007742 ret = get_errno(sys_getcwd1(p, arg2));
7743 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007744 break;
7745 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00007746 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007747 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00007748 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007749 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007750#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007751 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08007752 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007753 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007754 break;
7755#else
bellard5cd43932003-03-29 16:54:36 +00007756 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007757#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007758
7759#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00007760 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007761 {
7762 off_t *offp = NULL;
7763 off_t off;
7764 if (arg3) {
7765 ret = get_user_sal(off, arg3);
7766 if (is_error(ret)) {
7767 break;
7768 }
7769 offp = &off;
7770 }
7771 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7772 if (!is_error(ret) && arg3) {
7773 abi_long ret2 = put_user_sal(off, arg3);
7774 if (is_error(ret2)) {
7775 ret = ret2;
7776 }
7777 }
7778 break;
7779 }
7780#ifdef TARGET_NR_sendfile64
7781 case TARGET_NR_sendfile64:
7782 {
7783 off_t *offp = NULL;
7784 off_t off;
7785 if (arg3) {
7786 ret = get_user_s64(off, arg3);
7787 if (is_error(ret)) {
7788 break;
7789 }
7790 offp = &off;
7791 }
7792 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7793 if (!is_error(ret) && arg3) {
7794 abi_long ret2 = put_user_s64(off, arg3);
7795 if (is_error(ret2)) {
7796 ret = ret2;
7797 }
7798 }
7799 break;
7800 }
7801#endif
7802#else
7803 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01007804#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007805 case TARGET_NR_sendfile64:
7806#endif
bellard5cd43932003-03-29 16:54:36 +00007807 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007808#endif
7809
bellardebc05482003-09-30 21:08:41 +00007810#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007811 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007812 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007813#endif
7814#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007815 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007816 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007817#endif
bellard048f6b42005-11-26 18:47:20 +00007818#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007819 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007820 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7821 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007822 break;
bellard048f6b42005-11-26 18:47:20 +00007823#endif
bellardebc05482003-09-30 21:08:41 +00007824#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007825 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007826 {
7827 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007828 int resource = target_to_host_resource(arg1);
7829 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007830 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007831 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007832 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7833 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007834 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7835 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007836 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007837 }
7838 break;
7839 }
bellardebc05482003-09-30 21:08:41 +00007840#endif
bellarda315a142005-01-30 22:59:18 +00007841#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007842 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007843 if (!(p = lock_user_string(arg1)))
7844 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007845 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7846 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007847 break;
bellarda315a142005-01-30 22:59:18 +00007848#endif
7849#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00007850 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00007851 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00007852 break;
bellarda315a142005-01-30 22:59:18 +00007853#endif
7854#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00007855 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00007856 if (!(p = lock_user_string(arg1)))
7857 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007858 ret = get_errno(stat(path(p), &st));
7859 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007860 if (!is_error(ret))
7861 ret = host_to_target_stat64(cpu_env, arg2, &st);
7862 break;
bellarda315a142005-01-30 22:59:18 +00007863#endif
7864#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00007865 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00007866 if (!(p = lock_user_string(arg1)))
7867 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007868 ret = get_errno(lstat(path(p), &st));
7869 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007870 if (!is_error(ret))
7871 ret = host_to_target_stat64(cpu_env, arg2, &st);
7872 break;
bellarda315a142005-01-30 22:59:18 +00007873#endif
7874#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00007875 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00007876 ret = get_errno(fstat(arg1, &st));
7877 if (!is_error(ret))
7878 ret = host_to_target_stat64(cpu_env, arg2, &st);
7879 break;
bellardec86b0f2003-04-11 00:15:04 +00007880#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007881#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00007882#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007883 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007884#endif
7885#ifdef TARGET_NR_newfstatat
7886 case TARGET_NR_newfstatat:
7887#endif
balrog6a24a772008-09-20 02:23:36 +00007888 if (!(p = lock_user_string(arg2)))
7889 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007890 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00007891 if (!is_error(ret))
7892 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007893 break;
bellarda315a142005-01-30 22:59:18 +00007894#endif
bellard67867302003-11-23 17:05:30 +00007895 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007896 if (!(p = lock_user_string(arg1)))
7897 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007898 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7899 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007900 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007901#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007902 case TARGET_NR_getuid:
7903 ret = get_errno(high2lowuid(getuid()));
7904 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007905#endif
7906#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007907 case TARGET_NR_getgid:
7908 ret = get_errno(high2lowgid(getgid()));
7909 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007910#endif
7911#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007912 case TARGET_NR_geteuid:
7913 ret = get_errno(high2lowuid(geteuid()));
7914 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007915#endif
7916#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007917 case TARGET_NR_getegid:
7918 ret = get_errno(high2lowgid(getegid()));
7919 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007920#endif
bellard67867302003-11-23 17:05:30 +00007921 case TARGET_NR_setreuid:
7922 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7923 break;
7924 case TARGET_NR_setregid:
7925 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7926 break;
7927 case TARGET_NR_getgroups:
7928 {
7929 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007930 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007931 gid_t *grouplist;
7932 int i;
7933
7934 grouplist = alloca(gidsetsize * sizeof(gid_t));
7935 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007936 if (gidsetsize == 0)
7937 break;
bellard67867302003-11-23 17:05:30 +00007938 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00007939 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00007940 if (!target_grouplist)
7941 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007942 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007943 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007944 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00007945 }
7946 }
7947 break;
7948 case TARGET_NR_setgroups:
7949 {
7950 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007951 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007952 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00007953 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007954 if (gidsetsize) {
7955 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007956 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007957 if (!target_grouplist) {
7958 ret = -TARGET_EFAULT;
7959 goto fail;
7960 }
7961 for (i = 0; i < gidsetsize; i++) {
7962 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
7963 }
7964 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007965 }
bellard67867302003-11-23 17:05:30 +00007966 ret = get_errno(setgroups(gidsetsize, grouplist));
7967 }
7968 break;
7969 case TARGET_NR_fchown:
7970 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7971 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007972#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00007973 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007974 if (!(p = lock_user_string(arg2)))
7975 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007976 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
7977 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00007978 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007979 break;
7980#endif
bellard67867302003-11-23 17:05:30 +00007981#ifdef TARGET_NR_setresuid
7982 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007983 ret = get_errno(setresuid(low2highuid(arg1),
7984 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007985 low2highuid(arg3)));
7986 break;
7987#endif
7988#ifdef TARGET_NR_getresuid
7989 case TARGET_NR_getresuid:
7990 {
pbrook53a59602006-03-25 19:31:22 +00007991 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007992 ret = get_errno(getresuid(&ruid, &euid, &suid));
7993 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007994 if (put_user_u16(high2lowuid(ruid), arg1)
7995 || put_user_u16(high2lowuid(euid), arg2)
7996 || put_user_u16(high2lowuid(suid), arg3))
7997 goto efault;
bellard67867302003-11-23 17:05:30 +00007998 }
7999 }
8000 break;
8001#endif
8002#ifdef TARGET_NR_getresgid
8003 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00008004 ret = get_errno(setresgid(low2highgid(arg1),
8005 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00008006 low2highgid(arg3)));
8007 break;
8008#endif
8009#ifdef TARGET_NR_getresgid
8010 case TARGET_NR_getresgid:
8011 {
pbrook53a59602006-03-25 19:31:22 +00008012 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00008013 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8014 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008015 if (put_user_u16(high2lowgid(rgid), arg1)
8016 || put_user_u16(high2lowgid(egid), arg2)
8017 || put_user_u16(high2lowgid(sgid), arg3))
8018 goto efault;
bellard67867302003-11-23 17:05:30 +00008019 }
8020 }
8021 break;
8022#endif
8023 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00008024 if (!(p = lock_user_string(arg1)))
8025 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008026 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
8027 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008028 break;
8029 case TARGET_NR_setuid:
8030 ret = get_errno(setuid(low2highuid(arg1)));
8031 break;
8032 case TARGET_NR_setgid:
8033 ret = get_errno(setgid(low2highgid(arg1)));
8034 break;
8035 case TARGET_NR_setfsuid:
8036 ret = get_errno(setfsuid(arg1));
8037 break;
8038 case TARGET_NR_setfsgid:
8039 ret = get_errno(setfsgid(arg1));
8040 break;
bellard67867302003-11-23 17:05:30 +00008041
bellarda315a142005-01-30 22:59:18 +00008042#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00008043 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00008044 if (!(p = lock_user_string(arg1)))
8045 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008046 ret = get_errno(lchown(p, arg2, arg3));
8047 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008048 break;
bellarda315a142005-01-30 22:59:18 +00008049#endif
8050#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00008051 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00008052 ret = get_errno(getuid());
8053 break;
bellarda315a142005-01-30 22:59:18 +00008054#endif
aurel3264b4d282008-11-14 17:20:15 +00008055
8056#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8057 /* Alpha specific */
8058 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008059 {
8060 uid_t euid;
8061 euid=geteuid();
8062 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8063 }
aurel3264b4d282008-11-14 17:20:15 +00008064 ret = get_errno(getuid());
8065 break;
8066#endif
8067#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8068 /* Alpha specific */
8069 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008070 {
8071 uid_t egid;
8072 egid=getegid();
8073 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8074 }
aurel3264b4d282008-11-14 17:20:15 +00008075 ret = get_errno(getgid());
8076 break;
8077#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008078#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8079 /* Alpha specific */
8080 case TARGET_NR_osf_getsysinfo:
8081 ret = -TARGET_EOPNOTSUPP;
8082 switch (arg1) {
8083 case TARGET_GSI_IEEE_FP_CONTROL:
8084 {
8085 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8086
8087 /* Copied from linux ieee_fpcr_to_swcr. */
8088 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8089 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8090 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8091 | SWCR_TRAP_ENABLE_DZE
8092 | SWCR_TRAP_ENABLE_OVF);
8093 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8094 | SWCR_TRAP_ENABLE_INE);
8095 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8096 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8097
8098 if (put_user_u64 (swcr, arg2))
8099 goto efault;
8100 ret = 0;
8101 }
8102 break;
8103
8104 /* case GSI_IEEE_STATE_AT_SIGNAL:
8105 -- Not implemented in linux kernel.
8106 case GSI_UACPROC:
8107 -- Retrieves current unaligned access state; not much used.
8108 case GSI_PROC_TYPE:
8109 -- Retrieves implver information; surely not used.
8110 case GSI_GET_HWRPB:
8111 -- Grabs a copy of the HWRPB; surely not used.
8112 */
8113 }
8114 break;
8115#endif
8116#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8117 /* Alpha specific */
8118 case TARGET_NR_osf_setsysinfo:
8119 ret = -TARGET_EOPNOTSUPP;
8120 switch (arg1) {
8121 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008122 {
8123 uint64_t swcr, fpcr, orig_fpcr;
8124
Richard Henderson6e06d512012-06-01 09:08:21 -07008125 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008126 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008127 }
8128 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008129 fpcr = orig_fpcr & FPCR_DYN_MASK;
8130
8131 /* Copied from linux ieee_swcr_to_fpcr. */
8132 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8133 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8134 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8135 | SWCR_TRAP_ENABLE_DZE
8136 | SWCR_TRAP_ENABLE_OVF)) << 48;
8137 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8138 | SWCR_TRAP_ENABLE_INE)) << 57;
8139 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8140 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8141
Richard Henderson6e06d512012-06-01 09:08:21 -07008142 cpu_alpha_store_fpcr(cpu_env, fpcr);
8143 ret = 0;
8144 }
8145 break;
8146
8147 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8148 {
8149 uint64_t exc, fpcr, orig_fpcr;
8150 int si_code;
8151
8152 if (get_user_u64(exc, arg2)) {
8153 goto efault;
8154 }
8155
8156 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
8157
8158 /* We only add to the exception status here. */
8159 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
8160
8161 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008162 ret = 0;
8163
Richard Henderson6e06d512012-06-01 09:08:21 -07008164 /* Old exceptions are not signaled. */
8165 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008166
Richard Henderson6e06d512012-06-01 09:08:21 -07008167 /* If any exceptions set by this call,
8168 and are unmasked, send a signal. */
8169 si_code = 0;
8170 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
8171 si_code = TARGET_FPE_FLTRES;
8172 }
8173 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
8174 si_code = TARGET_FPE_FLTUND;
8175 }
8176 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
8177 si_code = TARGET_FPE_FLTOVF;
8178 }
8179 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
8180 si_code = TARGET_FPE_FLTDIV;
8181 }
8182 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
8183 si_code = TARGET_FPE_FLTINV;
8184 }
8185 if (si_code != 0) {
8186 target_siginfo_t info;
8187 info.si_signo = SIGFPE;
8188 info.si_errno = 0;
8189 info.si_code = si_code;
8190 info._sifields._sigfault._addr
8191 = ((CPUArchState *)cpu_env)->pc;
8192 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008193 }
8194 }
8195 break;
8196
8197 /* case SSI_NVPAIRS:
8198 -- Used with SSIN_UACPROC to enable unaligned accesses.
8199 case SSI_IEEE_STATE_AT_SIGNAL:
8200 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8201 -- Not implemented in linux kernel
8202 */
8203 }
8204 break;
8205#endif
8206#ifdef TARGET_NR_osf_sigprocmask
8207 /* Alpha specific. */
8208 case TARGET_NR_osf_sigprocmask:
8209 {
8210 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008211 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008212 sigset_t set, oldset;
8213
8214 switch(arg1) {
8215 case TARGET_SIG_BLOCK:
8216 how = SIG_BLOCK;
8217 break;
8218 case TARGET_SIG_UNBLOCK:
8219 how = SIG_UNBLOCK;
8220 break;
8221 case TARGET_SIG_SETMASK:
8222 how = SIG_SETMASK;
8223 break;
8224 default:
8225 ret = -TARGET_EINVAL;
8226 goto fail;
8227 }
8228 mask = arg2;
8229 target_to_host_old_sigset(&set, &mask);
Juan Quintelabc088ba2011-06-16 17:37:10 +01008230 sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008231 host_to_target_old_sigset(&mask, &oldset);
8232 ret = mask;
8233 }
8234 break;
8235#endif
aurel3264b4d282008-11-14 17:20:15 +00008236
bellarda315a142005-01-30 22:59:18 +00008237#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008238 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008239 ret = get_errno(getgid());
8240 break;
bellarda315a142005-01-30 22:59:18 +00008241#endif
8242#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00008243 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00008244 ret = get_errno(geteuid());
8245 break;
bellarda315a142005-01-30 22:59:18 +00008246#endif
8247#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00008248 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00008249 ret = get_errno(getegid());
8250 break;
bellarda315a142005-01-30 22:59:18 +00008251#endif
8252#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00008253 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00008254 ret = get_errno(setreuid(arg1, arg2));
8255 break;
bellarda315a142005-01-30 22:59:18 +00008256#endif
8257#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00008258 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00008259 ret = get_errno(setregid(arg1, arg2));
8260 break;
bellarda315a142005-01-30 22:59:18 +00008261#endif
8262#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00008263 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00008264 {
8265 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008266 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008267 gid_t *grouplist;
8268 int i;
8269
8270 grouplist = alloca(gidsetsize * sizeof(gid_t));
8271 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008272 if (gidsetsize == 0)
8273 break;
bellard99c475a2005-01-31 20:45:13 +00008274 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008275 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
8276 if (!target_grouplist) {
8277 ret = -TARGET_EFAULT;
8278 goto fail;
8279 }
balroga2155fc2008-09-20 02:12:08 +00008280 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00008281 target_grouplist[i] = tswap32(grouplist[i]);
8282 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00008283 }
8284 }
8285 break;
bellarda315a142005-01-30 22:59:18 +00008286#endif
8287#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00008288 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00008289 {
8290 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008291 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008292 gid_t *grouplist;
8293 int i;
ths3b46e622007-09-17 08:09:54 +00008294
bellard99c475a2005-01-31 20:45:13 +00008295 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00008296 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
8297 if (!target_grouplist) {
8298 ret = -TARGET_EFAULT;
8299 goto fail;
8300 }
bellard99c475a2005-01-31 20:45:13 +00008301 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00008302 grouplist[i] = tswap32(target_grouplist[i]);
8303 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00008304 ret = get_errno(setgroups(gidsetsize, grouplist));
8305 }
8306 break;
bellarda315a142005-01-30 22:59:18 +00008307#endif
8308#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00008309 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008310 ret = get_errno(fchown(arg1, arg2, arg3));
8311 break;
bellarda315a142005-01-30 22:59:18 +00008312#endif
8313#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008314 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008315 ret = get_errno(setresuid(arg1, arg2, arg3));
8316 break;
bellarda315a142005-01-30 22:59:18 +00008317#endif
8318#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008319 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008320 {
pbrook53a59602006-03-25 19:31:22 +00008321 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008322 ret = get_errno(getresuid(&ruid, &euid, &suid));
8323 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008324 if (put_user_u32(ruid, arg1)
8325 || put_user_u32(euid, arg2)
8326 || put_user_u32(suid, arg3))
8327 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008328 }
8329 }
8330 break;
bellarda315a142005-01-30 22:59:18 +00008331#endif
8332#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008333 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008334 ret = get_errno(setresgid(arg1, arg2, arg3));
8335 break;
bellarda315a142005-01-30 22:59:18 +00008336#endif
8337#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008338 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008339 {
pbrook53a59602006-03-25 19:31:22 +00008340 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008341 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8342 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008343 if (put_user_u32(rgid, arg1)
8344 || put_user_u32(egid, arg2)
8345 || put_user_u32(sgid, arg3))
8346 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008347 }
8348 }
8349 break;
bellarda315a142005-01-30 22:59:18 +00008350#endif
8351#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008352 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008353 if (!(p = lock_user_string(arg1)))
8354 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008355 ret = get_errno(chown(p, arg2, arg3));
8356 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008357 break;
bellarda315a142005-01-30 22:59:18 +00008358#endif
8359#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008360 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008361 ret = get_errno(setuid(arg1));
8362 break;
bellarda315a142005-01-30 22:59:18 +00008363#endif
8364#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008365 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008366 ret = get_errno(setgid(arg1));
8367 break;
bellarda315a142005-01-30 22:59:18 +00008368#endif
8369#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008370 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008371 ret = get_errno(setfsuid(arg1));
8372 break;
bellarda315a142005-01-30 22:59:18 +00008373#endif
8374#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008375 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008376 ret = get_errno(setfsgid(arg1));
8377 break;
bellarda315a142005-01-30 22:59:18 +00008378#endif
bellard67867302003-11-23 17:05:30 +00008379
bellard31e31b82003-02-18 22:55:36 +00008380 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008381 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008382#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008383 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008384 {
8385 void *a;
8386 ret = -TARGET_EFAULT;
8387 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8388 goto efault;
8389 if (!(p = lock_user_string(arg3)))
8390 goto mincore_fail;
8391 ret = get_errno(mincore(a, arg2, p));
8392 unlock_user(p, arg3, ret);
8393 mincore_fail:
8394 unlock_user(a, arg1, 0);
8395 }
8396 break;
bellardffa65c32004-01-04 23:57:22 +00008397#endif
aurel32408321b2008-10-01 21:46:32 +00008398#ifdef TARGET_NR_arm_fadvise64_64
8399 case TARGET_NR_arm_fadvise64_64:
8400 {
8401 /*
8402 * arm_fadvise64_64 looks like fadvise64_64 but
8403 * with different argument order
8404 */
8405 abi_long temp;
8406 temp = arg3;
8407 arg3 = arg4;
8408 arg4 = temp;
8409 }
8410#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008411#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008412#ifdef TARGET_NR_fadvise64_64
8413 case TARGET_NR_fadvise64_64:
8414#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008415#ifdef TARGET_NR_fadvise64
8416 case TARGET_NR_fadvise64:
8417#endif
8418#ifdef TARGET_S390X
8419 switch (arg4) {
8420 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8421 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8422 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8423 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8424 default: break;
8425 }
8426#endif
8427 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008428 break;
8429#endif
bellardffa65c32004-01-04 23:57:22 +00008430#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008431 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008432 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08008433 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00008434 This will break MADV_DONTNEED.
8435 This is a hint, so ignoring and returning success is ok. */
8436 ret = get_errno(0);
8437 break;
bellardffa65c32004-01-04 23:57:22 +00008438#endif
blueswir1992f48a2007-10-14 16:27:31 +00008439#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008440 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008441 {
thsb1e341e2007-03-20 21:50:52 +00008442 int cmd;
bellard77e46722003-04-29 20:39:06 +00008443 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008444 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008445#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008446 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008447#endif
bellard77e46722003-04-29 20:39:06 +00008448
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008449 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008450 if (cmd == -TARGET_EINVAL) {
8451 ret = cmd;
8452 break;
8453 }
thsb1e341e2007-03-20 21:50:52 +00008454
bellard60cd49d2003-03-16 22:53:56 +00008455 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008456 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008457#ifdef TARGET_ARM
8458 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008459 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8460 goto efault;
ths58134272007-03-31 18:59:32 +00008461 fl.l_type = tswap16(target_efl->l_type);
8462 fl.l_whence = tswap16(target_efl->l_whence);
8463 fl.l_start = tswap64(target_efl->l_start);
8464 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008465 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008466 unlock_user_struct(target_efl, arg3, 0);
8467 } else
8468#endif
8469 {
bellard9ee1fa22007-11-11 15:11:19 +00008470 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8471 goto efault;
ths58134272007-03-31 18:59:32 +00008472 fl.l_type = tswap16(target_fl->l_type);
8473 fl.l_whence = tswap16(target_fl->l_whence);
8474 fl.l_start = tswap64(target_fl->l_start);
8475 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008476 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008477 unlock_user_struct(target_fl, arg3, 0);
8478 }
thsb1e341e2007-03-20 21:50:52 +00008479 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008480 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008481#ifdef TARGET_ARM
8482 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008483 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8484 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008485 target_efl->l_type = tswap16(fl.l_type);
8486 target_efl->l_whence = tswap16(fl.l_whence);
8487 target_efl->l_start = tswap64(fl.l_start);
8488 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008489 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008490 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008491 } else
8492#endif
8493 {
bellard9ee1fa22007-11-11 15:11:19 +00008494 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8495 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008496 target_fl->l_type = tswap16(fl.l_type);
8497 target_fl->l_whence = tswap16(fl.l_whence);
8498 target_fl->l_start = tswap64(fl.l_start);
8499 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008500 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008501 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008502 }
bellard77e46722003-04-29 20:39:06 +00008503 }
8504 break;
8505
thsb1e341e2007-03-20 21:50:52 +00008506 case TARGET_F_SETLK64:
8507 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008508#ifdef TARGET_ARM
8509 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008510 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8511 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008512 fl.l_type = tswap16(target_efl->l_type);
8513 fl.l_whence = tswap16(target_efl->l_whence);
8514 fl.l_start = tswap64(target_efl->l_start);
8515 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008516 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008517 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008518 } else
8519#endif
8520 {
bellard9ee1fa22007-11-11 15:11:19 +00008521 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8522 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008523 fl.l_type = tswap16(target_fl->l_type);
8524 fl.l_whence = tswap16(target_fl->l_whence);
8525 fl.l_start = tswap64(target_fl->l_start);
8526 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008527 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008528 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008529 }
thsb1e341e2007-03-20 21:50:52 +00008530 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008531 break;
bellard60cd49d2003-03-16 22:53:56 +00008532 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008533 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008534 break;
8535 }
bellard77e46722003-04-29 20:39:06 +00008536 break;
8537 }
bellard60cd49d2003-03-16 22:53:56 +00008538#endif
ths7d600c82006-12-08 01:32:58 +00008539#ifdef TARGET_NR_cacheflush
8540 case TARGET_NR_cacheflush:
8541 /* self-modifying code is handled automatically, so nothing needed */
8542 ret = 0;
8543 break;
8544#endif
bellardebc05482003-09-30 21:08:41 +00008545#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008546 case TARGET_NR_security:
8547 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008548#endif
bellardc573ff62004-01-04 15:51:36 +00008549#ifdef TARGET_NR_getpagesize
8550 case TARGET_NR_getpagesize:
8551 ret = TARGET_PAGE_SIZE;
8552 break;
8553#endif
bellard31e31b82003-02-18 22:55:36 +00008554 case TARGET_NR_gettid:
8555 ret = get_errno(gettid());
8556 break;
thse5febef2007-04-01 18:31:35 +00008557#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008558 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008559#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008560 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008561 arg2 = arg3;
8562 arg3 = arg4;
8563 arg4 = arg5;
8564 }
aurel322054ac92008-10-13 21:08:07 +00008565 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8566#else
8567 ret = get_errno(readahead(arg1, arg2, arg3));
8568#endif
8569 break;
thse5febef2007-04-01 18:31:35 +00008570#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008571#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008572#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008573 case TARGET_NR_listxattr:
8574 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008575 {
8576 void *p, *b = 0;
8577 if (arg2) {
8578 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8579 if (!b) {
8580 ret = -TARGET_EFAULT;
8581 break;
8582 }
8583 }
8584 p = lock_user_string(arg1);
8585 if (p) {
8586 if (num == TARGET_NR_listxattr) {
8587 ret = get_errno(listxattr(p, b, arg3));
8588 } else {
8589 ret = get_errno(llistxattr(p, b, arg3));
8590 }
8591 } else {
8592 ret = -TARGET_EFAULT;
8593 }
8594 unlock_user(p, arg1, 0);
8595 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008596 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008597 }
8598 case TARGET_NR_flistxattr:
8599 {
8600 void *b = 0;
8601 if (arg2) {
8602 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8603 if (!b) {
8604 ret = -TARGET_EFAULT;
8605 break;
8606 }
8607 }
8608 ret = get_errno(flistxattr(arg1, b, arg3));
8609 unlock_user(b, arg2, arg3);
8610 break;
8611 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008612 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008613 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008614 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008615 void *p, *n, *v = 0;
8616 if (arg3) {
8617 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8618 if (!v) {
8619 ret = -TARGET_EFAULT;
8620 break;
8621 }
8622 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008623 p = lock_user_string(arg1);
8624 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008625 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008626 if (num == TARGET_NR_setxattr) {
8627 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8628 } else {
8629 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8630 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008631 } else {
8632 ret = -TARGET_EFAULT;
8633 }
8634 unlock_user(p, arg1, 0);
8635 unlock_user(n, arg2, 0);
8636 unlock_user(v, arg3, 0);
8637 }
8638 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008639 case TARGET_NR_fsetxattr:
8640 {
8641 void *n, *v = 0;
8642 if (arg3) {
8643 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8644 if (!v) {
8645 ret = -TARGET_EFAULT;
8646 break;
8647 }
8648 }
8649 n = lock_user_string(arg2);
8650 if (n) {
8651 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8652 } else {
8653 ret = -TARGET_EFAULT;
8654 }
8655 unlock_user(n, arg2, 0);
8656 unlock_user(v, arg3, 0);
8657 }
8658 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008659 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008660 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008661 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008662 void *p, *n, *v = 0;
8663 if (arg3) {
8664 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8665 if (!v) {
8666 ret = -TARGET_EFAULT;
8667 break;
8668 }
8669 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008670 p = lock_user_string(arg1);
8671 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008672 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008673 if (num == TARGET_NR_getxattr) {
8674 ret = get_errno(getxattr(p, n, v, arg4));
8675 } else {
8676 ret = get_errno(lgetxattr(p, n, v, arg4));
8677 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008678 } else {
8679 ret = -TARGET_EFAULT;
8680 }
8681 unlock_user(p, arg1, 0);
8682 unlock_user(n, arg2, 0);
8683 unlock_user(v, arg3, arg4);
8684 }
8685 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008686 case TARGET_NR_fgetxattr:
8687 {
8688 void *n, *v = 0;
8689 if (arg3) {
8690 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8691 if (!v) {
8692 ret = -TARGET_EFAULT;
8693 break;
8694 }
8695 }
8696 n = lock_user_string(arg2);
8697 if (n) {
8698 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8699 } else {
8700 ret = -TARGET_EFAULT;
8701 }
8702 unlock_user(n, arg2, 0);
8703 unlock_user(v, arg3, arg4);
8704 }
8705 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008706 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008707 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008708 {
8709 void *p, *n;
8710 p = lock_user_string(arg1);
8711 n = lock_user_string(arg2);
8712 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008713 if (num == TARGET_NR_removexattr) {
8714 ret = get_errno(removexattr(p, n));
8715 } else {
8716 ret = get_errno(lremovexattr(p, n));
8717 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008718 } else {
8719 ret = -TARGET_EFAULT;
8720 }
8721 unlock_user(p, arg1, 0);
8722 unlock_user(n, arg2, 0);
8723 }
8724 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008725 case TARGET_NR_fremovexattr:
8726 {
8727 void *n;
8728 n = lock_user_string(arg2);
8729 if (n) {
8730 ret = get_errno(fremovexattr(arg1, n));
8731 } else {
8732 ret = -TARGET_EFAULT;
8733 }
8734 unlock_user(n, arg2, 0);
8735 }
8736 break;
bellardebc05482003-09-30 21:08:41 +00008737#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008738#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008739#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008740 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008741#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00008742 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
8743 ret = 0;
8744 break;
edgar_iglef967792009-01-07 14:19:38 +00008745#elif defined(TARGET_CRIS)
8746 if (arg1 & 0xff)
8747 ret = -TARGET_EINVAL;
8748 else {
8749 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8750 ret = 0;
8751 }
8752 break;
bellard8d18e892007-11-14 15:18:40 +00008753#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8754 ret = do_set_thread_area(cpu_env, arg1);
8755 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008756#elif defined(TARGET_M68K)
8757 {
8758 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
8759 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01008760 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008761 break;
8762 }
ths6f5b89a2007-03-02 20:48:00 +00008763#else
8764 goto unimplemented_nowarn;
8765#endif
8766#endif
8767#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008768 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008769#if defined(TARGET_I386) && defined(TARGET_ABI32)
8770 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01008771 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008772#elif defined(TARGET_M68K)
8773 {
8774 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
8775 ret = ts->tp_value;
8776 break;
8777 }
bellard8d18e892007-11-14 15:18:40 +00008778#else
bellard5cd43932003-03-29 16:54:36 +00008779 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008780#endif
bellard8d18e892007-11-14 15:18:40 +00008781#endif
bellard48dc41e2006-06-21 18:15:50 +00008782#ifdef TARGET_NR_getdomainname
8783 case TARGET_NR_getdomainname:
8784 goto unimplemented_nowarn;
8785#endif
ths6f5b89a2007-03-02 20:48:00 +00008786
thsb5906f92007-03-19 13:32:45 +00008787#ifdef TARGET_NR_clock_gettime
8788 case TARGET_NR_clock_gettime:
8789 {
8790 struct timespec ts;
8791 ret = get_errno(clock_gettime(arg1, &ts));
8792 if (!is_error(ret)) {
8793 host_to_target_timespec(arg2, &ts);
8794 }
8795 break;
8796 }
8797#endif
8798#ifdef TARGET_NR_clock_getres
8799 case TARGET_NR_clock_getres:
8800 {
8801 struct timespec ts;
8802 ret = get_errno(clock_getres(arg1, &ts));
8803 if (!is_error(ret)) {
8804 host_to_target_timespec(arg2, &ts);
8805 }
8806 break;
8807 }
8808#endif
pbrook63d76512008-05-29 13:43:29 +00008809#ifdef TARGET_NR_clock_nanosleep
8810 case TARGET_NR_clock_nanosleep:
8811 {
8812 struct timespec ts;
8813 target_to_host_timespec(&ts, arg3);
8814 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8815 if (arg4)
8816 host_to_target_timespec(arg4, &ts);
8817 break;
8818 }
8819#endif
thsb5906f92007-03-19 13:32:45 +00008820
ths6f5b89a2007-03-02 20:48:00 +00008821#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8822 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008823 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8824 break;
ths6f5b89a2007-03-02 20:48:00 +00008825#endif
8826
ths3ae43202007-09-16 21:39:48 +00008827#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008828 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008829 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008830 break;
8831#endif
8832
ths3ae43202007-09-16 21:39:48 +00008833#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008834 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008835 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8836 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008837 break;
8838#endif
8839
ths4f2b1fe2007-06-21 21:57:12 +00008840#ifdef TARGET_NR_set_robust_list
8841 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00008842 case TARGET_NR_get_robust_list:
8843 /* The ABI for supporting robust futexes has userspace pass
8844 * the kernel a pointer to a linked list which is updated by
8845 * userspace after the syscall; the list is walked by the kernel
8846 * when the thread exits. Since the linked list in QEMU guest
8847 * memory isn't a valid linked list for the host and we have
8848 * no way to reliably intercept the thread-death event, we can't
8849 * support these. Silently return ENOSYS so that guest userspace
8850 * falls back to a non-robust futex implementation (which should
8851 * be OK except in the corner case of the guest crashing while
8852 * holding a mutex that is shared with another process via
8853 * shared memory).
8854 */
8855 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00008856#endif
8857
Peter Maydell1acae9f2013-07-02 14:04:12 +01008858#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00008859 case TARGET_NR_utimensat:
8860 {
Riku Voipioebc996f2009-04-21 15:01:51 +03008861 struct timespec *tsp, ts[2];
8862 if (!arg3) {
8863 tsp = NULL;
8864 } else {
8865 target_to_host_timespec(ts, arg3);
8866 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
8867 tsp = ts;
8868 }
ths9007f0e2007-09-25 17:50:37 +00008869 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03008870 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00008871 else {
bellard579a97f2007-11-11 14:26:47 +00008872 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00008873 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008874 goto fail;
8875 }
Riku Voipioebc996f2009-04-21 15:01:51 +03008876 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00008877 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00008878 }
8879 }
8880 break;
8881#endif
pbrookbd0c5662008-05-29 14:34:11 +00008882 case TARGET_NR_futex:
8883 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
8884 break;
aurel32dbfe4c32009-04-08 21:29:30 +00008885#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00008886 case TARGET_NR_inotify_init:
8887 ret = get_errno(sys_inotify_init());
8888 break;
8889#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008890#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00008891#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
8892 case TARGET_NR_inotify_init1:
8893 ret = get_errno(sys_inotify_init1(arg1));
8894 break;
8895#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008896#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008897#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00008898 case TARGET_NR_inotify_add_watch:
8899 p = lock_user_string(arg2);
8900 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
8901 unlock_user(p, arg2, 0);
8902 break;
8903#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008904#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00008905 case TARGET_NR_inotify_rm_watch:
8906 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
8907 break;
8908#endif
ths9007f0e2007-09-25 17:50:37 +00008909
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07008910#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00008911 case TARGET_NR_mq_open:
8912 {
8913 struct mq_attr posix_mq_attr;
8914
8915 p = lock_user_string(arg1 - 1);
8916 if (arg4 != 0)
8917 copy_from_user_mq_attr (&posix_mq_attr, arg4);
8918 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
8919 unlock_user (p, arg1, 0);
8920 }
8921 break;
8922
8923 case TARGET_NR_mq_unlink:
8924 p = lock_user_string(arg1 - 1);
8925 ret = get_errno(mq_unlink(p));
8926 unlock_user (p, arg1, 0);
8927 break;
8928
8929 case TARGET_NR_mq_timedsend:
8930 {
8931 struct timespec ts;
8932
8933 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8934 if (arg5 != 0) {
8935 target_to_host_timespec(&ts, arg5);
8936 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
8937 host_to_target_timespec(arg5, &ts);
8938 }
8939 else
8940 ret = get_errno(mq_send(arg1, p, arg3, arg4));
8941 unlock_user (p, arg2, arg3);
8942 }
8943 break;
8944
8945 case TARGET_NR_mq_timedreceive:
8946 {
8947 struct timespec ts;
8948 unsigned int prio;
8949
8950 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8951 if (arg5 != 0) {
8952 target_to_host_timespec(&ts, arg5);
8953 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
8954 host_to_target_timespec(arg5, &ts);
8955 }
8956 else
8957 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
8958 unlock_user (p, arg2, arg3);
8959 if (arg4 != 0)
8960 put_user_u32(prio, arg4);
8961 }
8962 break;
8963
8964 /* Not implemented for now... */
8965/* case TARGET_NR_mq_notify: */
8966/* break; */
8967
8968 case TARGET_NR_mq_getsetattr:
8969 {
8970 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
8971 ret = 0;
8972 if (arg3 != 0) {
8973 ret = mq_getattr(arg1, &posix_mq_attr_out);
8974 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
8975 }
8976 if (arg2 != 0) {
8977 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
8978 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
8979 }
8980
8981 }
8982 break;
8983#endif
8984
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308985#ifdef CONFIG_SPLICE
8986#ifdef TARGET_NR_tee
8987 case TARGET_NR_tee:
8988 {
8989 ret = get_errno(tee(arg1,arg2,arg3,arg4));
8990 }
8991 break;
8992#endif
8993#ifdef TARGET_NR_splice
8994 case TARGET_NR_splice:
8995 {
8996 loff_t loff_in, loff_out;
8997 loff_t *ploff_in = NULL, *ploff_out = NULL;
8998 if(arg2) {
8999 get_user_u64(loff_in, arg2);
9000 ploff_in = &loff_in;
9001 }
9002 if(arg4) {
9003 get_user_u64(loff_out, arg2);
9004 ploff_out = &loff_out;
9005 }
9006 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
9007 }
9008 break;
9009#endif
9010#ifdef TARGET_NR_vmsplice
9011 case TARGET_NR_vmsplice:
9012 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009013 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9014 if (vec != NULL) {
9015 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
9016 unlock_iovec(vec, arg2, arg3, 0);
9017 } else {
9018 ret = -host_to_target_errno(errno);
9019 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309020 }
9021 break;
9022#endif
9023#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03009024#ifdef CONFIG_EVENTFD
9025#if defined(TARGET_NR_eventfd)
9026 case TARGET_NR_eventfd:
9027 ret = get_errno(eventfd(arg1, 0));
9028 break;
9029#endif
9030#if defined(TARGET_NR_eventfd2)
9031 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02009032 {
9033 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
9034 if (arg2 & TARGET_O_NONBLOCK) {
9035 host_flags |= O_NONBLOCK;
9036 }
9037 if (arg2 & TARGET_O_CLOEXEC) {
9038 host_flags |= O_CLOEXEC;
9039 }
9040 ret = get_errno(eventfd(arg1, host_flags));
Riku Voipioc2882b92009-08-12 15:08:24 +03009041 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02009042 }
Riku Voipioc2882b92009-08-12 15:08:24 +03009043#endif
9044#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03009045#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
9046 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01009047#if TARGET_ABI_BITS == 32
9048 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
9049 target_offset64(arg5, arg6)));
9050#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03009051 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01009052#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009053 break;
9054#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009055#if defined(CONFIG_SYNC_FILE_RANGE)
9056#if defined(TARGET_NR_sync_file_range)
9057 case TARGET_NR_sync_file_range:
9058#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009059#if defined(TARGET_MIPS)
9060 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9061 target_offset64(arg5, arg6), arg7));
9062#else
Peter Maydellc727f472011-01-06 11:05:10 +00009063 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9064 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009065#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009066#else
9067 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9068#endif
9069 break;
9070#endif
9071#if defined(TARGET_NR_sync_file_range2)
9072 case TARGET_NR_sync_file_range2:
9073 /* This is like sync_file_range but the arguments are reordered */
9074#if TARGET_ABI_BITS == 32
9075 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9076 target_offset64(arg5, arg6), arg2));
9077#else
9078 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9079#endif
9080 break;
9081#endif
9082#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009083#if defined(CONFIG_EPOLL)
9084#if defined(TARGET_NR_epoll_create)
9085 case TARGET_NR_epoll_create:
9086 ret = get_errno(epoll_create(arg1));
9087 break;
9088#endif
9089#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9090 case TARGET_NR_epoll_create1:
9091 ret = get_errno(epoll_create1(arg1));
9092 break;
9093#endif
9094#if defined(TARGET_NR_epoll_ctl)
9095 case TARGET_NR_epoll_ctl:
9096 {
9097 struct epoll_event ep;
9098 struct epoll_event *epp = 0;
9099 if (arg4) {
9100 struct target_epoll_event *target_ep;
9101 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9102 goto efault;
9103 }
9104 ep.events = tswap32(target_ep->events);
9105 /* The epoll_data_t union is just opaque data to the kernel,
9106 * so we transfer all 64 bits across and need not worry what
9107 * actual data type it is.
9108 */
9109 ep.data.u64 = tswap64(target_ep->data.u64);
9110 unlock_user_struct(target_ep, arg4, 0);
9111 epp = &ep;
9112 }
9113 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9114 break;
9115 }
9116#endif
9117
9118#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
9119#define IMPLEMENT_EPOLL_PWAIT
9120#endif
9121#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
9122#if defined(TARGET_NR_epoll_wait)
9123 case TARGET_NR_epoll_wait:
9124#endif
9125#if defined(IMPLEMENT_EPOLL_PWAIT)
9126 case TARGET_NR_epoll_pwait:
9127#endif
9128 {
9129 struct target_epoll_event *target_ep;
9130 struct epoll_event *ep;
9131 int epfd = arg1;
9132 int maxevents = arg3;
9133 int timeout = arg4;
9134
9135 target_ep = lock_user(VERIFY_WRITE, arg2,
9136 maxevents * sizeof(struct target_epoll_event), 1);
9137 if (!target_ep) {
9138 goto efault;
9139 }
9140
9141 ep = alloca(maxevents * sizeof(struct epoll_event));
9142
9143 switch (num) {
9144#if defined(IMPLEMENT_EPOLL_PWAIT)
9145 case TARGET_NR_epoll_pwait:
9146 {
9147 target_sigset_t *target_set;
9148 sigset_t _set, *set = &_set;
9149
9150 if (arg5) {
9151 target_set = lock_user(VERIFY_READ, arg5,
9152 sizeof(target_sigset_t), 1);
9153 if (!target_set) {
9154 unlock_user(target_ep, arg2, 0);
9155 goto efault;
9156 }
9157 target_to_host_sigset(set, target_set);
9158 unlock_user(target_set, arg5, 0);
9159 } else {
9160 set = NULL;
9161 }
9162
9163 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
9164 break;
9165 }
9166#endif
9167#if defined(TARGET_NR_epoll_wait)
9168 case TARGET_NR_epoll_wait:
9169 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
9170 break;
9171#endif
9172 default:
9173 ret = -TARGET_ENOSYS;
9174 }
9175 if (!is_error(ret)) {
9176 int i;
9177 for (i = 0; i < ret; i++) {
9178 target_ep[i].events = tswap32(ep[i].events);
9179 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
9180 }
9181 }
9182 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
9183 break;
9184 }
9185#endif
9186#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01009187#ifdef TARGET_NR_prlimit64
9188 case TARGET_NR_prlimit64:
9189 {
9190 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
9191 struct target_rlimit64 *target_rnew, *target_rold;
9192 struct host_rlimit64 rnew, rold, *rnewp = 0;
9193 if (arg3) {
9194 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
9195 goto efault;
9196 }
9197 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
9198 rnew.rlim_max = tswap64(target_rnew->rlim_max);
9199 unlock_user_struct(target_rnew, arg3, 0);
9200 rnewp = &rnew;
9201 }
9202
9203 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
9204 if (!is_error(ret) && arg4) {
9205 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
9206 goto efault;
9207 }
9208 target_rold->rlim_cur = tswap64(rold.rlim_cur);
9209 target_rold->rlim_max = tswap64(rold.rlim_max);
9210 unlock_user_struct(target_rold, arg4, 1);
9211 }
9212 break;
9213 }
9214#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07009215#ifdef TARGET_NR_gethostname
9216 case TARGET_NR_gethostname:
9217 {
9218 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9219 if (name) {
9220 ret = get_errno(gethostname(name, arg2));
9221 unlock_user(name, arg1, arg2);
9222 } else {
9223 ret = -TARGET_EFAULT;
9224 }
9225 break;
9226 }
9227#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009228#ifdef TARGET_NR_atomic_cmpxchg_32
9229 case TARGET_NR_atomic_cmpxchg_32:
9230 {
9231 /* should use start_exclusive from main.c */
9232 abi_ulong mem_value;
9233 if (get_user_u32(mem_value, arg6)) {
9234 target_siginfo_t info;
9235 info.si_signo = SIGSEGV;
9236 info.si_errno = 0;
9237 info.si_code = TARGET_SEGV_MAPERR;
9238 info._sifields._sigfault._addr = arg6;
9239 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
9240 ret = 0xdeadbeef;
9241
9242 }
9243 if (mem_value == arg2)
9244 put_user_u32(arg1, arg6);
9245 ret = mem_value;
9246 break;
9247 }
9248#endif
9249#ifdef TARGET_NR_atomic_barrier
9250 case TARGET_NR_atomic_barrier:
9251 {
9252 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
9253 break;
9254 }
9255#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009256
9257#ifdef TARGET_NR_timer_create
9258 case TARGET_NR_timer_create:
9259 {
9260 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
9261
9262 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
9263 struct target_sigevent *ptarget_sevp;
9264 struct target_timer_t *ptarget_timer;
9265
9266 int clkid = arg1;
9267 int timer_index = next_free_host_timer();
9268
9269 if (timer_index < 0) {
9270 ret = -TARGET_EAGAIN;
9271 } else {
9272 timer_t *phtimer = g_posix_timers + timer_index;
9273
9274 if (arg2) {
9275 if (!lock_user_struct(VERIFY_READ, ptarget_sevp, arg2, 1)) {
9276 goto efault;
9277 }
9278
9279 host_sevp.sigev_signo = tswap32(ptarget_sevp->sigev_signo);
9280 host_sevp.sigev_notify = tswap32(ptarget_sevp->sigev_notify);
9281
9282 phost_sevp = &host_sevp;
9283 }
9284
9285 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
9286 if (ret) {
9287 phtimer = NULL;
9288 } else {
9289 if (!lock_user_struct(VERIFY_WRITE, ptarget_timer, arg3, 1)) {
9290 goto efault;
9291 }
9292 ptarget_timer->ptr = tswap32(0xcafe0000 | timer_index);
9293 unlock_user_struct(ptarget_timer, arg3, 1);
9294 }
9295 }
9296 break;
9297 }
9298#endif
9299
9300#ifdef TARGET_NR_timer_settime
9301 case TARGET_NR_timer_settime:
9302 {
9303 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
9304 * struct itimerspec * old_value */
9305 arg1 &= 0xffff;
9306 if (arg3 == 0 || arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9307 ret = -TARGET_EINVAL;
9308 } else {
9309 timer_t htimer = g_posix_timers[arg1];
9310 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
9311
9312 target_to_host_itimerspec(&hspec_new, arg3);
9313 ret = get_errno(
9314 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
9315 host_to_target_itimerspec(arg2, &hspec_old);
9316 }
9317 break;
9318 }
9319#endif
9320
9321#ifdef TARGET_NR_timer_gettime
9322 case TARGET_NR_timer_gettime:
9323 {
9324 /* args: timer_t timerid, struct itimerspec *curr_value */
9325 arg1 &= 0xffff;
9326 if (!arg2) {
9327 return -TARGET_EFAULT;
9328 } else if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9329 ret = -TARGET_EINVAL;
9330 } else {
9331 timer_t htimer = g_posix_timers[arg1];
9332 struct itimerspec hspec;
9333 ret = get_errno(timer_gettime(htimer, &hspec));
9334
9335 if (host_to_target_itimerspec(arg2, &hspec)) {
9336 ret = -TARGET_EFAULT;
9337 }
9338 }
9339 break;
9340 }
9341#endif
9342
9343#ifdef TARGET_NR_timer_getoverrun
9344 case TARGET_NR_timer_getoverrun:
9345 {
9346 /* args: timer_t timerid */
9347 arg1 &= 0xffff;
9348 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9349 ret = -TARGET_EINVAL;
9350 } else {
9351 timer_t htimer = g_posix_timers[arg1];
9352 ret = get_errno(timer_getoverrun(htimer));
9353 }
9354 break;
9355 }
9356#endif
9357
9358#ifdef TARGET_NR_timer_delete
9359 case TARGET_NR_timer_delete:
9360 {
9361 /* args: timer_t timerid */
9362 arg1 &= 0xffff;
9363 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9364 ret = -TARGET_EINVAL;
9365 } else {
9366 timer_t htimer = g_posix_timers[arg1];
9367 ret = get_errno(timer_delete(htimer));
9368 g_posix_timers[arg1] = 0;
9369 }
9370 break;
9371 }
9372#endif
9373
bellard31e31b82003-02-18 22:55:36 +00009374 default:
9375 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00009376 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00009377#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 +00009378 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00009379#endif
ths0da46a62007-10-20 20:23:07 +00009380 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00009381 break;
9382 }
bellard579a97f2007-11-11 14:26:47 +00009383fail:
bellardc573ff62004-01-04 15:51:36 +00009384#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00009385 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00009386#endif
thsb92c47c2007-11-01 00:07:38 +00009387 if(do_strace)
9388 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00009389 return ret;
bellard579a97f2007-11-11 14:26:47 +00009390efault:
9391 ret = -TARGET_EFAULT;
9392 goto fail;
bellard31e31b82003-02-18 22:55:36 +00009393}