blob: 6d70ef0979976ccf53c8c4d3385e9139e75cb7c8 [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>
bellard31e31b82003-02-18 22:55:36 +000031#include <sys/types.h>
thsd08d3bb2007-03-19 13:09:22 +000032#include <sys/ipc.h>
33#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000034#include <sys/wait.h>
35#include <sys/time.h>
36#include <sys/stat.h>
37#include <sys/mount.h>
ths39b9aae2007-02-11 18:36:44 +000038#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000039#include <sys/resource.h>
40#include <sys/mman.h>
41#include <sys/swap.h>
42#include <signal.h>
43#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020044#ifdef __ia64__
45int __clone2(int (*fn)(void *), void *child_stack_base,
46 size_t stack_size, int flags, void *arg, ...);
47#endif
bellard31e31b82003-02-18 22:55:36 +000048#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000049#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000050#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000051#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000052#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000053#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000054#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000055#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000056#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000057#include <sys/sysinfo.h>
aurel323b3f24a2009-04-15 16:12:13 +000058#include <sys/utsname.h>
bellard72f03902003-02-18 23:33:18 +000059//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000060#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000061#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020062#include <linux/wireless.h>
Jing Huang79bbbaa2012-07-23 13:50:58 +000063#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020064#include "qemu-common.h"
Juan Quintela9788c9c2009-07-27 16:13:02 +020065#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000066#include <sys/gmon.h>
67#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030068#ifdef CONFIG_EVENTFD
69#include <sys/eventfd.h>
70#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000071#ifdef CONFIG_EPOLL
72#include <sys/epoll.h>
73#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070074#ifdef CONFIG_ATTR
Avi Kivity4f26f2b2011-11-09 14:44:52 +020075#include "qemu-xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070076#endif
bellard31e31b82003-02-18 22:55:36 +000077
78#define termios host_termios
79#define winsize host_winsize
80#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000081#define sgttyb host_sgttyb /* same as target */
82#define tchars host_tchars /* same as target */
83#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000084
85#include <linux/termios.h>
86#include <linux/unistd.h>
87#include <linux/utsname.h>
88#include <linux/cdrom.h>
89#include <linux/hdreg.h>
90#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000091#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000092#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030093#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000094#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000095#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000096#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020097#include <linux/fb.h>
98#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +010099#include <linux/dm-ioctl.h>
pbrookd7e40362008-05-23 16:06:43 +0000100#include "linux_loop.h"
Loïc Minierda790302009-12-29 22:06:13 +0100101#include "cpu-uname.h"
bellard31e31b82003-02-18 22:55:36 +0000102
bellard3ef693a2003-03-23 20:17:16 +0000103#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000104
Juan Quintela2f7bb872009-07-27 16:13:24 +0200105#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +0000106#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
107 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
108#else
109/* XXX: Hardcode the above values. */
110#define CLONE_NPTL_FLAGS2 0
pbrook30813ce2008-06-02 15:45:44 +0000111#endif
112
bellard72f03902003-02-18 23:33:18 +0000113//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000114
bellard1a9353d2003-03-16 20:28:50 +0000115//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000116#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
117#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000118
bellard70a194b2003-08-11 22:20:16 +0000119
bellard70a194b2003-08-11 22:20:16 +0000120#undef _syscall0
121#undef _syscall1
122#undef _syscall2
123#undef _syscall3
124#undef _syscall4
125#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000126#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000127
bellard83fcb512006-06-14 13:37:16 +0000128#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000129static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000130{ \
131 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000132}
133
bellard83fcb512006-06-14 13:37:16 +0000134#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000135static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000136{ \
137 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000138}
139
bellard83fcb512006-06-14 13:37:16 +0000140#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000141static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000142{ \
143 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000144}
145
bellard83fcb512006-06-14 13:37:16 +0000146#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000147static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000148{ \
149 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000150}
151
bellard83fcb512006-06-14 13:37:16 +0000152#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000153static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000154{ \
155 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000156}
157
bellard83fcb512006-06-14 13:37:16 +0000158#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
159 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000160static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000161{ \
162 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000163}
bellard83fcb512006-06-14 13:37:16 +0000164
165
166#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
167 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000168static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
169 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000170{ \
171 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
172}
173
bellard70a194b2003-08-11 22:20:16 +0000174
bellard31e31b82003-02-18 22:55:36 +0000175#define __NR_sys_uname __NR_uname
ths92a34c12007-09-24 09:27:49 +0000176#define __NR_sys_faccessat __NR_faccessat
ths814d7972007-09-24 09:26:51 +0000177#define __NR_sys_fchmodat __NR_fchmodat
thsccfa72b2007-09-24 09:23:34 +0000178#define __NR_sys_fchownat __NR_fchownat
balrog6a24a772008-09-20 02:23:36 +0000179#define __NR_sys_fstatat64 __NR_fstatat64
balrogac8a6552008-09-20 02:25:39 +0000180#define __NR_sys_futimesat __NR_futimesat
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
ths64f0ce42007-09-24 09:25:06 +0000185#define __NR_sys_linkat __NR_linkat
ths4472ad02007-09-24 09:22:32 +0000186#define __NR_sys_mkdirat __NR_mkdirat
ths75ac37a2007-09-24 09:23:05 +0000187#define __NR_sys_mknodat __NR_mknodat
aurel329d33b762009-04-08 23:07:05 +0000188#define __NR_sys_newfstatat __NR_newfstatat
ths82424832007-09-24 09:21:55 +0000189#define __NR_sys_openat __NR_openat
ths5e0ccb12007-09-24 09:26:10 +0000190#define __NR_sys_readlinkat __NR_readlinkat
ths722183f2007-09-24 09:24:37 +0000191#define __NR_sys_renameat __NR_renameat
bellard66fb9762003-03-23 01:06:05 +0000192#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
thsf0b62432007-09-24 09:25:40 +0000193#define __NR_sys_symlinkat __NR_symlinkat
ths7494b0f2007-02-11 18:26:53 +0000194#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000195#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000196#define __NR_sys_tkill __NR_tkill
ths8170f562007-09-24 09:24:11 +0000197#define __NR_sys_unlinkat __NR_unlinkat
ths9007f0e2007-09-25 17:50:37 +0000198#define __NR_sys_utimensat __NR_utimensat
pbrookbd0c5662008-05-29 14:34:11 +0000199#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000200#define __NR_sys_inotify_init __NR_inotify_init
201#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
202#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000203
Alexander Graf42a39fb2011-04-15 17:32:45 +0200204#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
205 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000206#define __NR__llseek __NR_lseek
207#endif
208
bellard72f03902003-02-18 23:33:18 +0000209#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000210_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000211#else
ths0da46a62007-10-20 20:23:07 +0000212/* This is a replacement for the host gettid() and must return a host
213 errno. */
bellard72f03902003-02-18 23:33:18 +0000214static int gettid(void) {
215 return -ENOSYS;
216}
217#endif
aurel323b3f24a2009-04-15 16:12:13 +0000218_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
aurel323b3f24a2009-04-15 16:12:13 +0000219#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
220_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
221#endif
222_syscall2(int, sys_getpriority, int, which, int, who);
Richard Hendersond35b2612010-06-04 12:14:10 -0700223#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000224_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
225 loff_t *, res, uint, wh);
226#endif
227_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
228_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
229#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
230_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
231#endif
232#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
233_syscall2(int,sys_tkill,int,tid,int,sig)
234#endif
235#ifdef __NR_exit_group
236_syscall1(int,exit_group,int,error_code)
237#endif
238#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
239_syscall1(int,set_tid_address,int *,tidptr)
240#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +0200241#if defined(CONFIG_USE_NPTL)
aurel323b3f24a2009-04-15 16:12:13 +0000242#if defined(TARGET_NR_futex) && defined(__NR_futex)
243_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
244 const struct timespec *,timeout,int *,uaddr2,int,val3)
245#endif
246#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500247#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
248_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
249 unsigned long *, user_mask_ptr);
250#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
251_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
252 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200253_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
254 void *, arg);
aurel323b3f24a2009-04-15 16:12:13 +0000255
256static bitmask_transtbl fcntl_flags_tbl[] = {
257 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
258 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
259 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
260 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
261 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
262 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
263 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
264 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
265 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
266 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
267 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
268 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
269 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
270#if defined(O_DIRECT)
271 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
272#endif
273 { 0, 0, 0, 0 }
274};
275
276#define COPY_UTSNAME_FIELD(dest, src) \
277 do { \
278 /* __NEW_UTS_LEN doesn't include terminating null */ \
279 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
280 (dest)[__NEW_UTS_LEN] = '\0'; \
281 } while (0)
282
283static int sys_uname(struct new_utsname *buf)
284{
285 struct utsname uts_buf;
286
287 if (uname(&uts_buf) < 0)
288 return (-1);
289
290 /*
291 * Just in case these have some differences, we
292 * translate utsname to new_utsname (which is the
293 * struct linux kernel uses).
294 */
295
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200296 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000297 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
298 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
299 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
300 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
301 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
302#ifdef _GNU_SOURCE
303 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
304#endif
305 return (0);
306
307#undef COPY_UTSNAME_FIELD
308}
309
310static int sys_getcwd1(char *buf, size_t size)
311{
312 if (getcwd(buf, size) == NULL) {
313 /* getcwd() sets errno */
314 return (-1);
315 }
aurel32aaf4ad32009-04-16 14:17:14 +0000316 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000317}
318
319#ifdef CONFIG_ATFILE
320/*
321 * Host system seems to have atfile syscall stubs available. We
322 * now enable them one by one as specified by target syscall_nr.h.
323 */
324
325#ifdef TARGET_NR_faccessat
aurel32465c9f02009-04-19 08:52:17 +0000326static int sys_faccessat(int dirfd, const char *pathname, int mode)
aurel323b3f24a2009-04-15 16:12:13 +0000327{
aurel32465c9f02009-04-19 08:52:17 +0000328 return (faccessat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000329}
330#endif
331#ifdef TARGET_NR_fchmodat
aurel32465c9f02009-04-19 08:52:17 +0000332static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000333{
aurel32465c9f02009-04-19 08:52:17 +0000334 return (fchmodat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000335}
336#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300337#if defined(TARGET_NR_fchownat)
aurel323b3f24a2009-04-15 16:12:13 +0000338static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
339 gid_t group, int flags)
340{
341 return (fchownat(dirfd, pathname, owner, group, flags));
342}
343#endif
344#ifdef __NR_fstatat64
345static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
346 int flags)
347{
348 return (fstatat(dirfd, pathname, buf, flags));
349}
350#endif
351#ifdef __NR_newfstatat
352static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
353 int flags)
354{
355 return (fstatat(dirfd, pathname, buf, flags));
356}
357#endif
358#ifdef TARGET_NR_futimesat
359static int sys_futimesat(int dirfd, const char *pathname,
360 const struct timeval times[2])
361{
362 return (futimesat(dirfd, pathname, times));
363}
364#endif
365#ifdef TARGET_NR_linkat
366static int sys_linkat(int olddirfd, const char *oldpath,
367 int newdirfd, const char *newpath, int flags)
368{
369 return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
370}
371#endif
372#ifdef TARGET_NR_mkdirat
373static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
374{
375 return (mkdirat(dirfd, pathname, mode));
376}
377#endif
378#ifdef TARGET_NR_mknodat
379static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
380 dev_t dev)
381{
382 return (mknodat(dirfd, pathname, mode, dev));
383}
384#endif
385#ifdef TARGET_NR_openat
Alexander Graff4c69012011-09-25 06:25:35 +0200386static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000387{
388 /*
389 * open(2) has extra parameter 'mode' when called with
390 * flag O_CREAT.
391 */
392 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000393 return (openat(dirfd, pathname, flags, mode));
394 }
395 return (openat(dirfd, pathname, flags));
396}
397#endif
398#ifdef TARGET_NR_readlinkat
399static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
400{
401 return (readlinkat(dirfd, pathname, buf, bufsiz));
402}
403#endif
404#ifdef TARGET_NR_renameat
405static int sys_renameat(int olddirfd, const char *oldpath,
406 int newdirfd, const char *newpath)
407{
408 return (renameat(olddirfd, oldpath, newdirfd, newpath));
409}
410#endif
411#ifdef TARGET_NR_symlinkat
412static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
413{
414 return (symlinkat(oldpath, newdirfd, newpath));
415}
416#endif
417#ifdef TARGET_NR_unlinkat
418static int sys_unlinkat(int dirfd, const char *pathname, int flags)
419{
420 return (unlinkat(dirfd, pathname, flags));
421}
422#endif
aurel323b3f24a2009-04-15 16:12:13 +0000423#else /* !CONFIG_ATFILE */
424
425/*
426 * Try direct syscalls instead
427 */
ths92a34c12007-09-24 09:27:49 +0000428#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
aurel32465c9f02009-04-19 08:52:17 +0000429_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
ths92a34c12007-09-24 09:27:49 +0000430#endif
ths814d7972007-09-24 09:26:51 +0000431#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
aurel32465c9f02009-04-19 08:52:17 +0000432_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
ths814d7972007-09-24 09:26:51 +0000433#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300434#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +0000435_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
436 uid_t,owner,gid_t,group,int,flags)
437#endif
aurel329d33b762009-04-08 23:07:05 +0000438#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
439 defined(__NR_fstatat64)
balrog6a24a772008-09-20 02:23:36 +0000440_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
441 struct stat *,buf,int,flags)
442#endif
balrogac8a6552008-09-20 02:25:39 +0000443#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
444_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
445 const struct timeval *,times)
446#endif
aurel323b3f24a2009-04-15 16:12:13 +0000447#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
448 defined(__NR_newfstatat)
449_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
450 struct stat *,buf,int,flags)
blueswir18fcd3692008-08-17 20:26:25 +0000451#endif
ths64f0ce42007-09-24 09:25:06 +0000452#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
453_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
aurel323b3f24a2009-04-15 16:12:13 +0000454 int,newdirfd,const char *,newpath,int,flags)
ths64f0ce42007-09-24 09:25:06 +0000455#endif
ths4472ad02007-09-24 09:22:32 +0000456#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
457_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
458#endif
ths75ac37a2007-09-24 09:23:05 +0000459#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
460_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
461 mode_t,mode,dev_t,dev)
462#endif
ths82424832007-09-24 09:21:55 +0000463#if defined(TARGET_NR_openat) && defined(__NR_openat)
464_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
465#endif
ths5e0ccb12007-09-24 09:26:10 +0000466#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
467_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
468 char *,buf,size_t,bufsize)
469#endif
ths722183f2007-09-24 09:24:37 +0000470#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
471_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
472 int,newdirfd,const char *,newpath)
473#endif
thsb51eaa82007-09-25 16:09:22 +0000474#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +0000475_syscall3(int,sys_symlinkat,const char *,oldpath,
476 int,newdirfd,const char *,newpath)
477#endif
ths8170f562007-09-24 09:24:11 +0000478#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
479_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
480#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300481
482#endif /* CONFIG_ATFILE */
483
484#ifdef CONFIG_UTIMENSAT
485static int sys_utimensat(int dirfd, const char *pathname,
486 const struct timespec times[2], int flags)
487{
488 if (pathname == NULL)
489 return futimens(dirfd, times);
490 else
491 return utimensat(dirfd, pathname, times, flags);
492}
493#else
ths9007f0e2007-09-25 17:50:37 +0000494#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
495_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
496 const struct timespec *,tsp,int,flags)
497#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300498#endif /* CONFIG_UTIMENSAT */
aurel323b3f24a2009-04-15 16:12:13 +0000499
500#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000501#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000502
aurel3239b59762008-10-01 21:46:50 +0000503#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000504static int sys_inotify_init(void)
505{
506 return (inotify_init());
507}
aurel3239b59762008-10-01 21:46:50 +0000508#endif
509#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000510static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
511{
512 return (inotify_add_watch(fd, pathname, mask));
513}
aurel3239b59762008-10-01 21:46:50 +0000514#endif
515#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000516static int sys_inotify_rm_watch(int fd, int32_t wd)
517{
aurel328690e422009-04-17 13:50:32 +0000518 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000519}
aurel3239b59762008-10-01 21:46:50 +0000520#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000521#ifdef CONFIG_INOTIFY1
522#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
523static int sys_inotify_init1(int flags)
524{
525 return (inotify_init1(flags));
526}
527#endif
528#endif
aurel323b3f24a2009-04-15 16:12:13 +0000529#else
530/* Userspace can usually survive runtime without inotify */
531#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000532#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000533#undef TARGET_NR_inotify_add_watch
534#undef TARGET_NR_inotify_rm_watch
535#endif /* CONFIG_INOTIFY */
536
Mike Frysingerd8035d42011-02-07 01:05:51 -0500537#if defined(TARGET_NR_ppoll)
538#ifndef __NR_ppoll
539# define __NR_ppoll -1
540#endif
541#define __NR_sys_ppoll __NR_ppoll
542_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
543 struct timespec *, timeout, const __sigset_t *, sigmask,
544 size_t, sigsetsize)
545#endif
bellard66fb9762003-03-23 01:06:05 +0000546
Mike Frysinger055e0902011-06-03 17:01:49 -0400547#if defined(TARGET_NR_pselect6)
548#ifndef __NR_pselect6
549# define __NR_pselect6 -1
550#endif
551#define __NR_sys_pselect6 __NR_pselect6
552_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
553 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
554#endif
555
Peter Maydell163a05a2011-06-27 17:44:52 +0100556#if defined(TARGET_NR_prlimit64)
557#ifndef __NR_prlimit64
558# define __NR_prlimit64 -1
559#endif
560#define __NR_sys_prlimit64 __NR_prlimit64
561/* The glibc rlimit structure may not be that used by the underlying syscall */
562struct host_rlimit64 {
563 uint64_t rlim_cur;
564 uint64_t rlim_max;
565};
566_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
567 const struct host_rlimit64 *, new_limit,
568 struct host_rlimit64 *, old_limit)
569#endif
570
bellard66fb9762003-03-23 01:06:05 +0000571extern int personality(int);
bellard9de5e442003-03-23 16:49:39 +0000572extern int flock(int, int);
573extern int setfsuid(int);
574extern int setfsgid(int);
bellard19b84f32003-05-08 15:41:49 +0000575extern int setgroups(int, gid_t *);
bellard31e31b82003-02-18 22:55:36 +0000576
Riku Voipio48e515d2011-07-12 15:40:51 +0300577/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
578#ifdef TARGET_ARM
579static inline int regpairs_aligned(void *cpu_env) {
580 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
581}
582#elif defined(TARGET_MIPS)
583static inline int regpairs_aligned(void *cpu_env) { return 1; }
584#else
585static inline int regpairs_aligned(void *cpu_env) { return 0; }
586#endif
587
thsb92c47c2007-11-01 00:07:38 +0000588#define ERRNO_TABLE_SIZE 1200
589
590/* target_to_host_errno_table[] is initialized from
591 * host_to_target_errno_table[] in syscall_init(). */
592static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
593};
594
ths637947f2007-06-01 12:09:19 +0000595/*
thsfe8f0962007-07-12 10:59:21 +0000596 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000597 * minus the errnos that are not actually generic to all archs.
598 */
thsb92c47c2007-11-01 00:07:38 +0000599static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000600 [EIDRM] = TARGET_EIDRM,
601 [ECHRNG] = TARGET_ECHRNG,
602 [EL2NSYNC] = TARGET_EL2NSYNC,
603 [EL3HLT] = TARGET_EL3HLT,
604 [EL3RST] = TARGET_EL3RST,
605 [ELNRNG] = TARGET_ELNRNG,
606 [EUNATCH] = TARGET_EUNATCH,
607 [ENOCSI] = TARGET_ENOCSI,
608 [EL2HLT] = TARGET_EL2HLT,
609 [EDEADLK] = TARGET_EDEADLK,
610 [ENOLCK] = TARGET_ENOLCK,
611 [EBADE] = TARGET_EBADE,
612 [EBADR] = TARGET_EBADR,
613 [EXFULL] = TARGET_EXFULL,
614 [ENOANO] = TARGET_ENOANO,
615 [EBADRQC] = TARGET_EBADRQC,
616 [EBADSLT] = TARGET_EBADSLT,
617 [EBFONT] = TARGET_EBFONT,
618 [ENOSTR] = TARGET_ENOSTR,
619 [ENODATA] = TARGET_ENODATA,
620 [ETIME] = TARGET_ETIME,
621 [ENOSR] = TARGET_ENOSR,
622 [ENONET] = TARGET_ENONET,
623 [ENOPKG] = TARGET_ENOPKG,
624 [EREMOTE] = TARGET_EREMOTE,
625 [ENOLINK] = TARGET_ENOLINK,
626 [EADV] = TARGET_EADV,
627 [ESRMNT] = TARGET_ESRMNT,
628 [ECOMM] = TARGET_ECOMM,
629 [EPROTO] = TARGET_EPROTO,
630 [EDOTDOT] = TARGET_EDOTDOT,
631 [EMULTIHOP] = TARGET_EMULTIHOP,
632 [EBADMSG] = TARGET_EBADMSG,
633 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
634 [EOVERFLOW] = TARGET_EOVERFLOW,
635 [ENOTUNIQ] = TARGET_ENOTUNIQ,
636 [EBADFD] = TARGET_EBADFD,
637 [EREMCHG] = TARGET_EREMCHG,
638 [ELIBACC] = TARGET_ELIBACC,
639 [ELIBBAD] = TARGET_ELIBBAD,
640 [ELIBSCN] = TARGET_ELIBSCN,
641 [ELIBMAX] = TARGET_ELIBMAX,
642 [ELIBEXEC] = TARGET_ELIBEXEC,
643 [EILSEQ] = TARGET_EILSEQ,
644 [ENOSYS] = TARGET_ENOSYS,
645 [ELOOP] = TARGET_ELOOP,
646 [ERESTART] = TARGET_ERESTART,
647 [ESTRPIPE] = TARGET_ESTRPIPE,
648 [ENOTEMPTY] = TARGET_ENOTEMPTY,
649 [EUSERS] = TARGET_EUSERS,
650 [ENOTSOCK] = TARGET_ENOTSOCK,
651 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
652 [EMSGSIZE] = TARGET_EMSGSIZE,
653 [EPROTOTYPE] = TARGET_EPROTOTYPE,
654 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
655 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
656 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
657 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
658 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
659 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
660 [EADDRINUSE] = TARGET_EADDRINUSE,
661 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
662 [ENETDOWN] = TARGET_ENETDOWN,
663 [ENETUNREACH] = TARGET_ENETUNREACH,
664 [ENETRESET] = TARGET_ENETRESET,
665 [ECONNABORTED] = TARGET_ECONNABORTED,
666 [ECONNRESET] = TARGET_ECONNRESET,
667 [ENOBUFS] = TARGET_ENOBUFS,
668 [EISCONN] = TARGET_EISCONN,
669 [ENOTCONN] = TARGET_ENOTCONN,
670 [EUCLEAN] = TARGET_EUCLEAN,
671 [ENOTNAM] = TARGET_ENOTNAM,
672 [ENAVAIL] = TARGET_ENAVAIL,
673 [EISNAM] = TARGET_EISNAM,
674 [EREMOTEIO] = TARGET_EREMOTEIO,
675 [ESHUTDOWN] = TARGET_ESHUTDOWN,
676 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
677 [ETIMEDOUT] = TARGET_ETIMEDOUT,
678 [ECONNREFUSED] = TARGET_ECONNREFUSED,
679 [EHOSTDOWN] = TARGET_EHOSTDOWN,
680 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
681 [EALREADY] = TARGET_EALREADY,
682 [EINPROGRESS] = TARGET_EINPROGRESS,
683 [ESTALE] = TARGET_ESTALE,
684 [ECANCELED] = TARGET_ECANCELED,
685 [ENOMEDIUM] = TARGET_ENOMEDIUM,
686 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000687#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000688 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000689#endif
690#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000691 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000692#endif
693#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000694 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000695#endif
696#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000697 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000698#endif
699#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000700 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000701#endif
702#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000703 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000704#endif
thsb92c47c2007-11-01 00:07:38 +0000705};
ths637947f2007-06-01 12:09:19 +0000706
707static inline int host_to_target_errno(int err)
708{
709 if(host_to_target_errno_table[err])
710 return host_to_target_errno_table[err];
711 return err;
712}
713
thsb92c47c2007-11-01 00:07:38 +0000714static inline int target_to_host_errno(int err)
715{
716 if (target_to_host_errno_table[err])
717 return target_to_host_errno_table[err];
718 return err;
719}
720
blueswir1992f48a2007-10-14 16:27:31 +0000721static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000722{
723 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000724 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000725 else
726 return ret;
727}
728
blueswir1992f48a2007-10-14 16:27:31 +0000729static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000730{
blueswir1992f48a2007-10-14 16:27:31 +0000731 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000732}
733
thsb92c47c2007-11-01 00:07:38 +0000734char *target_strerror(int err)
735{
Alexander Graf962b2892011-11-21 12:04:07 +0100736 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
737 return NULL;
738 }
thsb92c47c2007-11-01 00:07:38 +0000739 return strerror(target_to_host_errno(err));
740}
741
blueswir1992f48a2007-10-14 16:27:31 +0000742static abi_ulong target_brk;
743static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000744static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000745
blueswir1992f48a2007-10-14 16:27:31 +0000746void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000747{
blueswir14c1de732007-07-07 20:45:44 +0000748 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000749 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000750}
751
vincent4d1de872011-06-14 21:56:33 +0000752//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
753#define DEBUGF_BRK(message, args...)
754
ths0da46a62007-10-20 20:23:07 +0000755/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000756abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000757{
blueswir1992f48a2007-10-14 16:27:31 +0000758 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000759 int new_alloc_size;
760
Paul Brook3a0c6c42012-02-09 19:04:27 +0000761 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000762
vincent4d1de872011-06-14 21:56:33 +0000763 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000764 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000765 return target_brk;
766 }
767 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000768 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
769 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000770 return target_brk;
771 }
bellard31e31b82003-02-18 22:55:36 +0000772
vincent4d1de872011-06-14 21:56:33 +0000773 /* If the new brk is less than the highest page reserved to the
774 * target heap allocation, set it and we're almost done... */
775 if (new_brk <= brk_page) {
776 /* Heap contents are initialized to zero, as for anonymous
777 * mapped pages. */
778 if (new_brk > target_brk) {
779 memset(g2h(target_brk), 0, new_brk - target_brk);
780 }
bellard31e31b82003-02-18 22:55:36 +0000781 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000782 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000783 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000784 }
785
Peter Maydell00faf082011-04-18 16:34:24 +0100786 /* We need to allocate more memory after the brk... Note that
787 * we don't use MAP_FIXED because that will map over the top of
788 * any existing mapping (like the one with the host libc or qemu
789 * itself); instead we treat "mapped but at wrong address" as
790 * a failure and unmap again.
791 */
vincent4d1de872011-06-14 21:56:33 +0000792 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000793 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000794 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100795 MAP_ANON|MAP_PRIVATE, 0, 0));
796
797 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200798 /* Heap contents are initialized to zero, as for anonymous
799 * mapped pages. Technically the new pages are already
800 * initialized to zero since they *are* anonymous mapped
801 * pages, however we have to take care with the contents that
802 * come from the remaining part of the previous page: it may
803 * contains garbage data due to a previous heap usage (grown
804 * then shrunken). */
805 memset(g2h(target_brk), 0, brk_page - target_brk);
806
Peter Maydell00faf082011-04-18 16:34:24 +0100807 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000808 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000809 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
810 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100811 return target_brk;
812 } else if (mapped_addr != -1) {
813 /* Mapped but at wrong address, meaning there wasn't actually
814 * enough space for this brk.
815 */
816 target_munmap(mapped_addr, new_alloc_size);
817 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000818 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000819 }
820 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000821 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100822 }
balrog7ab240a2008-04-26 12:17:34 +0000823
Richard Henderson7dd46c02010-05-03 10:07:49 -0700824#if defined(TARGET_ALPHA)
825 /* We (partially) emulate OSF/1 on Alpha, which requires we
826 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100827 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700828#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100829 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000830 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000831}
832
ths26edcf42007-12-09 02:25:24 +0000833static inline abi_long copy_from_user_fdset(fd_set *fds,
834 abi_ulong target_fds_addr,
835 int n)
bellard31e31b82003-02-18 22:55:36 +0000836{
ths26edcf42007-12-09 02:25:24 +0000837 int i, nw, j, k;
838 abi_ulong b, *target_fds;
839
840 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
841 if (!(target_fds = lock_user(VERIFY_READ,
842 target_fds_addr,
843 sizeof(abi_ulong) * nw,
844 1)))
845 return -TARGET_EFAULT;
846
847 FD_ZERO(fds);
848 k = 0;
849 for (i = 0; i < nw; i++) {
850 /* grab the abi_ulong */
851 __get_user(b, &target_fds[i]);
852 for (j = 0; j < TARGET_ABI_BITS; j++) {
853 /* check the bit inside the abi_ulong */
854 if ((b >> j) & 1)
855 FD_SET(k, fds);
856 k++;
bellard31e31b82003-02-18 22:55:36 +0000857 }
bellard31e31b82003-02-18 22:55:36 +0000858 }
ths26edcf42007-12-09 02:25:24 +0000859
860 unlock_user(target_fds, target_fds_addr, 0);
861
862 return 0;
bellard31e31b82003-02-18 22:55:36 +0000863}
864
Mike Frysinger055e0902011-06-03 17:01:49 -0400865static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
866 abi_ulong target_fds_addr,
867 int n)
868{
869 if (target_fds_addr) {
870 if (copy_from_user_fdset(fds, target_fds_addr, n))
871 return -TARGET_EFAULT;
872 *fds_ptr = fds;
873 } else {
874 *fds_ptr = NULL;
875 }
876 return 0;
877}
878
ths26edcf42007-12-09 02:25:24 +0000879static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
880 const fd_set *fds,
881 int n)
bellard31e31b82003-02-18 22:55:36 +0000882{
bellard31e31b82003-02-18 22:55:36 +0000883 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000884 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000885 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000886
ths26edcf42007-12-09 02:25:24 +0000887 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
888 if (!(target_fds = lock_user(VERIFY_WRITE,
889 target_fds_addr,
890 sizeof(abi_ulong) * nw,
891 0)))
892 return -TARGET_EFAULT;
893
894 k = 0;
895 for (i = 0; i < nw; i++) {
896 v = 0;
897 for (j = 0; j < TARGET_ABI_BITS; j++) {
898 v |= ((FD_ISSET(k, fds) != 0) << j);
899 k++;
bellard31e31b82003-02-18 22:55:36 +0000900 }
ths26edcf42007-12-09 02:25:24 +0000901 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000902 }
ths26edcf42007-12-09 02:25:24 +0000903
904 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
905
906 return 0;
bellard31e31b82003-02-18 22:55:36 +0000907}
908
bellardc596ed12003-07-13 17:32:31 +0000909#if defined(__alpha__)
910#define HOST_HZ 1024
911#else
912#define HOST_HZ 100
913#endif
914
blueswir1992f48a2007-10-14 16:27:31 +0000915static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000916{
917#if HOST_HZ == TARGET_HZ
918 return ticks;
919#else
920 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
921#endif
922}
923
bellard579a97f2007-11-11 14:26:47 +0000924static inline abi_long host_to_target_rusage(abi_ulong target_addr,
925 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000926{
pbrook53a59602006-03-25 19:31:22 +0000927 struct target_rusage *target_rusage;
928
bellard579a97f2007-11-11 14:26:47 +0000929 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
930 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200931 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
932 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
933 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
934 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
935 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
936 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
937 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
938 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
939 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
940 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
941 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
942 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
943 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
944 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
945 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
946 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
947 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
948 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000949 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000950
951 return 0;
bellardb4091862003-05-16 15:39:34 +0000952}
953
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200954static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900955{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200956 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300957 rlim_t result;
958
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200959 target_rlim_swap = tswapal(target_rlim);
960 if (target_rlim_swap == TARGET_RLIM_INFINITY)
961 return RLIM_INFINITY;
962
963 result = target_rlim_swap;
964 if (target_rlim_swap != (rlim_t)result)
965 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300966
967 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900968}
969
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200970static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900971{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200972 abi_ulong target_rlim_swap;
973 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300974
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200975 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300976 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900977 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300978 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200979 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300980
981 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900982}
983
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300984static inline int target_to_host_resource(int code)
985{
986 switch (code) {
987 case TARGET_RLIMIT_AS:
988 return RLIMIT_AS;
989 case TARGET_RLIMIT_CORE:
990 return RLIMIT_CORE;
991 case TARGET_RLIMIT_CPU:
992 return RLIMIT_CPU;
993 case TARGET_RLIMIT_DATA:
994 return RLIMIT_DATA;
995 case TARGET_RLIMIT_FSIZE:
996 return RLIMIT_FSIZE;
997 case TARGET_RLIMIT_LOCKS:
998 return RLIMIT_LOCKS;
999 case TARGET_RLIMIT_MEMLOCK:
1000 return RLIMIT_MEMLOCK;
1001 case TARGET_RLIMIT_MSGQUEUE:
1002 return RLIMIT_MSGQUEUE;
1003 case TARGET_RLIMIT_NICE:
1004 return RLIMIT_NICE;
1005 case TARGET_RLIMIT_NOFILE:
1006 return RLIMIT_NOFILE;
1007 case TARGET_RLIMIT_NPROC:
1008 return RLIMIT_NPROC;
1009 case TARGET_RLIMIT_RSS:
1010 return RLIMIT_RSS;
1011 case TARGET_RLIMIT_RTPRIO:
1012 return RLIMIT_RTPRIO;
1013 case TARGET_RLIMIT_SIGPENDING:
1014 return RLIMIT_SIGPENDING;
1015 case TARGET_RLIMIT_STACK:
1016 return RLIMIT_STACK;
1017 default:
1018 return code;
1019 }
1020}
1021
ths788f5ec2007-12-09 02:37:05 +00001022static inline abi_long copy_from_user_timeval(struct timeval *tv,
1023 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001024{
pbrook53a59602006-03-25 19:31:22 +00001025 struct target_timeval *target_tv;
1026
ths788f5ec2007-12-09 02:37:05 +00001027 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001028 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001029
1030 __get_user(tv->tv_sec, &target_tv->tv_sec);
1031 __get_user(tv->tv_usec, &target_tv->tv_usec);
1032
1033 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001034
1035 return 0;
bellard31e31b82003-02-18 22:55:36 +00001036}
1037
ths788f5ec2007-12-09 02:37:05 +00001038static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1039 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001040{
pbrook53a59602006-03-25 19:31:22 +00001041 struct target_timeval *target_tv;
1042
ths788f5ec2007-12-09 02:37:05 +00001043 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001044 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001045
1046 __put_user(tv->tv_sec, &target_tv->tv_sec);
1047 __put_user(tv->tv_usec, &target_tv->tv_usec);
1048
1049 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001050
1051 return 0;
bellard31e31b82003-02-18 22:55:36 +00001052}
1053
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001054#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1055#include <mqueue.h>
1056
aurel3224e10032009-04-15 16:11:43 +00001057static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1058 abi_ulong target_mq_attr_addr)
1059{
1060 struct target_mq_attr *target_mq_attr;
1061
1062 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1063 target_mq_attr_addr, 1))
1064 return -TARGET_EFAULT;
1065
1066 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1067 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1068 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1069 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1070
1071 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1072
1073 return 0;
1074}
1075
1076static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1077 const struct mq_attr *attr)
1078{
1079 struct target_mq_attr *target_mq_attr;
1080
1081 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1082 target_mq_attr_addr, 0))
1083 return -TARGET_EFAULT;
1084
1085 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1086 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1087 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1088 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1089
1090 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1091
1092 return 0;
1093}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001094#endif
bellard31e31b82003-02-18 22:55:36 +00001095
Mike Frysinger055e0902011-06-03 17:01:49 -04001096#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001097/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001098static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001099 abi_ulong rfd_addr, abi_ulong wfd_addr,
1100 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001101{
1102 fd_set rfds, wfds, efds;
1103 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1104 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001105 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001106
Mike Frysinger055e0902011-06-03 17:01:49 -04001107 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1108 if (ret) {
1109 return ret;
pbrook53a59602006-03-25 19:31:22 +00001110 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001111 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1112 if (ret) {
1113 return ret;
pbrook53a59602006-03-25 19:31:22 +00001114 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001115 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1116 if (ret) {
1117 return ret;
pbrook53a59602006-03-25 19:31:22 +00001118 }
ths3b46e622007-09-17 08:09:54 +00001119
ths26edcf42007-12-09 02:25:24 +00001120 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001121 if (copy_from_user_timeval(&tv, target_tv_addr))
1122 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001123 tv_ptr = &tv;
1124 } else {
1125 tv_ptr = NULL;
1126 }
ths26edcf42007-12-09 02:25:24 +00001127
bellard31e31b82003-02-18 22:55:36 +00001128 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001129
ths26edcf42007-12-09 02:25:24 +00001130 if (!is_error(ret)) {
1131 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1132 return -TARGET_EFAULT;
1133 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1134 return -TARGET_EFAULT;
1135 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1136 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001137
ths788f5ec2007-12-09 02:37:05 +00001138 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1139 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001140 }
bellard579a97f2007-11-11 14:26:47 +00001141
bellard31e31b82003-02-18 22:55:36 +00001142 return ret;
1143}
Mike Frysinger055e0902011-06-03 17:01:49 -04001144#endif
bellard31e31b82003-02-18 22:55:36 +00001145
Riku Voipio099d6b02009-05-05 12:10:04 +03001146static abi_long do_pipe2(int host_pipe[], int flags)
1147{
1148#ifdef CONFIG_PIPE2
1149 return pipe2(host_pipe, flags);
1150#else
1151 return -ENOSYS;
1152#endif
1153}
1154
Richard Hendersonfb41a662010-05-03 10:07:52 -07001155static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1156 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001157{
1158 int host_pipe[2];
1159 abi_long ret;
1160 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1161
1162 if (is_error(ret))
1163 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001164
1165 /* Several targets have special calling conventions for the original
1166 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1167 if (!is_pipe2) {
1168#if defined(TARGET_ALPHA)
1169 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1170 return host_pipe[0];
1171#elif defined(TARGET_MIPS)
1172 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1173 return host_pipe[0];
1174#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001175 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001176 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001177#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001178 }
1179
Riku Voipio099d6b02009-05-05 12:10:04 +03001180 if (put_user_s32(host_pipe[0], pipedes)
1181 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1182 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001183 return get_errno(ret);
1184}
1185
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001186static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1187 abi_ulong target_addr,
1188 socklen_t len)
1189{
1190 struct target_ip_mreqn *target_smreqn;
1191
1192 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1193 if (!target_smreqn)
1194 return -TARGET_EFAULT;
1195 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1196 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1197 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001198 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001199 unlock_user(target_smreqn, target_addr, 0);
1200
1201 return 0;
1202}
1203
bellard579a97f2007-11-11 14:26:47 +00001204static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1205 abi_ulong target_addr,
1206 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001207{
aurel32607175e2009-04-15 16:11:59 +00001208 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1209 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001210 struct target_sockaddr *target_saddr;
1211
bellard579a97f2007-11-11 14:26:47 +00001212 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1213 if (!target_saddr)
1214 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001215
1216 sa_family = tswap16(target_saddr->sa_family);
1217
1218 /* Oops. The caller might send a incomplete sun_path; sun_path
1219 * must be terminated by \0 (see the manual page), but
1220 * unfortunately it is quite common to specify sockaddr_un
1221 * length as "strlen(x->sun_path)" while it should be
1222 * "strlen(...) + 1". We'll fix that here if needed.
1223 * Linux kernel has a similar feature.
1224 */
1225
1226 if (sa_family == AF_UNIX) {
1227 if (len < unix_maxlen && len > 0) {
1228 char *cp = (char*)target_saddr;
1229
1230 if ( cp[len-1] && !cp[len] )
1231 len++;
1232 }
1233 if (len > unix_maxlen)
1234 len = unix_maxlen;
1235 }
1236
pbrook53a59602006-03-25 19:31:22 +00001237 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001238 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001239 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001240
1241 return 0;
bellard7854b052003-03-29 17:22:23 +00001242}
1243
bellard579a97f2007-11-11 14:26:47 +00001244static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1245 struct sockaddr *addr,
1246 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001247{
pbrook53a59602006-03-25 19:31:22 +00001248 struct target_sockaddr *target_saddr;
1249
bellard579a97f2007-11-11 14:26:47 +00001250 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1251 if (!target_saddr)
1252 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001253 memcpy(target_saddr, addr, len);
1254 target_saddr->sa_family = tswap16(addr->sa_family);
1255 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001256
1257 return 0;
bellard7854b052003-03-29 17:22:23 +00001258}
1259
bellard5a4a8982007-11-11 17:39:18 +00001260static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1261 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001262{
1263 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001264 abi_long msg_controllen;
1265 abi_ulong target_cmsg_addr;
1266 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001267 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001268
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001269 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001270 if (msg_controllen < sizeof (struct target_cmsghdr))
1271 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001272 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001273 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1274 if (!target_cmsg)
1275 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001276
1277 while (cmsg && target_cmsg) {
1278 void *data = CMSG_DATA(cmsg);
1279 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1280
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001281 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001282 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1283
1284 space += CMSG_SPACE(len);
1285 if (space > msgh->msg_controllen) {
1286 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001287 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001288 break;
1289 }
1290
1291 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1292 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1293 cmsg->cmsg_len = CMSG_LEN(len);
1294
bellard3532fa72006-06-24 15:06:03 +00001295 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001296 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1297 memcpy(data, target_data, len);
1298 } else {
1299 int *fd = (int *)data;
1300 int *target_fd = (int *)target_data;
1301 int i, numfds = len / sizeof(int);
1302
1303 for (i = 0; i < numfds; i++)
1304 fd[i] = tswap32(target_fd[i]);
1305 }
1306
1307 cmsg = CMSG_NXTHDR(msgh, cmsg);
1308 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1309 }
bellard5a4a8982007-11-11 17:39:18 +00001310 unlock_user(target_cmsg, target_cmsg_addr, 0);
1311 the_end:
bellard7854b052003-03-29 17:22:23 +00001312 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001313 return 0;
bellard7854b052003-03-29 17:22:23 +00001314}
1315
pbrook53a59602006-03-25 19:31:22 +00001316/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001317static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1318 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001319{
1320 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001321 abi_long msg_controllen;
1322 abi_ulong target_cmsg_addr;
1323 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001324 socklen_t space = 0;
1325
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001326 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001327 if (msg_controllen < sizeof (struct target_cmsghdr))
1328 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001329 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001330 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1331 if (!target_cmsg)
1332 return -TARGET_EFAULT;
1333
bellard7854b052003-03-29 17:22:23 +00001334 while (cmsg && target_cmsg) {
1335 void *data = CMSG_DATA(cmsg);
1336 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1337
1338 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1339
1340 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001341 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001342 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001343 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001344 break;
1345 }
1346
1347 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1348 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001349 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001350
Jing Huang03e1ad92012-07-23 13:52:07 +00001351 if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
1352 (cmsg->cmsg_type == SCM_RIGHTS)) {
bellard7854b052003-03-29 17:22:23 +00001353 int *fd = (int *)data;
1354 int *target_fd = (int *)target_data;
1355 int i, numfds = len / sizeof(int);
1356
1357 for (i = 0; i < numfds; i++)
1358 target_fd[i] = tswap32(fd[i]);
Jing Huang03e1ad92012-07-23 13:52:07 +00001359 } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
1360 (cmsg->cmsg_type == SO_TIMESTAMP) &&
1361 (len == sizeof(struct timeval))) {
1362 /* copy struct timeval to target */
1363 struct timeval *tv = (struct timeval *)data;
1364 struct target_timeval *target_tv =
1365 (struct target_timeval *)target_data;
Peter Maydell120b4382012-07-23 18:16:23 +01001366 printf("qemu: copying host to target timeval: %lx %lx\n",
1367 tv->tv_sec, tv->tv_usec);
Jing Huang03e1ad92012-07-23 13:52:07 +00001368
Peter Maydell120b4382012-07-23 18:16:23 +01001369 target_tv->tv_sec = tswapal(tv->tv_sec);
1370 target_tv->tv_usec = tswapal(tv->tv_usec);
Jing Huang03e1ad92012-07-23 13:52:07 +00001371 } else {
1372 gemu_log("Unsupported ancillary data: %d/%d\n",
1373 cmsg->cmsg_level, cmsg->cmsg_type);
1374 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001375 }
1376
1377 cmsg = CMSG_NXTHDR(msgh, cmsg);
1378 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1379 }
bellard5a4a8982007-11-11 17:39:18 +00001380 unlock_user(target_cmsg, target_cmsg_addr, space);
1381 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001382 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001383 return 0;
bellard7854b052003-03-29 17:22:23 +00001384}
1385
ths0da46a62007-10-20 20:23:07 +00001386/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001387static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001388 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001389{
blueswir1992f48a2007-10-14 16:27:31 +00001390 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001391 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001392 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001393 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001394
bellard8853f862004-02-22 14:57:26 +00001395 switch(level) {
1396 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001397 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001398 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001399 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001400
bellard2f619692007-11-16 10:46:05 +00001401 if (get_user_u32(val, optval_addr))
1402 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001403 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1404 break;
1405 case SOL_IP:
1406 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001407 case IP_TOS:
1408 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001409 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001410 case IP_ROUTER_ALERT:
1411 case IP_RECVOPTS:
1412 case IP_RETOPTS:
1413 case IP_PKTINFO:
1414 case IP_MTU_DISCOVER:
1415 case IP_RECVERR:
1416 case IP_RECVTOS:
1417#ifdef IP_FREEBIND
1418 case IP_FREEBIND:
1419#endif
1420 case IP_MULTICAST_TTL:
1421 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001422 val = 0;
1423 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001424 if (get_user_u32(val, optval_addr))
1425 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001426 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001427 if (get_user_u8(val, optval_addr))
1428 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001429 }
1430 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1431 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001432 case IP_ADD_MEMBERSHIP:
1433 case IP_DROP_MEMBERSHIP:
1434 if (optlen < sizeof (struct target_ip_mreq) ||
1435 optlen > sizeof (struct target_ip_mreqn))
1436 return -TARGET_EINVAL;
1437
1438 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1439 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1440 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1441 break;
1442
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001443 case IP_BLOCK_SOURCE:
1444 case IP_UNBLOCK_SOURCE:
1445 case IP_ADD_SOURCE_MEMBERSHIP:
1446 case IP_DROP_SOURCE_MEMBERSHIP:
1447 if (optlen != sizeof (struct target_ip_mreq_source))
1448 return -TARGET_EINVAL;
1449
1450 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1451 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1452 unlock_user (ip_mreq_source, optval_addr, 0);
1453 break;
1454
bellard8853f862004-02-22 14:57:26 +00001455 default:
1456 goto unimplemented;
1457 }
1458 break;
Jing Huang79bbbaa2012-07-23 13:50:58 +00001459 case SOL_RAW:
1460 switch (optname) {
1461 case ICMP_FILTER:
1462 /* struct icmp_filter takes an u32 value */
1463 if (optlen < sizeof(uint32_t)) {
1464 return -TARGET_EINVAL;
1465 }
1466
1467 if (get_user_u32(val, optval_addr)) {
1468 return -TARGET_EFAULT;
1469 }
1470 ret = get_errno(setsockopt(sockfd, level, optname,
1471 &val, sizeof(val)));
1472 break;
1473
1474 default:
1475 goto unimplemented;
1476 }
1477 break;
bellard3532fa72006-06-24 15:06:03 +00001478 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001479 switch (optname) {
1480 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001481 case TARGET_SO_DEBUG:
1482 optname = SO_DEBUG;
1483 break;
1484 case TARGET_SO_REUSEADDR:
1485 optname = SO_REUSEADDR;
1486 break;
1487 case TARGET_SO_TYPE:
1488 optname = SO_TYPE;
1489 break;
1490 case TARGET_SO_ERROR:
1491 optname = SO_ERROR;
1492 break;
1493 case TARGET_SO_DONTROUTE:
1494 optname = SO_DONTROUTE;
1495 break;
1496 case TARGET_SO_BROADCAST:
1497 optname = SO_BROADCAST;
1498 break;
1499 case TARGET_SO_SNDBUF:
1500 optname = SO_SNDBUF;
1501 break;
1502 case TARGET_SO_RCVBUF:
1503 optname = SO_RCVBUF;
1504 break;
1505 case TARGET_SO_KEEPALIVE:
1506 optname = SO_KEEPALIVE;
1507 break;
1508 case TARGET_SO_OOBINLINE:
1509 optname = SO_OOBINLINE;
1510 break;
1511 case TARGET_SO_NO_CHECK:
1512 optname = SO_NO_CHECK;
1513 break;
1514 case TARGET_SO_PRIORITY:
1515 optname = SO_PRIORITY;
1516 break;
bellard5e83e8e2005-03-01 22:32:06 +00001517#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001518 case TARGET_SO_BSDCOMPAT:
1519 optname = SO_BSDCOMPAT;
1520 break;
bellard5e83e8e2005-03-01 22:32:06 +00001521#endif
bellard3532fa72006-06-24 15:06:03 +00001522 case TARGET_SO_PASSCRED:
1523 optname = SO_PASSCRED;
1524 break;
1525 case TARGET_SO_TIMESTAMP:
1526 optname = SO_TIMESTAMP;
1527 break;
1528 case TARGET_SO_RCVLOWAT:
1529 optname = SO_RCVLOWAT;
1530 break;
1531 case TARGET_SO_RCVTIMEO:
1532 optname = SO_RCVTIMEO;
1533 break;
1534 case TARGET_SO_SNDTIMEO:
1535 optname = SO_SNDTIMEO;
1536 break;
bellard8853f862004-02-22 14:57:26 +00001537 break;
1538 default:
1539 goto unimplemented;
1540 }
bellard3532fa72006-06-24 15:06:03 +00001541 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001542 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001543
bellard2f619692007-11-16 10:46:05 +00001544 if (get_user_u32(val, optval_addr))
1545 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001546 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001547 break;
bellard7854b052003-03-29 17:22:23 +00001548 default:
bellard8853f862004-02-22 14:57:26 +00001549 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001550 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001551 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001552 }
bellard8853f862004-02-22 14:57:26 +00001553 return ret;
bellard7854b052003-03-29 17:22:23 +00001554}
1555
ths0da46a62007-10-20 20:23:07 +00001556/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001557static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001558 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001559{
blueswir1992f48a2007-10-14 16:27:31 +00001560 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001561 int len, val;
1562 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001563
1564 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001565 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001566 level = SOL_SOCKET;
1567 switch (optname) {
1568 /* These don't just return a single integer */
1569 case TARGET_SO_LINGER:
1570 case TARGET_SO_RCVTIMEO:
1571 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001572 case TARGET_SO_PEERNAME:
1573 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001574 case TARGET_SO_PEERCRED: {
1575 struct ucred cr;
1576 socklen_t crlen;
1577 struct target_ucred *tcr;
1578
1579 if (get_user_u32(len, optlen)) {
1580 return -TARGET_EFAULT;
1581 }
1582 if (len < 0) {
1583 return -TARGET_EINVAL;
1584 }
1585
1586 crlen = sizeof(cr);
1587 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1588 &cr, &crlen));
1589 if (ret < 0) {
1590 return ret;
1591 }
1592 if (len > crlen) {
1593 len = crlen;
1594 }
1595 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1596 return -TARGET_EFAULT;
1597 }
1598 __put_user(cr.pid, &tcr->pid);
1599 __put_user(cr.uid, &tcr->uid);
1600 __put_user(cr.gid, &tcr->gid);
1601 unlock_user_struct(tcr, optval_addr, 1);
1602 if (put_user_u32(len, optlen)) {
1603 return -TARGET_EFAULT;
1604 }
1605 break;
1606 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001607 /* Options with 'int' argument. */
1608 case TARGET_SO_DEBUG:
1609 optname = SO_DEBUG;
1610 goto int_case;
1611 case TARGET_SO_REUSEADDR:
1612 optname = SO_REUSEADDR;
1613 goto int_case;
1614 case TARGET_SO_TYPE:
1615 optname = SO_TYPE;
1616 goto int_case;
1617 case TARGET_SO_ERROR:
1618 optname = SO_ERROR;
1619 goto int_case;
1620 case TARGET_SO_DONTROUTE:
1621 optname = SO_DONTROUTE;
1622 goto int_case;
1623 case TARGET_SO_BROADCAST:
1624 optname = SO_BROADCAST;
1625 goto int_case;
1626 case TARGET_SO_SNDBUF:
1627 optname = SO_SNDBUF;
1628 goto int_case;
1629 case TARGET_SO_RCVBUF:
1630 optname = SO_RCVBUF;
1631 goto int_case;
1632 case TARGET_SO_KEEPALIVE:
1633 optname = SO_KEEPALIVE;
1634 goto int_case;
1635 case TARGET_SO_OOBINLINE:
1636 optname = SO_OOBINLINE;
1637 goto int_case;
1638 case TARGET_SO_NO_CHECK:
1639 optname = SO_NO_CHECK;
1640 goto int_case;
1641 case TARGET_SO_PRIORITY:
1642 optname = SO_PRIORITY;
1643 goto int_case;
1644#ifdef SO_BSDCOMPAT
1645 case TARGET_SO_BSDCOMPAT:
1646 optname = SO_BSDCOMPAT;
1647 goto int_case;
1648#endif
1649 case TARGET_SO_PASSCRED:
1650 optname = SO_PASSCRED;
1651 goto int_case;
1652 case TARGET_SO_TIMESTAMP:
1653 optname = SO_TIMESTAMP;
1654 goto int_case;
1655 case TARGET_SO_RCVLOWAT:
1656 optname = SO_RCVLOWAT;
1657 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001658 default:
bellard2efbe912005-07-23 15:10:20 +00001659 goto int_case;
1660 }
1661 break;
1662 case SOL_TCP:
1663 /* TCP options all take an 'int' value. */
1664 int_case:
bellard2f619692007-11-16 10:46:05 +00001665 if (get_user_u32(len, optlen))
1666 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001667 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001668 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001669 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001670 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1671 if (ret < 0)
1672 return ret;
bellard2efbe912005-07-23 15:10:20 +00001673 if (len > lv)
1674 len = lv;
bellard2f619692007-11-16 10:46:05 +00001675 if (len == 4) {
1676 if (put_user_u32(val, optval_addr))
1677 return -TARGET_EFAULT;
1678 } else {
1679 if (put_user_u8(val, optval_addr))
1680 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001681 }
bellard2f619692007-11-16 10:46:05 +00001682 if (put_user_u32(len, optlen))
1683 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001684 break;
1685 case SOL_IP:
1686 switch(optname) {
1687 case IP_TOS:
1688 case IP_TTL:
1689 case IP_HDRINCL:
1690 case IP_ROUTER_ALERT:
1691 case IP_RECVOPTS:
1692 case IP_RETOPTS:
1693 case IP_PKTINFO:
1694 case IP_MTU_DISCOVER:
1695 case IP_RECVERR:
1696 case IP_RECVTOS:
1697#ifdef IP_FREEBIND
1698 case IP_FREEBIND:
1699#endif
1700 case IP_MULTICAST_TTL:
1701 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001702 if (get_user_u32(len, optlen))
1703 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001704 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001705 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001706 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001707 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1708 if (ret < 0)
1709 return ret;
bellard2efbe912005-07-23 15:10:20 +00001710 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001711 len = 1;
bellard2f619692007-11-16 10:46:05 +00001712 if (put_user_u32(len, optlen)
1713 || put_user_u8(val, optval_addr))
1714 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001715 } else {
bellard2efbe912005-07-23 15:10:20 +00001716 if (len > sizeof(int))
1717 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001718 if (put_user_u32(len, optlen)
1719 || put_user_u32(val, optval_addr))
1720 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001721 }
bellard8853f862004-02-22 14:57:26 +00001722 break;
bellard2efbe912005-07-23 15:10:20 +00001723 default:
thsc02f4992007-12-18 02:39:59 +00001724 ret = -TARGET_ENOPROTOOPT;
1725 break;
bellard8853f862004-02-22 14:57:26 +00001726 }
1727 break;
1728 default:
1729 unimplemented:
1730 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1731 level, optname);
thsc02f4992007-12-18 02:39:59 +00001732 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001733 break;
1734 }
1735 return ret;
bellard7854b052003-03-29 17:22:23 +00001736}
1737
bellard579a97f2007-11-11 14:26:47 +00001738/* FIXME
1739 * lock_iovec()/unlock_iovec() have a return code of 0 for success where
1740 * other lock functions have a return code of 0 for failure.
1741 */
1742static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
1743 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001744{
1745 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001746 abi_ulong base;
balrogd732dcb2008-10-28 10:21:03 +00001747 int i;
pbrook53a59602006-03-25 19:31:22 +00001748
bellard579a97f2007-11-11 14:26:47 +00001749 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1750 if (!target_vec)
1751 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001752 for(i = 0;i < count; i++) {
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001753 base = tswapal(target_vec[i].iov_base);
1754 vec[i].iov_len = tswapal(target_vec[i].iov_len);
bellard41df8412008-02-04 22:26:57 +00001755 if (vec[i].iov_len != 0) {
1756 vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
balrogd732dcb2008-10-28 10:21:03 +00001757 /* Don't check lock_user return value. We must call writev even
1758 if a element has invalid base address. */
bellard41df8412008-02-04 22:26:57 +00001759 } else {
1760 /* zero length pointer is ignored */
1761 vec[i].iov_base = NULL;
1762 }
pbrook53a59602006-03-25 19:31:22 +00001763 }
1764 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001765 return 0;
pbrook53a59602006-03-25 19:31:22 +00001766}
1767
bellard579a97f2007-11-11 14:26:47 +00001768static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1769 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001770{
1771 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001772 abi_ulong base;
pbrook53a59602006-03-25 19:31:22 +00001773 int i;
1774
bellard579a97f2007-11-11 14:26:47 +00001775 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1776 if (!target_vec)
1777 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001778 for(i = 0;i < count; i++) {
balrogd732dcb2008-10-28 10:21:03 +00001779 if (target_vec[i].iov_base) {
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001780 base = tswapal(target_vec[i].iov_base);
balrogd732dcb2008-10-28 10:21:03 +00001781 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1782 }
pbrook53a59602006-03-25 19:31:22 +00001783 }
1784 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001785
1786 return 0;
pbrook53a59602006-03-25 19:31:22 +00001787}
1788
ths0da46a62007-10-20 20:23:07 +00001789/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001790static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001791{
1792#if defined(TARGET_MIPS)
1793 switch(type) {
1794 case TARGET_SOCK_DGRAM:
1795 type = SOCK_DGRAM;
1796 break;
1797 case TARGET_SOCK_STREAM:
1798 type = SOCK_STREAM;
1799 break;
1800 case TARGET_SOCK_RAW:
1801 type = SOCK_RAW;
1802 break;
1803 case TARGET_SOCK_RDM:
1804 type = SOCK_RDM;
1805 break;
1806 case TARGET_SOCK_SEQPACKET:
1807 type = SOCK_SEQPACKET;
1808 break;
1809 case TARGET_SOCK_PACKET:
1810 type = SOCK_PACKET;
1811 break;
1812 }
1813#endif
balrog12bc92a2007-10-30 21:06:14 +00001814 if (domain == PF_NETLINK)
1815 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
bellard3532fa72006-06-24 15:06:03 +00001816 return get_errno(socket(domain, type, protocol));
1817}
1818
ths0da46a62007-10-20 20:23:07 +00001819/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001820static abi_long do_bind(int sockfd, abi_ulong target_addr,
1821 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001822{
aurel328f7aeaf2009-01-30 19:47:57 +00001823 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001824 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001825
Blue Swirl38724252010-09-18 05:53:14 +00001826 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001827 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001828 }
aurel328f7aeaf2009-01-30 19:47:57 +00001829
aurel32607175e2009-04-15 16:11:59 +00001830 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001831
Arnaud Patard917507b2009-06-19 10:44:45 +03001832 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1833 if (ret)
1834 return ret;
1835
bellard3532fa72006-06-24 15:06:03 +00001836 return get_errno(bind(sockfd, addr, addrlen));
1837}
1838
ths0da46a62007-10-20 20:23:07 +00001839/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001840static abi_long do_connect(int sockfd, abi_ulong target_addr,
1841 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001842{
aurel328f7aeaf2009-01-30 19:47:57 +00001843 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001844 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001845
Blue Swirl38724252010-09-18 05:53:14 +00001846 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001847 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001848 }
aurel328f7aeaf2009-01-30 19:47:57 +00001849
1850 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001851
Arnaud Patard917507b2009-06-19 10:44:45 +03001852 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1853 if (ret)
1854 return ret;
1855
bellard3532fa72006-06-24 15:06:03 +00001856 return get_errno(connect(sockfd, addr, addrlen));
1857}
1858
ths0da46a62007-10-20 20:23:07 +00001859/* do_sendrecvmsg() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001860static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1861 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001862{
balrog6de645c2008-10-28 10:26:29 +00001863 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001864 struct target_msghdr *msgp;
1865 struct msghdr msg;
1866 int count;
1867 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001868 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001869
bellard579a97f2007-11-11 14:26:47 +00001870 /* FIXME */
1871 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1872 msgp,
1873 target_msg,
1874 send ? 1 : 0))
1875 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001876 if (msgp->msg_name) {
1877 msg.msg_namelen = tswap32(msgp->msg_namelen);
1878 msg.msg_name = alloca(msg.msg_namelen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001879 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001880 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001881 if (ret) {
1882 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
1883 return ret;
1884 }
bellard3532fa72006-06-24 15:06:03 +00001885 } else {
1886 msg.msg_name = NULL;
1887 msg.msg_namelen = 0;
1888 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001889 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00001890 msg.msg_control = alloca(msg.msg_controllen);
1891 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001892
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001893 count = tswapal(msgp->msg_iovlen);
bellard3532fa72006-06-24 15:06:03 +00001894 vec = alloca(count * sizeof(struct iovec));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001895 target_vec = tswapal(msgp->msg_iov);
bellard579a97f2007-11-11 14:26:47 +00001896 lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
bellard3532fa72006-06-24 15:06:03 +00001897 msg.msg_iovlen = count;
1898 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001899
bellard3532fa72006-06-24 15:06:03 +00001900 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001901 ret = target_to_host_cmsg(&msg, msgp);
1902 if (ret == 0)
1903 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001904 } else {
1905 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001906 if (!is_error(ret)) {
1907 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001908 ret = host_to_target_cmsg(msgp, &msg);
Jing Huanga5e98f32012-07-23 13:49:24 +00001909 if (!is_error(ret)) {
1910 msgp->msg_namelen = tswap32(msg.msg_namelen);
1911 if (msg.msg_name != NULL) {
1912 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
1913 msg.msg_name, msg.msg_namelen);
1914 if (ret) {
1915 goto out;
1916 }
1917 }
1918
balrog6de645c2008-10-28 10:26:29 +00001919 ret = len;
Jing Huanga5e98f32012-07-23 13:49:24 +00001920 }
balrog6de645c2008-10-28 10:26:29 +00001921 }
bellard3532fa72006-06-24 15:06:03 +00001922 }
Jing Huanga5e98f32012-07-23 13:49:24 +00001923
1924out:
bellard3532fa72006-06-24 15:06:03 +00001925 unlock_iovec(vec, target_vec, count, !send);
bellard579a97f2007-11-11 14:26:47 +00001926 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001927 return ret;
1928}
1929
ths0da46a62007-10-20 20:23:07 +00001930/* do_accept() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001931static abi_long do_accept(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001932 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001933{
bellard2f619692007-11-16 10:46:05 +00001934 socklen_t addrlen;
1935 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001936 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001937
Arnaud Patard917507b2009-06-19 10:44:45 +03001938 if (target_addr == 0)
1939 return get_errno(accept(fd, NULL, NULL));
1940
1941 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00001942 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03001943 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00001944
Blue Swirl38724252010-09-18 05:53:14 +00001945 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001946 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001947 }
aurel328f7aeaf2009-01-30 19:47:57 +00001948
Arnaud Patard917507b2009-06-19 10:44:45 +03001949 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1950 return -TARGET_EINVAL;
1951
bellard2f619692007-11-16 10:46:05 +00001952 addr = alloca(addrlen);
1953
pbrook1be9e1d2006-11-19 15:26:04 +00001954 ret = get_errno(accept(fd, addr, &addrlen));
1955 if (!is_error(ret)) {
1956 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001957 if (put_user_u32(addrlen, target_addrlen_addr))
1958 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001959 }
1960 return ret;
1961}
1962
ths0da46a62007-10-20 20:23:07 +00001963/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001964static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001965 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001966{
bellard2f619692007-11-16 10:46:05 +00001967 socklen_t addrlen;
1968 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001969 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001970
bellard2f619692007-11-16 10:46:05 +00001971 if (get_user_u32(addrlen, target_addrlen_addr))
1972 return -TARGET_EFAULT;
1973
Blue Swirl38724252010-09-18 05:53:14 +00001974 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001975 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001976 }
aurel328f7aeaf2009-01-30 19:47:57 +00001977
Arnaud Patard917507b2009-06-19 10:44:45 +03001978 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1979 return -TARGET_EFAULT;
1980
bellard2f619692007-11-16 10:46:05 +00001981 addr = alloca(addrlen);
1982
pbrook1be9e1d2006-11-19 15:26:04 +00001983 ret = get_errno(getpeername(fd, addr, &addrlen));
1984 if (!is_error(ret)) {
1985 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001986 if (put_user_u32(addrlen, target_addrlen_addr))
1987 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001988 }
1989 return ret;
1990}
1991
ths0da46a62007-10-20 20:23:07 +00001992/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001993static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001994 abi_ulong target_addrlen_addr)
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
bellard2f619692007-11-16 10:46:05 +00002000 if (get_user_u32(addrlen, target_addrlen_addr))
2001 return -TARGET_EFAULT;
2002
Blue Swirl38724252010-09-18 05:53:14 +00002003 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002004 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002005 }
aurel328f7aeaf2009-01-30 19:47:57 +00002006
Arnaud Patard917507b2009-06-19 10:44:45 +03002007 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2008 return -TARGET_EFAULT;
2009
bellard2f619692007-11-16 10:46:05 +00002010 addr = alloca(addrlen);
2011
pbrook1be9e1d2006-11-19 15:26:04 +00002012 ret = get_errno(getsockname(fd, addr, &addrlen));
2013 if (!is_error(ret)) {
2014 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002015 if (put_user_u32(addrlen, target_addrlen_addr))
2016 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002017 }
2018 return ret;
2019}
2020
ths0da46a62007-10-20 20:23:07 +00002021/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002022static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002023 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002024{
2025 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002026 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002027
2028 ret = get_errno(socketpair(domain, type, protocol, tab));
2029 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002030 if (put_user_s32(tab[0], target_tab_addr)
2031 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2032 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002033 }
2034 return ret;
2035}
2036
ths0da46a62007-10-20 20:23:07 +00002037/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002038static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2039 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002040{
2041 void *addr;
2042 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002043 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002044
Blue Swirl38724252010-09-18 05:53:14 +00002045 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002046 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002047 }
aurel328f7aeaf2009-01-30 19:47:57 +00002048
bellard579a97f2007-11-11 14:26:47 +00002049 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2050 if (!host_msg)
2051 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002052 if (target_addr) {
2053 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002054 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2055 if (ret) {
2056 unlock_user(host_msg, msg, 0);
2057 return ret;
2058 }
pbrook1be9e1d2006-11-19 15:26:04 +00002059 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2060 } else {
2061 ret = get_errno(send(fd, host_msg, len, flags));
2062 }
2063 unlock_user(host_msg, msg, 0);
2064 return ret;
2065}
2066
ths0da46a62007-10-20 20:23:07 +00002067/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002068static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2069 abi_ulong target_addr,
2070 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002071{
2072 socklen_t addrlen;
2073 void *addr;
2074 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002075 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002076
bellard579a97f2007-11-11 14:26:47 +00002077 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2078 if (!host_msg)
2079 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002080 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002081 if (get_user_u32(addrlen, target_addrlen)) {
2082 ret = -TARGET_EFAULT;
2083 goto fail;
2084 }
Blue Swirl38724252010-09-18 05:53:14 +00002085 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002086 ret = -TARGET_EINVAL;
2087 goto fail;
2088 }
pbrook1be9e1d2006-11-19 15:26:04 +00002089 addr = alloca(addrlen);
2090 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2091 } else {
2092 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002093 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002094 }
2095 if (!is_error(ret)) {
2096 if (target_addr) {
2097 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002098 if (put_user_u32(addrlen, target_addrlen)) {
2099 ret = -TARGET_EFAULT;
2100 goto fail;
2101 }
pbrook1be9e1d2006-11-19 15:26:04 +00002102 }
2103 unlock_user(host_msg, msg, len);
2104 } else {
bellard2f619692007-11-16 10:46:05 +00002105fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002106 unlock_user(host_msg, msg, 0);
2107 }
2108 return ret;
2109}
2110
j_mayer32407102007-09-26 23:01:49 +00002111#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002112/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002113static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002114{
blueswir1992f48a2007-10-14 16:27:31 +00002115 abi_long ret;
2116 const int n = sizeof(abi_ulong);
bellard31e31b82003-02-18 22:55:36 +00002117
2118 switch(num) {
2119 case SOCKOP_socket:
bellard7854b052003-03-29 17:22:23 +00002120 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002121 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002122
Ulrich Hecht98818182009-07-03 17:09:28 +02002123 if (get_user_ual(domain, vptr)
2124 || get_user_ual(type, vptr + n)
2125 || get_user_ual(protocol, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002126 return -TARGET_EFAULT;
2127
bellard3532fa72006-06-24 15:06:03 +00002128 ret = do_socket(domain, type, protocol);
bellard7854b052003-03-29 17:22:23 +00002129 }
bellard31e31b82003-02-18 22:55:36 +00002130 break;
2131 case SOCKOP_bind:
bellard7854b052003-03-29 17:22:23 +00002132 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002133 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002134 abi_ulong target_addr;
2135 socklen_t addrlen;
2136
Ulrich Hecht98818182009-07-03 17:09:28 +02002137 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002138 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002139 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002140 return -TARGET_EFAULT;
2141
bellard3532fa72006-06-24 15:06:03 +00002142 ret = do_bind(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002143 }
bellard31e31b82003-02-18 22:55:36 +00002144 break;
2145 case SOCKOP_connect:
bellard7854b052003-03-29 17:22:23 +00002146 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002147 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002148 abi_ulong target_addr;
2149 socklen_t addrlen;
2150
Ulrich Hecht98818182009-07-03 17:09:28 +02002151 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002152 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002153 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002154 return -TARGET_EFAULT;
2155
bellard3532fa72006-06-24 15:06:03 +00002156 ret = do_connect(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002157 }
bellard31e31b82003-02-18 22:55:36 +00002158 break;
2159 case SOCKOP_listen:
bellard7854b052003-03-29 17:22:23 +00002160 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002161 abi_ulong sockfd, backlog;
bellard2f619692007-11-16 10:46:05 +00002162
Ulrich Hecht98818182009-07-03 17:09:28 +02002163 if (get_user_ual(sockfd, vptr)
2164 || get_user_ual(backlog, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002165 return -TARGET_EFAULT;
2166
bellard7854b052003-03-29 17:22:23 +00002167 ret = get_errno(listen(sockfd, backlog));
2168 }
bellard31e31b82003-02-18 22:55:36 +00002169 break;
2170 case SOCKOP_accept:
2171 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002172 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002173 abi_ulong target_addr, target_addrlen;
2174
Ulrich Hecht98818182009-07-03 17:09:28 +02002175 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002176 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002177 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002178 return -TARGET_EFAULT;
2179
pbrook1be9e1d2006-11-19 15:26:04 +00002180 ret = do_accept(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002181 }
2182 break;
2183 case SOCKOP_getsockname:
2184 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002185 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002186 abi_ulong target_addr, target_addrlen;
2187
Ulrich Hecht98818182009-07-03 17:09:28 +02002188 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002189 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002190 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002191 return -TARGET_EFAULT;
2192
pbrook1be9e1d2006-11-19 15:26:04 +00002193 ret = do_getsockname(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002194 }
2195 break;
2196 case SOCKOP_getpeername:
2197 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002198 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002199 abi_ulong target_addr, target_addrlen;
2200
Ulrich Hecht98818182009-07-03 17:09:28 +02002201 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002202 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002203 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002204 return -TARGET_EFAULT;
2205
pbrook1be9e1d2006-11-19 15:26:04 +00002206 ret = do_getpeername(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002207 }
2208 break;
2209 case SOCKOP_socketpair:
2210 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002211 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002212 abi_ulong tab;
2213
Ulrich Hecht98818182009-07-03 17:09:28 +02002214 if (get_user_ual(domain, vptr)
2215 || get_user_ual(type, vptr + n)
2216 || get_user_ual(protocol, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002217 || get_user_ual(tab, vptr + 3 * n))
2218 return -TARGET_EFAULT;
2219
pbrook1be9e1d2006-11-19 15:26:04 +00002220 ret = do_socketpair(domain, type, protocol, tab);
bellard31e31b82003-02-18 22:55:36 +00002221 }
2222 break;
2223 case SOCKOP_send:
bellard7854b052003-03-29 17:22:23 +00002224 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002225 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002226 abi_ulong msg;
2227 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002228 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002229
Ulrich Hecht98818182009-07-03 17:09:28 +02002230 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002231 || get_user_ual(msg, vptr + n)
2232 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002233 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002234 return -TARGET_EFAULT;
2235
pbrook1be9e1d2006-11-19 15:26:04 +00002236 ret = do_sendto(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002237 }
bellard31e31b82003-02-18 22:55:36 +00002238 break;
2239 case SOCKOP_recv:
bellard7854b052003-03-29 17:22:23 +00002240 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002241 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002242 abi_ulong msg;
2243 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002244 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002245
Ulrich Hecht98818182009-07-03 17:09:28 +02002246 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002247 || get_user_ual(msg, vptr + n)
2248 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002249 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002250 return -TARGET_EFAULT;
2251
pbrook1be9e1d2006-11-19 15:26:04 +00002252 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002253 }
bellard31e31b82003-02-18 22:55:36 +00002254 break;
2255 case SOCKOP_sendto:
bellard7854b052003-03-29 17:22:23 +00002256 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002257 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002258 abi_ulong msg;
2259 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002260 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002261 abi_ulong addr;
2262 socklen_t addrlen;
2263
Ulrich Hecht98818182009-07-03 17:09:28 +02002264 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002265 || get_user_ual(msg, vptr + n)
2266 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002267 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002268 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002269 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002270 return -TARGET_EFAULT;
2271
pbrook1be9e1d2006-11-19 15:26:04 +00002272 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002273 }
bellard31e31b82003-02-18 22:55:36 +00002274 break;
2275 case SOCKOP_recvfrom:
2276 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002277 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002278 abi_ulong msg;
2279 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002280 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002281 abi_ulong addr;
2282 socklen_t addrlen;
2283
Ulrich Hecht98818182009-07-03 17:09:28 +02002284 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002285 || get_user_ual(msg, vptr + n)
2286 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002287 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002288 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002289 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002290 return -TARGET_EFAULT;
2291
pbrook1be9e1d2006-11-19 15:26:04 +00002292 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
bellard31e31b82003-02-18 22:55:36 +00002293 }
2294 break;
2295 case SOCKOP_shutdown:
bellard7854b052003-03-29 17:22:23 +00002296 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002297 abi_ulong sockfd, how;
bellard2f619692007-11-16 10:46:05 +00002298
Ulrich Hecht98818182009-07-03 17:09:28 +02002299 if (get_user_ual(sockfd, vptr)
2300 || get_user_ual(how, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002301 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002302
2303 ret = get_errno(shutdown(sockfd, how));
2304 }
bellard31e31b82003-02-18 22:55:36 +00002305 break;
2306 case SOCKOP_sendmsg:
2307 case SOCKOP_recvmsg:
bellard1a9353d2003-03-16 20:28:50 +00002308 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002309 abi_ulong fd;
blueswir1992f48a2007-10-14 16:27:31 +00002310 abi_ulong target_msg;
Ulrich Hecht98818182009-07-03 17:09:28 +02002311 abi_ulong flags;
bellard1a9353d2003-03-16 20:28:50 +00002312
Ulrich Hecht98818182009-07-03 17:09:28 +02002313 if (get_user_ual(fd, vptr)
bellard2f619692007-11-16 10:46:05 +00002314 || get_user_ual(target_msg, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002315 || get_user_ual(flags, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002316 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002317
ths5fafdf22007-09-16 21:08:06 +00002318 ret = do_sendrecvmsg(fd, target_msg, flags,
bellard3532fa72006-06-24 15:06:03 +00002319 (num == SOCKOP_sendmsg));
bellard1a9353d2003-03-16 20:28:50 +00002320 }
2321 break;
bellard31e31b82003-02-18 22:55:36 +00002322 case SOCKOP_setsockopt:
bellard7854b052003-03-29 17:22:23 +00002323 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002324 abi_ulong sockfd;
2325 abi_ulong level;
2326 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002327 abi_ulong optval;
2328 socklen_t optlen;
2329
Ulrich Hecht98818182009-07-03 17:09:28 +02002330 if (get_user_ual(sockfd, vptr)
2331 || get_user_ual(level, vptr + n)
2332 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002333 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002334 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002335 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002336
2337 ret = do_setsockopt(sockfd, level, optname, optval, optlen);
2338 }
2339 break;
bellard31e31b82003-02-18 22:55:36 +00002340 case SOCKOP_getsockopt:
bellard7854b052003-03-29 17:22:23 +00002341 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002342 abi_ulong sockfd;
2343 abi_ulong level;
2344 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002345 abi_ulong optval;
2346 socklen_t optlen;
bellard7854b052003-03-29 17:22:23 +00002347
Ulrich Hecht98818182009-07-03 17:09:28 +02002348 if (get_user_ual(sockfd, vptr)
2349 || get_user_ual(level, vptr + n)
2350 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002351 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002352 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002353 return -TARGET_EFAULT;
2354
2355 ret = do_getsockopt(sockfd, level, optname, optval, optlen);
bellard7854b052003-03-29 17:22:23 +00002356 }
2357 break;
bellard31e31b82003-02-18 22:55:36 +00002358 default:
2359 gemu_log("Unsupported socketcall: %d\n", num);
ths0da46a62007-10-20 20:23:07 +00002360 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002361 break;
2362 }
2363 return ret;
2364}
j_mayer32407102007-09-26 23:01:49 +00002365#endif
bellard31e31b82003-02-18 22:55:36 +00002366
bellard8853f862004-02-22 14:57:26 +00002367#define N_SHM_REGIONS 32
2368
2369static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002370 abi_ulong start;
2371 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002372} shm_regions[N_SHM_REGIONS];
2373
ths3eb6b042007-06-03 14:26:27 +00002374struct target_ipc_perm
2375{
blueswir1992f48a2007-10-14 16:27:31 +00002376 abi_long __key;
2377 abi_ulong uid;
2378 abi_ulong gid;
2379 abi_ulong cuid;
2380 abi_ulong cgid;
ths3eb6b042007-06-03 14:26:27 +00002381 unsigned short int mode;
2382 unsigned short int __pad1;
2383 unsigned short int __seq;
2384 unsigned short int __pad2;
blueswir1992f48a2007-10-14 16:27:31 +00002385 abi_ulong __unused1;
2386 abi_ulong __unused2;
ths3eb6b042007-06-03 14:26:27 +00002387};
2388
2389struct target_semid_ds
2390{
2391 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002392 abi_ulong sem_otime;
2393 abi_ulong __unused1;
2394 abi_ulong sem_ctime;
2395 abi_ulong __unused2;
2396 abi_ulong sem_nsems;
2397 abi_ulong __unused3;
2398 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002399};
2400
bellard579a97f2007-11-11 14:26:47 +00002401static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2402 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002403{
2404 struct target_ipc_perm *target_ip;
2405 struct target_semid_ds *target_sd;
2406
bellard579a97f2007-11-11 14:26:47 +00002407 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2408 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002409 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002410 host_ip->__key = tswapal(target_ip->__key);
2411 host_ip->uid = tswapal(target_ip->uid);
2412 host_ip->gid = tswapal(target_ip->gid);
2413 host_ip->cuid = tswapal(target_ip->cuid);
2414 host_ip->cgid = tswapal(target_ip->cgid);
2415 host_ip->mode = tswap16(target_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002416 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002417 return 0;
ths3eb6b042007-06-03 14:26:27 +00002418}
2419
bellard579a97f2007-11-11 14:26:47 +00002420static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2421 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002422{
2423 struct target_ipc_perm *target_ip;
2424 struct target_semid_ds *target_sd;
2425
bellard579a97f2007-11-11 14:26:47 +00002426 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2427 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002428 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002429 target_ip->__key = tswapal(host_ip->__key);
2430 target_ip->uid = tswapal(host_ip->uid);
2431 target_ip->gid = tswapal(host_ip->gid);
2432 target_ip->cuid = tswapal(host_ip->cuid);
2433 target_ip->cgid = tswapal(host_ip->cgid);
2434 target_ip->mode = tswap16(host_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002435 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002436 return 0;
ths3eb6b042007-06-03 14:26:27 +00002437}
2438
bellard579a97f2007-11-11 14:26:47 +00002439static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2440 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002441{
2442 struct target_semid_ds *target_sd;
2443
bellard579a97f2007-11-11 14:26:47 +00002444 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2445 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002446 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2447 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002448 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2449 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2450 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002451 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002452 return 0;
ths3eb6b042007-06-03 14:26:27 +00002453}
2454
bellard579a97f2007-11-11 14:26:47 +00002455static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2456 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002457{
2458 struct target_semid_ds *target_sd;
2459
bellard579a97f2007-11-11 14:26:47 +00002460 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2461 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002462 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002463 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002464 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2465 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2466 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002467 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002468 return 0;
ths3eb6b042007-06-03 14:26:27 +00002469}
2470
aurel32e5289082009-04-18 16:16:12 +00002471struct target_seminfo {
2472 int semmap;
2473 int semmni;
2474 int semmns;
2475 int semmnu;
2476 int semmsl;
2477 int semopm;
2478 int semume;
2479 int semusz;
2480 int semvmx;
2481 int semaem;
2482};
2483
2484static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2485 struct seminfo *host_seminfo)
2486{
2487 struct target_seminfo *target_seminfo;
2488 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2489 return -TARGET_EFAULT;
2490 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2491 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2492 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2493 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2494 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2495 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2496 __put_user(host_seminfo->semume, &target_seminfo->semume);
2497 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2498 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2499 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2500 unlock_user_struct(target_seminfo, target_addr, 1);
2501 return 0;
2502}
2503
thsfa294812007-02-02 22:05:00 +00002504union semun {
2505 int val;
ths3eb6b042007-06-03 14:26:27 +00002506 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002507 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002508 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002509};
2510
ths3eb6b042007-06-03 14:26:27 +00002511union target_semun {
2512 int val;
aurel32e5289082009-04-18 16:16:12 +00002513 abi_ulong buf;
2514 abi_ulong array;
2515 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002516};
2517
aurel32e5289082009-04-18 16:16:12 +00002518static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2519 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002520{
aurel32e5289082009-04-18 16:16:12 +00002521 int nsems;
2522 unsigned short *array;
2523 union semun semun;
2524 struct semid_ds semid_ds;
2525 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002526
aurel32e5289082009-04-18 16:16:12 +00002527 semun.buf = &semid_ds;
2528
2529 ret = semctl(semid, 0, IPC_STAT, semun);
2530 if (ret == -1)
2531 return get_errno(ret);
2532
2533 nsems = semid_ds.sem_nsems;
2534
2535 *host_array = malloc(nsems*sizeof(unsigned short));
2536 array = lock_user(VERIFY_READ, target_addr,
2537 nsems*sizeof(unsigned short), 1);
2538 if (!array)
2539 return -TARGET_EFAULT;
2540
2541 for(i=0; i<nsems; i++) {
2542 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002543 }
aurel32e5289082009-04-18 16:16:12 +00002544 unlock_user(array, target_addr, 0);
2545
bellard579a97f2007-11-11 14:26:47 +00002546 return 0;
ths3eb6b042007-06-03 14:26:27 +00002547}
2548
aurel32e5289082009-04-18 16:16:12 +00002549static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2550 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002551{
aurel32e5289082009-04-18 16:16:12 +00002552 int nsems;
2553 unsigned short *array;
2554 union semun semun;
2555 struct semid_ds semid_ds;
2556 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002557
aurel32e5289082009-04-18 16:16:12 +00002558 semun.buf = &semid_ds;
2559
2560 ret = semctl(semid, 0, IPC_STAT, semun);
2561 if (ret == -1)
2562 return get_errno(ret);
2563
2564 nsems = semid_ds.sem_nsems;
2565
2566 array = lock_user(VERIFY_WRITE, target_addr,
2567 nsems*sizeof(unsigned short), 0);
2568 if (!array)
2569 return -TARGET_EFAULT;
2570
2571 for(i=0; i<nsems; i++) {
2572 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002573 }
aurel32e5289082009-04-18 16:16:12 +00002574 free(*host_array);
2575 unlock_user(array, target_addr, 1);
2576
bellard579a97f2007-11-11 14:26:47 +00002577 return 0;
ths3eb6b042007-06-03 14:26:27 +00002578}
2579
aurel32e5289082009-04-18 16:16:12 +00002580static inline abi_long do_semctl(int semid, int semnum, int cmd,
2581 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002582{
2583 union semun arg;
2584 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302585 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002586 struct seminfo seminfo;
2587 abi_long ret = -TARGET_EINVAL;
2588 abi_long err;
2589 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002590
2591 switch( cmd ) {
2592 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002593 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002594 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002595 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002596 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002597 break;
2598 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002599 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002600 err = target_to_host_semarray(semid, &array, target_su.array);
2601 if (err)
2602 return err;
2603 arg.array = array;
2604 ret = get_errno(semctl(semid, semnum, cmd, arg));
2605 err = host_to_target_semarray(semid, target_su.array, &array);
2606 if (err)
2607 return err;
ths3eb6b042007-06-03 14:26:27 +00002608 break;
2609 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002610 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002611 case SEM_STAT:
2612 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2613 if (err)
2614 return err;
2615 arg.buf = &dsarg;
2616 ret = get_errno(semctl(semid, semnum, cmd, arg));
2617 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2618 if (err)
2619 return err;
ths3eb6b042007-06-03 14:26:27 +00002620 break;
aurel32e5289082009-04-18 16:16:12 +00002621 case IPC_INFO:
2622 case SEM_INFO:
2623 arg.__buf = &seminfo;
2624 ret = get_errno(semctl(semid, semnum, cmd, arg));
2625 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2626 if (err)
2627 return err;
2628 break;
2629 case IPC_RMID:
2630 case GETPID:
2631 case GETNCNT:
2632 case GETZCNT:
2633 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2634 break;
ths3eb6b042007-06-03 14:26:27 +00002635 }
2636
2637 return ret;
2638}
2639
aurel32e5289082009-04-18 16:16:12 +00002640struct target_sembuf {
2641 unsigned short sem_num;
2642 short sem_op;
2643 short sem_flg;
2644};
2645
2646static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2647 abi_ulong target_addr,
2648 unsigned nsops)
2649{
2650 struct target_sembuf *target_sembuf;
2651 int i;
2652
2653 target_sembuf = lock_user(VERIFY_READ, target_addr,
2654 nsops*sizeof(struct target_sembuf), 1);
2655 if (!target_sembuf)
2656 return -TARGET_EFAULT;
2657
2658 for(i=0; i<nsops; i++) {
2659 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2660 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2661 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2662 }
2663
2664 unlock_user(target_sembuf, target_addr, 0);
2665
2666 return 0;
2667}
2668
2669static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2670{
2671 struct sembuf sops[nsops];
2672
2673 if (target_to_host_sembuf(sops, ptr, nsops))
2674 return -TARGET_EFAULT;
2675
2676 return semop(semid, sops, nsops);
2677}
2678
ths1bc012f2007-06-03 14:27:49 +00002679struct target_msqid_ds
2680{
aurel321c54ff92008-10-13 21:08:44 +00002681 struct target_ipc_perm msg_perm;
2682 abi_ulong msg_stime;
2683#if TARGET_ABI_BITS == 32
2684 abi_ulong __unused1;
2685#endif
2686 abi_ulong msg_rtime;
2687#if TARGET_ABI_BITS == 32
2688 abi_ulong __unused2;
2689#endif
2690 abi_ulong msg_ctime;
2691#if TARGET_ABI_BITS == 32
2692 abi_ulong __unused3;
2693#endif
2694 abi_ulong __msg_cbytes;
2695 abi_ulong msg_qnum;
2696 abi_ulong msg_qbytes;
2697 abi_ulong msg_lspid;
2698 abi_ulong msg_lrpid;
2699 abi_ulong __unused4;
2700 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002701};
2702
bellard579a97f2007-11-11 14:26:47 +00002703static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2704 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002705{
2706 struct target_msqid_ds *target_md;
2707
bellard579a97f2007-11-11 14:26:47 +00002708 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2709 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002710 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2711 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002712 host_md->msg_stime = tswapal(target_md->msg_stime);
2713 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2714 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2715 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2716 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2717 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2718 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2719 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002720 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002721 return 0;
ths1bc012f2007-06-03 14:27:49 +00002722}
2723
bellard579a97f2007-11-11 14:26:47 +00002724static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2725 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002726{
2727 struct target_msqid_ds *target_md;
2728
bellard579a97f2007-11-11 14:26:47 +00002729 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2730 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002731 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2732 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002733 target_md->msg_stime = tswapal(host_md->msg_stime);
2734 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2735 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2736 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2737 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2738 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2739 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2740 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002741 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002742 return 0;
ths1bc012f2007-06-03 14:27:49 +00002743}
2744
aurel321c54ff92008-10-13 21:08:44 +00002745struct target_msginfo {
2746 int msgpool;
2747 int msgmap;
2748 int msgmax;
2749 int msgmnb;
2750 int msgmni;
2751 int msgssz;
2752 int msgtql;
2753 unsigned short int msgseg;
2754};
2755
2756static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2757 struct msginfo *host_msginfo)
2758{
2759 struct target_msginfo *target_msginfo;
2760 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2761 return -TARGET_EFAULT;
2762 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2763 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2764 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2765 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2766 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2767 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2768 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2769 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2770 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002771 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002772}
2773
2774static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002775{
2776 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002777 struct msginfo msginfo;
2778 abi_long ret = -TARGET_EINVAL;
2779
2780 cmd &= 0xff;
2781
2782 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002783 case IPC_STAT:
2784 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002785 case MSG_STAT:
2786 if (target_to_host_msqid_ds(&dsarg,ptr))
2787 return -TARGET_EFAULT;
2788 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2789 if (host_to_target_msqid_ds(ptr,&dsarg))
2790 return -TARGET_EFAULT;
2791 break;
2792 case IPC_RMID:
2793 ret = get_errno(msgctl(msgid, cmd, NULL));
2794 break;
2795 case IPC_INFO:
2796 case MSG_INFO:
2797 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2798 if (host_to_target_msginfo(ptr, &msginfo))
2799 return -TARGET_EFAULT;
2800 break;
ths1bc012f2007-06-03 14:27:49 +00002801 }
aurel321c54ff92008-10-13 21:08:44 +00002802
ths1bc012f2007-06-03 14:27:49 +00002803 return ret;
2804}
2805
2806struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002807 abi_long mtype;
2808 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002809};
2810
blueswir1992f48a2007-10-14 16:27:31 +00002811static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2812 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002813{
2814 struct target_msgbuf *target_mb;
2815 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002816 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002817
bellard579a97f2007-11-11 14:26:47 +00002818 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2819 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002820 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002821 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002822 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002823 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2824 free(host_mb);
2825 unlock_user_struct(target_mb, msgp, 0);
2826
2827 return ret;
2828}
2829
blueswir1992f48a2007-10-14 16:27:31 +00002830static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002831 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002832 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002833{
2834 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002835 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002836 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002837 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002838
bellard579a97f2007-11-11 14:26:47 +00002839 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2840 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002841
ths1bc012f2007-06-03 14:27:49 +00002842 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002843 ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002844
bellard579a97f2007-11-11 14:26:47 +00002845 if (ret > 0) {
2846 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2847 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2848 if (!target_mtext) {
2849 ret = -TARGET_EFAULT;
2850 goto end;
2851 }
aurel321c54ff92008-10-13 21:08:44 +00002852 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002853 unlock_user(target_mtext, target_mtext_addr, ret);
2854 }
aurel321c54ff92008-10-13 21:08:44 +00002855
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002856 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002857 free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002858
bellard579a97f2007-11-11 14:26:47 +00002859end:
2860 if (target_mb)
2861 unlock_user_struct(target_mb, msgp, 1);
ths1bc012f2007-06-03 14:27:49 +00002862 return ret;
2863}
2864
Riku Voipio88a8c982009-04-03 10:42:00 +03002865struct target_shmid_ds
2866{
2867 struct target_ipc_perm shm_perm;
2868 abi_ulong shm_segsz;
2869 abi_ulong shm_atime;
2870#if TARGET_ABI_BITS == 32
2871 abi_ulong __unused1;
2872#endif
2873 abi_ulong shm_dtime;
2874#if TARGET_ABI_BITS == 32
2875 abi_ulong __unused2;
2876#endif
2877 abi_ulong shm_ctime;
2878#if TARGET_ABI_BITS == 32
2879 abi_ulong __unused3;
2880#endif
2881 int shm_cpid;
2882 int shm_lpid;
2883 abi_ulong shm_nattch;
2884 unsigned long int __unused4;
2885 unsigned long int __unused5;
2886};
2887
2888static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2889 abi_ulong target_addr)
2890{
2891 struct target_shmid_ds *target_sd;
2892
2893 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2894 return -TARGET_EFAULT;
2895 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2896 return -TARGET_EFAULT;
2897 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2898 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2899 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2900 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2901 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2902 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2903 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2904 unlock_user_struct(target_sd, target_addr, 0);
2905 return 0;
2906}
2907
2908static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2909 struct shmid_ds *host_sd)
2910{
2911 struct target_shmid_ds *target_sd;
2912
2913 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2914 return -TARGET_EFAULT;
2915 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2916 return -TARGET_EFAULT;
2917 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2918 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2919 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2920 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2921 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2922 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2923 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2924 unlock_user_struct(target_sd, target_addr, 1);
2925 return 0;
2926}
2927
2928struct target_shminfo {
2929 abi_ulong shmmax;
2930 abi_ulong shmmin;
2931 abi_ulong shmmni;
2932 abi_ulong shmseg;
2933 abi_ulong shmall;
2934};
2935
2936static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2937 struct shminfo *host_shminfo)
2938{
2939 struct target_shminfo *target_shminfo;
2940 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2941 return -TARGET_EFAULT;
2942 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2943 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2944 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2945 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2946 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2947 unlock_user_struct(target_shminfo, target_addr, 1);
2948 return 0;
2949}
2950
2951struct target_shm_info {
2952 int used_ids;
2953 abi_ulong shm_tot;
2954 abi_ulong shm_rss;
2955 abi_ulong shm_swp;
2956 abi_ulong swap_attempts;
2957 abi_ulong swap_successes;
2958};
2959
2960static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2961 struct shm_info *host_shm_info)
2962{
2963 struct target_shm_info *target_shm_info;
2964 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2965 return -TARGET_EFAULT;
2966 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2967 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2968 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2969 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2970 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2971 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
2972 unlock_user_struct(target_shm_info, target_addr, 1);
2973 return 0;
2974}
2975
2976static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
2977{
2978 struct shmid_ds dsarg;
2979 struct shminfo shminfo;
2980 struct shm_info shm_info;
2981 abi_long ret = -TARGET_EINVAL;
2982
2983 cmd &= 0xff;
2984
2985 switch(cmd) {
2986 case IPC_STAT:
2987 case IPC_SET:
2988 case SHM_STAT:
2989 if (target_to_host_shmid_ds(&dsarg, buf))
2990 return -TARGET_EFAULT;
2991 ret = get_errno(shmctl(shmid, cmd, &dsarg));
2992 if (host_to_target_shmid_ds(buf, &dsarg))
2993 return -TARGET_EFAULT;
2994 break;
2995 case IPC_INFO:
2996 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
2997 if (host_to_target_shminfo(buf, &shminfo))
2998 return -TARGET_EFAULT;
2999 break;
3000 case SHM_INFO:
3001 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3002 if (host_to_target_shm_info(buf, &shm_info))
3003 return -TARGET_EFAULT;
3004 break;
3005 case IPC_RMID:
3006 case SHM_LOCK:
3007 case SHM_UNLOCK:
3008 ret = get_errno(shmctl(shmid, cmd, NULL));
3009 break;
3010 }
3011
3012 return ret;
3013}
3014
3015static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3016{
3017 abi_long raddr;
3018 void *host_raddr;
3019 struct shmid_ds shm_info;
3020 int i,ret;
3021
3022 /* find out the length of the shared memory segment */
3023 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3024 if (is_error(ret)) {
3025 /* can't get length, bail out */
3026 return ret;
3027 }
3028
3029 mmap_lock();
3030
3031 if (shmaddr)
3032 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3033 else {
3034 abi_ulong mmap_start;
3035
3036 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3037
3038 if (mmap_start == -1) {
3039 errno = ENOMEM;
3040 host_raddr = (void *)-1;
3041 } else
3042 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3043 }
3044
3045 if (host_raddr == (void *)-1) {
3046 mmap_unlock();
3047 return get_errno((long)host_raddr);
3048 }
3049 raddr=h2g((unsigned long)host_raddr);
3050
3051 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3052 PAGE_VALID | PAGE_READ |
3053 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3054
3055 for (i = 0; i < N_SHM_REGIONS; i++) {
3056 if (shm_regions[i].start == 0) {
3057 shm_regions[i].start = raddr;
3058 shm_regions[i].size = shm_info.shm_segsz;
3059 break;
3060 }
3061 }
3062
3063 mmap_unlock();
3064 return raddr;
3065
3066}
3067
3068static inline abi_long do_shmdt(abi_ulong shmaddr)
3069{
3070 int i;
3071
3072 for (i = 0; i < N_SHM_REGIONS; ++i) {
3073 if (shm_regions[i].start == shmaddr) {
3074 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003075 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003076 break;
3077 }
3078 }
3079
3080 return get_errno(shmdt(g2h(shmaddr)));
3081}
3082
aurel321c54ff92008-10-13 21:08:44 +00003083#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003084/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003085/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003086static abi_long do_ipc(unsigned int call, int first,
3087 int second, int third,
3088 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003089{
3090 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003091 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003092
3093 version = call >> 16;
3094 call &= 0xffff;
3095
3096 switch (call) {
thsfa294812007-02-02 22:05:00 +00003097 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003098 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003099 break;
3100
3101 case IPCOP_semget:
3102 ret = get_errno(semget(first, second, third));
3103 break;
3104
3105 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003106 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003107 break;
thsd96372e2007-02-02 22:05:44 +00003108
aurel321c54ff92008-10-13 21:08:44 +00003109 case IPCOP_msgget:
3110 ret = get_errno(msgget(first, second));
3111 break;
thsd96372e2007-02-02 22:05:44 +00003112
aurel321c54ff92008-10-13 21:08:44 +00003113 case IPCOP_msgsnd:
3114 ret = do_msgsnd(first, ptr, second, third);
3115 break;
thsd96372e2007-02-02 22:05:44 +00003116
aurel321c54ff92008-10-13 21:08:44 +00003117 case IPCOP_msgctl:
3118 ret = do_msgctl(first, second, ptr);
3119 break;
thsd96372e2007-02-02 22:05:44 +00003120
aurel321c54ff92008-10-13 21:08:44 +00003121 case IPCOP_msgrcv:
3122 switch (version) {
3123 case 0:
3124 {
3125 struct target_ipc_kludge {
3126 abi_long msgp;
3127 abi_long msgtyp;
3128 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003129
aurel321c54ff92008-10-13 21:08:44 +00003130 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3131 ret = -TARGET_EFAULT;
3132 break;
ths1bc012f2007-06-03 14:27:49 +00003133 }
aurel321c54ff92008-10-13 21:08:44 +00003134
3135 ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
3136
3137 unlock_user_struct(tmp, ptr, 0);
3138 break;
3139 }
3140 default:
3141 ret = do_msgrcv(first, ptr, second, fifth, third);
3142 }
3143 break;
thsd96372e2007-02-02 22:05:44 +00003144
bellard8853f862004-02-22 14:57:26 +00003145 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003146 switch (version) {
3147 default:
bellard5a4a8982007-11-11 17:39:18 +00003148 {
3149 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003150 raddr = do_shmat(first, ptr, second);
3151 if (is_error(raddr))
3152 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003153 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003154 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003155 break;
3156 }
3157 case 1:
3158 ret = -TARGET_EINVAL;
3159 break;
bellard5a4a8982007-11-11 17:39:18 +00003160 }
bellard8853f862004-02-22 14:57:26 +00003161 break;
3162 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003163 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003164 break;
3165
3166 case IPCOP_shmget:
3167 /* IPC_* flag values are the same on all linux platforms */
3168 ret = get_errno(shmget(first, second, third));
3169 break;
3170
3171 /* IPC_* and SHM_* command values are the same on all linux platforms */
3172 case IPCOP_shmctl:
Riku Voipio88a8c982009-04-03 10:42:00 +03003173 ret = do_shmctl(first, second, third);
bellard8853f862004-02-22 14:57:26 +00003174 break;
3175 default:
j_mayer32407102007-09-26 23:01:49 +00003176 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003177 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003178 break;
3179 }
3180 return ret;
3181}
j_mayer32407102007-09-26 23:01:49 +00003182#endif
bellard8853f862004-02-22 14:57:26 +00003183
bellard31e31b82003-02-18 22:55:36 +00003184/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003185
Blue Swirl001faf32009-05-13 17:53:17 +00003186#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003187#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3188enum {
3189#include "syscall_types.h"
3190};
3191#undef STRUCT
3192#undef STRUCT_SPECIAL
3193
Blue Swirl001faf32009-05-13 17:53:17 +00003194#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003195#define STRUCT_SPECIAL(name)
3196#include "syscall_types.h"
3197#undef STRUCT
3198#undef STRUCT_SPECIAL
3199
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003200typedef struct IOCTLEntry IOCTLEntry;
3201
3202typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3203 int fd, abi_long cmd, abi_long arg);
3204
3205struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003206 unsigned int target_cmd;
3207 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003208 const char *name;
3209 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003210 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003211 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003212};
bellard31e31b82003-02-18 22:55:36 +00003213
3214#define IOC_R 0x0001
3215#define IOC_W 0x0002
3216#define IOC_RW (IOC_R | IOC_W)
3217
3218#define MAX_STRUCT_SIZE 4096
3219
Peter Maydelldace20d2011-01-10 13:11:24 +00003220#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003221/* So fiemap access checks don't overflow on 32 bit systems.
3222 * This is very slightly smaller than the limit imposed by
3223 * the underlying kernel.
3224 */
3225#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3226 / sizeof(struct fiemap_extent))
3227
3228static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3229 int fd, abi_long cmd, abi_long arg)
3230{
3231 /* The parameter for this ioctl is a struct fiemap followed
3232 * by an array of struct fiemap_extent whose size is set
3233 * in fiemap->fm_extent_count. The array is filled in by the
3234 * ioctl.
3235 */
3236 int target_size_in, target_size_out;
3237 struct fiemap *fm;
3238 const argtype *arg_type = ie->arg_type;
3239 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3240 void *argptr, *p;
3241 abi_long ret;
3242 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3243 uint32_t outbufsz;
3244 int free_fm = 0;
3245
3246 assert(arg_type[0] == TYPE_PTR);
3247 assert(ie->access == IOC_RW);
3248 arg_type++;
3249 target_size_in = thunk_type_size(arg_type, 0);
3250 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3251 if (!argptr) {
3252 return -TARGET_EFAULT;
3253 }
3254 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3255 unlock_user(argptr, arg, 0);
3256 fm = (struct fiemap *)buf_temp;
3257 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3258 return -TARGET_EINVAL;
3259 }
3260
3261 outbufsz = sizeof (*fm) +
3262 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3263
3264 if (outbufsz > MAX_STRUCT_SIZE) {
3265 /* We can't fit all the extents into the fixed size buffer.
3266 * Allocate one that is large enough and use it instead.
3267 */
3268 fm = malloc(outbufsz);
3269 if (!fm) {
3270 return -TARGET_ENOMEM;
3271 }
3272 memcpy(fm, buf_temp, sizeof(struct fiemap));
3273 free_fm = 1;
3274 }
3275 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3276 if (!is_error(ret)) {
3277 target_size_out = target_size_in;
3278 /* An extent_count of 0 means we were only counting the extents
3279 * so there are no structs to copy
3280 */
3281 if (fm->fm_extent_count != 0) {
3282 target_size_out += fm->fm_mapped_extents * extent_size;
3283 }
3284 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3285 if (!argptr) {
3286 ret = -TARGET_EFAULT;
3287 } else {
3288 /* Convert the struct fiemap */
3289 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3290 if (fm->fm_extent_count != 0) {
3291 p = argptr + target_size_in;
3292 /* ...and then all the struct fiemap_extents */
3293 for (i = 0; i < fm->fm_mapped_extents; i++) {
3294 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3295 THUNK_TARGET);
3296 p += extent_size;
3297 }
3298 }
3299 unlock_user(argptr, arg, target_size_out);
3300 }
3301 }
3302 if (free_fm) {
3303 free(fm);
3304 }
3305 return ret;
3306}
Peter Maydelldace20d2011-01-10 13:11:24 +00003307#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003308
Laurent Vivier059c2f22011-03-30 00:12:12 +02003309static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3310 int fd, abi_long cmd, abi_long arg)
3311{
3312 const argtype *arg_type = ie->arg_type;
3313 int target_size;
3314 void *argptr;
3315 int ret;
3316 struct ifconf *host_ifconf;
3317 uint32_t outbufsz;
3318 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3319 int target_ifreq_size;
3320 int nb_ifreq;
3321 int free_buf = 0;
3322 int i;
3323 int target_ifc_len;
3324 abi_long target_ifc_buf;
3325 int host_ifc_len;
3326 char *host_ifc_buf;
3327
3328 assert(arg_type[0] == TYPE_PTR);
3329 assert(ie->access == IOC_RW);
3330
3331 arg_type++;
3332 target_size = thunk_type_size(arg_type, 0);
3333
3334 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3335 if (!argptr)
3336 return -TARGET_EFAULT;
3337 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3338 unlock_user(argptr, arg, 0);
3339
3340 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3341 target_ifc_len = host_ifconf->ifc_len;
3342 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3343
3344 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3345 nb_ifreq = target_ifc_len / target_ifreq_size;
3346 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3347
3348 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3349 if (outbufsz > MAX_STRUCT_SIZE) {
3350 /* We can't fit all the extents into the fixed size buffer.
3351 * Allocate one that is large enough and use it instead.
3352 */
3353 host_ifconf = malloc(outbufsz);
3354 if (!host_ifconf) {
3355 return -TARGET_ENOMEM;
3356 }
3357 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3358 free_buf = 1;
3359 }
3360 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3361
3362 host_ifconf->ifc_len = host_ifc_len;
3363 host_ifconf->ifc_buf = host_ifc_buf;
3364
3365 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3366 if (!is_error(ret)) {
3367 /* convert host ifc_len to target ifc_len */
3368
3369 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3370 target_ifc_len = nb_ifreq * target_ifreq_size;
3371 host_ifconf->ifc_len = target_ifc_len;
3372
3373 /* restore target ifc_buf */
3374
3375 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3376
3377 /* copy struct ifconf to target user */
3378
3379 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3380 if (!argptr)
3381 return -TARGET_EFAULT;
3382 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3383 unlock_user(argptr, arg, target_size);
3384
3385 /* copy ifreq[] to target user */
3386
3387 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3388 for (i = 0; i < nb_ifreq ; i++) {
3389 thunk_convert(argptr + i * target_ifreq_size,
3390 host_ifc_buf + i * sizeof(struct ifreq),
3391 ifreq_arg_type, THUNK_TARGET);
3392 }
3393 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3394 }
3395
3396 if (free_buf) {
3397 free(host_ifconf);
3398 }
3399
3400 return ret;
3401}
3402
Alexander Graf56e904e2012-01-31 18:42:06 +01003403static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3404 abi_long cmd, abi_long arg)
3405{
3406 void *argptr;
3407 struct dm_ioctl *host_dm;
3408 abi_long guest_data;
3409 uint32_t guest_data_size;
3410 int target_size;
3411 const argtype *arg_type = ie->arg_type;
3412 abi_long ret;
3413 void *big_buf = NULL;
3414 char *host_data;
3415
3416 arg_type++;
3417 target_size = thunk_type_size(arg_type, 0);
3418 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3419 if (!argptr) {
3420 ret = -TARGET_EFAULT;
3421 goto out;
3422 }
3423 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3424 unlock_user(argptr, arg, 0);
3425
3426 /* buf_temp is too small, so fetch things into a bigger buffer */
3427 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3428 memcpy(big_buf, buf_temp, target_size);
3429 buf_temp = big_buf;
3430 host_dm = big_buf;
3431
3432 guest_data = arg + host_dm->data_start;
3433 if ((guest_data - arg) < 0) {
3434 ret = -EINVAL;
3435 goto out;
3436 }
3437 guest_data_size = host_dm->data_size - host_dm->data_start;
3438 host_data = (char*)host_dm + host_dm->data_start;
3439
3440 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3441 switch (ie->host_cmd) {
3442 case DM_REMOVE_ALL:
3443 case DM_LIST_DEVICES:
3444 case DM_DEV_CREATE:
3445 case DM_DEV_REMOVE:
3446 case DM_DEV_SUSPEND:
3447 case DM_DEV_STATUS:
3448 case DM_DEV_WAIT:
3449 case DM_TABLE_STATUS:
3450 case DM_TABLE_CLEAR:
3451 case DM_TABLE_DEPS:
3452 case DM_LIST_VERSIONS:
3453 /* no input data */
3454 break;
3455 case DM_DEV_RENAME:
3456 case DM_DEV_SET_GEOMETRY:
3457 /* data contains only strings */
3458 memcpy(host_data, argptr, guest_data_size);
3459 break;
3460 case DM_TARGET_MSG:
3461 memcpy(host_data, argptr, guest_data_size);
3462 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3463 break;
3464 case DM_TABLE_LOAD:
3465 {
3466 void *gspec = argptr;
3467 void *cur_data = host_data;
3468 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3469 int spec_size = thunk_type_size(arg_type, 0);
3470 int i;
3471
3472 for (i = 0; i < host_dm->target_count; i++) {
3473 struct dm_target_spec *spec = cur_data;
3474 uint32_t next;
3475 int slen;
3476
3477 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3478 slen = strlen((char*)gspec + spec_size) + 1;
3479 next = spec->next;
3480 spec->next = sizeof(*spec) + slen;
3481 strcpy((char*)&spec[1], gspec + spec_size);
3482 gspec += next;
3483 cur_data += spec->next;
3484 }
3485 break;
3486 }
3487 default:
3488 ret = -TARGET_EINVAL;
3489 goto out;
3490 }
3491 unlock_user(argptr, guest_data, 0);
3492
3493 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3494 if (!is_error(ret)) {
3495 guest_data = arg + host_dm->data_start;
3496 guest_data_size = host_dm->data_size - host_dm->data_start;
3497 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3498 switch (ie->host_cmd) {
3499 case DM_REMOVE_ALL:
3500 case DM_DEV_CREATE:
3501 case DM_DEV_REMOVE:
3502 case DM_DEV_RENAME:
3503 case DM_DEV_SUSPEND:
3504 case DM_DEV_STATUS:
3505 case DM_TABLE_LOAD:
3506 case DM_TABLE_CLEAR:
3507 case DM_TARGET_MSG:
3508 case DM_DEV_SET_GEOMETRY:
3509 /* no return data */
3510 break;
3511 case DM_LIST_DEVICES:
3512 {
3513 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3514 uint32_t remaining_data = guest_data_size;
3515 void *cur_data = argptr;
3516 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3517 int nl_size = 12; /* can't use thunk_size due to alignment */
3518
3519 while (1) {
3520 uint32_t next = nl->next;
3521 if (next) {
3522 nl->next = nl_size + (strlen(nl->name) + 1);
3523 }
3524 if (remaining_data < nl->next) {
3525 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3526 break;
3527 }
3528 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3529 strcpy(cur_data + nl_size, nl->name);
3530 cur_data += nl->next;
3531 remaining_data -= nl->next;
3532 if (!next) {
3533 break;
3534 }
3535 nl = (void*)nl + next;
3536 }
3537 break;
3538 }
3539 case DM_DEV_WAIT:
3540 case DM_TABLE_STATUS:
3541 {
3542 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3543 void *cur_data = argptr;
3544 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3545 int spec_size = thunk_type_size(arg_type, 0);
3546 int i;
3547
3548 for (i = 0; i < host_dm->target_count; i++) {
3549 uint32_t next = spec->next;
3550 int slen = strlen((char*)&spec[1]) + 1;
3551 spec->next = (cur_data - argptr) + spec_size + slen;
3552 if (guest_data_size < spec->next) {
3553 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3554 break;
3555 }
3556 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3557 strcpy(cur_data + spec_size, (char*)&spec[1]);
3558 cur_data = argptr + spec->next;
3559 spec = (void*)host_dm + host_dm->data_start + next;
3560 }
3561 break;
3562 }
3563 case DM_TABLE_DEPS:
3564 {
3565 void *hdata = (void*)host_dm + host_dm->data_start;
3566 int count = *(uint32_t*)hdata;
3567 uint64_t *hdev = hdata + 8;
3568 uint64_t *gdev = argptr + 8;
3569 int i;
3570
3571 *(uint32_t*)argptr = tswap32(count);
3572 for (i = 0; i < count; i++) {
3573 *gdev = tswap64(*hdev);
3574 gdev++;
3575 hdev++;
3576 }
3577 break;
3578 }
3579 case DM_LIST_VERSIONS:
3580 {
3581 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3582 uint32_t remaining_data = guest_data_size;
3583 void *cur_data = argptr;
3584 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3585 int vers_size = thunk_type_size(arg_type, 0);
3586
3587 while (1) {
3588 uint32_t next = vers->next;
3589 if (next) {
3590 vers->next = vers_size + (strlen(vers->name) + 1);
3591 }
3592 if (remaining_data < vers->next) {
3593 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3594 break;
3595 }
3596 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3597 strcpy(cur_data + vers_size, vers->name);
3598 cur_data += vers->next;
3599 remaining_data -= vers->next;
3600 if (!next) {
3601 break;
3602 }
3603 vers = (void*)vers + next;
3604 }
3605 break;
3606 }
3607 default:
3608 ret = -TARGET_EINVAL;
3609 goto out;
3610 }
3611 unlock_user(argptr, guest_data, guest_data_size);
3612
3613 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3614 if (!argptr) {
3615 ret = -TARGET_EFAULT;
3616 goto out;
3617 }
3618 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3619 unlock_user(argptr, arg, target_size);
3620 }
3621out:
3622 if (big_buf) {
3623 free(big_buf);
3624 }
3625 return ret;
3626}
3627
blueswir19f106a72008-10-05 10:52:52 +00003628static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003629#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003630 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3631#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3632 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003633#include "ioctls.h"
3634 { 0, 0, },
3635};
3636
pbrook53a59602006-03-25 19:31:22 +00003637/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003638/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003639static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003640{
3641 const IOCTLEntry *ie;
3642 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003643 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003644 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003645 int target_size;
3646 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003647
3648 ie = ioctl_entries;
3649 for(;;) {
3650 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003651 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003652 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003653 }
3654 if (ie->target_cmd == cmd)
3655 break;
3656 ie++;
3657 }
3658 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003659#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003660 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003661#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003662 if (ie->do_ioctl) {
3663 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3664 }
3665
bellard31e31b82003-02-18 22:55:36 +00003666 switch(arg_type[0]) {
3667 case TYPE_NULL:
3668 /* no argument */
3669 ret = get_errno(ioctl(fd, ie->host_cmd));
3670 break;
3671 case TYPE_PTRVOID:
3672 case TYPE_INT:
3673 /* int argment */
3674 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3675 break;
3676 case TYPE_PTR:
3677 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003678 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003679 switch(ie->access) {
3680 case IOC_R:
3681 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3682 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003683 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3684 if (!argptr)
3685 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003686 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3687 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003688 }
3689 break;
3690 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003691 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3692 if (!argptr)
3693 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003694 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3695 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003696 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3697 break;
3698 default:
3699 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003700 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3701 if (!argptr)
3702 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003703 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3704 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003705 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3706 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003707 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3708 if (!argptr)
3709 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003710 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3711 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003712 }
3713 break;
3714 }
3715 break;
3716 default:
j_mayer32407102007-09-26 23:01:49 +00003717 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3718 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003719 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003720 break;
3721 }
3722 return ret;
3723}
3724
blueswir1b39bc502008-10-05 10:51:10 +00003725static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003726 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3727 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3728 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3729 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3730 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3731 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3732 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3733 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3734 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3735 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3736 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3737 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3738 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3739 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3740 { 0, 0, 0, 0 }
3741};
3742
blueswir1b39bc502008-10-05 10:51:10 +00003743static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003744 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3745 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3746 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3747 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3748 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3749 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3750 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3751 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3752 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3753 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3754 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3755 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3756 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3757 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3758 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3759 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3760 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3761 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3762 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3763 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3764 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3765 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3766 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3767 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3768 { 0, 0, 0, 0 }
3769};
3770
blueswir1b39bc502008-10-05 10:51:10 +00003771static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003772 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3773 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3774 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3775 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3776 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3777 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3778 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3779 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3780 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3781 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3782 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3783 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3784 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3785 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3786 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3787 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3788 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3789 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3790 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3791 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3792 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3793 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3794 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3795 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3796 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3797 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3798 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3799 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3800 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3801 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3802 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3803 { 0, 0, 0, 0 }
3804};
3805
blueswir1b39bc502008-10-05 10:51:10 +00003806static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003807 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3808 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3809 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3810 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3811 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3812 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3813 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3814 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3815 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3816 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3817 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3818 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3819 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3820 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3821 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3822 { 0, 0, 0, 0 }
3823};
3824
3825static void target_to_host_termios (void *dst, const void *src)
3826{
3827 struct host_termios *host = dst;
3828 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003829
ths5fafdf22007-09-16 21:08:06 +00003830 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003831 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003832 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003833 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003834 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003835 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003836 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003837 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3838 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003839
Arnaud Patard44607122009-04-21 17:39:08 +03003840 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003841 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3842 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003843 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003844 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003845 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003846 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003847 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003848 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003849 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003850 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3851 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003852 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3853 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3854 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3855 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3856 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003857 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003858}
ths3b46e622007-09-17 08:09:54 +00003859
bellard31e31b82003-02-18 22:55:36 +00003860static void host_to_target_termios (void *dst, const void *src)
3861{
3862 struct target_termios *target = dst;
3863 const struct host_termios *host = src;
3864
ths5fafdf22007-09-16 21:08:06 +00003865 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003866 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003867 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003868 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003869 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003870 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003871 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003872 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3873 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003874
Arnaud Patard44607122009-04-21 17:39:08 +03003875 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003876 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3877 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3878 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3879 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3880 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3881 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3882 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3883 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3884 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3885 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3886 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3887 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3888 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3889 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3890 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3891 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3892 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3893}
3894
blueswir18e853dc2008-10-05 10:49:32 +00003895static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003896 .convert = { host_to_target_termios, target_to_host_termios },
3897 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3898 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3899};
3900
bellard5286db72003-06-05 00:57:30 +00003901static bitmask_transtbl mmap_flags_tbl[] = {
3902 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3903 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3904 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3905 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3906 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3907 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3908 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3909 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3910 { 0, 0, 0, 0 }
3911};
3912
bellard2ab83ea2003-06-15 19:56:46 +00003913#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003914
3915/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003916static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003917
bellard03acab62007-11-11 14:57:14 +00003918static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003919{
3920 int size;
pbrook53a59602006-03-25 19:31:22 +00003921 void *p;
bellard6dbad632003-03-16 18:05:05 +00003922
3923 if (!ldt_table)
3924 return 0;
3925 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3926 if (size > bytecount)
3927 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003928 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3929 if (!p)
bellard03acab62007-11-11 14:57:14 +00003930 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003931 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003932 memcpy(p, ldt_table, size);
3933 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003934 return size;
3935}
3936
3937/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003938static abi_long write_ldt(CPUX86State *env,
3939 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003940{
3941 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003942 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003943 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003944 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003945 uint32_t *lp, entry_1, entry_2;
3946
3947 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003948 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003949 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003950 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003951 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003952 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00003953 ldt_info.limit = tswap32(target_ldt_info->limit);
3954 ldt_info.flags = tswap32(target_ldt_info->flags);
3955 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003956
bellard6dbad632003-03-16 18:05:05 +00003957 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003958 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003959 seg_32bit = ldt_info.flags & 1;
3960 contents = (ldt_info.flags >> 1) & 3;
3961 read_exec_only = (ldt_info.flags >> 3) & 1;
3962 limit_in_pages = (ldt_info.flags >> 4) & 1;
3963 seg_not_present = (ldt_info.flags >> 5) & 1;
3964 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00003965#ifdef TARGET_ABI32
3966 lm = 0;
3967#else
3968 lm = (ldt_info.flags >> 7) & 1;
3969#endif
bellard6dbad632003-03-16 18:05:05 +00003970 if (contents == 3) {
3971 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00003972 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003973 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00003974 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003975 }
3976 /* allocate the LDT */
3977 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00003978 env->ldt.base = target_mmap(0,
3979 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
3980 PROT_READ|PROT_WRITE,
3981 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3982 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00003983 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00003984 memset(g2h(env->ldt.base), 0,
3985 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00003986 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00003987 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00003988 }
3989
3990 /* NOTE: same code as Linux kernel */
3991 /* Allow LDTs to be cleared by the user. */
3992 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3993 if (oldmode ||
3994 (contents == 0 &&
3995 read_exec_only == 1 &&
3996 seg_32bit == 0 &&
3997 limit_in_pages == 0 &&
3998 seg_not_present == 1 &&
3999 useable == 0 )) {
4000 entry_1 = 0;
4001 entry_2 = 0;
4002 goto install;
4003 }
4004 }
ths3b46e622007-09-17 08:09:54 +00004005
bellard6dbad632003-03-16 18:05:05 +00004006 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4007 (ldt_info.limit & 0x0ffff);
4008 entry_2 = (ldt_info.base_addr & 0xff000000) |
4009 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4010 (ldt_info.limit & 0xf0000) |
4011 ((read_exec_only ^ 1) << 9) |
4012 (contents << 10) |
4013 ((seg_not_present ^ 1) << 15) |
4014 (seg_32bit << 22) |
4015 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004016 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004017 0x7000;
4018 if (!oldmode)
4019 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004020
bellard6dbad632003-03-16 18:05:05 +00004021 /* Install the new entry ... */
4022install:
4023 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4024 lp[0] = tswap32(entry_1);
4025 lp[1] = tswap32(entry_2);
4026 return 0;
4027}
4028
4029/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004030static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4031 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004032{
bellard03acab62007-11-11 14:57:14 +00004033 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004034
bellard6dbad632003-03-16 18:05:05 +00004035 switch (func) {
4036 case 0:
4037 ret = read_ldt(ptr, bytecount);
4038 break;
4039 case 1:
4040 ret = write_ldt(env, ptr, bytecount, 1);
4041 break;
4042 case 0x11:
4043 ret = write_ldt(env, ptr, bytecount, 0);
4044 break;
bellard03acab62007-11-11 14:57:14 +00004045 default:
4046 ret = -TARGET_ENOSYS;
4047 break;
bellard6dbad632003-03-16 18:05:05 +00004048 }
4049 return ret;
4050}
bellard1b6b0292003-03-22 17:31:38 +00004051
blueswir14583f582008-08-24 10:35:55 +00004052#if defined(TARGET_I386) && defined(TARGET_ABI32)
blueswir18fcd3692008-08-17 20:26:25 +00004053static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004054{
4055 uint64_t *gdt_table = g2h(env->gdt.base);
4056 struct target_modify_ldt_ldt_s ldt_info;
4057 struct target_modify_ldt_ldt_s *target_ldt_info;
4058 int seg_32bit, contents, read_exec_only, limit_in_pages;
4059 int seg_not_present, useable, lm;
4060 uint32_t *lp, entry_1, entry_2;
4061 int i;
4062
4063 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4064 if (!target_ldt_info)
4065 return -TARGET_EFAULT;
4066 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004067 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004068 ldt_info.limit = tswap32(target_ldt_info->limit);
4069 ldt_info.flags = tswap32(target_ldt_info->flags);
4070 if (ldt_info.entry_number == -1) {
4071 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4072 if (gdt_table[i] == 0) {
4073 ldt_info.entry_number = i;
4074 target_ldt_info->entry_number = tswap32(i);
4075 break;
4076 }
4077 }
4078 }
4079 unlock_user_struct(target_ldt_info, ptr, 1);
4080
4081 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4082 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4083 return -TARGET_EINVAL;
4084 seg_32bit = ldt_info.flags & 1;
4085 contents = (ldt_info.flags >> 1) & 3;
4086 read_exec_only = (ldt_info.flags >> 3) & 1;
4087 limit_in_pages = (ldt_info.flags >> 4) & 1;
4088 seg_not_present = (ldt_info.flags >> 5) & 1;
4089 useable = (ldt_info.flags >> 6) & 1;
4090#ifdef TARGET_ABI32
4091 lm = 0;
4092#else
4093 lm = (ldt_info.flags >> 7) & 1;
4094#endif
4095
4096 if (contents == 3) {
4097 if (seg_not_present == 0)
4098 return -TARGET_EINVAL;
4099 }
4100
4101 /* NOTE: same code as Linux kernel */
4102 /* Allow LDTs to be cleared by the user. */
4103 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4104 if ((contents == 0 &&
4105 read_exec_only == 1 &&
4106 seg_32bit == 0 &&
4107 limit_in_pages == 0 &&
4108 seg_not_present == 1 &&
4109 useable == 0 )) {
4110 entry_1 = 0;
4111 entry_2 = 0;
4112 goto install;
4113 }
4114 }
4115
4116 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4117 (ldt_info.limit & 0x0ffff);
4118 entry_2 = (ldt_info.base_addr & 0xff000000) |
4119 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4120 (ldt_info.limit & 0xf0000) |
4121 ((read_exec_only ^ 1) << 9) |
4122 (contents << 10) |
4123 ((seg_not_present ^ 1) << 15) |
4124 (seg_32bit << 22) |
4125 (limit_in_pages << 23) |
4126 (useable << 20) |
4127 (lm << 21) |
4128 0x7000;
4129
4130 /* Install the new entry ... */
4131install:
4132 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4133 lp[0] = tswap32(entry_1);
4134 lp[1] = tswap32(entry_2);
4135 return 0;
4136}
4137
blueswir18fcd3692008-08-17 20:26:25 +00004138static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004139{
4140 struct target_modify_ldt_ldt_s *target_ldt_info;
4141 uint64_t *gdt_table = g2h(env->gdt.base);
4142 uint32_t base_addr, limit, flags;
4143 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4144 int seg_not_present, useable, lm;
4145 uint32_t *lp, entry_1, entry_2;
4146
4147 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4148 if (!target_ldt_info)
4149 return -TARGET_EFAULT;
4150 idx = tswap32(target_ldt_info->entry_number);
4151 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4152 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4153 unlock_user_struct(target_ldt_info, ptr, 1);
4154 return -TARGET_EINVAL;
4155 }
4156 lp = (uint32_t *)(gdt_table + idx);
4157 entry_1 = tswap32(lp[0]);
4158 entry_2 = tswap32(lp[1]);
4159
4160 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4161 contents = (entry_2 >> 10) & 3;
4162 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4163 seg_32bit = (entry_2 >> 22) & 1;
4164 limit_in_pages = (entry_2 >> 23) & 1;
4165 useable = (entry_2 >> 20) & 1;
4166#ifdef TARGET_ABI32
4167 lm = 0;
4168#else
4169 lm = (entry_2 >> 21) & 1;
4170#endif
4171 flags = (seg_32bit << 0) | (contents << 1) |
4172 (read_exec_only << 3) | (limit_in_pages << 4) |
4173 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4174 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4175 base_addr = (entry_1 >> 16) |
4176 (entry_2 & 0xff000000) |
4177 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004178 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004179 target_ldt_info->limit = tswap32(limit);
4180 target_ldt_info->flags = tswap32(flags);
4181 unlock_user_struct(target_ldt_info, ptr, 1);
4182 return 0;
4183}
blueswir14583f582008-08-24 10:35:55 +00004184#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004185
bellardd2fd1af2007-11-14 18:08:56 +00004186#ifndef TARGET_ABI32
blueswir18fcd3692008-08-17 20:26:25 +00004187static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004188{
Juan Quintela1add8692011-06-16 17:37:09 +01004189 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004190 abi_ulong val;
4191 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004192
bellardd2fd1af2007-11-14 18:08:56 +00004193 switch(code) {
4194 case TARGET_ARCH_SET_GS:
4195 case TARGET_ARCH_SET_FS:
4196 if (code == TARGET_ARCH_SET_GS)
4197 idx = R_GS;
4198 else
4199 idx = R_FS;
4200 cpu_x86_load_seg(env, idx, 0);
4201 env->segs[idx].base = addr;
4202 break;
4203 case TARGET_ARCH_GET_GS:
4204 case TARGET_ARCH_GET_FS:
4205 if (code == TARGET_ARCH_GET_GS)
4206 idx = R_GS;
4207 else
4208 idx = R_FS;
4209 val = env->segs[idx].base;
4210 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004211 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004212 break;
4213 default:
4214 ret = -TARGET_EINVAL;
4215 break;
4216 }
Juan Quintela1add8692011-06-16 17:37:09 +01004217 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004218}
4219#endif
4220
bellard2ab83ea2003-06-15 19:56:46 +00004221#endif /* defined(TARGET_I386) */
4222
Riku Voipio05098a92011-03-04 15:27:29 +02004223#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004224
Riku Voipio05098a92011-03-04 15:27:29 +02004225#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004226
4227static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4228typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004229 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004230 pthread_mutex_t mutex;
4231 pthread_cond_t cond;
4232 pthread_t thread;
4233 uint32_t tid;
4234 abi_ulong child_tidptr;
4235 abi_ulong parent_tidptr;
4236 sigset_t sigmask;
4237} new_thread_info;
4238
4239static void *clone_func(void *arg)
4240{
4241 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004242 CPUArchState *env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004243 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004244
4245 env = info->env;
4246 thread_env = env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004247 ts = (TaskState *)thread_env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004248 info->tid = gettid();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004249 env->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004250 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004251 if (info->child_tidptr)
4252 put_user_u32(info->tid, info->child_tidptr);
4253 if (info->parent_tidptr)
4254 put_user_u32(info->tid, info->parent_tidptr);
4255 /* Enable signals. */
4256 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4257 /* Signal to the parent that we're ready. */
4258 pthread_mutex_lock(&info->mutex);
4259 pthread_cond_broadcast(&info->cond);
4260 pthread_mutex_unlock(&info->mutex);
4261 /* Wait until the parent has finshed initializing the tls state. */
4262 pthread_mutex_lock(&clone_lock);
4263 pthread_mutex_unlock(&clone_lock);
4264 cpu_loop(env);
4265 /* never exits */
4266 return NULL;
4267}
4268#else
bellard1b6b0292003-03-22 17:31:38 +00004269
4270static int clone_func(void *arg)
4271{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004272 CPUArchState *env = arg;
bellard1b6b0292003-03-22 17:31:38 +00004273 cpu_loop(env);
4274 /* never exits */
4275 return 0;
4276}
pbrookd865bab2008-06-07 22:12:17 +00004277#endif
bellard1b6b0292003-03-22 17:31:38 +00004278
ths0da46a62007-10-20 20:23:07 +00004279/* do_fork() Must return host values and target errnos (unlike most
4280 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004281static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004282 abi_ulong parent_tidptr, target_ulong newtls,
4283 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004284{
4285 int ret;
bellard5cd43932003-03-29 16:54:36 +00004286 TaskState *ts;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004287 CPUArchState *new_env;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004288#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004289 unsigned int nptl_flags;
4290 sigset_t sigmask;
Riku Voipio91907492010-11-26 16:21:34 +02004291#else
4292 uint8_t *new_stack;
pbrookd865bab2008-06-07 22:12:17 +00004293#endif
ths3b46e622007-09-17 08:09:54 +00004294
balrog436d1242008-09-21 02:39:45 +00004295 /* Emulate vfork() with fork() */
4296 if (flags & CLONE_VFORK)
4297 flags &= ~(CLONE_VFORK | CLONE_VM);
4298
bellard1b6b0292003-03-22 17:31:38 +00004299 if (flags & CLONE_VM) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004300 TaskState *parent_ts = (TaskState *)env->opaque;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004301#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004302 new_thread_info info;
4303 pthread_attr_t attr;
pbrookbd0c5662008-05-29 14:34:11 +00004304#endif
Anthony Liguori7267c092011-08-20 22:09:37 -05004305 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004306 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004307 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004308 new_env = cpu_copy(env);
Blue Swirlb4558d72009-11-07 16:34:12 +00004309#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
Andreas Färberff18b762012-05-05 14:47:34 +02004310 cpu_reset(ENV_GET_CPU(new_env));
Blue Swirlb4558d72009-11-07 16:34:12 +00004311#endif
pbrook6e68e072008-05-30 17:22:15 +00004312 /* Init regs that differ from the parent. */
4313 cpu_clone_regs(new_env, newsp);
bellard5cd43932003-03-29 16:54:36 +00004314 new_env->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004315 ts->bprm = parent_ts->bprm;
4316 ts->info = parent_ts->info;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004317#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004318 nptl_flags = flags;
4319 flags &= ~CLONE_NPTL_FLAGS2;
4320
pbrookc2764712009-03-07 15:24:59 +00004321 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4322 ts->child_tidptr = child_tidptr;
4323 }
4324
pbrookd865bab2008-06-07 22:12:17 +00004325 if (nptl_flags & CLONE_SETTLS)
4326 cpu_set_tls (new_env, newtls);
4327
4328 /* Grab a mutex so that thread setup appears atomic. */
4329 pthread_mutex_lock(&clone_lock);
4330
4331 memset(&info, 0, sizeof(info));
4332 pthread_mutex_init(&info.mutex, NULL);
4333 pthread_mutex_lock(&info.mutex);
4334 pthread_cond_init(&info.cond, NULL);
4335 info.env = new_env;
4336 if (nptl_flags & CLONE_CHILD_SETTID)
4337 info.child_tidptr = child_tidptr;
4338 if (nptl_flags & CLONE_PARENT_SETTID)
4339 info.parent_tidptr = parent_tidptr;
4340
4341 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004342 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4343 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004344 /* It is not safe to deliver signals until the child has finished
4345 initializing, so temporarily block all signals. */
4346 sigfillset(&sigmask);
4347 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4348
4349 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004350 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004351
4352 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4353 pthread_attr_destroy(&attr);
4354 if (ret == 0) {
4355 /* Wait for the child to initialize. */
4356 pthread_cond_wait(&info.cond, &info.mutex);
4357 ret = info.tid;
4358 if (flags & CLONE_PARENT_SETTID)
4359 put_user_u32(ret, parent_tidptr);
4360 } else {
4361 ret = -1;
4362 }
4363 pthread_mutex_unlock(&info.mutex);
4364 pthread_cond_destroy(&info.cond);
4365 pthread_mutex_destroy(&info.mutex);
4366 pthread_mutex_unlock(&clone_lock);
4367#else
4368 if (flags & CLONE_NPTL_FLAGS2)
4369 return -EINVAL;
4370 /* This is probably going to die very quickly, but do it anyway. */
Anthony Liguori7267c092011-08-20 22:09:37 -05004371 new_stack = g_malloc0 (NEW_STACK_SIZE);
bellard27725c12003-04-29 21:08:18 +00004372#ifdef __ia64__
Aurelien Jarno60e99242010-03-29 02:12:51 +02004373 ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
bellard27725c12003-04-29 21:08:18 +00004374#else
4375 ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
4376#endif
pbrookd865bab2008-06-07 22:12:17 +00004377#endif
bellard1b6b0292003-03-22 17:31:38 +00004378 } else {
4379 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004380 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004381 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004382 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004383 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004384 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004385 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004386 cpu_clone_regs(env, newsp);
4387 fork_end(1);
Juan Quintela2f7bb872009-07-27 16:13:24 +02004388#if defined(CONFIG_USE_NPTL)
aurel322b1319c2008-12-18 22:44:04 +00004389 /* There is a race condition here. The parent process could
4390 theoretically read the TID in the child process before the child
4391 tid is set. This would require using either ptrace
4392 (not implemented) or having *_tidptr to point at a shared memory
4393 mapping. We can't repeat the spinlock hack used above because
4394 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004395 if (flags & CLONE_CHILD_SETTID)
4396 put_user_u32(gettid(), child_tidptr);
4397 if (flags & CLONE_PARENT_SETTID)
4398 put_user_u32(gettid(), parent_tidptr);
4399 ts = (TaskState *)env->opaque;
4400 if (flags & CLONE_SETTLS)
4401 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004402 if (flags & CLONE_CHILD_CLEARTID)
4403 ts->child_tidptr = child_tidptr;
aurel322b1319c2008-12-18 22:44:04 +00004404#endif
pbrookd865bab2008-06-07 22:12:17 +00004405 } else {
4406 fork_end(0);
4407 }
bellard1b6b0292003-03-22 17:31:38 +00004408 }
4409 return ret;
4410}
4411
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004412/* warning : doesn't handle linux specific flags... */
4413static int target_to_host_fcntl_cmd(int cmd)
4414{
4415 switch(cmd) {
4416 case TARGET_F_DUPFD:
4417 case TARGET_F_GETFD:
4418 case TARGET_F_SETFD:
4419 case TARGET_F_GETFL:
4420 case TARGET_F_SETFL:
4421 return cmd;
4422 case TARGET_F_GETLK:
4423 return F_GETLK;
4424 case TARGET_F_SETLK:
4425 return F_SETLK;
4426 case TARGET_F_SETLKW:
4427 return F_SETLKW;
4428 case TARGET_F_GETOWN:
4429 return F_GETOWN;
4430 case TARGET_F_SETOWN:
4431 return F_SETOWN;
4432 case TARGET_F_GETSIG:
4433 return F_GETSIG;
4434 case TARGET_F_SETSIG:
4435 return F_SETSIG;
4436#if TARGET_ABI_BITS == 32
4437 case TARGET_F_GETLK64:
4438 return F_GETLK64;
4439 case TARGET_F_SETLK64:
4440 return F_SETLK64;
4441 case TARGET_F_SETLKW64:
4442 return F_SETLKW64;
4443#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004444 case TARGET_F_SETLEASE:
4445 return F_SETLEASE;
4446 case TARGET_F_GETLEASE:
4447 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004448#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004449 case TARGET_F_DUPFD_CLOEXEC:
4450 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004451#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004452 case TARGET_F_NOTIFY:
4453 return F_NOTIFY;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004454 default:
4455 return -TARGET_EINVAL;
4456 }
4457 return -TARGET_EINVAL;
4458}
4459
blueswir1992f48a2007-10-14 16:27:31 +00004460static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004461{
4462 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004463 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004464 struct flock64 fl64;
4465 struct target_flock64 *target_fl64;
blueswir1992f48a2007-10-14 16:27:31 +00004466 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004467 int host_cmd = target_to_host_fcntl_cmd(cmd);
4468
4469 if (host_cmd == -TARGET_EINVAL)
4470 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004471
bellard7775e9e2003-05-14 22:46:48 +00004472 switch(cmd) {
4473 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004474 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4475 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004476 fl.l_type = tswap16(target_fl->l_type);
4477 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004478 fl.l_start = tswapal(target_fl->l_start);
4479 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004480 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004481 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004482 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004483 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004484 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4485 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004486 target_fl->l_type = tswap16(fl.l_type);
4487 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004488 target_fl->l_start = tswapal(fl.l_start);
4489 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004490 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004491 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004492 }
4493 break;
ths3b46e622007-09-17 08:09:54 +00004494
bellard7775e9e2003-05-14 22:46:48 +00004495 case TARGET_F_SETLK:
4496 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004497 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4498 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004499 fl.l_type = tswap16(target_fl->l_type);
4500 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004501 fl.l_start = tswapal(target_fl->l_start);
4502 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004503 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004504 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004505 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004506 break;
ths3b46e622007-09-17 08:09:54 +00004507
bellard7775e9e2003-05-14 22:46:48 +00004508 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004509 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4510 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004511 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4512 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004513 fl64.l_start = tswap64(target_fl64->l_start);
4514 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004515 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004516 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004517 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004518 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004519 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4520 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004521 target_fl64->l_type = tswap16(fl64.l_type) >> 1;
4522 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004523 target_fl64->l_start = tswap64(fl64.l_start);
4524 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004525 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004526 unlock_user_struct(target_fl64, arg, 1);
4527 }
bellard9ee1fa22007-11-11 15:11:19 +00004528 break;
bellard7775e9e2003-05-14 22:46:48 +00004529 case TARGET_F_SETLK64:
4530 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004531 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4532 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004533 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4534 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004535 fl64.l_start = tswap64(target_fl64->l_start);
4536 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004537 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004538 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004539 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004540 break;
4541
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004542 case TARGET_F_GETFL:
4543 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004544 if (ret >= 0) {
4545 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4546 }
bellardffa65c32004-01-04 23:57:22 +00004547 break;
4548
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004549 case TARGET_F_SETFL:
4550 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4551 break;
4552
4553 case TARGET_F_SETOWN:
4554 case TARGET_F_GETOWN:
4555 case TARGET_F_SETSIG:
4556 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004557 case TARGET_F_SETLEASE:
4558 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004559 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004560 break;
4561
bellard7775e9e2003-05-14 22:46:48 +00004562 default:
bellard9ee1fa22007-11-11 15:11:19 +00004563 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004564 break;
4565 }
4566 return ret;
4567}
4568
bellard67867302003-11-23 17:05:30 +00004569#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004570
bellard67867302003-11-23 17:05:30 +00004571static inline int high2lowuid(int uid)
4572{
4573 if (uid > 65535)
4574 return 65534;
4575 else
4576 return uid;
4577}
4578
4579static inline int high2lowgid(int gid)
4580{
4581 if (gid > 65535)
4582 return 65534;
4583 else
4584 return gid;
4585}
4586
4587static inline int low2highuid(int uid)
4588{
4589 if ((int16_t)uid == -1)
4590 return -1;
4591 else
4592 return uid;
4593}
4594
4595static inline int low2highgid(int gid)
4596{
4597 if ((int16_t)gid == -1)
4598 return -1;
4599 else
4600 return gid;
4601}
Riku Voipio0c866a72011-04-18 15:23:06 +03004602static inline int tswapid(int id)
4603{
4604 return tswap16(id);
4605}
4606#else /* !USE_UID16 */
4607static inline int high2lowuid(int uid)
4608{
4609 return uid;
4610}
4611static inline int high2lowgid(int gid)
4612{
4613 return gid;
4614}
4615static inline int low2highuid(int uid)
4616{
4617 return uid;
4618}
4619static inline int low2highgid(int gid)
4620{
4621 return gid;
4622}
4623static inline int tswapid(int id)
4624{
4625 return tswap32(id);
4626}
bellard67867302003-11-23 17:05:30 +00004627#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004628
bellard31e31b82003-02-18 22:55:36 +00004629void syscall_init(void)
4630{
bellard2ab83ea2003-06-15 19:56:46 +00004631 IOCTLEntry *ie;
4632 const argtype *arg_type;
4633 int size;
thsb92c47c2007-11-01 00:07:38 +00004634 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004635
Blue Swirl001faf32009-05-13 17:53:17 +00004636#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004637#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004638#include "syscall_types.h"
4639#undef STRUCT
4640#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004641
Peter Maydell9df109b2012-07-23 18:54:00 +01004642 /* Build target_to_host_errno_table[] table from
4643 * host_to_target_errno_table[]. */
4644 for (i=0; i < ERRNO_TABLE_SIZE; i++)
4645 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4646
bellard2ab83ea2003-06-15 19:56:46 +00004647 /* we patch the ioctl size if necessary. We rely on the fact that
4648 no ioctl has all the bits at '1' in the size field */
4649 ie = ioctl_entries;
4650 while (ie->target_cmd != 0) {
4651 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4652 TARGET_IOC_SIZEMASK) {
4653 arg_type = ie->arg_type;
4654 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004655 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004656 ie->target_cmd);
4657 exit(1);
4658 }
4659 arg_type++;
4660 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004661 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004662 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4663 (size << TARGET_IOC_SIZESHIFT);
4664 }
thsb92c47c2007-11-01 00:07:38 +00004665
bellard2ab83ea2003-06-15 19:56:46 +00004666 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004667#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4668 (defined(__x86_64__) && defined(TARGET_X86_64))
4669 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4670 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4671 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004672 }
4673#endif
4674 ie++;
4675 }
bellard31e31b82003-02-18 22:55:36 +00004676}
bellardc573ff62004-01-04 15:51:36 +00004677
blueswir1992f48a2007-10-14 16:27:31 +00004678#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004679static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4680{
thsaf325d32008-06-10 15:29:15 +00004681#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004682 return ((uint64_t)word0 << 32) | word1;
4683#else
4684 return ((uint64_t)word1 << 32) | word0;
4685#endif
4686}
blueswir1992f48a2007-10-14 16:27:31 +00004687#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004688static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4689{
4690 return word0;
4691}
blueswir1992f48a2007-10-14 16:27:31 +00004692#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004693
4694#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004695static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4696 abi_long arg2,
4697 abi_long arg3,
4698 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004699{
Riku Voipio48e515d2011-07-12 15:40:51 +03004700 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004701 arg2 = arg3;
4702 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004703 }
pbrookce4defa2006-02-09 16:49:55 +00004704 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4705}
4706#endif
4707
4708#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004709static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4710 abi_long arg2,
4711 abi_long arg3,
4712 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004713{
Riku Voipio48e515d2011-07-12 15:40:51 +03004714 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004715 arg2 = arg3;
4716 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004717 }
pbrookce4defa2006-02-09 16:49:55 +00004718 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4719}
4720#endif
4721
bellard579a97f2007-11-11 14:26:47 +00004722static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4723 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004724{
4725 struct target_timespec *target_ts;
4726
bellard579a97f2007-11-11 14:26:47 +00004727 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4728 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004729 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4730 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004731 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004732 return 0;
pbrook53a59602006-03-25 19:31:22 +00004733}
4734
bellard579a97f2007-11-11 14:26:47 +00004735static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4736 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004737{
4738 struct target_timespec *target_ts;
4739
bellard579a97f2007-11-11 14:26:47 +00004740 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4741 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004742 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4743 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004744 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004745 return 0;
pbrook53a59602006-03-25 19:31:22 +00004746}
4747
aurel329d33b762009-04-08 23:07:05 +00004748#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004749static inline abi_long host_to_target_stat64(void *cpu_env,
4750 abi_ulong target_addr,
4751 struct stat *host_st)
4752{
4753#ifdef TARGET_ARM
4754 if (((CPUARMState *)cpu_env)->eabi) {
4755 struct target_eabi_stat64 *target_st;
4756
4757 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4758 return -TARGET_EFAULT;
4759 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4760 __put_user(host_st->st_dev, &target_st->st_dev);
4761 __put_user(host_st->st_ino, &target_st->st_ino);
4762#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4763 __put_user(host_st->st_ino, &target_st->__st_ino);
4764#endif
4765 __put_user(host_st->st_mode, &target_st->st_mode);
4766 __put_user(host_st->st_nlink, &target_st->st_nlink);
4767 __put_user(host_st->st_uid, &target_st->st_uid);
4768 __put_user(host_st->st_gid, &target_st->st_gid);
4769 __put_user(host_st->st_rdev, &target_st->st_rdev);
4770 __put_user(host_st->st_size, &target_st->st_size);
4771 __put_user(host_st->st_blksize, &target_st->st_blksize);
4772 __put_user(host_st->st_blocks, &target_st->st_blocks);
4773 __put_user(host_st->st_atime, &target_st->target_st_atime);
4774 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4775 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4776 unlock_user_struct(target_st, target_addr, 1);
4777 } else
4778#endif
4779 {
Richard Hendersoned18c5c2010-04-26 10:27:22 -07004780#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
aurel329d33b762009-04-08 23:07:05 +00004781 struct target_stat *target_st;
4782#else
balrog6a24a772008-09-20 02:23:36 +00004783 struct target_stat64 *target_st;
aurel329d33b762009-04-08 23:07:05 +00004784#endif
balrog6a24a772008-09-20 02:23:36 +00004785
4786 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4787 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004788 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004789 __put_user(host_st->st_dev, &target_st->st_dev);
4790 __put_user(host_st->st_ino, &target_st->st_ino);
4791#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4792 __put_user(host_st->st_ino, &target_st->__st_ino);
4793#endif
4794 __put_user(host_st->st_mode, &target_st->st_mode);
4795 __put_user(host_st->st_nlink, &target_st->st_nlink);
4796 __put_user(host_st->st_uid, &target_st->st_uid);
4797 __put_user(host_st->st_gid, &target_st->st_gid);
4798 __put_user(host_st->st_rdev, &target_st->st_rdev);
4799 /* XXX: better use of kernel struct */
4800 __put_user(host_st->st_size, &target_st->st_size);
4801 __put_user(host_st->st_blksize, &target_st->st_blksize);
4802 __put_user(host_st->st_blocks, &target_st->st_blocks);
4803 __put_user(host_st->st_atime, &target_st->target_st_atime);
4804 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4805 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4806 unlock_user_struct(target_st, target_addr, 1);
4807 }
4808
4809 return 0;
4810}
4811#endif
4812
Juan Quintela2f7bb872009-07-27 16:13:24 +02004813#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00004814/* ??? Using host futex calls even when target atomic operations
4815 are not really atomic probably breaks things. However implementing
4816 futexes locally would make futexes shared between multiple processes
4817 tricky. However they're probably useless because guest atomic
4818 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004819static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4820 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004821{
4822 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004823 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004824
4825 /* ??? We assume FUTEX_* constants are the same on both host
4826 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004827#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004828 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004829#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004830 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004831#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004832 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004833 case FUTEX_WAIT:
4834 if (timeout) {
4835 pts = &ts;
4836 target_to_host_timespec(pts, timeout);
4837 } else {
4838 pts = NULL;
4839 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004840 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
pbrookbd0c5662008-05-29 14:34:11 +00004841 pts, NULL, 0));
4842 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004843 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004844 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004845 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004846 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004847 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004848 case FUTEX_WAKE_OP:
4849 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4850 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4851 But the prototype takes a `struct timespec *'; insert casts
4852 to satisfy the compiler. We do not need to tswap TIMEOUT
4853 since it's not compared to guest memory. */
4854 pts = (struct timespec *)(uintptr_t) timeout;
4855 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4856 g2h(uaddr2),
4857 (base_op == FUTEX_CMP_REQUEUE
4858 ? tswap32(val3)
4859 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004860 default:
4861 return -TARGET_ENOSYS;
4862 }
4863}
4864#endif
4865
pbrook1d9d8b52009-04-16 15:17:02 +00004866/* Map host to target signal numbers for the wait family of syscalls.
4867 Assume all other status bits are the same. */
4868static int host_to_target_waitstatus(int status)
4869{
4870 if (WIFSIGNALED(status)) {
4871 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4872 }
4873 if (WIFSTOPPED(status)) {
4874 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4875 | (status & 0xff);
4876 }
4877 return status;
4878}
4879
pbrooka745ec62008-05-06 15:36:17 +00004880int get_osversion(void)
4881{
4882 static int osversion;
4883 struct new_utsname buf;
4884 const char *s;
4885 int i, n, tmp;
4886 if (osversion)
4887 return osversion;
4888 if (qemu_uname_release && *qemu_uname_release) {
4889 s = qemu_uname_release;
4890 } else {
4891 if (sys_uname(&buf))
4892 return 0;
4893 s = buf.release;
4894 }
4895 tmp = 0;
4896 for (i = 0; i < 3; i++) {
4897 n = 0;
4898 while (*s >= '0' && *s <= '9') {
4899 n *= 10;
4900 n += *s - '0';
4901 s++;
4902 }
4903 tmp = (tmp << 8) + n;
4904 if (*s == '.')
4905 s++;
4906 }
4907 osversion = tmp;
4908 return osversion;
4909}
4910
Alexander Graf36c08d42011-11-02 20:23:24 +01004911
4912static int open_self_maps(void *cpu_env, int fd)
4913{
Alexander Graf1a49ef22012-05-01 16:30:28 +01004914#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Andreas Färber9349b4f2012-03-14 01:38:32 +01004915 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01004916#endif
4917 FILE *fp;
4918 char *line = NULL;
4919 size_t len = 0;
4920 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01004921
Alexander Graf1a49ef22012-05-01 16:30:28 +01004922 fp = fopen("/proc/self/maps", "r");
4923 if (fp == NULL) {
4924 return -EACCES;
4925 }
4926
4927 while ((read = getline(&line, &len, fp)) != -1) {
4928 int fields, dev_maj, dev_min, inode;
4929 uint64_t min, max, offset;
4930 char flag_r, flag_w, flag_x, flag_p;
4931 char path[512] = "";
4932 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
4933 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
4934 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
4935
4936 if ((fields < 10) || (fields > 11)) {
4937 continue;
4938 }
4939 if (!strncmp(path, "[stack]", 7)) {
4940 continue;
4941 }
4942 if (h2g_valid(min) && h2g_valid(max)) {
4943 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
4944 " %c%c%c%c %08" PRIx64 " %02x:%02x %d%s%s\n",
4945 h2g(min), h2g(max), flag_r, flag_w,
4946 flag_x, flag_p, offset, dev_maj, dev_min, inode,
4947 path[0] ? " " : "", path);
4948 }
4949 }
4950
4951 free(line);
4952 fclose(fp);
4953
4954#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Alexander Graf36c08d42011-11-02 20:23:24 +01004955 dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
4956 (unsigned long long)ts->info->stack_limit,
4957 (unsigned long long)(ts->stack_base + (TARGET_PAGE_SIZE - 1))
4958 & TARGET_PAGE_MASK,
Alexander Graf1a49ef22012-05-01 16:30:28 +01004959 (unsigned long long)0);
4960#endif
Alexander Graf36c08d42011-11-02 20:23:24 +01004961
4962 return 0;
4963}
4964
Alexander Graf480b8e72011-11-02 20:23:25 +01004965static int open_self_stat(void *cpu_env, int fd)
4966{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004967 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01004968 abi_ulong start_stack = ts->info->start_stack;
4969 int i;
4970
4971 for (i = 0; i < 44; i++) {
4972 char buf[128];
4973 int len;
4974 uint64_t val = 0;
4975
Fabio Erculianie0e65be2012-01-03 09:38:34 +00004976 if (i == 0) {
4977 /* pid */
4978 val = getpid();
4979 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
4980 } else if (i == 1) {
4981 /* app name */
4982 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
4983 } else if (i == 27) {
4984 /* stack bottom */
4985 val = start_stack;
4986 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
4987 } else {
4988 /* for the rest, there is MasterCard */
4989 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01004990 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00004991
Alexander Graf480b8e72011-11-02 20:23:25 +01004992 len = strlen(buf);
4993 if (write(fd, buf, len) != len) {
4994 return -1;
4995 }
4996 }
4997
4998 return 0;
4999}
5000
Alexander Graf257450e2011-11-02 20:23:26 +01005001static int open_self_auxv(void *cpu_env, int fd)
5002{
Andreas Färber9349b4f2012-03-14 01:38:32 +01005003 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005004 abi_ulong auxv = ts->info->saved_auxv;
5005 abi_ulong len = ts->info->auxv_len;
5006 char *ptr;
5007
5008 /*
5009 * Auxiliary vector is stored in target process stack.
5010 * read in whole auxv vector and copy it to file
5011 */
5012 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5013 if (ptr != NULL) {
5014 while (len > 0) {
5015 ssize_t r;
5016 r = write(fd, ptr, len);
5017 if (r <= 0) {
5018 break;
5019 }
5020 len -= r;
5021 ptr += r;
5022 }
5023 lseek(fd, 0, SEEK_SET);
5024 unlock_user(ptr, auxv, len);
5025 }
5026
5027 return 0;
5028}
5029
Alexander Graf3be14d02011-11-02 20:23:23 +01005030static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
5031{
5032 struct fake_open {
5033 const char *filename;
5034 int (*fill)(void *cpu_env, int fd);
5035 };
5036 const struct fake_open *fake_open;
5037 static const struct fake_open fakes[] = {
Alexander Graf36c08d42011-11-02 20:23:24 +01005038 { "/proc/self/maps", open_self_maps },
Alexander Graf480b8e72011-11-02 20:23:25 +01005039 { "/proc/self/stat", open_self_stat },
Alexander Graf257450e2011-11-02 20:23:26 +01005040 { "/proc/self/auxv", open_self_auxv },
Alexander Graf3be14d02011-11-02 20:23:23 +01005041 { NULL, NULL }
5042 };
5043
5044 for (fake_open = fakes; fake_open->filename; fake_open++) {
5045 if (!strncmp(pathname, fake_open->filename,
5046 strlen(fake_open->filename))) {
5047 break;
5048 }
5049 }
5050
5051 if (fake_open->filename) {
5052 const char *tmpdir;
5053 char filename[PATH_MAX];
5054 int fd, r;
5055
5056 /* create temporary file to map stat to */
5057 tmpdir = getenv("TMPDIR");
5058 if (!tmpdir)
5059 tmpdir = "/tmp";
5060 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5061 fd = mkstemp(filename);
5062 if (fd < 0) {
5063 return fd;
5064 }
5065 unlink(filename);
5066
5067 if ((r = fake_open->fill(cpu_env, fd))) {
5068 close(fd);
5069 return r;
5070 }
5071 lseek(fd, 0, SEEK_SET);
5072
5073 return fd;
5074 }
5075
5076 return get_errno(open(path(pathname), flags, mode));
5077}
5078
ths0da46a62007-10-20 20:23:07 +00005079/* do_syscall() should always have a single exit point at the end so
5080 that actions, such as logging of syscall results, can be performed.
5081 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005082abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5083 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005084 abi_long arg5, abi_long arg6, abi_long arg7,
5085 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005086{
blueswir1992f48a2007-10-14 16:27:31 +00005087 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005088 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005089 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005090 void *p;
ths3b46e622007-09-17 08:09:54 +00005091
bellard72f03902003-02-18 23:33:18 +00005092#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005093 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005094#endif
thsb92c47c2007-11-01 00:07:38 +00005095 if(do_strace)
5096 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5097
bellard31e31b82003-02-18 22:55:36 +00005098 switch(num) {
5099 case TARGET_NR_exit:
Juan Quintela2f7bb872009-07-27 16:13:24 +02005100#ifdef CONFIG_USE_NPTL
pbrookc2764712009-03-07 15:24:59 +00005101 /* In old applications this may be used to implement _exit(2).
5102 However in threaded applictions it is used for thread termination,
5103 and _exit_group is used for application termination.
5104 Do thread termination if we have more then one thread. */
5105 /* FIXME: This probably breaks if a signal arrives. We should probably
5106 be disabling signals. */
5107 if (first_cpu->next_cpu) {
Nathan Froyd1e9fa732009-06-03 11:33:08 -07005108 TaskState *ts;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005109 CPUArchState **lastp;
5110 CPUArchState *p;
pbrookc2764712009-03-07 15:24:59 +00005111
5112 cpu_list_lock();
5113 lastp = &first_cpu;
5114 p = first_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005115 while (p && p != (CPUArchState *)cpu_env) {
pbrookc2764712009-03-07 15:24:59 +00005116 lastp = &p->next_cpu;
5117 p = p->next_cpu;
5118 }
5119 /* If we didn't find the CPU for this thread then something is
5120 horribly wrong. */
5121 if (!p)
5122 abort();
5123 /* Remove the CPU from the list. */
5124 *lastp = p->next_cpu;
5125 cpu_list_unlock();
Andreas Färber9349b4f2012-03-14 01:38:32 +01005126 ts = ((CPUArchState *)cpu_env)->opaque;
pbrookc2764712009-03-07 15:24:59 +00005127 if (ts->child_tidptr) {
5128 put_user_u32(0, ts->child_tidptr);
5129 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5130 NULL, NULL, 0);
5131 }
Nathan Froyd48e15fc2010-10-29 07:48:57 -07005132 thread_env = NULL;
Andreas Färber11ea4092012-04-15 18:51:01 +02005133 object_delete(OBJECT(ENV_GET_CPU(cpu_env)));
Anthony Liguori7267c092011-08-20 22:09:37 -05005134 g_free(ts);
pbrookc2764712009-03-07 15:24:59 +00005135 pthread_exit(NULL);
5136 }
5137#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +02005138#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005139 _mcleanup();
5140#endif
bellarde9009672005-04-26 20:42:36 +00005141 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005142 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005143 ret = 0; /* avoid warning */
5144 break;
5145 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005146 if (arg3 == 0)
5147 ret = 0;
5148 else {
5149 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5150 goto efault;
5151 ret = get_errno(read(arg1, p, arg3));
5152 unlock_user(p, arg2, ret);
5153 }
bellard31e31b82003-02-18 22:55:36 +00005154 break;
5155 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005156 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5157 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005158 ret = get_errno(write(arg1, p, arg3));
5159 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005160 break;
5161 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005162 if (!(p = lock_user_string(arg1)))
5163 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005164 ret = get_errno(do_open(cpu_env, p,
5165 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5166 arg3));
pbrook53a59602006-03-25 19:31:22 +00005167 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005168 break;
ths82424832007-09-24 09:21:55 +00005169#if defined(TARGET_NR_openat) && defined(__NR_openat)
5170 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005171 if (!(p = lock_user_string(arg2)))
5172 goto efault;
5173 ret = get_errno(sys_openat(arg1,
5174 path(p),
5175 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5176 arg4));
5177 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005178 break;
5179#endif
bellard31e31b82003-02-18 22:55:36 +00005180 case TARGET_NR_close:
5181 ret = get_errno(close(arg1));
5182 break;
5183 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005184 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005185 break;
5186 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005187 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005188 break;
thse5febef2007-04-01 18:31:35 +00005189#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005190 case TARGET_NR_waitpid:
5191 {
pbrook53a59602006-03-25 19:31:22 +00005192 int status;
5193 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005194 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005195 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005196 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005197 }
5198 break;
thse5febef2007-04-01 18:31:35 +00005199#endif
pbrookf0cbb612008-05-30 18:20:05 +00005200#ifdef TARGET_NR_waitid
5201 case TARGET_NR_waitid:
5202 {
5203 siginfo_t info;
5204 info.si_pid = 0;
5205 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5206 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005207 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005208 goto efault;
5209 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005210 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005211 }
5212 }
5213 break;
5214#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005215#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005216 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005217 if (!(p = lock_user_string(arg1)))
5218 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005219 ret = get_errno(creat(p, arg2));
5220 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005221 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005222#endif
bellard31e31b82003-02-18 22:55:36 +00005223 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005224 {
5225 void * p2;
5226 p = lock_user_string(arg1);
5227 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005228 if (!p || !p2)
5229 ret = -TARGET_EFAULT;
5230 else
5231 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005232 unlock_user(p2, arg2, 0);
5233 unlock_user(p, arg1, 0);
5234 }
bellard31e31b82003-02-18 22:55:36 +00005235 break;
ths64f0ce42007-09-24 09:25:06 +00005236#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
5237 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005238 {
5239 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005240 if (!arg2 || !arg4)
5241 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005242 p = lock_user_string(arg2);
5243 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005244 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005245 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005246 else
5247 ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005248 unlock_user(p, arg2, 0);
5249 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005250 }
5251 break;
5252#endif
bellard31e31b82003-02-18 22:55:36 +00005253 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005254 if (!(p = lock_user_string(arg1)))
5255 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005256 ret = get_errno(unlink(p));
5257 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005258 break;
ths8170f562007-09-24 09:24:11 +00005259#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
5260 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005261 if (!(p = lock_user_string(arg2)))
5262 goto efault;
5263 ret = get_errno(sys_unlinkat(arg1, p, arg3));
5264 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005265 break;
balrogb7d35e62007-12-12 00:40:24 +00005266#endif
bellard31e31b82003-02-18 22:55:36 +00005267 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005268 {
5269 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005270 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005271 abi_ulong gp;
5272 abi_ulong guest_argp;
5273 abi_ulong guest_envp;
5274 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005275 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005276 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005277
bellardf7341ff2003-03-30 21:00:25 +00005278 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005279 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005280 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005281 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005282 goto efault;
ths03aa1972007-12-02 06:28:08 +00005283 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005284 break;
bellard7854b052003-03-29 17:22:23 +00005285 argc++;
bellard2f619692007-11-16 10:46:05 +00005286 }
bellardf7341ff2003-03-30 21:00:25 +00005287 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005288 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005289 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005290 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005291 goto efault;
ths03aa1972007-12-02 06:28:08 +00005292 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005293 break;
bellard7854b052003-03-29 17:22:23 +00005294 envc++;
bellard2f619692007-11-16 10:46:05 +00005295 }
bellard7854b052003-03-29 17:22:23 +00005296
bellardf7341ff2003-03-30 21:00:25 +00005297 argp = alloca((argc + 1) * sizeof(void *));
5298 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005299
pbrookda94d262008-05-30 18:24:00 +00005300 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005301 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005302 if (get_user_ual(addr, gp))
5303 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005304 if (!addr)
5305 break;
bellard2f619692007-11-16 10:46:05 +00005306 if (!(*q = lock_user_string(addr)))
5307 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005308 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005309 }
bellardf7341ff2003-03-30 21:00:25 +00005310 *q = NULL;
5311
pbrookda94d262008-05-30 18:24:00 +00005312 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005313 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005314 if (get_user_ual(addr, gp))
5315 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005316 if (!addr)
5317 break;
bellard2f619692007-11-16 10:46:05 +00005318 if (!(*q = lock_user_string(addr)))
5319 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005320 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005321 }
bellardf7341ff2003-03-30 21:00:25 +00005322 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005323
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005324 /* This case will not be caught by the host's execve() if its
5325 page size is bigger than the target's. */
5326 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5327 ret = -TARGET_E2BIG;
5328 goto execve_end;
5329 }
bellard2f619692007-11-16 10:46:05 +00005330 if (!(p = lock_user_string(arg1)))
5331 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005332 ret = get_errno(execve(p, argp, envp));
5333 unlock_user(p, arg1, 0);
5334
bellard2f619692007-11-16 10:46:05 +00005335 goto execve_end;
5336
5337 execve_efault:
5338 ret = -TARGET_EFAULT;
5339
5340 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005341 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005342 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005343 if (get_user_ual(addr, gp)
5344 || !addr)
5345 break;
pbrook53a59602006-03-25 19:31:22 +00005346 unlock_user(*q, addr, 0);
5347 }
5348 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005349 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005350 if (get_user_ual(addr, gp)
5351 || !addr)
5352 break;
pbrook53a59602006-03-25 19:31:22 +00005353 unlock_user(*q, addr, 0);
5354 }
bellard7854b052003-03-29 17:22:23 +00005355 }
bellard31e31b82003-02-18 22:55:36 +00005356 break;
5357 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005358 if (!(p = lock_user_string(arg1)))
5359 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005360 ret = get_errno(chdir(p));
5361 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005362 break;
bellarda315a142005-01-30 22:59:18 +00005363#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005364 case TARGET_NR_time:
5365 {
pbrook53a59602006-03-25 19:31:22 +00005366 time_t host_time;
5367 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005368 if (!is_error(ret)
5369 && arg1
5370 && put_user_sal(host_time, arg1))
5371 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005372 }
5373 break;
bellarda315a142005-01-30 22:59:18 +00005374#endif
bellard31e31b82003-02-18 22:55:36 +00005375 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005376 if (!(p = lock_user_string(arg1)))
5377 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005378 ret = get_errno(mknod(p, arg2, arg3));
5379 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005380 break;
ths75ac37a2007-09-24 09:23:05 +00005381#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
5382 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005383 if (!(p = lock_user_string(arg2)))
5384 goto efault;
5385 ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
5386 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005387 break;
5388#endif
bellard31e31b82003-02-18 22:55:36 +00005389 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005390 if (!(p = lock_user_string(arg1)))
5391 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005392 ret = get_errno(chmod(p, arg2));
5393 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005394 break;
bellardebc05482003-09-30 21:08:41 +00005395#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005396 case TARGET_NR_break:
5397 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005398#endif
5399#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005400 case TARGET_NR_oldstat:
5401 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005402#endif
bellard31e31b82003-02-18 22:55:36 +00005403 case TARGET_NR_lseek:
5404 ret = get_errno(lseek(arg1, arg2, arg3));
5405 break;
Richard Henderson92317332010-05-03 10:07:53 -07005406#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5407 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005408 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005409 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005410 ret = get_errno(getpid());
5411 break;
Richard Henderson92317332010-05-03 10:07:53 -07005412#endif
5413#ifdef TARGET_NR_getpid
5414 case TARGET_NR_getpid:
5415 ret = get_errno(getpid());
5416 break;
5417#endif
bellard31e31b82003-02-18 22:55:36 +00005418 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00005419 {
5420 /* need to look at the data field */
5421 void *p2, *p3;
5422 p = lock_user_string(arg1);
5423 p2 = lock_user_string(arg2);
5424 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005425 if (!p || !p2 || !p3)
5426 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005427 else {
bellard579a97f2007-11-11 14:26:47 +00005428 /* FIXME - arg5 should be locked, but it isn't clear how to
5429 * do that since it's not guaranteed to be a NULL-terminated
5430 * string.
5431 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005432 if ( ! arg5 )
5433 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
5434 else
5435 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
5436 }
bellard579a97f2007-11-11 14:26:47 +00005437 unlock_user(p, arg1, 0);
5438 unlock_user(p2, arg2, 0);
5439 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00005440 break;
5441 }
thse5febef2007-04-01 18:31:35 +00005442#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005443 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005444 if (!(p = lock_user_string(arg1)))
5445 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005446 ret = get_errno(umount(p));
5447 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005448 break;
thse5febef2007-04-01 18:31:35 +00005449#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005450#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005451 case TARGET_NR_stime:
5452 {
pbrook53a59602006-03-25 19:31:22 +00005453 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005454 if (get_user_sal(host_time, arg1))
5455 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005456 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005457 }
5458 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005459#endif
bellard31e31b82003-02-18 22:55:36 +00005460 case TARGET_NR_ptrace:
5461 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005462#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005463 case TARGET_NR_alarm:
5464 ret = alarm(arg1);
5465 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005466#endif
bellardebc05482003-09-30 21:08:41 +00005467#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005468 case TARGET_NR_oldfstat:
5469 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005470#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005471#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005472 case TARGET_NR_pause:
5473 ret = get_errno(pause());
5474 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005475#endif
thse5febef2007-04-01 18:31:35 +00005476#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005477 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005478 {
pbrook53a59602006-03-25 19:31:22 +00005479 struct utimbuf tbuf, *host_tbuf;
5480 struct target_utimbuf *target_tbuf;
5481 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005482 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5483 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005484 tbuf.actime = tswapal(target_tbuf->actime);
5485 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005486 unlock_user_struct(target_tbuf, arg2, 0);
5487 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005488 } else {
pbrook53a59602006-03-25 19:31:22 +00005489 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005490 }
bellard579a97f2007-11-11 14:26:47 +00005491 if (!(p = lock_user_string(arg1)))
5492 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005493 ret = get_errno(utime(p, host_tbuf));
5494 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005495 }
5496 break;
thse5febef2007-04-01 18:31:35 +00005497#endif
bellard978a66f2004-12-06 22:58:05 +00005498 case TARGET_NR_utimes:
5499 {
bellard978a66f2004-12-06 22:58:05 +00005500 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005501 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005502 if (copy_from_user_timeval(&tv[0], arg2)
5503 || copy_from_user_timeval(&tv[1],
5504 arg2 + sizeof(struct target_timeval)))
5505 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005506 tvp = tv;
5507 } else {
5508 tvp = NULL;
5509 }
bellard579a97f2007-11-11 14:26:47 +00005510 if (!(p = lock_user_string(arg1)))
5511 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005512 ret = get_errno(utimes(p, tvp));
5513 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005514 }
5515 break;
balrogac8a6552008-09-20 02:25:39 +00005516#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
5517 case TARGET_NR_futimesat:
5518 {
5519 struct timeval *tvp, tv[2];
5520 if (arg3) {
5521 if (copy_from_user_timeval(&tv[0], arg3)
5522 || copy_from_user_timeval(&tv[1],
5523 arg3 + sizeof(struct target_timeval)))
5524 goto efault;
5525 tvp = tv;
5526 } else {
5527 tvp = NULL;
5528 }
5529 if (!(p = lock_user_string(arg2)))
5530 goto efault;
5531 ret = get_errno(sys_futimesat(arg1, path(p), tvp));
5532 unlock_user(p, arg2, 0);
5533 }
5534 break;
5535#endif
bellardebc05482003-09-30 21:08:41 +00005536#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005537 case TARGET_NR_stty:
5538 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005539#endif
5540#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005541 case TARGET_NR_gtty:
5542 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005543#endif
bellard31e31b82003-02-18 22:55:36 +00005544 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005545 if (!(p = lock_user_string(arg1)))
5546 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005547 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005548 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005549 break;
ths92a34c12007-09-24 09:27:49 +00005550#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5551 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005552 if (!(p = lock_user_string(arg2)))
5553 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00005554 ret = get_errno(sys_faccessat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005555 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005556 break;
5557#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005558#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005559 case TARGET_NR_nice:
5560 ret = get_errno(nice(arg1));
5561 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005562#endif
bellardebc05482003-09-30 21:08:41 +00005563#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005564 case TARGET_NR_ftime:
5565 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005566#endif
bellard31e31b82003-02-18 22:55:36 +00005567 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005568 sync();
5569 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005570 break;
5571 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005572 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005573 break;
5574 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005575 {
5576 void *p2;
5577 p = lock_user_string(arg1);
5578 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005579 if (!p || !p2)
5580 ret = -TARGET_EFAULT;
5581 else
5582 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005583 unlock_user(p2, arg2, 0);
5584 unlock_user(p, arg1, 0);
5585 }
bellard31e31b82003-02-18 22:55:36 +00005586 break;
ths722183f2007-09-24 09:24:37 +00005587#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
5588 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005589 {
bellard579a97f2007-11-11 14:26:47 +00005590 void *p2;
ths722183f2007-09-24 09:24:37 +00005591 p = lock_user_string(arg2);
5592 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005593 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005594 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005595 else
5596 ret = get_errno(sys_renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005597 unlock_user(p2, arg4, 0);
5598 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005599 }
5600 break;
5601#endif
bellard31e31b82003-02-18 22:55:36 +00005602 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005603 if (!(p = lock_user_string(arg1)))
5604 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005605 ret = get_errno(mkdir(p, arg2));
5606 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005607 break;
ths4472ad02007-09-24 09:22:32 +00005608#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
5609 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005610 if (!(p = lock_user_string(arg2)))
5611 goto efault;
5612 ret = get_errno(sys_mkdirat(arg1, p, arg3));
5613 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005614 break;
5615#endif
bellard31e31b82003-02-18 22:55:36 +00005616 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005617 if (!(p = lock_user_string(arg1)))
5618 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005619 ret = get_errno(rmdir(p));
5620 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005621 break;
5622 case TARGET_NR_dup:
5623 ret = get_errno(dup(arg1));
5624 break;
5625 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005626 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005627 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005628#ifdef TARGET_NR_pipe2
5629 case TARGET_NR_pipe2:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005630 ret = do_pipe(cpu_env, arg1, arg2, 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005631 break;
5632#endif
bellard31e31b82003-02-18 22:55:36 +00005633 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005634 {
pbrook53a59602006-03-25 19:31:22 +00005635 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005636 struct tms tms;
5637 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005638 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005639 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5640 if (!tmsp)
5641 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005642 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5643 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5644 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5645 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005646 }
bellardc596ed12003-07-13 17:32:31 +00005647 if (!is_error(ret))
5648 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005649 }
5650 break;
bellardebc05482003-09-30 21:08:41 +00005651#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005652 case TARGET_NR_prof:
5653 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005654#endif
thse5febef2007-04-01 18:31:35 +00005655#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005656 case TARGET_NR_signal:
5657 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005658#endif
bellard31e31b82003-02-18 22:55:36 +00005659 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005660 if (arg1 == 0) {
5661 ret = get_errno(acct(NULL));
5662 } else {
5663 if (!(p = lock_user_string(arg1)))
5664 goto efault;
5665 ret = get_errno(acct(path(p)));
5666 unlock_user(p, arg1, 0);
5667 }
pbrook24836682006-04-16 14:14:53 +00005668 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005669#ifdef TARGET_NR_umount2 /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005670 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005671 if (!(p = lock_user_string(arg1)))
5672 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005673 ret = get_errno(umount2(p, arg2));
5674 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005675 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005676#endif
bellardebc05482003-09-30 21:08:41 +00005677#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005678 case TARGET_NR_lock:
5679 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005680#endif
bellard31e31b82003-02-18 22:55:36 +00005681 case TARGET_NR_ioctl:
5682 ret = do_ioctl(arg1, arg2, arg3);
5683 break;
5684 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005685 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005686 break;
bellardebc05482003-09-30 21:08:41 +00005687#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005688 case TARGET_NR_mpx:
5689 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005690#endif
bellard31e31b82003-02-18 22:55:36 +00005691 case TARGET_NR_setpgid:
5692 ret = get_errno(setpgid(arg1, arg2));
5693 break;
bellardebc05482003-09-30 21:08:41 +00005694#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005695 case TARGET_NR_ulimit:
5696 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005697#endif
5698#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005699 case TARGET_NR_oldolduname:
5700 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005701#endif
bellard31e31b82003-02-18 22:55:36 +00005702 case TARGET_NR_umask:
5703 ret = get_errno(umask(arg1));
5704 break;
5705 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005706 if (!(p = lock_user_string(arg1)))
5707 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005708 ret = get_errno(chroot(p));
5709 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005710 break;
5711 case TARGET_NR_ustat:
5712 goto unimplemented;
5713 case TARGET_NR_dup2:
5714 ret = get_errno(dup2(arg1, arg2));
5715 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005716#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5717 case TARGET_NR_dup3:
5718 ret = get_errno(dup3(arg1, arg2, arg3));
5719 break;
5720#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005721#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005722 case TARGET_NR_getppid:
5723 ret = get_errno(getppid());
5724 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005725#endif
bellard31e31b82003-02-18 22:55:36 +00005726 case TARGET_NR_getpgrp:
5727 ret = get_errno(getpgrp());
5728 break;
5729 case TARGET_NR_setsid:
5730 ret = get_errno(setsid());
5731 break;
thse5febef2007-04-01 18:31:35 +00005732#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005733 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005734 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005735#if defined(TARGET_ALPHA)
5736 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005737 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005738 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005739 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5740 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005741 act._sa_handler = old_act->_sa_handler;
5742 target_siginitset(&act.sa_mask, old_act->sa_mask);
5743 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005744 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005745 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005746 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005747 }
5748 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005749 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005750 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5751 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005752 old_act->_sa_handler = oact._sa_handler;
5753 old_act->sa_mask = oact.sa_mask.sig[0];
5754 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005755 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005756 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005757#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005758 struct target_sigaction act, oact, *pact, *old_act;
5759
5760 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005761 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5762 goto efault;
bellard106ec872006-06-27 21:08:10 +00005763 act._sa_handler = old_act->_sa_handler;
5764 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5765 act.sa_flags = old_act->sa_flags;
5766 unlock_user_struct(old_act, arg2, 0);
5767 pact = &act;
5768 } else {
5769 pact = NULL;
5770 }
5771
5772 ret = get_errno(do_sigaction(arg1, pact, &oact));
5773
5774 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005775 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5776 goto efault;
bellard106ec872006-06-27 21:08:10 +00005777 old_act->_sa_handler = oact._sa_handler;
5778 old_act->sa_flags = oact.sa_flags;
5779 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5780 old_act->sa_mask.sig[1] = 0;
5781 old_act->sa_mask.sig[2] = 0;
5782 old_act->sa_mask.sig[3] = 0;
5783 unlock_user_struct(old_act, arg3, 1);
5784 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005785#else
5786 struct target_old_sigaction *old_act;
5787 struct target_sigaction act, oact, *pact;
5788 if (arg2) {
5789 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5790 goto efault;
5791 act._sa_handler = old_act->_sa_handler;
5792 target_siginitset(&act.sa_mask, old_act->sa_mask);
5793 act.sa_flags = old_act->sa_flags;
5794 act.sa_restorer = old_act->sa_restorer;
5795 unlock_user_struct(old_act, arg2, 0);
5796 pact = &act;
5797 } else {
5798 pact = NULL;
5799 }
5800 ret = get_errno(do_sigaction(arg1, pact, &oact));
5801 if (!is_error(ret) && arg3) {
5802 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5803 goto efault;
5804 old_act->_sa_handler = oact._sa_handler;
5805 old_act->sa_mask = oact.sa_mask.sig[0];
5806 old_act->sa_flags = oact.sa_flags;
5807 old_act->sa_restorer = oact.sa_restorer;
5808 unlock_user_struct(old_act, arg3, 1);
5809 }
ths388bb212007-05-13 13:58:00 +00005810#endif
bellard31e31b82003-02-18 22:55:36 +00005811 }
5812 break;
thse5febef2007-04-01 18:31:35 +00005813#endif
bellard66fb9762003-03-23 01:06:05 +00005814 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005815 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005816#if defined(TARGET_ALPHA)
5817 struct target_sigaction act, oact, *pact = 0;
5818 struct target_rt_sigaction *rt_act;
5819 /* ??? arg4 == sizeof(sigset_t). */
5820 if (arg2) {
5821 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5822 goto efault;
5823 act._sa_handler = rt_act->_sa_handler;
5824 act.sa_mask = rt_act->sa_mask;
5825 act.sa_flags = rt_act->sa_flags;
5826 act.sa_restorer = arg5;
5827 unlock_user_struct(rt_act, arg2, 0);
5828 pact = &act;
5829 }
5830 ret = get_errno(do_sigaction(arg1, pact, &oact));
5831 if (!is_error(ret) && arg3) {
5832 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5833 goto efault;
5834 rt_act->_sa_handler = oact._sa_handler;
5835 rt_act->sa_mask = oact.sa_mask;
5836 rt_act->sa_flags = oact.sa_flags;
5837 unlock_user_struct(rt_act, arg3, 1);
5838 }
5839#else
pbrook53a59602006-03-25 19:31:22 +00005840 struct target_sigaction *act;
5841 struct target_sigaction *oact;
5842
bellard579a97f2007-11-11 14:26:47 +00005843 if (arg2) {
5844 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5845 goto efault;
5846 } else
pbrook53a59602006-03-25 19:31:22 +00005847 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005848 if (arg3) {
5849 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5850 ret = -TARGET_EFAULT;
5851 goto rt_sigaction_fail;
5852 }
5853 } else
pbrook53a59602006-03-25 19:31:22 +00005854 oact = NULL;
5855 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005856 rt_sigaction_fail:
5857 if (act)
pbrook53a59602006-03-25 19:31:22 +00005858 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005859 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005860 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005861#endif
pbrook53a59602006-03-25 19:31:22 +00005862 }
bellard66fb9762003-03-23 01:06:05 +00005863 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005864#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005865 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005866 {
5867 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005868 abi_ulong target_set;
bellard66fb9762003-03-23 01:06:05 +00005869 sigprocmask(0, NULL, &cur_set);
5870 host_to_target_old_sigset(&target_set, &cur_set);
5871 ret = target_set;
5872 }
5873 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005874#endif
5875#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005876 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005877 {
5878 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005879 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00005880 sigprocmask(0, NULL, &cur_set);
5881 target_to_host_old_sigset(&set, &target_set);
5882 sigorset(&set, &set, &cur_set);
5883 sigprocmask(SIG_SETMASK, &set, &oset);
5884 host_to_target_old_sigset(&target_set, &oset);
5885 ret = target_set;
5886 }
5887 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005888#endif
thse5febef2007-04-01 18:31:35 +00005889#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00005890 case TARGET_NR_sigprocmask:
5891 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005892#if defined(TARGET_ALPHA)
5893 sigset_t set, oldset;
5894 abi_ulong mask;
5895 int how;
5896
5897 switch (arg1) {
5898 case TARGET_SIG_BLOCK:
5899 how = SIG_BLOCK;
5900 break;
5901 case TARGET_SIG_UNBLOCK:
5902 how = SIG_UNBLOCK;
5903 break;
5904 case TARGET_SIG_SETMASK:
5905 how = SIG_SETMASK;
5906 break;
5907 default:
5908 ret = -TARGET_EINVAL;
5909 goto fail;
5910 }
5911 mask = arg2;
5912 target_to_host_old_sigset(&set, &mask);
5913
5914 ret = get_errno(sigprocmask(how, &set, &oldset));
5915
5916 if (!is_error(ret)) {
5917 host_to_target_old_sigset(&mask, &oldset);
5918 ret = mask;
5919 ((CPUAlphaState *)cpu_env)->[IR_V0] = 0; /* force no error */
5920 }
5921#else
bellard66fb9762003-03-23 01:06:05 +00005922 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07005923 int how;
ths3b46e622007-09-17 08:09:54 +00005924
pbrook53a59602006-03-25 19:31:22 +00005925 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005926 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00005927 case TARGET_SIG_BLOCK:
5928 how = SIG_BLOCK;
5929 break;
5930 case TARGET_SIG_UNBLOCK:
5931 how = SIG_UNBLOCK;
5932 break;
5933 case TARGET_SIG_SETMASK:
5934 how = SIG_SETMASK;
5935 break;
5936 default:
ths0da46a62007-10-20 20:23:07 +00005937 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005938 goto fail;
5939 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005940 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005941 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005942 target_to_host_old_sigset(&set, p);
5943 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005944 set_ptr = &set;
5945 } else {
5946 how = 0;
5947 set_ptr = NULL;
5948 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005949 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005950 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005951 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005952 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005953 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005954 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005955 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005956#endif
bellard66fb9762003-03-23 01:06:05 +00005957 }
5958 break;
thse5febef2007-04-01 18:31:35 +00005959#endif
bellard66fb9762003-03-23 01:06:05 +00005960 case TARGET_NR_rt_sigprocmask:
5961 {
5962 int how = arg1;
5963 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00005964
pbrook53a59602006-03-25 19:31:22 +00005965 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00005966 switch(how) {
5967 case TARGET_SIG_BLOCK:
5968 how = SIG_BLOCK;
5969 break;
5970 case TARGET_SIG_UNBLOCK:
5971 how = SIG_UNBLOCK;
5972 break;
5973 case TARGET_SIG_SETMASK:
5974 how = SIG_SETMASK;
5975 break;
5976 default:
ths0da46a62007-10-20 20:23:07 +00005977 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005978 goto fail;
5979 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005980 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005981 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005982 target_to_host_sigset(&set, p);
5983 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005984 set_ptr = &set;
5985 } else {
5986 how = 0;
5987 set_ptr = NULL;
5988 }
5989 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005990 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005991 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005992 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005993 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005994 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005995 }
5996 }
5997 break;
thse5febef2007-04-01 18:31:35 +00005998#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00005999 case TARGET_NR_sigpending:
6000 {
6001 sigset_t set;
6002 ret = get_errno(sigpending(&set));
6003 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006004 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006005 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006006 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006007 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006008 }
6009 }
6010 break;
thse5febef2007-04-01 18:31:35 +00006011#endif
bellard66fb9762003-03-23 01:06:05 +00006012 case TARGET_NR_rt_sigpending:
6013 {
6014 sigset_t set;
6015 ret = get_errno(sigpending(&set));
6016 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006017 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006018 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006019 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006020 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006021 }
6022 }
6023 break;
thse5febef2007-04-01 18:31:35 +00006024#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006025 case TARGET_NR_sigsuspend:
6026 {
6027 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006028#if defined(TARGET_ALPHA)
6029 abi_ulong mask = arg1;
6030 target_to_host_old_sigset(&set, &mask);
6031#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006032 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006033 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006034 target_to_host_old_sigset(&set, p);
6035 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006036#endif
bellard66fb9762003-03-23 01:06:05 +00006037 ret = get_errno(sigsuspend(&set));
6038 }
6039 break;
thse5febef2007-04-01 18:31:35 +00006040#endif
bellard66fb9762003-03-23 01:06:05 +00006041 case TARGET_NR_rt_sigsuspend:
6042 {
6043 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006044 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006045 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006046 target_to_host_sigset(&set, p);
6047 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006048 ret = get_errno(sigsuspend(&set));
6049 }
6050 break;
6051 case TARGET_NR_rt_sigtimedwait:
6052 {
bellard66fb9762003-03-23 01:06:05 +00006053 sigset_t set;
6054 struct timespec uts, *puts;
6055 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006056
Anthony Liguoric227f092009-10-01 16:12:16 -05006057 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006058 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006059 target_to_host_sigset(&set, p);
6060 unlock_user(p, arg1, 0);
6061 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006062 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006063 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006064 } else {
6065 puts = NULL;
6066 }
6067 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
pbrook53a59602006-03-25 19:31:22 +00006068 if (!is_error(ret) && arg2) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006069 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006070 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006071 host_to_target_siginfo(p, &uinfo);
Anthony Liguoric227f092009-10-01 16:12:16 -05006072 unlock_user(p, arg2, sizeof(target_siginfo_t));
bellard66fb9762003-03-23 01:06:05 +00006073 }
6074 }
6075 break;
6076 case TARGET_NR_rt_sigqueueinfo:
6077 {
6078 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006079 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006080 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006081 target_to_host_siginfo(&uinfo, p);
6082 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006083 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6084 }
6085 break;
thse5febef2007-04-01 18:31:35 +00006086#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006087 case TARGET_NR_sigreturn:
6088 /* NOTE: ret is eax, so not transcoding must be done */
6089 ret = do_sigreturn(cpu_env);
6090 break;
thse5febef2007-04-01 18:31:35 +00006091#endif
bellard66fb9762003-03-23 01:06:05 +00006092 case TARGET_NR_rt_sigreturn:
6093 /* NOTE: ret is eax, so not transcoding must be done */
6094 ret = do_rt_sigreturn(cpu_env);
6095 break;
bellard31e31b82003-02-18 22:55:36 +00006096 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006097 if (!(p = lock_user_string(arg1)))
6098 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006099 ret = get_errno(sethostname(p, arg2));
6100 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006101 break;
6102 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006103 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006104 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006105 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006106 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006107 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6108 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006109 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6110 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006111 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006112 ret = get_errno(setrlimit(resource, &rlim));
6113 }
6114 break;
bellard31e31b82003-02-18 22:55:36 +00006115 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006116 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006117 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006118 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006119 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006120
bellard9de5e442003-03-23 16:49:39 +00006121 ret = get_errno(getrlimit(resource, &rlim));
6122 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006123 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6124 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006125 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6126 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006127 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006128 }
6129 }
6130 break;
bellard31e31b82003-02-18 22:55:36 +00006131 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006132 {
6133 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006134 ret = get_errno(getrusage(arg1, &rusage));
6135 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006136 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006137 }
6138 }
6139 break;
bellard31e31b82003-02-18 22:55:36 +00006140 case TARGET_NR_gettimeofday:
6141 {
bellard31e31b82003-02-18 22:55:36 +00006142 struct timeval tv;
6143 ret = get_errno(gettimeofday(&tv, NULL));
6144 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006145 if (copy_to_user_timeval(arg1, &tv))
6146 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006147 }
6148 }
6149 break;
6150 case TARGET_NR_settimeofday:
6151 {
bellard31e31b82003-02-18 22:55:36 +00006152 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00006153 if (copy_from_user_timeval(&tv, arg1))
6154 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006155 ret = get_errno(settimeofday(&tv, NULL));
6156 }
6157 break;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006158#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390)
bellard31e31b82003-02-18 22:55:36 +00006159 case TARGET_NR_select:
bellardf2674e32003-07-09 12:26:09 +00006160 {
pbrook53a59602006-03-25 19:31:22 +00006161 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006162 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006163 long nsel;
6164
bellard579a97f2007-11-11 14:26:47 +00006165 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6166 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006167 nsel = tswapal(sel->n);
6168 inp = tswapal(sel->inp);
6169 outp = tswapal(sel->outp);
6170 exp = tswapal(sel->exp);
6171 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006172 unlock_user_struct(sel, arg1, 0);
6173 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006174 }
6175 break;
bellard048f6b42005-11-26 18:47:20 +00006176#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006177#ifdef TARGET_NR_pselect6
6178 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006179 {
6180 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6181 fd_set rfds, wfds, efds;
6182 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6183 struct timespec ts, *ts_ptr;
6184
6185 /*
6186 * The 6th arg is actually two args smashed together,
6187 * so we cannot use the C library.
6188 */
6189 sigset_t set;
6190 struct {
6191 sigset_t *set;
6192 size_t size;
6193 } sig, *sig_ptr;
6194
6195 abi_ulong arg_sigset, arg_sigsize, *arg7;
6196 target_sigset_t *target_sigset;
6197
6198 n = arg1;
6199 rfd_addr = arg2;
6200 wfd_addr = arg3;
6201 efd_addr = arg4;
6202 ts_addr = arg5;
6203
6204 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6205 if (ret) {
6206 goto fail;
6207 }
6208 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6209 if (ret) {
6210 goto fail;
6211 }
6212 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6213 if (ret) {
6214 goto fail;
6215 }
6216
6217 /*
6218 * This takes a timespec, and not a timeval, so we cannot
6219 * use the do_select() helper ...
6220 */
6221 if (ts_addr) {
6222 if (target_to_host_timespec(&ts, ts_addr)) {
6223 goto efault;
6224 }
6225 ts_ptr = &ts;
6226 } else {
6227 ts_ptr = NULL;
6228 }
6229
6230 /* Extract the two packed args for the sigset */
6231 if (arg6) {
6232 sig_ptr = &sig;
6233 sig.size = _NSIG / 8;
6234
6235 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6236 if (!arg7) {
6237 goto efault;
6238 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006239 arg_sigset = tswapal(arg7[0]);
6240 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006241 unlock_user(arg7, arg6, 0);
6242
6243 if (arg_sigset) {
6244 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006245 if (arg_sigsize != sizeof(*target_sigset)) {
6246 /* Like the kernel, we enforce correct size sigsets */
6247 ret = -TARGET_EINVAL;
6248 goto fail;
6249 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006250 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6251 sizeof(*target_sigset), 1);
6252 if (!target_sigset) {
6253 goto efault;
6254 }
6255 target_to_host_sigset(&set, target_sigset);
6256 unlock_user(target_sigset, arg_sigset, 0);
6257 } else {
6258 sig.set = NULL;
6259 }
6260 } else {
6261 sig_ptr = NULL;
6262 }
6263
6264 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6265 ts_ptr, sig_ptr));
6266
6267 if (!is_error(ret)) {
6268 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6269 goto efault;
6270 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6271 goto efault;
6272 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6273 goto efault;
6274
6275 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6276 goto efault;
6277 }
6278 }
6279 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006280#endif
bellard31e31b82003-02-18 22:55:36 +00006281 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006282 {
6283 void *p2;
6284 p = lock_user_string(arg1);
6285 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006286 if (!p || !p2)
6287 ret = -TARGET_EFAULT;
6288 else
6289 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006290 unlock_user(p2, arg2, 0);
6291 unlock_user(p, arg1, 0);
6292 }
bellard31e31b82003-02-18 22:55:36 +00006293 break;
thsf0b62432007-09-24 09:25:40 +00006294#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
6295 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006296 {
bellard579a97f2007-11-11 14:26:47 +00006297 void *p2;
thsf0b62432007-09-24 09:25:40 +00006298 p = lock_user_string(arg1);
6299 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006300 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006301 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006302 else
6303 ret = get_errno(sys_symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006304 unlock_user(p2, arg3, 0);
6305 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006306 }
6307 break;
6308#endif
bellardebc05482003-09-30 21:08:41 +00006309#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006310 case TARGET_NR_oldlstat:
6311 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006312#endif
bellard31e31b82003-02-18 22:55:36 +00006313 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006314 {
aurel32d088d662009-01-30 20:09:01 +00006315 void *p2, *temp;
pbrook53a59602006-03-25 19:31:22 +00006316 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006317 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
6318 if (!p || !p2)
6319 ret = -TARGET_EFAULT;
aurel32d088d662009-01-30 20:09:01 +00006320 else {
6321 if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
6322 char real[PATH_MAX];
6323 temp = realpath(exec_path,real);
6324 ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
6325 snprintf((char *)p2, arg3, "%s", real);
6326 }
6327 else
6328 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006329 }
pbrook53a59602006-03-25 19:31:22 +00006330 unlock_user(p2, arg2, ret);
6331 unlock_user(p, arg1, 0);
6332 }
bellard31e31b82003-02-18 22:55:36 +00006333 break;
ths5e0ccb12007-09-24 09:26:10 +00006334#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
6335 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006336 {
bellard579a97f2007-11-11 14:26:47 +00006337 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006338 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006339 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
6340 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006341 ret = -TARGET_EFAULT;
ths5e0ccb12007-09-24 09:26:10 +00006342 else
6343 ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
bellard579a97f2007-11-11 14:26:47 +00006344 unlock_user(p2, arg3, ret);
6345 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006346 }
6347 break;
6348#endif
thse5febef2007-04-01 18:31:35 +00006349#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006350 case TARGET_NR_uselib:
6351 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006352#endif
6353#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006354 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006355 if (!(p = lock_user_string(arg1)))
6356 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006357 ret = get_errno(swapon(p, arg2));
6358 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006359 break;
thse5febef2007-04-01 18:31:35 +00006360#endif
bellard31e31b82003-02-18 22:55:36 +00006361 case TARGET_NR_reboot:
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006362 if (!(p = lock_user_string(arg4)))
6363 goto efault;
6364 ret = reboot(arg1, arg2, arg3, p);
6365 unlock_user(p, arg4, 0);
6366 break;
thse5febef2007-04-01 18:31:35 +00006367#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006368 case TARGET_NR_readdir:
6369 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006370#endif
6371#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006372 case TARGET_NR_mmap:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006373#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
6374 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6375 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006376 {
blueswir1992f48a2007-10-14 16:27:31 +00006377 abi_ulong *v;
6378 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006379 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6380 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006381 v1 = tswapal(v[0]);
6382 v2 = tswapal(v[1]);
6383 v3 = tswapal(v[2]);
6384 v4 = tswapal(v[3]);
6385 v5 = tswapal(v[4]);
6386 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006387 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006388 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006389 target_to_host_bitmask(v4, mmap_flags_tbl),
6390 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006391 }
bellard31e31b82003-02-18 22:55:36 +00006392#else
ths5fafdf22007-09-16 21:08:06 +00006393 ret = get_errno(target_mmap(arg1, arg2, arg3,
6394 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006395 arg5,
6396 arg6));
bellard31e31b82003-02-18 22:55:36 +00006397#endif
bellard6fb883e2003-07-09 17:12:39 +00006398 break;
thse5febef2007-04-01 18:31:35 +00006399#endif
bellarda315a142005-01-30 22:59:18 +00006400#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006401 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006402#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006403#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006404#endif
ths5fafdf22007-09-16 21:08:06 +00006405 ret = get_errno(target_mmap(arg1, arg2, arg3,
6406 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006407 arg5,
bellardc573ff62004-01-04 15:51:36 +00006408 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006409 break;
bellarda315a142005-01-30 22:59:18 +00006410#endif
bellard31e31b82003-02-18 22:55:36 +00006411 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006412 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006413 break;
bellard9de5e442003-03-23 16:49:39 +00006414 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006415 {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006416 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006417 /* Special hack to detect libc making the stack executable. */
6418 if ((arg3 & PROT_GROWSDOWN)
6419 && arg1 >= ts->info->stack_limit
6420 && arg1 <= ts->info->start_stack) {
6421 arg3 &= ~PROT_GROWSDOWN;
6422 arg2 = arg2 + arg1 - ts->info->stack_limit;
6423 arg1 = ts->info->stack_limit;
6424 }
6425 }
bellard54936002003-05-13 00:25:15 +00006426 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006427 break;
thse5febef2007-04-01 18:31:35 +00006428#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006429 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006430 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006431 break;
thse5febef2007-04-01 18:31:35 +00006432#endif
pbrook53a59602006-03-25 19:31:22 +00006433 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006434#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006435 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006436 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006437 break;
thse5febef2007-04-01 18:31:35 +00006438#endif
6439#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006440 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006441 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006442 break;
thse5febef2007-04-01 18:31:35 +00006443#endif
6444#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006445 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006446 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006447 break;
thse5febef2007-04-01 18:31:35 +00006448#endif
6449#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006450 case TARGET_NR_mlockall:
6451 ret = get_errno(mlockall(arg1));
6452 break;
thse5febef2007-04-01 18:31:35 +00006453#endif
6454#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006455 case TARGET_NR_munlockall:
6456 ret = get_errno(munlockall());
6457 break;
thse5febef2007-04-01 18:31:35 +00006458#endif
bellard31e31b82003-02-18 22:55:36 +00006459 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006460 if (!(p = lock_user_string(arg1)))
6461 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006462 ret = get_errno(truncate(p, arg2));
6463 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006464 break;
6465 case TARGET_NR_ftruncate:
6466 ret = get_errno(ftruncate(arg1, arg2));
6467 break;
6468 case TARGET_NR_fchmod:
6469 ret = get_errno(fchmod(arg1, arg2));
6470 break;
ths814d7972007-09-24 09:26:51 +00006471#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
6472 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006473 if (!(p = lock_user_string(arg2)))
6474 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00006475 ret = get_errno(sys_fchmodat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006476 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006477 break;
6478#endif
bellard31e31b82003-02-18 22:55:36 +00006479 case TARGET_NR_getpriority:
thsc6cda172007-10-09 03:42:34 +00006480 /* libc does special remapping of the return value of
6481 * sys_getpriority() so it's just easiest to call
6482 * sys_getpriority() directly rather than through libc. */
Ulrich Hecht69137202009-09-17 21:08:37 +03006483 ret = get_errno(sys_getpriority(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006484 break;
6485 case TARGET_NR_setpriority:
6486 ret = get_errno(setpriority(arg1, arg2, arg3));
6487 break;
bellardebc05482003-09-30 21:08:41 +00006488#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006489 case TARGET_NR_profil:
6490 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006491#endif
bellard31e31b82003-02-18 22:55:36 +00006492 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006493 if (!(p = lock_user_string(arg1)))
6494 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006495 ret = get_errno(statfs(path(p), &stfs));
6496 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006497 convert_statfs:
6498 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006499 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006500
bellard579a97f2007-11-11 14:26:47 +00006501 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6502 goto efault;
6503 __put_user(stfs.f_type, &target_stfs->f_type);
6504 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6505 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6506 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6507 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6508 __put_user(stfs.f_files, &target_stfs->f_files);
6509 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6510 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6511 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6512 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
pbrook53a59602006-03-25 19:31:22 +00006513 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006514 }
6515 break;
6516 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006517 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006518 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006519#ifdef TARGET_NR_statfs64
6520 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006521 if (!(p = lock_user_string(arg1)))
6522 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006523 ret = get_errno(statfs(path(p), &stfs));
6524 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006525 convert_statfs64:
6526 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006527 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006528
bellard579a97f2007-11-11 14:26:47 +00006529 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6530 goto efault;
6531 __put_user(stfs.f_type, &target_stfs->f_type);
6532 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6533 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6534 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6535 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6536 __put_user(stfs.f_files, &target_stfs->f_files);
6537 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6538 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6539 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6540 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
6541 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006542 }
6543 break;
6544 case TARGET_NR_fstatfs64:
6545 ret = get_errno(fstatfs(arg1, &stfs));
6546 goto convert_statfs64;
6547#endif
bellardebc05482003-09-30 21:08:41 +00006548#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006549 case TARGET_NR_ioperm:
6550 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006551#endif
thse5febef2007-04-01 18:31:35 +00006552#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006553 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006554 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006555 break;
thse5febef2007-04-01 18:31:35 +00006556#endif
bellard3532fa72006-06-24 15:06:03 +00006557#ifdef TARGET_NR_accept
6558 case TARGET_NR_accept:
pbrook1be9e1d2006-11-19 15:26:04 +00006559 ret = do_accept(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006560 break;
6561#endif
6562#ifdef TARGET_NR_bind
6563 case TARGET_NR_bind:
6564 ret = do_bind(arg1, arg2, arg3);
6565 break;
6566#endif
6567#ifdef TARGET_NR_connect
6568 case TARGET_NR_connect:
6569 ret = do_connect(arg1, arg2, arg3);
6570 break;
6571#endif
6572#ifdef TARGET_NR_getpeername
6573 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006574 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006575 break;
6576#endif
6577#ifdef TARGET_NR_getsockname
6578 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006579 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006580 break;
6581#endif
6582#ifdef TARGET_NR_getsockopt
6583 case TARGET_NR_getsockopt:
6584 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6585 break;
6586#endif
6587#ifdef TARGET_NR_listen
6588 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006589 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006590 break;
6591#endif
6592#ifdef TARGET_NR_recv
6593 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006594 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006595 break;
6596#endif
6597#ifdef TARGET_NR_recvfrom
6598 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006599 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006600 break;
6601#endif
6602#ifdef TARGET_NR_recvmsg
6603 case TARGET_NR_recvmsg:
6604 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6605 break;
6606#endif
6607#ifdef TARGET_NR_send
6608 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006609 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006610 break;
6611#endif
6612#ifdef TARGET_NR_sendmsg
6613 case TARGET_NR_sendmsg:
6614 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6615 break;
6616#endif
6617#ifdef TARGET_NR_sendto
6618 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006619 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006620 break;
6621#endif
6622#ifdef TARGET_NR_shutdown
6623 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006624 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006625 break;
6626#endif
6627#ifdef TARGET_NR_socket
6628 case TARGET_NR_socket:
6629 ret = do_socket(arg1, arg2, arg3);
6630 break;
6631#endif
6632#ifdef TARGET_NR_socketpair
6633 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006634 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006635 break;
6636#endif
6637#ifdef TARGET_NR_setsockopt
6638 case TARGET_NR_setsockopt:
6639 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6640 break;
6641#endif
ths7494b0f2007-02-11 18:26:53 +00006642
bellard31e31b82003-02-18 22:55:36 +00006643 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006644 if (!(p = lock_user_string(arg2)))
6645 goto efault;
thse5574482007-02-11 20:03:13 +00006646 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6647 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006648 break;
6649
bellard31e31b82003-02-18 22:55:36 +00006650 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006651 {
bellard66fb9762003-03-23 01:06:05 +00006652 struct itimerval value, ovalue, *pvalue;
6653
pbrook53a59602006-03-25 19:31:22 +00006654 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006655 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006656 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6657 || copy_from_user_timeval(&pvalue->it_value,
6658 arg2 + sizeof(struct target_timeval)))
6659 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006660 } else {
6661 pvalue = NULL;
6662 }
6663 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006664 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006665 if (copy_to_user_timeval(arg3,
6666 &ovalue.it_interval)
6667 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6668 &ovalue.it_value))
6669 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006670 }
6671 }
6672 break;
bellard31e31b82003-02-18 22:55:36 +00006673 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006674 {
bellard66fb9762003-03-23 01:06:05 +00006675 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006676
bellard66fb9762003-03-23 01:06:05 +00006677 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006678 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006679 if (copy_to_user_timeval(arg2,
6680 &value.it_interval)
6681 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6682 &value.it_value))
6683 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006684 }
6685 }
6686 break;
bellard31e31b82003-02-18 22:55:36 +00006687 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006688 if (!(p = lock_user_string(arg1)))
6689 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006690 ret = get_errno(stat(path(p), &st));
6691 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006692 goto do_stat;
6693 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006694 if (!(p = lock_user_string(arg1)))
6695 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006696 ret = get_errno(lstat(path(p), &st));
6697 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006698 goto do_stat;
6699 case TARGET_NR_fstat:
6700 {
6701 ret = get_errno(fstat(arg1, &st));
6702 do_stat:
6703 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006704 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006705
bellard579a97f2007-11-11 14:26:47 +00006706 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6707 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006708 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006709 __put_user(st.st_dev, &target_st->st_dev);
6710 __put_user(st.st_ino, &target_st->st_ino);
6711 __put_user(st.st_mode, &target_st->st_mode);
6712 __put_user(st.st_uid, &target_st->st_uid);
6713 __put_user(st.st_gid, &target_st->st_gid);
6714 __put_user(st.st_nlink, &target_st->st_nlink);
6715 __put_user(st.st_rdev, &target_st->st_rdev);
6716 __put_user(st.st_size, &target_st->st_size);
6717 __put_user(st.st_blksize, &target_st->st_blksize);
6718 __put_user(st.st_blocks, &target_st->st_blocks);
6719 __put_user(st.st_atime, &target_st->target_st_atime);
6720 __put_user(st.st_mtime, &target_st->target_st_mtime);
6721 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006722 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006723 }
6724 }
6725 break;
bellardebc05482003-09-30 21:08:41 +00006726#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006727 case TARGET_NR_olduname:
6728 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006729#endif
6730#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006731 case TARGET_NR_iopl:
6732 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006733#endif
bellard31e31b82003-02-18 22:55:36 +00006734 case TARGET_NR_vhangup:
6735 ret = get_errno(vhangup());
6736 break;
bellardebc05482003-09-30 21:08:41 +00006737#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006738 case TARGET_NR_idle:
6739 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006740#endif
bellard42ad6ae2005-01-03 22:48:11 +00006741#ifdef TARGET_NR_syscall
6742 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006743 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6744 arg6, arg7, arg8, 0);
6745 break;
bellard42ad6ae2005-01-03 22:48:11 +00006746#endif
bellard31e31b82003-02-18 22:55:36 +00006747 case TARGET_NR_wait4:
6748 {
6749 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006750 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006751 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006752 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00006753 if (target_rusage)
6754 rusage_ptr = &rusage;
6755 else
6756 rusage_ptr = NULL;
6757 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6758 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01006759 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00006760 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006761 if (put_user_s32(status, status_ptr))
6762 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006763 }
bellard2f619692007-11-16 10:46:05 +00006764 if (target_rusage)
6765 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00006766 }
6767 }
6768 break;
thse5febef2007-04-01 18:31:35 +00006769#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006770 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006771 if (!(p = lock_user_string(arg1)))
6772 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006773 ret = get_errno(swapoff(p));
6774 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006775 break;
thse5febef2007-04-01 18:31:35 +00006776#endif
bellard31e31b82003-02-18 22:55:36 +00006777 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006778 {
pbrook53a59602006-03-25 19:31:22 +00006779 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006780 struct sysinfo value;
6781 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006782 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006783 {
bellard579a97f2007-11-11 14:26:47 +00006784 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6785 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006786 __put_user(value.uptime, &target_value->uptime);
6787 __put_user(value.loads[0], &target_value->loads[0]);
6788 __put_user(value.loads[1], &target_value->loads[1]);
6789 __put_user(value.loads[2], &target_value->loads[2]);
6790 __put_user(value.totalram, &target_value->totalram);
6791 __put_user(value.freeram, &target_value->freeram);
6792 __put_user(value.sharedram, &target_value->sharedram);
6793 __put_user(value.bufferram, &target_value->bufferram);
6794 __put_user(value.totalswap, &target_value->totalswap);
6795 __put_user(value.freeswap, &target_value->freeswap);
6796 __put_user(value.procs, &target_value->procs);
6797 __put_user(value.totalhigh, &target_value->totalhigh);
6798 __put_user(value.freehigh, &target_value->freehigh);
6799 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006800 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006801 }
6802 }
6803 break;
thse5febef2007-04-01 18:31:35 +00006804#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006805 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006806 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6807 break;
thse5febef2007-04-01 18:31:35 +00006808#endif
aurel32e5289082009-04-18 16:16:12 +00006809#ifdef TARGET_NR_semget
6810 case TARGET_NR_semget:
6811 ret = get_errno(semget(arg1, arg2, arg3));
6812 break;
6813#endif
6814#ifdef TARGET_NR_semop
6815 case TARGET_NR_semop:
6816 ret = get_errno(do_semop(arg1, arg2, arg3));
6817 break;
6818#endif
6819#ifdef TARGET_NR_semctl
6820 case TARGET_NR_semctl:
6821 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6822 break;
6823#endif
aurel32eeb438c2008-10-13 21:08:55 +00006824#ifdef TARGET_NR_msgctl
6825 case TARGET_NR_msgctl:
6826 ret = do_msgctl(arg1, arg2, arg3);
6827 break;
6828#endif
6829#ifdef TARGET_NR_msgget
6830 case TARGET_NR_msgget:
6831 ret = get_errno(msgget(arg1, arg2));
6832 break;
6833#endif
6834#ifdef TARGET_NR_msgrcv
6835 case TARGET_NR_msgrcv:
6836 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
6837 break;
6838#endif
6839#ifdef TARGET_NR_msgsnd
6840 case TARGET_NR_msgsnd:
6841 ret = do_msgsnd(arg1, arg2, arg3, arg4);
6842 break;
6843#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03006844#ifdef TARGET_NR_shmget
6845 case TARGET_NR_shmget:
6846 ret = get_errno(shmget(arg1, arg2, arg3));
6847 break;
6848#endif
6849#ifdef TARGET_NR_shmctl
6850 case TARGET_NR_shmctl:
6851 ret = do_shmctl(arg1, arg2, arg3);
6852 break;
6853#endif
6854#ifdef TARGET_NR_shmat
6855 case TARGET_NR_shmat:
6856 ret = do_shmat(arg1, arg2, arg3);
6857 break;
6858#endif
6859#ifdef TARGET_NR_shmdt
6860 case TARGET_NR_shmdt:
6861 ret = do_shmdt(arg1);
6862 break;
6863#endif
bellard31e31b82003-02-18 22:55:36 +00006864 case TARGET_NR_fsync:
6865 ret = get_errno(fsync(arg1));
6866 break;
bellard31e31b82003-02-18 22:55:36 +00006867 case TARGET_NR_clone:
Richard Hendersona4b388f2010-04-12 16:17:22 -07006868#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
aurel320b6d3ae2008-09-15 07:43:43 +00006869 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
edgar_iglb15ad612009-01-07 19:43:47 +00006870#elif defined(TARGET_CRIS)
6871 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006872#elif defined(TARGET_S390X)
6873 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00006874#else
pbrookd865bab2008-06-07 22:12:17 +00006875 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
aurel320b6d3ae2008-09-15 07:43:43 +00006876#endif
bellard1b6b0292003-03-22 17:31:38 +00006877 break;
bellardec86b0f2003-04-11 00:15:04 +00006878#ifdef __NR_exit_group
6879 /* new thread calls */
6880 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02006881#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00006882 _mcleanup();
6883#endif
bellarde9009672005-04-26 20:42:36 +00006884 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00006885 ret = get_errno(exit_group(arg1));
6886 break;
6887#endif
bellard31e31b82003-02-18 22:55:36 +00006888 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00006889 if (!(p = lock_user_string(arg1)))
6890 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006891 ret = get_errno(setdomainname(p, arg2));
6892 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006893 break;
6894 case TARGET_NR_uname:
6895 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00006896 {
6897 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00006898
bellard579a97f2007-11-11 14:26:47 +00006899 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
6900 goto efault;
bellard29e619b2004-09-13 21:41:04 +00006901 ret = get_errno(sys_uname(buf));
6902 if (!is_error(ret)) {
6903 /* Overrite the native machine name with whatever is being
6904 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01006905 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00006906 /* Allow the user to override the reported release. */
6907 if (qemu_uname_release && *qemu_uname_release)
6908 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00006909 }
pbrook53a59602006-03-25 19:31:22 +00006910 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00006911 }
bellard31e31b82003-02-18 22:55:36 +00006912 break;
bellard6dbad632003-03-16 18:05:05 +00006913#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00006914 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00006915 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00006916 break;
j_mayer84409dd2007-04-06 08:56:50 +00006917#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00006918 case TARGET_NR_vm86old:
6919 goto unimplemented;
6920 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00006921 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00006922 break;
6923#endif
j_mayer84409dd2007-04-06 08:56:50 +00006924#endif
bellard31e31b82003-02-18 22:55:36 +00006925 case TARGET_NR_adjtimex:
6926 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006927#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00006928 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00006929#endif
bellard31e31b82003-02-18 22:55:36 +00006930 case TARGET_NR_init_module:
6931 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00006932#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00006933 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00006934#endif
bellard31e31b82003-02-18 22:55:36 +00006935 goto unimplemented;
6936 case TARGET_NR_quotactl:
6937 goto unimplemented;
6938 case TARGET_NR_getpgid:
6939 ret = get_errno(getpgid(arg1));
6940 break;
6941 case TARGET_NR_fchdir:
6942 ret = get_errno(fchdir(arg1));
6943 break;
j_mayer84409dd2007-04-06 08:56:50 +00006944#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00006945 case TARGET_NR_bdflush:
6946 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00006947#endif
thse5febef2007-04-01 18:31:35 +00006948#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00006949 case TARGET_NR_sysfs:
6950 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006951#endif
bellard31e31b82003-02-18 22:55:36 +00006952 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00006953 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00006954 break;
thse5febef2007-04-01 18:31:35 +00006955#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00006956 case TARGET_NR_afs_syscall:
6957 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006958#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006959#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006960 case TARGET_NR__llseek:
6961 {
6962 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00006963#if !defined(__NR_llseek)
6964 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
6965 if (res == -1) {
6966 ret = get_errno(res);
6967 } else {
6968 ret = 0;
6969 }
6970#else
bellard31e31b82003-02-18 22:55:36 +00006971 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00006972#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00006973 if ((ret == 0) && put_user_s64(res, arg4)) {
6974 goto efault;
6975 }
bellard31e31b82003-02-18 22:55:36 +00006976 }
6977 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006978#endif
bellard31e31b82003-02-18 22:55:36 +00006979 case TARGET_NR_getdents:
Ulrich Hechtd83c8732009-07-24 19:10:28 +02006980#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00006981 {
pbrook53a59602006-03-25 19:31:22 +00006982 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00006983 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006984 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00006985
6986 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00006987 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00006988 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00006989 goto fail;
6990 }
ths3b46e622007-09-17 08:09:54 +00006991
bellard4add45b2003-06-05 01:52:59 +00006992 ret = get_errno(sys_getdents(arg1, dirp, count));
6993 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006994 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00006995 struct target_dirent *tde;
6996 int len = ret;
6997 int reclen, treclen;
6998 int count1, tnamelen;
6999
7000 count1 = 0;
7001 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007002 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7003 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007004 tde = target_dirp;
7005 while (len > 0) {
7006 reclen = de->d_reclen;
blueswir1992f48a2007-10-14 16:27:31 +00007007 treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
bellard4add45b2003-06-05 01:52:59 +00007008 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007009 tde->d_ino = tswapal(de->d_ino);
7010 tde->d_off = tswapal(de->d_off);
blueswir1992f48a2007-10-14 16:27:31 +00007011 tnamelen = treclen - (2 * sizeof(abi_long) + 2);
bellard4add45b2003-06-05 01:52:59 +00007012 if (tnamelen > 256)
7013 tnamelen = 256;
bellard80a9d032005-01-03 23:31:27 +00007014 /* XXX: may not be correct */
blueswir1be15b142008-10-25 11:21:28 +00007015 pstrcpy(tde->d_name, tnamelen, de->d_name);
aurel326556a832008-10-13 21:08:17 +00007016 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007017 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007018 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007019 count1 += treclen;
7020 }
7021 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007022 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007023 }
7024 free(dirp);
7025 }
7026#else
bellard31e31b82003-02-18 22:55:36 +00007027 {
aurel326556a832008-10-13 21:08:17 +00007028 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007029 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007030
bellard579a97f2007-11-11 14:26:47 +00007031 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7032 goto efault;
bellard72f03902003-02-18 23:33:18 +00007033 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007034 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007035 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007036 int len = ret;
7037 int reclen;
7038 de = dirp;
7039 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007040 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007041 if (reclen > len)
7042 break;
bellard8083a3e2003-03-24 23:12:16 +00007043 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007044 tswapls(&de->d_ino);
7045 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007046 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007047 len -= reclen;
7048 }
7049 }
pbrook53a59602006-03-25 19:31:22 +00007050 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007051 }
bellard4add45b2003-06-05 01:52:59 +00007052#endif
bellard31e31b82003-02-18 22:55:36 +00007053 break;
ths3ae43202007-09-16 21:39:48 +00007054#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007055 case TARGET_NR_getdents64:
7056 {
aurel326556a832008-10-13 21:08:17 +00007057 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007058 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007059 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7060 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007061 ret = get_errno(sys_getdents64(arg1, dirp, count));
7062 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007063 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007064 int len = ret;
7065 int reclen;
7066 de = dirp;
7067 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007068 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007069 if (reclen > len)
7070 break;
bellard8083a3e2003-03-24 23:12:16 +00007071 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007072 tswap64s((uint64_t *)&de->d_ino);
7073 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007074 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007075 len -= reclen;
7076 }
7077 }
pbrook53a59602006-03-25 19:31:22 +00007078 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007079 }
7080 break;
bellarda541f292004-04-12 20:39:29 +00007081#endif /* TARGET_NR_getdents64 */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007082#if defined(TARGET_NR__newselect) || defined(TARGET_S390X)
7083#ifdef TARGET_S390X
7084 case TARGET_NR_select:
7085#else
bellard31e31b82003-02-18 22:55:36 +00007086 case TARGET_NR__newselect:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007087#endif
pbrook53a59602006-03-25 19:31:22 +00007088 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007089 break;
thse5febef2007-04-01 18:31:35 +00007090#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007091#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7092# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007093 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007094# endif
7095# ifdef TARGET_NR_ppoll
7096 case TARGET_NR_ppoll:
7097# endif
bellard9de5e442003-03-23 16:49:39 +00007098 {
pbrook53a59602006-03-25 19:31:22 +00007099 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007100 unsigned int nfds = arg2;
7101 int timeout = arg3;
7102 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007103 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007104
bellard579a97f2007-11-11 14:26:47 +00007105 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7106 if (!target_pfd)
7107 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007108
bellard9de5e442003-03-23 16:49:39 +00007109 pfd = alloca(sizeof(struct pollfd) * nfds);
7110 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007111 pfd[i].fd = tswap32(target_pfd[i].fd);
7112 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007113 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007114
7115# ifdef TARGET_NR_ppoll
7116 if (num == TARGET_NR_ppoll) {
7117 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7118 target_sigset_t *target_set;
7119 sigset_t _set, *set = &_set;
7120
7121 if (arg3) {
7122 if (target_to_host_timespec(timeout_ts, arg3)) {
7123 unlock_user(target_pfd, arg1, 0);
7124 goto efault;
7125 }
7126 } else {
7127 timeout_ts = NULL;
7128 }
7129
7130 if (arg4) {
7131 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7132 if (!target_set) {
7133 unlock_user(target_pfd, arg1, 0);
7134 goto efault;
7135 }
7136 target_to_host_sigset(set, target_set);
7137 } else {
7138 set = NULL;
7139 }
7140
7141 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7142
7143 if (!is_error(ret) && arg3) {
7144 host_to_target_timespec(arg3, timeout_ts);
7145 }
7146 if (arg4) {
7147 unlock_user(target_set, arg4, 0);
7148 }
7149 } else
7150# endif
7151 ret = get_errno(poll(pfd, nfds, timeout));
7152
bellard9de5e442003-03-23 16:49:39 +00007153 if (!is_error(ret)) {
7154 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007155 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007156 }
7157 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007158 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007159 }
7160 break;
thse5febef2007-04-01 18:31:35 +00007161#endif
bellard31e31b82003-02-18 22:55:36 +00007162 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007163 /* NOTE: the flock constant seems to be the same for every
7164 Linux platform */
7165 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007166 break;
7167 case TARGET_NR_readv:
7168 {
7169 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00007170 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00007171
7172 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00007173 if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
7174 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007175 ret = get_errno(readv(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00007176 unlock_iovec(vec, arg2, count, 1);
bellard31e31b82003-02-18 22:55:36 +00007177 }
7178 break;
7179 case TARGET_NR_writev:
7180 {
7181 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00007182 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00007183
7184 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00007185 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
7186 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007187 ret = get_errno(writev(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00007188 unlock_iovec(vec, arg2, count, 0);
bellard31e31b82003-02-18 22:55:36 +00007189 }
7190 break;
7191 case TARGET_NR_getsid:
7192 ret = get_errno(getsid(arg1));
7193 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007194#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007195 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007196 ret = get_errno(fdatasync(arg1));
7197 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007198#endif
bellard31e31b82003-02-18 22:55:36 +00007199 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007200 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007201 return value. */
ths0da46a62007-10-20 20:23:07 +00007202 ret = -TARGET_ENOTDIR;
7203 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007204 case TARGET_NR_sched_getaffinity:
7205 {
7206 unsigned int mask_size;
7207 unsigned long *mask;
7208
7209 /*
7210 * sched_getaffinity needs multiples of ulong, so need to take
7211 * care of mismatches between target ulong and host ulong sizes.
7212 */
7213 if (arg2 & (sizeof(abi_ulong) - 1)) {
7214 ret = -TARGET_EINVAL;
7215 break;
7216 }
7217 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7218
7219 mask = alloca(mask_size);
7220 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7221
7222 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09007223 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007224 goto efault;
7225 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007226 }
7227 }
7228 break;
7229 case TARGET_NR_sched_setaffinity:
7230 {
7231 unsigned int mask_size;
7232 unsigned long *mask;
7233
7234 /*
7235 * sched_setaffinity needs multiples of ulong, so need to take
7236 * care of mismatches between target ulong and host ulong sizes.
7237 */
7238 if (arg2 & (sizeof(abi_ulong) - 1)) {
7239 ret = -TARGET_EINVAL;
7240 break;
7241 }
7242 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7243
7244 mask = alloca(mask_size);
7245 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7246 goto efault;
7247 }
7248 memcpy(mask, p, arg2);
7249 unlock_user_struct(p, arg2, 0);
7250
7251 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7252 }
7253 break;
bellard31e31b82003-02-18 22:55:36 +00007254 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007255 {
pbrook53a59602006-03-25 19:31:22 +00007256 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007257 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007258
bellard579a97f2007-11-11 14:26:47 +00007259 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7260 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007261 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007262 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007263 ret = get_errno(sched_setparam(arg1, &schp));
7264 }
7265 break;
bellard31e31b82003-02-18 22:55:36 +00007266 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007267 {
pbrook53a59602006-03-25 19:31:22 +00007268 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007269 struct sched_param schp;
7270 ret = get_errno(sched_getparam(arg1, &schp));
7271 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007272 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7273 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007274 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007275 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007276 }
7277 }
7278 break;
bellard31e31b82003-02-18 22:55:36 +00007279 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007280 {
pbrook53a59602006-03-25 19:31:22 +00007281 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007282 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007283 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7284 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007285 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007286 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007287 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7288 }
7289 break;
bellard31e31b82003-02-18 22:55:36 +00007290 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007291 ret = get_errno(sched_getscheduler(arg1));
7292 break;
bellard31e31b82003-02-18 22:55:36 +00007293 case TARGET_NR_sched_yield:
7294 ret = get_errno(sched_yield());
7295 break;
7296 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007297 ret = get_errno(sched_get_priority_max(arg1));
7298 break;
bellard31e31b82003-02-18 22:55:36 +00007299 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007300 ret = get_errno(sched_get_priority_min(arg1));
7301 break;
bellard31e31b82003-02-18 22:55:36 +00007302 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007303 {
bellard5cd43932003-03-29 16:54:36 +00007304 struct timespec ts;
7305 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7306 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007307 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007308 }
7309 }
7310 break;
bellard31e31b82003-02-18 22:55:36 +00007311 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007312 {
bellard1b6b0292003-03-22 17:31:38 +00007313 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007314 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007315 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007316 if (is_error(ret) && arg2) {
7317 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007318 }
7319 }
7320 break;
thse5febef2007-04-01 18:31:35 +00007321#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007322 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007323 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007324#endif
7325#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007326 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007327 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007328#endif
bellard31e31b82003-02-18 22:55:36 +00007329 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007330 switch (arg1) {
7331 case PR_GET_PDEATHSIG:
7332 {
7333 int deathsig;
7334 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7335 if (!is_error(ret) && arg2
7336 && put_user_ual(deathsig, arg2)) {
7337 goto efault;
thse5574482007-02-11 20:03:13 +00007338 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007339 break;
7340 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007341#ifdef PR_GET_NAME
7342 case PR_GET_NAME:
7343 {
7344 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7345 if (!name) {
7346 goto efault;
7347 }
7348 ret = get_errno(prctl(arg1, (unsigned long)name,
7349 arg3, arg4, arg5));
7350 unlock_user(name, arg2, 16);
7351 break;
7352 }
7353 case PR_SET_NAME:
7354 {
7355 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7356 if (!name) {
7357 goto efault;
7358 }
7359 ret = get_errno(prctl(arg1, (unsigned long)name,
7360 arg3, arg4, arg5));
7361 unlock_user(name, arg2, 0);
7362 break;
7363 }
7364#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007365 default:
7366 /* Most prctl options have no pointer arguments */
7367 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7368 break;
7369 }
ths39b9aae2007-02-11 18:36:44 +00007370 break;
bellardd2fd1af2007-11-14 18:08:56 +00007371#ifdef TARGET_NR_arch_prctl
7372 case TARGET_NR_arch_prctl:
7373#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7374 ret = do_arch_prctl(cpu_env, arg1, arg2);
7375 break;
7376#else
7377 goto unimplemented;
7378#endif
7379#endif
bellard67867302003-11-23 17:05:30 +00007380#ifdef TARGET_NR_pread
bellard31e31b82003-02-18 22:55:36 +00007381 case TARGET_NR_pread:
Riku Voipio48e515d2011-07-12 15:40:51 +03007382 if (regpairs_aligned(cpu_env))
balroga4ae00b2008-09-20 03:14:14 +00007383 arg4 = arg5;
bellard579a97f2007-11-11 14:26:47 +00007384 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7385 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007386 ret = get_errno(pread(arg1, p, arg3, arg4));
7387 unlock_user(p, arg2, ret);
bellard206f0fa2003-05-14 19:01:56 +00007388 break;
bellard31e31b82003-02-18 22:55:36 +00007389 case TARGET_NR_pwrite:
Riku Voipio48e515d2011-07-12 15:40:51 +03007390 if (regpairs_aligned(cpu_env))
balroga4ae00b2008-09-20 03:14:14 +00007391 arg4 = arg5;
bellard579a97f2007-11-11 14:26:47 +00007392 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7393 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007394 ret = get_errno(pwrite(arg1, p, arg3, arg4));
7395 unlock_user(p, arg2, 0);
bellard206f0fa2003-05-14 19:01:56 +00007396 break;
bellard67867302003-11-23 17:05:30 +00007397#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007398#ifdef TARGET_NR_pread64
7399 case TARGET_NR_pread64:
7400 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7401 goto efault;
7402 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7403 unlock_user(p, arg2, ret);
7404 break;
7405 case TARGET_NR_pwrite64:
7406 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7407 goto efault;
7408 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7409 unlock_user(p, arg2, 0);
7410 break;
7411#endif
bellard31e31b82003-02-18 22:55:36 +00007412 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007413 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7414 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007415 ret = get_errno(sys_getcwd1(p, arg2));
7416 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007417 break;
7418 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00007419 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007420 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00007421 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007422 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007423#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007424 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007425 defined(TARGET_M68K) || defined(TARGET_S390X)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007426 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007427 break;
7428#else
bellard5cd43932003-03-29 16:54:36 +00007429 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007430#endif
bellard31e31b82003-02-18 22:55:36 +00007431 case TARGET_NR_sendfile:
bellard5cd43932003-03-29 16:54:36 +00007432 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007433#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007434 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007435 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007436#endif
7437#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007438 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007439 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007440#endif
bellard048f6b42005-11-26 18:47:20 +00007441#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007442 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007443 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7444 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007445 break;
bellard048f6b42005-11-26 18:47:20 +00007446#endif
bellardebc05482003-09-30 21:08:41 +00007447#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007448 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007449 {
7450 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007451 int resource = target_to_host_resource(arg1);
7452 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007453 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007454 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007455 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7456 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007457 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7458 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007459 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007460 }
7461 break;
7462 }
bellardebc05482003-09-30 21:08:41 +00007463#endif
bellarda315a142005-01-30 22:59:18 +00007464#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007465 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007466 if (!(p = lock_user_string(arg1)))
7467 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007468 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7469 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007470 break;
bellarda315a142005-01-30 22:59:18 +00007471#endif
7472#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00007473 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00007474 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00007475 break;
bellarda315a142005-01-30 22:59:18 +00007476#endif
7477#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00007478 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00007479 if (!(p = lock_user_string(arg1)))
7480 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007481 ret = get_errno(stat(path(p), &st));
7482 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007483 if (!is_error(ret))
7484 ret = host_to_target_stat64(cpu_env, arg2, &st);
7485 break;
bellarda315a142005-01-30 22:59:18 +00007486#endif
7487#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00007488 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00007489 if (!(p = lock_user_string(arg1)))
7490 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007491 ret = get_errno(lstat(path(p), &st));
7492 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007493 if (!is_error(ret))
7494 ret = host_to_target_stat64(cpu_env, arg2, &st);
7495 break;
bellarda315a142005-01-30 22:59:18 +00007496#endif
7497#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00007498 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00007499 ret = get_errno(fstat(arg1, &st));
7500 if (!is_error(ret))
7501 ret = host_to_target_stat64(cpu_env, arg2, &st);
7502 break;
bellardec86b0f2003-04-11 00:15:04 +00007503#endif
aurel329d33b762009-04-08 23:07:05 +00007504#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
7505 (defined(__NR_fstatat64) || defined(__NR_newfstatat))
7506#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007507 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007508#endif
7509#ifdef TARGET_NR_newfstatat
7510 case TARGET_NR_newfstatat:
7511#endif
balrog6a24a772008-09-20 02:23:36 +00007512 if (!(p = lock_user_string(arg2)))
7513 goto efault;
aurel329d33b762009-04-08 23:07:05 +00007514#ifdef __NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007515 ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
aurel329d33b762009-04-08 23:07:05 +00007516#else
7517 ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
7518#endif
balrog6a24a772008-09-20 02:23:36 +00007519 if (!is_error(ret))
7520 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007521 break;
bellarda315a142005-01-30 22:59:18 +00007522#endif
bellard67867302003-11-23 17:05:30 +00007523 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007524 if (!(p = lock_user_string(arg1)))
7525 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007526 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7527 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007528 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007529#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007530 case TARGET_NR_getuid:
7531 ret = get_errno(high2lowuid(getuid()));
7532 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007533#endif
7534#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007535 case TARGET_NR_getgid:
7536 ret = get_errno(high2lowgid(getgid()));
7537 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007538#endif
7539#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007540 case TARGET_NR_geteuid:
7541 ret = get_errno(high2lowuid(geteuid()));
7542 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007543#endif
7544#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007545 case TARGET_NR_getegid:
7546 ret = get_errno(high2lowgid(getegid()));
7547 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007548#endif
bellard67867302003-11-23 17:05:30 +00007549 case TARGET_NR_setreuid:
7550 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7551 break;
7552 case TARGET_NR_setregid:
7553 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7554 break;
7555 case TARGET_NR_getgroups:
7556 {
7557 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007558 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007559 gid_t *grouplist;
7560 int i;
7561
7562 grouplist = alloca(gidsetsize * sizeof(gid_t));
7563 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007564 if (gidsetsize == 0)
7565 break;
bellard67867302003-11-23 17:05:30 +00007566 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007567 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
7568 if (!target_grouplist)
7569 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007570 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007571 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007572 unlock_user(target_grouplist, arg2, gidsetsize * 2);
bellard67867302003-11-23 17:05:30 +00007573 }
7574 }
7575 break;
7576 case TARGET_NR_setgroups:
7577 {
7578 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007579 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007580 gid_t *grouplist;
7581 int i;
7582
7583 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007584 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
7585 if (!target_grouplist) {
7586 ret = -TARGET_EFAULT;
7587 goto fail;
7588 }
bellard67867302003-11-23 17:05:30 +00007589 for(i = 0;i < gidsetsize; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007590 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007591 unlock_user(target_grouplist, arg2, 0);
bellard67867302003-11-23 17:05:30 +00007592 ret = get_errno(setgroups(gidsetsize, grouplist));
7593 }
7594 break;
7595 case TARGET_NR_fchown:
7596 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7597 break;
thsccfa72b2007-09-24 09:23:34 +00007598#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
7599 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007600 if (!(p = lock_user_string(arg2)))
7601 goto efault;
7602 ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5));
7603 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007604 break;
7605#endif
bellard67867302003-11-23 17:05:30 +00007606#ifdef TARGET_NR_setresuid
7607 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007608 ret = get_errno(setresuid(low2highuid(arg1),
7609 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007610 low2highuid(arg3)));
7611 break;
7612#endif
7613#ifdef TARGET_NR_getresuid
7614 case TARGET_NR_getresuid:
7615 {
pbrook53a59602006-03-25 19:31:22 +00007616 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007617 ret = get_errno(getresuid(&ruid, &euid, &suid));
7618 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007619 if (put_user_u16(high2lowuid(ruid), arg1)
7620 || put_user_u16(high2lowuid(euid), arg2)
7621 || put_user_u16(high2lowuid(suid), arg3))
7622 goto efault;
bellard67867302003-11-23 17:05:30 +00007623 }
7624 }
7625 break;
7626#endif
7627#ifdef TARGET_NR_getresgid
7628 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007629 ret = get_errno(setresgid(low2highgid(arg1),
7630 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007631 low2highgid(arg3)));
7632 break;
7633#endif
7634#ifdef TARGET_NR_getresgid
7635 case TARGET_NR_getresgid:
7636 {
pbrook53a59602006-03-25 19:31:22 +00007637 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007638 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7639 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007640 if (put_user_u16(high2lowgid(rgid), arg1)
7641 || put_user_u16(high2lowgid(egid), arg2)
7642 || put_user_u16(high2lowgid(sgid), arg3))
7643 goto efault;
bellard67867302003-11-23 17:05:30 +00007644 }
7645 }
7646 break;
7647#endif
7648 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007649 if (!(p = lock_user_string(arg1)))
7650 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007651 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7652 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007653 break;
7654 case TARGET_NR_setuid:
7655 ret = get_errno(setuid(low2highuid(arg1)));
7656 break;
7657 case TARGET_NR_setgid:
7658 ret = get_errno(setgid(low2highgid(arg1)));
7659 break;
7660 case TARGET_NR_setfsuid:
7661 ret = get_errno(setfsuid(arg1));
7662 break;
7663 case TARGET_NR_setfsgid:
7664 ret = get_errno(setfsgid(arg1));
7665 break;
bellard67867302003-11-23 17:05:30 +00007666
bellarda315a142005-01-30 22:59:18 +00007667#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00007668 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00007669 if (!(p = lock_user_string(arg1)))
7670 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007671 ret = get_errno(lchown(p, arg2, arg3));
7672 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007673 break;
bellarda315a142005-01-30 22:59:18 +00007674#endif
7675#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00007676 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00007677 ret = get_errno(getuid());
7678 break;
bellarda315a142005-01-30 22:59:18 +00007679#endif
aurel3264b4d282008-11-14 17:20:15 +00007680
7681#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
7682 /* Alpha specific */
7683 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007684 {
7685 uid_t euid;
7686 euid=geteuid();
7687 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
7688 }
aurel3264b4d282008-11-14 17:20:15 +00007689 ret = get_errno(getuid());
7690 break;
7691#endif
7692#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
7693 /* Alpha specific */
7694 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007695 {
7696 uid_t egid;
7697 egid=getegid();
7698 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
7699 }
aurel3264b4d282008-11-14 17:20:15 +00007700 ret = get_errno(getgid());
7701 break;
7702#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08007703#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
7704 /* Alpha specific */
7705 case TARGET_NR_osf_getsysinfo:
7706 ret = -TARGET_EOPNOTSUPP;
7707 switch (arg1) {
7708 case TARGET_GSI_IEEE_FP_CONTROL:
7709 {
7710 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
7711
7712 /* Copied from linux ieee_fpcr_to_swcr. */
7713 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
7714 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
7715 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
7716 | SWCR_TRAP_ENABLE_DZE
7717 | SWCR_TRAP_ENABLE_OVF);
7718 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
7719 | SWCR_TRAP_ENABLE_INE);
7720 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
7721 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
7722
7723 if (put_user_u64 (swcr, arg2))
7724 goto efault;
7725 ret = 0;
7726 }
7727 break;
7728
7729 /* case GSI_IEEE_STATE_AT_SIGNAL:
7730 -- Not implemented in linux kernel.
7731 case GSI_UACPROC:
7732 -- Retrieves current unaligned access state; not much used.
7733 case GSI_PROC_TYPE:
7734 -- Retrieves implver information; surely not used.
7735 case GSI_GET_HWRPB:
7736 -- Grabs a copy of the HWRPB; surely not used.
7737 */
7738 }
7739 break;
7740#endif
7741#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
7742 /* Alpha specific */
7743 case TARGET_NR_osf_setsysinfo:
7744 ret = -TARGET_EOPNOTSUPP;
7745 switch (arg1) {
7746 case TARGET_SSI_IEEE_FP_CONTROL:
7747 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
7748 {
7749 uint64_t swcr, fpcr, orig_fpcr;
7750
7751 if (get_user_u64 (swcr, arg2))
7752 goto efault;
7753 orig_fpcr = cpu_alpha_load_fpcr (cpu_env);
7754 fpcr = orig_fpcr & FPCR_DYN_MASK;
7755
7756 /* Copied from linux ieee_swcr_to_fpcr. */
7757 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
7758 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
7759 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
7760 | SWCR_TRAP_ENABLE_DZE
7761 | SWCR_TRAP_ENABLE_OVF)) << 48;
7762 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
7763 | SWCR_TRAP_ENABLE_INE)) << 57;
7764 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
7765 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
7766
7767 cpu_alpha_store_fpcr (cpu_env, fpcr);
7768 ret = 0;
7769
7770 if (arg1 == TARGET_SSI_IEEE_RAISE_EXCEPTION) {
7771 /* Old exceptions are not signaled. */
7772 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
7773
7774 /* If any exceptions set by this call, and are unmasked,
7775 send a signal. */
7776 /* ??? FIXME */
7777 }
7778 }
7779 break;
7780
7781 /* case SSI_NVPAIRS:
7782 -- Used with SSIN_UACPROC to enable unaligned accesses.
7783 case SSI_IEEE_STATE_AT_SIGNAL:
7784 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
7785 -- Not implemented in linux kernel
7786 */
7787 }
7788 break;
7789#endif
7790#ifdef TARGET_NR_osf_sigprocmask
7791 /* Alpha specific. */
7792 case TARGET_NR_osf_sigprocmask:
7793 {
7794 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01007795 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08007796 sigset_t set, oldset;
7797
7798 switch(arg1) {
7799 case TARGET_SIG_BLOCK:
7800 how = SIG_BLOCK;
7801 break;
7802 case TARGET_SIG_UNBLOCK:
7803 how = SIG_UNBLOCK;
7804 break;
7805 case TARGET_SIG_SETMASK:
7806 how = SIG_SETMASK;
7807 break;
7808 default:
7809 ret = -TARGET_EINVAL;
7810 goto fail;
7811 }
7812 mask = arg2;
7813 target_to_host_old_sigset(&set, &mask);
Juan Quintelabc088ba2011-06-16 17:37:10 +01007814 sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007815 host_to_target_old_sigset(&mask, &oldset);
7816 ret = mask;
7817 }
7818 break;
7819#endif
aurel3264b4d282008-11-14 17:20:15 +00007820
bellarda315a142005-01-30 22:59:18 +00007821#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00007822 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00007823 ret = get_errno(getgid());
7824 break;
bellarda315a142005-01-30 22:59:18 +00007825#endif
7826#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00007827 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00007828 ret = get_errno(geteuid());
7829 break;
bellarda315a142005-01-30 22:59:18 +00007830#endif
7831#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00007832 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00007833 ret = get_errno(getegid());
7834 break;
bellarda315a142005-01-30 22:59:18 +00007835#endif
7836#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00007837 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00007838 ret = get_errno(setreuid(arg1, arg2));
7839 break;
bellarda315a142005-01-30 22:59:18 +00007840#endif
7841#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00007842 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00007843 ret = get_errno(setregid(arg1, arg2));
7844 break;
bellarda315a142005-01-30 22:59:18 +00007845#endif
7846#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00007847 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00007848 {
7849 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007850 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007851 gid_t *grouplist;
7852 int i;
7853
7854 grouplist = alloca(gidsetsize * sizeof(gid_t));
7855 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007856 if (gidsetsize == 0)
7857 break;
bellard99c475a2005-01-31 20:45:13 +00007858 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007859 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
7860 if (!target_grouplist) {
7861 ret = -TARGET_EFAULT;
7862 goto fail;
7863 }
balroga2155fc2008-09-20 02:12:08 +00007864 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00007865 target_grouplist[i] = tswap32(grouplist[i]);
7866 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00007867 }
7868 }
7869 break;
bellarda315a142005-01-30 22:59:18 +00007870#endif
7871#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00007872 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00007873 {
7874 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007875 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007876 gid_t *grouplist;
7877 int i;
ths3b46e622007-09-17 08:09:54 +00007878
bellard99c475a2005-01-31 20:45:13 +00007879 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007880 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
7881 if (!target_grouplist) {
7882 ret = -TARGET_EFAULT;
7883 goto fail;
7884 }
bellard99c475a2005-01-31 20:45:13 +00007885 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00007886 grouplist[i] = tswap32(target_grouplist[i]);
7887 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00007888 ret = get_errno(setgroups(gidsetsize, grouplist));
7889 }
7890 break;
bellarda315a142005-01-30 22:59:18 +00007891#endif
7892#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00007893 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00007894 ret = get_errno(fchown(arg1, arg2, arg3));
7895 break;
bellarda315a142005-01-30 22:59:18 +00007896#endif
7897#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00007898 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007899 ret = get_errno(setresuid(arg1, arg2, arg3));
7900 break;
bellarda315a142005-01-30 22:59:18 +00007901#endif
7902#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00007903 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007904 {
pbrook53a59602006-03-25 19:31:22 +00007905 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00007906 ret = get_errno(getresuid(&ruid, &euid, &suid));
7907 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007908 if (put_user_u32(ruid, arg1)
7909 || put_user_u32(euid, arg2)
7910 || put_user_u32(suid, arg3))
7911 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007912 }
7913 }
7914 break;
bellarda315a142005-01-30 22:59:18 +00007915#endif
7916#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00007917 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007918 ret = get_errno(setresgid(arg1, arg2, arg3));
7919 break;
bellarda315a142005-01-30 22:59:18 +00007920#endif
7921#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00007922 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007923 {
pbrook53a59602006-03-25 19:31:22 +00007924 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00007925 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7926 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007927 if (put_user_u32(rgid, arg1)
7928 || put_user_u32(egid, arg2)
7929 || put_user_u32(sgid, arg3))
7930 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007931 }
7932 }
7933 break;
bellarda315a142005-01-30 22:59:18 +00007934#endif
7935#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00007936 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00007937 if (!(p = lock_user_string(arg1)))
7938 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007939 ret = get_errno(chown(p, arg2, arg3));
7940 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007941 break;
bellarda315a142005-01-30 22:59:18 +00007942#endif
7943#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00007944 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00007945 ret = get_errno(setuid(arg1));
7946 break;
bellarda315a142005-01-30 22:59:18 +00007947#endif
7948#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00007949 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00007950 ret = get_errno(setgid(arg1));
7951 break;
bellarda315a142005-01-30 22:59:18 +00007952#endif
7953#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00007954 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00007955 ret = get_errno(setfsuid(arg1));
7956 break;
bellarda315a142005-01-30 22:59:18 +00007957#endif
7958#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00007959 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00007960 ret = get_errno(setfsgid(arg1));
7961 break;
bellarda315a142005-01-30 22:59:18 +00007962#endif
bellard67867302003-11-23 17:05:30 +00007963
bellard31e31b82003-02-18 22:55:36 +00007964 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00007965 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00007966#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00007967 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00007968 {
7969 void *a;
7970 ret = -TARGET_EFAULT;
7971 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
7972 goto efault;
7973 if (!(p = lock_user_string(arg3)))
7974 goto mincore_fail;
7975 ret = get_errno(mincore(a, arg2, p));
7976 unlock_user(p, arg3, ret);
7977 mincore_fail:
7978 unlock_user(a, arg1, 0);
7979 }
7980 break;
bellardffa65c32004-01-04 23:57:22 +00007981#endif
aurel32408321b2008-10-01 21:46:32 +00007982#ifdef TARGET_NR_arm_fadvise64_64
7983 case TARGET_NR_arm_fadvise64_64:
7984 {
7985 /*
7986 * arm_fadvise64_64 looks like fadvise64_64 but
7987 * with different argument order
7988 */
7989 abi_long temp;
7990 temp = arg3;
7991 arg3 = arg4;
7992 arg4 = temp;
7993 }
7994#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007995#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00007996#ifdef TARGET_NR_fadvise64_64
7997 case TARGET_NR_fadvise64_64:
7998#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007999#ifdef TARGET_NR_fadvise64
8000 case TARGET_NR_fadvise64:
8001#endif
8002#ifdef TARGET_S390X
8003 switch (arg4) {
8004 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8005 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8006 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8007 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8008 default: break;
8009 }
8010#endif
8011 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008012 break;
8013#endif
bellardffa65c32004-01-04 23:57:22 +00008014#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008015 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008016 /* A straight passthrough may not be safe because qemu sometimes
8017 turns private flie-backed mappings into anonymous mappings.
8018 This will break MADV_DONTNEED.
8019 This is a hint, so ignoring and returning success is ok. */
8020 ret = get_errno(0);
8021 break;
bellardffa65c32004-01-04 23:57:22 +00008022#endif
blueswir1992f48a2007-10-14 16:27:31 +00008023#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008024 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008025 {
thsb1e341e2007-03-20 21:50:52 +00008026 int cmd;
bellard77e46722003-04-29 20:39:06 +00008027 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008028 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008029#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008030 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008031#endif
bellard77e46722003-04-29 20:39:06 +00008032
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008033 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008034 if (cmd == -TARGET_EINVAL) {
8035 ret = cmd;
8036 break;
8037 }
thsb1e341e2007-03-20 21:50:52 +00008038
bellard60cd49d2003-03-16 22:53:56 +00008039 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008040 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008041#ifdef TARGET_ARM
8042 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008043 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8044 goto efault;
ths58134272007-03-31 18:59:32 +00008045 fl.l_type = tswap16(target_efl->l_type);
8046 fl.l_whence = tswap16(target_efl->l_whence);
8047 fl.l_start = tswap64(target_efl->l_start);
8048 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008049 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008050 unlock_user_struct(target_efl, arg3, 0);
8051 } else
8052#endif
8053 {
bellard9ee1fa22007-11-11 15:11:19 +00008054 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8055 goto efault;
ths58134272007-03-31 18:59:32 +00008056 fl.l_type = tswap16(target_fl->l_type);
8057 fl.l_whence = tswap16(target_fl->l_whence);
8058 fl.l_start = tswap64(target_fl->l_start);
8059 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008060 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008061 unlock_user_struct(target_fl, arg3, 0);
8062 }
thsb1e341e2007-03-20 21:50:52 +00008063 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008064 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008065#ifdef TARGET_ARM
8066 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008067 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8068 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008069 target_efl->l_type = tswap16(fl.l_type);
8070 target_efl->l_whence = tswap16(fl.l_whence);
8071 target_efl->l_start = tswap64(fl.l_start);
8072 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008073 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008074 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008075 } else
8076#endif
8077 {
bellard9ee1fa22007-11-11 15:11:19 +00008078 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8079 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008080 target_fl->l_type = tswap16(fl.l_type);
8081 target_fl->l_whence = tswap16(fl.l_whence);
8082 target_fl->l_start = tswap64(fl.l_start);
8083 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008084 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008085 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008086 }
bellard77e46722003-04-29 20:39:06 +00008087 }
8088 break;
8089
thsb1e341e2007-03-20 21:50:52 +00008090 case TARGET_F_SETLK64:
8091 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008092#ifdef TARGET_ARM
8093 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008094 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8095 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008096 fl.l_type = tswap16(target_efl->l_type);
8097 fl.l_whence = tswap16(target_efl->l_whence);
8098 fl.l_start = tswap64(target_efl->l_start);
8099 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008100 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008101 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008102 } else
8103#endif
8104 {
bellard9ee1fa22007-11-11 15:11:19 +00008105 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8106 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008107 fl.l_type = tswap16(target_fl->l_type);
8108 fl.l_whence = tswap16(target_fl->l_whence);
8109 fl.l_start = tswap64(target_fl->l_start);
8110 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008111 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008112 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008113 }
thsb1e341e2007-03-20 21:50:52 +00008114 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008115 break;
bellard60cd49d2003-03-16 22:53:56 +00008116 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008117 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008118 break;
8119 }
bellard77e46722003-04-29 20:39:06 +00008120 break;
8121 }
bellard60cd49d2003-03-16 22:53:56 +00008122#endif
ths7d600c82006-12-08 01:32:58 +00008123#ifdef TARGET_NR_cacheflush
8124 case TARGET_NR_cacheflush:
8125 /* self-modifying code is handled automatically, so nothing needed */
8126 ret = 0;
8127 break;
8128#endif
bellardebc05482003-09-30 21:08:41 +00008129#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008130 case TARGET_NR_security:
8131 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008132#endif
bellardc573ff62004-01-04 15:51:36 +00008133#ifdef TARGET_NR_getpagesize
8134 case TARGET_NR_getpagesize:
8135 ret = TARGET_PAGE_SIZE;
8136 break;
8137#endif
bellard31e31b82003-02-18 22:55:36 +00008138 case TARGET_NR_gettid:
8139 ret = get_errno(gettid());
8140 break;
thse5febef2007-04-01 18:31:35 +00008141#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008142 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008143#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008144 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008145 arg2 = arg3;
8146 arg3 = arg4;
8147 arg4 = arg5;
8148 }
aurel322054ac92008-10-13 21:08:07 +00008149 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8150#else
8151 ret = get_errno(readahead(arg1, arg2, arg3));
8152#endif
8153 break;
thse5febef2007-04-01 18:31:35 +00008154#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008155#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008156#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008157 case TARGET_NR_listxattr:
8158 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008159 {
8160 void *p, *b = 0;
8161 if (arg2) {
8162 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8163 if (!b) {
8164 ret = -TARGET_EFAULT;
8165 break;
8166 }
8167 }
8168 p = lock_user_string(arg1);
8169 if (p) {
8170 if (num == TARGET_NR_listxattr) {
8171 ret = get_errno(listxattr(p, b, arg3));
8172 } else {
8173 ret = get_errno(llistxattr(p, b, arg3));
8174 }
8175 } else {
8176 ret = -TARGET_EFAULT;
8177 }
8178 unlock_user(p, arg1, 0);
8179 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008180 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008181 }
8182 case TARGET_NR_flistxattr:
8183 {
8184 void *b = 0;
8185 if (arg2) {
8186 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8187 if (!b) {
8188 ret = -TARGET_EFAULT;
8189 break;
8190 }
8191 }
8192 ret = get_errno(flistxattr(arg1, b, arg3));
8193 unlock_user(b, arg2, arg3);
8194 break;
8195 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008196 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008197 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008198 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008199 void *p, *n, *v = 0;
8200 if (arg3) {
8201 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8202 if (!v) {
8203 ret = -TARGET_EFAULT;
8204 break;
8205 }
8206 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008207 p = lock_user_string(arg1);
8208 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008209 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008210 if (num == TARGET_NR_setxattr) {
8211 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8212 } else {
8213 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8214 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008215 } else {
8216 ret = -TARGET_EFAULT;
8217 }
8218 unlock_user(p, arg1, 0);
8219 unlock_user(n, arg2, 0);
8220 unlock_user(v, arg3, 0);
8221 }
8222 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008223 case TARGET_NR_fsetxattr:
8224 {
8225 void *n, *v = 0;
8226 if (arg3) {
8227 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8228 if (!v) {
8229 ret = -TARGET_EFAULT;
8230 break;
8231 }
8232 }
8233 n = lock_user_string(arg2);
8234 if (n) {
8235 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8236 } else {
8237 ret = -TARGET_EFAULT;
8238 }
8239 unlock_user(n, arg2, 0);
8240 unlock_user(v, arg3, 0);
8241 }
8242 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008243 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008244 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008245 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008246 void *p, *n, *v = 0;
8247 if (arg3) {
8248 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8249 if (!v) {
8250 ret = -TARGET_EFAULT;
8251 break;
8252 }
8253 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008254 p = lock_user_string(arg1);
8255 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008256 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008257 if (num == TARGET_NR_getxattr) {
8258 ret = get_errno(getxattr(p, n, v, arg4));
8259 } else {
8260 ret = get_errno(lgetxattr(p, n, v, arg4));
8261 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008262 } else {
8263 ret = -TARGET_EFAULT;
8264 }
8265 unlock_user(p, arg1, 0);
8266 unlock_user(n, arg2, 0);
8267 unlock_user(v, arg3, arg4);
8268 }
8269 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008270 case TARGET_NR_fgetxattr:
8271 {
8272 void *n, *v = 0;
8273 if (arg3) {
8274 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8275 if (!v) {
8276 ret = -TARGET_EFAULT;
8277 break;
8278 }
8279 }
8280 n = lock_user_string(arg2);
8281 if (n) {
8282 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8283 } else {
8284 ret = -TARGET_EFAULT;
8285 }
8286 unlock_user(n, arg2, 0);
8287 unlock_user(v, arg3, arg4);
8288 }
8289 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008290 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008291 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008292 {
8293 void *p, *n;
8294 p = lock_user_string(arg1);
8295 n = lock_user_string(arg2);
8296 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008297 if (num == TARGET_NR_removexattr) {
8298 ret = get_errno(removexattr(p, n));
8299 } else {
8300 ret = get_errno(lremovexattr(p, n));
8301 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008302 } else {
8303 ret = -TARGET_EFAULT;
8304 }
8305 unlock_user(p, arg1, 0);
8306 unlock_user(n, arg2, 0);
8307 }
8308 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008309 case TARGET_NR_fremovexattr:
8310 {
8311 void *n;
8312 n = lock_user_string(arg2);
8313 if (n) {
8314 ret = get_errno(fremovexattr(arg1, n));
8315 } else {
8316 ret = -TARGET_EFAULT;
8317 }
8318 unlock_user(n, arg2, 0);
8319 }
8320 break;
bellardebc05482003-09-30 21:08:41 +00008321#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008322#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008323#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008324 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008325#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00008326 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
8327 ret = 0;
8328 break;
edgar_iglef967792009-01-07 14:19:38 +00008329#elif defined(TARGET_CRIS)
8330 if (arg1 & 0xff)
8331 ret = -TARGET_EINVAL;
8332 else {
8333 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8334 ret = 0;
8335 }
8336 break;
bellard8d18e892007-11-14 15:18:40 +00008337#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8338 ret = do_set_thread_area(cpu_env, arg1);
8339 break;
ths6f5b89a2007-03-02 20:48:00 +00008340#else
8341 goto unimplemented_nowarn;
8342#endif
8343#endif
8344#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008345 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008346#if defined(TARGET_I386) && defined(TARGET_ABI32)
8347 ret = do_get_thread_area(cpu_env, arg1);
8348#else
bellard5cd43932003-03-29 16:54:36 +00008349 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008350#endif
bellard8d18e892007-11-14 15:18:40 +00008351#endif
bellard48dc41e2006-06-21 18:15:50 +00008352#ifdef TARGET_NR_getdomainname
8353 case TARGET_NR_getdomainname:
8354 goto unimplemented_nowarn;
8355#endif
ths6f5b89a2007-03-02 20:48:00 +00008356
thsb5906f92007-03-19 13:32:45 +00008357#ifdef TARGET_NR_clock_gettime
8358 case TARGET_NR_clock_gettime:
8359 {
8360 struct timespec ts;
8361 ret = get_errno(clock_gettime(arg1, &ts));
8362 if (!is_error(ret)) {
8363 host_to_target_timespec(arg2, &ts);
8364 }
8365 break;
8366 }
8367#endif
8368#ifdef TARGET_NR_clock_getres
8369 case TARGET_NR_clock_getres:
8370 {
8371 struct timespec ts;
8372 ret = get_errno(clock_getres(arg1, &ts));
8373 if (!is_error(ret)) {
8374 host_to_target_timespec(arg2, &ts);
8375 }
8376 break;
8377 }
8378#endif
pbrook63d76512008-05-29 13:43:29 +00008379#ifdef TARGET_NR_clock_nanosleep
8380 case TARGET_NR_clock_nanosleep:
8381 {
8382 struct timespec ts;
8383 target_to_host_timespec(&ts, arg3);
8384 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8385 if (arg4)
8386 host_to_target_timespec(arg4, &ts);
8387 break;
8388 }
8389#endif
thsb5906f92007-03-19 13:32:45 +00008390
ths6f5b89a2007-03-02 20:48:00 +00008391#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8392 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008393 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8394 break;
ths6f5b89a2007-03-02 20:48:00 +00008395#endif
8396
ths3ae43202007-09-16 21:39:48 +00008397#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008398 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008399 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008400 break;
8401#endif
8402
ths3ae43202007-09-16 21:39:48 +00008403#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008404 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008405 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8406 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008407 break;
8408#endif
8409
ths4f2b1fe2007-06-21 21:57:12 +00008410#ifdef TARGET_NR_set_robust_list
8411 case TARGET_NR_set_robust_list:
8412 goto unimplemented_nowarn;
8413#endif
8414
ths9007f0e2007-09-25 17:50:37 +00008415#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
8416 case TARGET_NR_utimensat:
8417 {
Riku Voipioebc996f2009-04-21 15:01:51 +03008418 struct timespec *tsp, ts[2];
8419 if (!arg3) {
8420 tsp = NULL;
8421 } else {
8422 target_to_host_timespec(ts, arg3);
8423 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
8424 tsp = ts;
8425 }
ths9007f0e2007-09-25 17:50:37 +00008426 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03008427 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00008428 else {
bellard579a97f2007-11-11 14:26:47 +00008429 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00008430 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008431 goto fail;
8432 }
Riku Voipioebc996f2009-04-21 15:01:51 +03008433 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00008434 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00008435 }
8436 }
8437 break;
8438#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +02008439#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00008440 case TARGET_NR_futex:
8441 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
8442 break;
8443#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008444#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00008445 case TARGET_NR_inotify_init:
8446 ret = get_errno(sys_inotify_init());
8447 break;
8448#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008449#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00008450#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
8451 case TARGET_NR_inotify_init1:
8452 ret = get_errno(sys_inotify_init1(arg1));
8453 break;
8454#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008455#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008456#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00008457 case TARGET_NR_inotify_add_watch:
8458 p = lock_user_string(arg2);
8459 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
8460 unlock_user(p, arg2, 0);
8461 break;
8462#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008463#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00008464 case TARGET_NR_inotify_rm_watch:
8465 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
8466 break;
8467#endif
ths9007f0e2007-09-25 17:50:37 +00008468
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07008469#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00008470 case TARGET_NR_mq_open:
8471 {
8472 struct mq_attr posix_mq_attr;
8473
8474 p = lock_user_string(arg1 - 1);
8475 if (arg4 != 0)
8476 copy_from_user_mq_attr (&posix_mq_attr, arg4);
8477 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
8478 unlock_user (p, arg1, 0);
8479 }
8480 break;
8481
8482 case TARGET_NR_mq_unlink:
8483 p = lock_user_string(arg1 - 1);
8484 ret = get_errno(mq_unlink(p));
8485 unlock_user (p, arg1, 0);
8486 break;
8487
8488 case TARGET_NR_mq_timedsend:
8489 {
8490 struct timespec ts;
8491
8492 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8493 if (arg5 != 0) {
8494 target_to_host_timespec(&ts, arg5);
8495 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
8496 host_to_target_timespec(arg5, &ts);
8497 }
8498 else
8499 ret = get_errno(mq_send(arg1, p, arg3, arg4));
8500 unlock_user (p, arg2, arg3);
8501 }
8502 break;
8503
8504 case TARGET_NR_mq_timedreceive:
8505 {
8506 struct timespec ts;
8507 unsigned int prio;
8508
8509 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8510 if (arg5 != 0) {
8511 target_to_host_timespec(&ts, arg5);
8512 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
8513 host_to_target_timespec(arg5, &ts);
8514 }
8515 else
8516 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
8517 unlock_user (p, arg2, arg3);
8518 if (arg4 != 0)
8519 put_user_u32(prio, arg4);
8520 }
8521 break;
8522
8523 /* Not implemented for now... */
8524/* case TARGET_NR_mq_notify: */
8525/* break; */
8526
8527 case TARGET_NR_mq_getsetattr:
8528 {
8529 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
8530 ret = 0;
8531 if (arg3 != 0) {
8532 ret = mq_getattr(arg1, &posix_mq_attr_out);
8533 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
8534 }
8535 if (arg2 != 0) {
8536 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
8537 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
8538 }
8539
8540 }
8541 break;
8542#endif
8543
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308544#ifdef CONFIG_SPLICE
8545#ifdef TARGET_NR_tee
8546 case TARGET_NR_tee:
8547 {
8548 ret = get_errno(tee(arg1,arg2,arg3,arg4));
8549 }
8550 break;
8551#endif
8552#ifdef TARGET_NR_splice
8553 case TARGET_NR_splice:
8554 {
8555 loff_t loff_in, loff_out;
8556 loff_t *ploff_in = NULL, *ploff_out = NULL;
8557 if(arg2) {
8558 get_user_u64(loff_in, arg2);
8559 ploff_in = &loff_in;
8560 }
8561 if(arg4) {
8562 get_user_u64(loff_out, arg2);
8563 ploff_out = &loff_out;
8564 }
8565 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
8566 }
8567 break;
8568#endif
8569#ifdef TARGET_NR_vmsplice
8570 case TARGET_NR_vmsplice:
8571 {
8572 int count = arg3;
8573 struct iovec *vec;
8574
8575 vec = alloca(count * sizeof(struct iovec));
8576 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
8577 goto efault;
8578 ret = get_errno(vmsplice(arg1, vec, count, arg4));
8579 unlock_iovec(vec, arg2, count, 0);
8580 }
8581 break;
8582#endif
8583#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03008584#ifdef CONFIG_EVENTFD
8585#if defined(TARGET_NR_eventfd)
8586 case TARGET_NR_eventfd:
8587 ret = get_errno(eventfd(arg1, 0));
8588 break;
8589#endif
8590#if defined(TARGET_NR_eventfd2)
8591 case TARGET_NR_eventfd2:
8592 ret = get_errno(eventfd(arg1, arg2));
8593 break;
8594#endif
8595#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03008596#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
8597 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01008598#if TARGET_ABI_BITS == 32
8599 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
8600 target_offset64(arg5, arg6)));
8601#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03008602 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01008603#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008604 break;
8605#endif
Peter Maydellc727f472011-01-06 11:05:10 +00008606#if defined(CONFIG_SYNC_FILE_RANGE)
8607#if defined(TARGET_NR_sync_file_range)
8608 case TARGET_NR_sync_file_range:
8609#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03008610#if defined(TARGET_MIPS)
8611 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8612 target_offset64(arg5, arg6), arg7));
8613#else
Peter Maydellc727f472011-01-06 11:05:10 +00008614 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
8615 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03008616#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00008617#else
8618 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
8619#endif
8620 break;
8621#endif
8622#if defined(TARGET_NR_sync_file_range2)
8623 case TARGET_NR_sync_file_range2:
8624 /* This is like sync_file_range but the arguments are reordered */
8625#if TARGET_ABI_BITS == 32
8626 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8627 target_offset64(arg5, arg6), arg2));
8628#else
8629 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
8630#endif
8631 break;
8632#endif
8633#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00008634#if defined(CONFIG_EPOLL)
8635#if defined(TARGET_NR_epoll_create)
8636 case TARGET_NR_epoll_create:
8637 ret = get_errno(epoll_create(arg1));
8638 break;
8639#endif
8640#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
8641 case TARGET_NR_epoll_create1:
8642 ret = get_errno(epoll_create1(arg1));
8643 break;
8644#endif
8645#if defined(TARGET_NR_epoll_ctl)
8646 case TARGET_NR_epoll_ctl:
8647 {
8648 struct epoll_event ep;
8649 struct epoll_event *epp = 0;
8650 if (arg4) {
8651 struct target_epoll_event *target_ep;
8652 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
8653 goto efault;
8654 }
8655 ep.events = tswap32(target_ep->events);
8656 /* The epoll_data_t union is just opaque data to the kernel,
8657 * so we transfer all 64 bits across and need not worry what
8658 * actual data type it is.
8659 */
8660 ep.data.u64 = tswap64(target_ep->data.u64);
8661 unlock_user_struct(target_ep, arg4, 0);
8662 epp = &ep;
8663 }
8664 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
8665 break;
8666 }
8667#endif
8668
8669#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
8670#define IMPLEMENT_EPOLL_PWAIT
8671#endif
8672#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
8673#if defined(TARGET_NR_epoll_wait)
8674 case TARGET_NR_epoll_wait:
8675#endif
8676#if defined(IMPLEMENT_EPOLL_PWAIT)
8677 case TARGET_NR_epoll_pwait:
8678#endif
8679 {
8680 struct target_epoll_event *target_ep;
8681 struct epoll_event *ep;
8682 int epfd = arg1;
8683 int maxevents = arg3;
8684 int timeout = arg4;
8685
8686 target_ep = lock_user(VERIFY_WRITE, arg2,
8687 maxevents * sizeof(struct target_epoll_event), 1);
8688 if (!target_ep) {
8689 goto efault;
8690 }
8691
8692 ep = alloca(maxevents * sizeof(struct epoll_event));
8693
8694 switch (num) {
8695#if defined(IMPLEMENT_EPOLL_PWAIT)
8696 case TARGET_NR_epoll_pwait:
8697 {
8698 target_sigset_t *target_set;
8699 sigset_t _set, *set = &_set;
8700
8701 if (arg5) {
8702 target_set = lock_user(VERIFY_READ, arg5,
8703 sizeof(target_sigset_t), 1);
8704 if (!target_set) {
8705 unlock_user(target_ep, arg2, 0);
8706 goto efault;
8707 }
8708 target_to_host_sigset(set, target_set);
8709 unlock_user(target_set, arg5, 0);
8710 } else {
8711 set = NULL;
8712 }
8713
8714 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
8715 break;
8716 }
8717#endif
8718#if defined(TARGET_NR_epoll_wait)
8719 case TARGET_NR_epoll_wait:
8720 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
8721 break;
8722#endif
8723 default:
8724 ret = -TARGET_ENOSYS;
8725 }
8726 if (!is_error(ret)) {
8727 int i;
8728 for (i = 0; i < ret; i++) {
8729 target_ep[i].events = tswap32(ep[i].events);
8730 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
8731 }
8732 }
8733 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
8734 break;
8735 }
8736#endif
8737#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01008738#ifdef TARGET_NR_prlimit64
8739 case TARGET_NR_prlimit64:
8740 {
8741 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
8742 struct target_rlimit64 *target_rnew, *target_rold;
8743 struct host_rlimit64 rnew, rold, *rnewp = 0;
8744 if (arg3) {
8745 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
8746 goto efault;
8747 }
8748 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
8749 rnew.rlim_max = tswap64(target_rnew->rlim_max);
8750 unlock_user_struct(target_rnew, arg3, 0);
8751 rnewp = &rnew;
8752 }
8753
8754 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
8755 if (!is_error(ret) && arg4) {
8756 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
8757 goto efault;
8758 }
8759 target_rold->rlim_cur = tswap64(rold.rlim_cur);
8760 target_rold->rlim_max = tswap64(rold.rlim_max);
8761 unlock_user_struct(target_rold, arg4, 1);
8762 }
8763 break;
8764 }
8765#endif
bellard31e31b82003-02-18 22:55:36 +00008766 default:
8767 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00008768 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00008769#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 +00008770 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00008771#endif
ths0da46a62007-10-20 20:23:07 +00008772 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00008773 break;
8774 }
bellard579a97f2007-11-11 14:26:47 +00008775fail:
bellardc573ff62004-01-04 15:51:36 +00008776#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00008777 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00008778#endif
thsb92c47c2007-11-01 00:07:38 +00008779 if(do_strace)
8780 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00008781 return ret;
bellard579a97f2007-11-11 14:26:47 +00008782efault:
8783 ret = -TARGET_EFAULT;
8784 goto fail;
bellard31e31b82003-02-18 22:55:36 +00008785}