syscall.c 179.9 KB
Newer Older
1 2
/*
 *  Linux syscalls
3
 *
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *  Copyright (c) 2003 Fabrice Bellard
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
B
bellard 已提交
23
#include <string.h>
24 25 26 27 28
#include <elf.h>
#include <endian.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
B
bellard 已提交
29
#include <time.h>
30
#include <limits.h>
31
#include <sys/types.h>
T
ths 已提交
32 33
#include <sys/ipc.h>
#include <sys/msg.h>
34 35 36 37
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/mount.h>
38
#include <sys/prctl.h>
39 40 41 42 43 44 45
#include <sys/resource.h>
#include <sys/mman.h>
#include <sys/swap.h>
#include <signal.h>
#include <sched.h>
#include <sys/socket.h>
#include <sys/uio.h>
B
bellard 已提交
46
#include <sys/poll.h>
B
bellard 已提交
47
#include <sys/times.h>
48
#include <sys/shm.h>
49
#include <sys/sem.h>
B
bellard 已提交
50
#include <sys/statfs.h>
51
#include <utime.h>
B
bellard 已提交
52
#include <sys/sysinfo.h>
B
bellard 已提交
53
//#include <sys/user.h>
54
#include <netinet/ip.h>
B
bellard 已提交
55
#include <netinet/tcp.h>
56 57 58 59

#define termios host_termios
#define winsize host_winsize
#define termio host_termio
B
bellard 已提交
60 61 62
#define sgttyb host_sgttyb /* same as target */
#define tchars host_tchars /* same as target */
#define ltchars host_ltchars /* same as target */
63 64 65 66 67 68 69

#include <linux/termios.h>
#include <linux/unistd.h>
#include <linux/utsname.h>
#include <linux/cdrom.h>
#include <linux/hdreg.h>
#include <linux/soundcard.h>
B
bellard 已提交
70
#include <linux/dirent.h>
B
bellard 已提交
71
#include <linux/kd.h>
72
#include "linux_loop.h"
73

B
bellard 已提交
74
#include "qemu.h"
75

P
pbrook 已提交
76 77
#if defined(USE_NPTL)
#include <linux/futex.h>
P
pbrook 已提交
78 79 80 81 82
#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
    CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
#else
/* XXX: Hardcode the above values.  */
#define CLONE_NPTL_FLAGS2 0
P
pbrook 已提交
83 84
#endif

B
bellard 已提交
85
//#define DEBUG
86

P
pbrook 已提交
87
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
88
    || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
89 90 91 92
/* 16 bit uid wrappers emulation */
#define USE_UID16
#endif

B
bellard 已提交
93 94 95 96
//#include <linux/msdos_fs.h>
#define	VFAT_IOCTL_READDIR_BOTH		_IOR('r', 1, struct dirent [2])
#define	VFAT_IOCTL_READDIR_SHORT	_IOR('r', 2, struct dirent [2])

97 98 99 100 101 102 103

#undef _syscall0
#undef _syscall1
#undef _syscall2
#undef _syscall3
#undef _syscall4
#undef _syscall5
B
bellard 已提交
104
#undef _syscall6
105

B
bellard 已提交
106 107 108 109 110
#define _syscall0(type,name)		\
type name (void)			\
{					\
	return syscall(__NR_##name);	\
}
111

B
bellard 已提交
112 113 114 115
#define _syscall1(type,name,type1,arg1)		\
type name (type1 arg1)				\
{						\
	return syscall(__NR_##name, arg1);	\
116 117
}

B
bellard 已提交
118 119 120 121
#define _syscall2(type,name,type1,arg1,type2,arg2)	\
type name (type1 arg1,type2 arg2)			\
{							\
	return syscall(__NR_##name, arg1, arg2);	\
122 123
}

B
bellard 已提交
124 125 126 127
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)	\
type name (type1 arg1,type2 arg2,type3 arg3)			\
{								\
	return syscall(__NR_##name, arg1, arg2, arg3);		\
128 129
}

B
bellard 已提交
130 131 132 133
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)	\
type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4)				\
{										\
	return syscall(__NR_##name, arg1, arg2, arg3, arg4);			\
134 135
}

B
bellard 已提交
136 137 138 139 140
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,	\
		  type5,arg5)							\
type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5)		\
{										\
	return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5);		\
141 142
}

B
bellard 已提交
143 144 145 146 147 148

#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,	\
		  type5,arg5,type6,arg6)					\
type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6)	\
{										\
	return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6);	\
149
}
B
bellard 已提交
150

151

152
#define __NR_sys_uname __NR_uname
153
#define __NR_sys_faccessat __NR_faccessat
154
#define __NR_sys_fchmodat __NR_fchmodat
155
#define __NR_sys_fchownat __NR_fchownat
B
bellard 已提交
156 157
#define __NR_sys_getcwd1 __NR_getcwd
#define __NR_sys_getdents __NR_getdents
B
bellard 已提交
158
#define __NR_sys_getdents64 __NR_getdents64
159
#define __NR_sys_getpriority __NR_getpriority
160
#define __NR_sys_linkat __NR_linkat
161
#define __NR_sys_mkdirat __NR_mkdirat
162
#define __NR_sys_mknodat __NR_mknodat
163
#define __NR_sys_openat __NR_openat
164
#define __NR_sys_readlinkat __NR_readlinkat
165
#define __NR_sys_renameat __NR_renameat
B
bellard 已提交
166
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
167
#define __NR_sys_symlinkat __NR_symlinkat
168
#define __NR_sys_syslog __NR_syslog
T
ths 已提交
169
#define __NR_sys_tgkill __NR_tgkill
T
ths 已提交
170
#define __NR_sys_tkill __NR_tkill
171
#define __NR_sys_unlinkat __NR_unlinkat
172
#define __NR_sys_utimensat __NR_utimensat
173
#define __NR_sys_futex __NR_futex
174

175
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
B
bellard 已提交
176 177 178
#define __NR__llseek __NR_lseek
#endif

B
bellard 已提交
179
#ifdef __NR_gettid
180
_syscall0(int, gettid)
B
bellard 已提交
181
#else
182 183
/* This is a replacement for the host gettid() and must return a host
   errno. */
B
bellard 已提交
184 185 186 187
static int gettid(void) {
    return -ENOSYS;
}
#endif
188
_syscall1(int,sys_uname,struct new_utsname *,buf)
189 190 191
#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
_syscall4(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode,int,flags)
#endif
192 193 194 195
#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
_syscall4(int,sys_fchmodat,int,dirfd,const char *,pathname,
          mode_t,mode,int,flags)
#endif
196 197 198 199
#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
          uid_t,owner,gid_t,group,int,flags)
#endif
B
bellard 已提交
200 201
_syscall2(int,sys_getcwd1,char *,buf,size_t,size)
_syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count);
T
ths 已提交
202
#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
B
bellard 已提交
203
_syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count);
T
ths 已提交
204
#endif
205
_syscall2(int, sys_getpriority, int, which, int, who);
206 207
_syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
          loff_t *, res, uint, wh);
208 209 210 211
#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
	  int,newdirfd,const char *,newpath,int,flags)
#endif
212 213 214
#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
#endif
215 216 217 218
#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
          mode_t,mode,dev_t,dev)
#endif
219 220 221
#if defined(TARGET_NR_openat) && defined(__NR_openat)
_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
#endif
222 223 224 225
#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
          char *,buf,size_t,bufsize)
#endif
226 227 228 229
#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
          int,newdirfd,const char *,newpath)
#endif
B
bellard 已提交
230
_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
231
#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
232 233 234
_syscall3(int,sys_symlinkat,const char *,oldpath,
          int,newdirfd,const char *,newpath)
#endif
235
_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
T
ths 已提交
236
#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
T
ths 已提交
237
_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
T
ths 已提交
238
#endif
T
ths 已提交
239
#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
T
ths 已提交
240 241
_syscall2(int,sys_tkill,int,tid,int,sig)
#endif
242 243 244
#ifdef __NR_exit_group
_syscall1(int,exit_group,int,error_code)
#endif
245 246 247
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
_syscall1(int,set_tid_address,int *,tidptr)
#endif
248 249 250
#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
#endif
251 252 253 254
#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
          const struct timespec *,tsp,int,flags)
#endif
255 256 257 258 259
#if defined(TARGET_NR_futex) && defined(__NR_futex)
_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
          const struct timespec *,timeout,int *,uaddr2,int,val3)
          
#endif
B
bellard 已提交
260 261

extern int personality(int);
B
bellard 已提交
262 263 264
extern int flock(int, int);
extern int setfsuid(int);
extern int setfsgid(int);
B
bellard 已提交
265 266 267 268
extern int setresuid(uid_t, uid_t, uid_t);
extern int getresuid(uid_t *, uid_t *, uid_t *);
extern int setresgid(gid_t, gid_t, gid_t);
extern int getresgid(gid_t *, gid_t *, gid_t *);
B
bellard 已提交
269
extern int setgroups(int, gid_t *);
270

271 272 273 274 275 276 277
#define ERRNO_TABLE_SIZE 1200

/* target_to_host_errno_table[] is initialized from
 * host_to_target_errno_table[] in syscall_init(). */
static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
};

278
/*
T
ths 已提交
279
 * This list is the union of errno values overridden in asm-<arch>/errno.h
280 281
 * minus the errnos that are not actually generic to all archs.
 */
282
static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
    [EIDRM]		= TARGET_EIDRM,
    [ECHRNG]		= TARGET_ECHRNG,
    [EL2NSYNC]		= TARGET_EL2NSYNC,
    [EL3HLT]		= TARGET_EL3HLT,
    [EL3RST]		= TARGET_EL3RST,
    [ELNRNG]		= TARGET_ELNRNG,
    [EUNATCH]		= TARGET_EUNATCH,
    [ENOCSI]		= TARGET_ENOCSI,
    [EL2HLT]		= TARGET_EL2HLT,
    [EDEADLK]		= TARGET_EDEADLK,
    [ENOLCK]		= TARGET_ENOLCK,
    [EBADE]		= TARGET_EBADE,
    [EBADR]		= TARGET_EBADR,
    [EXFULL]		= TARGET_EXFULL,
    [ENOANO]		= TARGET_ENOANO,
    [EBADRQC]		= TARGET_EBADRQC,
    [EBADSLT]		= TARGET_EBADSLT,
    [EBFONT]		= TARGET_EBFONT,
    [ENOSTR]		= TARGET_ENOSTR,
    [ENODATA]		= TARGET_ENODATA,
    [ETIME]		= TARGET_ETIME,
    [ENOSR]		= TARGET_ENOSR,
    [ENONET]		= TARGET_ENONET,
    [ENOPKG]		= TARGET_ENOPKG,
    [EREMOTE]		= TARGET_EREMOTE,
    [ENOLINK]		= TARGET_ENOLINK,
    [EADV]		= TARGET_EADV,
    [ESRMNT]		= TARGET_ESRMNT,
    [ECOMM]		= TARGET_ECOMM,
    [EPROTO]		= TARGET_EPROTO,
    [EDOTDOT]		= TARGET_EDOTDOT,
    [EMULTIHOP]		= TARGET_EMULTIHOP,
    [EBADMSG]		= TARGET_EBADMSG,
    [ENAMETOOLONG]	= TARGET_ENAMETOOLONG,
    [EOVERFLOW]		= TARGET_EOVERFLOW,
    [ENOTUNIQ]		= TARGET_ENOTUNIQ,
    [EBADFD]		= TARGET_EBADFD,
    [EREMCHG]		= TARGET_EREMCHG,
    [ELIBACC]		= TARGET_ELIBACC,
    [ELIBBAD]		= TARGET_ELIBBAD,
    [ELIBSCN]		= TARGET_ELIBSCN,
    [ELIBMAX]		= TARGET_ELIBMAX,
    [ELIBEXEC]		= TARGET_ELIBEXEC,
    [EILSEQ]		= TARGET_EILSEQ,
    [ENOSYS]		= TARGET_ENOSYS,
    [ELOOP]		= TARGET_ELOOP,
    [ERESTART]		= TARGET_ERESTART,
    [ESTRPIPE]		= TARGET_ESTRPIPE,
    [ENOTEMPTY]		= TARGET_ENOTEMPTY,
    [EUSERS]		= TARGET_EUSERS,
    [ENOTSOCK]		= TARGET_ENOTSOCK,
    [EDESTADDRREQ]	= TARGET_EDESTADDRREQ,
    [EMSGSIZE]		= TARGET_EMSGSIZE,
    [EPROTOTYPE]	= TARGET_EPROTOTYPE,
    [ENOPROTOOPT]	= TARGET_ENOPROTOOPT,
    [EPROTONOSUPPORT]	= TARGET_EPROTONOSUPPORT,
    [ESOCKTNOSUPPORT]	= TARGET_ESOCKTNOSUPPORT,
    [EOPNOTSUPP]	= TARGET_EOPNOTSUPP,
    [EPFNOSUPPORT]	= TARGET_EPFNOSUPPORT,
    [EAFNOSUPPORT]	= TARGET_EAFNOSUPPORT,
    [EADDRINUSE]	= TARGET_EADDRINUSE,
    [EADDRNOTAVAIL]	= TARGET_EADDRNOTAVAIL,
    [ENETDOWN]		= TARGET_ENETDOWN,
    [ENETUNREACH]	= TARGET_ENETUNREACH,
    [ENETRESET]		= TARGET_ENETRESET,
    [ECONNABORTED]	= TARGET_ECONNABORTED,
    [ECONNRESET]	= TARGET_ECONNRESET,
    [ENOBUFS]		= TARGET_ENOBUFS,
    [EISCONN]		= TARGET_EISCONN,
    [ENOTCONN]		= TARGET_ENOTCONN,
    [EUCLEAN]		= TARGET_EUCLEAN,
    [ENOTNAM]		= TARGET_ENOTNAM,
    [ENAVAIL]		= TARGET_ENAVAIL,
    [EISNAM]		= TARGET_EISNAM,
    [EREMOTEIO]		= TARGET_EREMOTEIO,
    [ESHUTDOWN]		= TARGET_ESHUTDOWN,
    [ETOOMANYREFS]	= TARGET_ETOOMANYREFS,
    [ETIMEDOUT]		= TARGET_ETIMEDOUT,
    [ECONNREFUSED]	= TARGET_ECONNREFUSED,
    [EHOSTDOWN]		= TARGET_EHOSTDOWN,
    [EHOSTUNREACH]	= TARGET_EHOSTUNREACH,
    [EALREADY]		= TARGET_EALREADY,
    [EINPROGRESS]	= TARGET_EINPROGRESS,
    [ESTALE]		= TARGET_ESTALE,
    [ECANCELED]		= TARGET_ECANCELED,
    [ENOMEDIUM]		= TARGET_ENOMEDIUM,
    [EMEDIUMTYPE]	= TARGET_EMEDIUMTYPE,
T
ths 已提交
370
#ifdef ENOKEY
371
    [ENOKEY]		= TARGET_ENOKEY,
T
ths 已提交
372 373
#endif
#ifdef EKEYEXPIRED
374
    [EKEYEXPIRED]	= TARGET_EKEYEXPIRED,
T
ths 已提交
375 376
#endif
#ifdef EKEYREVOKED
377
    [EKEYREVOKED]	= TARGET_EKEYREVOKED,
T
ths 已提交
378 379
#endif
#ifdef EKEYREJECTED
380
    [EKEYREJECTED]	= TARGET_EKEYREJECTED,
T
ths 已提交
381 382
#endif
#ifdef EOWNERDEAD
383
    [EOWNERDEAD]	= TARGET_EOWNERDEAD,
T
ths 已提交
384 385
#endif
#ifdef ENOTRECOVERABLE
386
    [ENOTRECOVERABLE]	= TARGET_ENOTRECOVERABLE,
T
ths 已提交
387
#endif
388
};
389 390 391 392 393 394 395 396

static inline int host_to_target_errno(int err)
{
    if(host_to_target_errno_table[err])
        return host_to_target_errno_table[err];
    return err;
}

397 398 399 400 401 402 403
static inline int target_to_host_errno(int err)
{
    if (target_to_host_errno_table[err])
        return target_to_host_errno_table[err];
    return err;
}

404
static inline abi_long get_errno(abi_long ret)
405 406
{
    if (ret == -1)
407
        return -host_to_target_errno(errno);
408 409 410 411
    else
        return ret;
}

412
static inline int is_error(abi_long ret)
413
{
414
    return (abi_ulong)ret >= (abi_ulong)(-4096);
415 416
}

417 418 419 420 421
char *target_strerror(int err)
{
    return strerror(target_to_host_errno(err));
}

422 423
static abi_ulong target_brk;
static abi_ulong target_original_brk;
424

425
void target_set_brk(abi_ulong new_brk)
426
{
427
    target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
428 429
}

430
/* do_brk() must return target values and target errnos. */
431
abi_long do_brk(abi_ulong new_brk)
432
{
433 434
    abi_ulong brk_page;
    abi_long mapped_addr;
435 436 437
    int	new_alloc_size;

    if (!new_brk)
438
        return target_brk;
439
    if (new_brk < target_original_brk)
440
        return target_brk;
441

442
    brk_page = HOST_PAGE_ALIGN(target_brk);
443 444 445 446

    /* If the new brk is less than this, set it and we're done... */
    if (new_brk < brk_page) {
	target_brk = new_brk;
447
    	return target_brk;
448 449 450
    }

    /* We need to allocate more memory after the brk... */
B
bellard 已提交
451
    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
452
    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
B
bellard 已提交
453 454
                                        PROT_READ|PROT_WRITE,
                                        MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0));
455 456

    if (!is_error(mapped_addr))
457
	target_brk = new_brk;
458 459
    
    return target_brk;
460 461
}

462 463 464
static inline abi_long copy_from_user_fdset(fd_set *fds,
                                            abi_ulong target_fds_addr,
                                            int n)
465
{
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
    int i, nw, j, k;
    abi_ulong b, *target_fds;

    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
    if (!(target_fds = lock_user(VERIFY_READ,
                                 target_fds_addr,
                                 sizeof(abi_ulong) * nw,
                                 1)))
        return -TARGET_EFAULT;

    FD_ZERO(fds);
    k = 0;
    for (i = 0; i < nw; i++) {
        /* grab the abi_ulong */
        __get_user(b, &target_fds[i]);
        for (j = 0; j < TARGET_ABI_BITS; j++) {
            /* check the bit inside the abi_ulong */
            if ((b >> j) & 1)
                FD_SET(k, fds);
            k++;
486 487
        }
    }
488 489 490 491

    unlock_user(target_fds, target_fds_addr, 0);

    return 0;
492 493
}

494 495 496
static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
                                          const fd_set *fds,
                                          int n)
497 498
{
    int i, nw, j, k;
499
    abi_long v;
500
    abi_ulong *target_fds;
501

502 503 504 505 506 507 508 509 510 511 512 513 514
    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
    if (!(target_fds = lock_user(VERIFY_WRITE,
                                 target_fds_addr,
                                 sizeof(abi_ulong) * nw,
                                 0)))
        return -TARGET_EFAULT;

    k = 0;
    for (i = 0; i < nw; i++) {
        v = 0;
        for (j = 0; j < TARGET_ABI_BITS; j++) {
            v |= ((FD_ISSET(k, fds) != 0) << j);
            k++;
515
        }
516
        __put_user(v, &target_fds[i]);
517
    }
518 519 520 521

    unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);

    return 0;
522 523
}

B
bellard 已提交
524 525 526 527 528 529
#if defined(__alpha__)
#define HOST_HZ 1024
#else
#define HOST_HZ 100
#endif

530
static inline abi_long host_to_target_clock_t(long ticks)
B
bellard 已提交
531 532 533 534 535 536 537 538
{
#if HOST_HZ == TARGET_HZ
    return ticks;
#else
    return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
#endif
}

539 540
static inline abi_long host_to_target_rusage(abi_ulong target_addr,
                                             const struct rusage *rusage)
B
bellard 已提交
541
{
542 543
    struct target_rusage *target_rusage;

544 545
    if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
        return -TARGET_EFAULT;
B
bellard 已提交
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
    target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec);
    target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec);
    target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec);
    target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec);
    target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss);
    target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss);
    target_rusage->ru_idrss = tswapl(rusage->ru_idrss);
    target_rusage->ru_isrss = tswapl(rusage->ru_isrss);
    target_rusage->ru_minflt = tswapl(rusage->ru_minflt);
    target_rusage->ru_majflt = tswapl(rusage->ru_majflt);
    target_rusage->ru_nswap = tswapl(rusage->ru_nswap);
    target_rusage->ru_inblock = tswapl(rusage->ru_inblock);
    target_rusage->ru_oublock = tswapl(rusage->ru_oublock);
    target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd);
    target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv);
    target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals);
    target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw);
    target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw);
564
    unlock_user_struct(target_rusage, target_addr, 1);
565 566

    return 0;
B
bellard 已提交
567 568
}

569 570
static inline abi_long copy_from_user_timeval(struct timeval *tv,
                                              abi_ulong target_tv_addr)
571
{
572 573
    struct target_timeval *target_tv;

574
    if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
575
        return -TARGET_EFAULT;
576 577 578 579 580

    __get_user(tv->tv_sec, &target_tv->tv_sec);
    __get_user(tv->tv_usec, &target_tv->tv_usec);

    unlock_user_struct(target_tv, target_tv_addr, 0);
581 582

    return 0;
583 584
}

585 586
static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
                                            const struct timeval *tv)
587
{
588 589
    struct target_timeval *target_tv;

590
    if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
591
        return -TARGET_EFAULT;
592 593 594 595 596

    __put_user(tv->tv_sec, &target_tv->tv_sec);
    __put_user(tv->tv_usec, &target_tv->tv_usec);

    unlock_user_struct(target_tv, target_tv_addr, 1);
597 598

    return 0;
599 600 601
}


602
/* do_select() must return target values and target errnos. */
603
static abi_long do_select(int n,
604 605
                          abi_ulong rfd_addr, abi_ulong wfd_addr,
                          abi_ulong efd_addr, abi_ulong target_tv_addr)
606 607 608 609
{
    fd_set rfds, wfds, efds;
    fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
    struct timeval tv, *tv_ptr;
610
    abi_long ret;
611

612 613 614 615
    if (rfd_addr) {
        if (copy_from_user_fdset(&rfds, rfd_addr, n))
            return -TARGET_EFAULT;
        rfds_ptr = &rfds;
616 617 618
    } else {
        rfds_ptr = NULL;
    }
619 620 621 622
    if (wfd_addr) {
        if (copy_from_user_fdset(&wfds, wfd_addr, n))
            return -TARGET_EFAULT;
        wfds_ptr = &wfds;
623 624 625
    } else {
        wfds_ptr = NULL;
    }
626 627 628 629
    if (efd_addr) {
        if (copy_from_user_fdset(&efds, efd_addr, n))
            return -TARGET_EFAULT;
        efds_ptr = &efds;
630 631 632
    } else {
        efds_ptr = NULL;
    }
633

634
    if (target_tv_addr) {
635 636
        if (copy_from_user_timeval(&tv, target_tv_addr))
            return -TARGET_EFAULT;
637 638 639 640
        tv_ptr = &tv;
    } else {
        tv_ptr = NULL;
    }
641

642
    ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
643

644 645 646 647 648 649 650
    if (!is_error(ret)) {
        if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
            return -TARGET_EFAULT;
        if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
            return -TARGET_EFAULT;
        if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
            return -TARGET_EFAULT;
651

652 653
        if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
            return -TARGET_EFAULT;
654
    }
655

656 657 658
    return ret;
}

659 660 661
static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
                                               abi_ulong target_addr,
                                               socklen_t len)
B
bellard 已提交
662
{
663 664
    struct target_sockaddr *target_saddr;

665 666 667
    target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
    if (!target_saddr)
        return -TARGET_EFAULT;
668 669 670
    memcpy(addr, target_saddr, len);
    addr->sa_family = tswap16(target_saddr->sa_family);
    unlock_user(target_saddr, target_addr, 0);
671 672

    return 0;
B
bellard 已提交
673 674
}

675 676 677
static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
                                               struct sockaddr *addr,
                                               socklen_t len)
B
bellard 已提交
678
{
679 680
    struct target_sockaddr *target_saddr;

681 682 683
    target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
    if (!target_saddr)
        return -TARGET_EFAULT;
684 685 686
    memcpy(target_saddr, addr, len);
    target_saddr->sa_family = tswap16(addr->sa_family);
    unlock_user(target_saddr, target_addr, len);
687 688

    return 0;
B
bellard 已提交
689 690
}

691
/* ??? Should this also swap msgh->name?  */
692 693
static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
                                           struct target_msghdr *target_msgh)
B
bellard 已提交
694 695
{
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
696 697 698
    abi_long msg_controllen;
    abi_ulong target_cmsg_addr;
    struct target_cmsghdr *target_cmsg;
B
bellard 已提交
699
    socklen_t space = 0;
700 701 702 703 704 705 706 707
    
    msg_controllen = tswapl(target_msgh->msg_controllen);
    if (msg_controllen < sizeof (struct target_cmsghdr)) 
        goto the_end;
    target_cmsg_addr = tswapl(target_msgh->msg_control);
    target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
    if (!target_cmsg)
        return -TARGET_EFAULT;
B
bellard 已提交
708 709 710 711 712

    while (cmsg && target_cmsg) {
        void *data = CMSG_DATA(cmsg);
        void *target_data = TARGET_CMSG_DATA(target_cmsg);

713
        int len = tswapl(target_cmsg->cmsg_len)
B
bellard 已提交
714 715 716 717 718
                  - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));

        space += CMSG_SPACE(len);
        if (space > msgh->msg_controllen) {
            space -= CMSG_SPACE(len);
B
bellard 已提交
719
            gemu_log("Host cmsg overflow\n");
B
bellard 已提交
720 721 722 723 724 725 726
            break;
        }

        cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
        cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
        cmsg->cmsg_len = CMSG_LEN(len);

727
        if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
B
bellard 已提交
728 729 730 731 732 733 734 735 736 737 738 739 740 741
            gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
            memcpy(data, target_data, len);
        } else {
            int *fd = (int *)data;
            int *target_fd = (int *)target_data;
            int i, numfds = len / sizeof(int);

            for (i = 0; i < numfds; i++)
                fd[i] = tswap32(target_fd[i]);
        }

        cmsg = CMSG_NXTHDR(msgh, cmsg);
        target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
    }
742 743
    unlock_user(target_cmsg, target_cmsg_addr, 0);
 the_end:
B
bellard 已提交
744
    msgh->msg_controllen = space;
745
    return 0;
B
bellard 已提交
746 747
}

748
/* ??? Should this also swap msgh->name?  */
749 750
static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
                                           struct msghdr *msgh)
B
bellard 已提交
751 752
{
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
753 754 755
    abi_long msg_controllen;
    abi_ulong target_cmsg_addr;
    struct target_cmsghdr *target_cmsg;
B
bellard 已提交
756 757
    socklen_t space = 0;

758 759 760 761 762 763 764 765
    msg_controllen = tswapl(target_msgh->msg_controllen);
    if (msg_controllen < sizeof (struct target_cmsghdr)) 
        goto the_end;
    target_cmsg_addr = tswapl(target_msgh->msg_control);
    target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
    if (!target_cmsg)
        return -TARGET_EFAULT;

B
bellard 已提交
766 767 768 769 770 771 772
    while (cmsg && target_cmsg) {
        void *data = CMSG_DATA(cmsg);
        void *target_data = TARGET_CMSG_DATA(target_cmsg);

        int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));

        space += TARGET_CMSG_SPACE(len);
773
        if (space > msg_controllen) {
B
bellard 已提交
774
            space -= TARGET_CMSG_SPACE(len);
B
bellard 已提交
775
            gemu_log("Target cmsg overflow\n");
B
bellard 已提交
776 777 778 779 780 781 782
            break;
        }

        target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
        target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
        target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len));

783
        if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
B
bellard 已提交
784 785 786 787 788 789 790 791 792 793 794 795 796 797
            gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
            memcpy(target_data, data, len);
        } else {
            int *fd = (int *)data;
            int *target_fd = (int *)target_data;
            int i, numfds = len / sizeof(int);

            for (i = 0; i < numfds; i++)
                target_fd[i] = tswap32(fd[i]);
        }

        cmsg = CMSG_NXTHDR(msgh, cmsg);
        target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
    }
798 799 800 801
    unlock_user(target_cmsg, target_cmsg_addr, space);
 the_end:
    target_msgh->msg_controllen = tswapl(space);
    return 0;
B
bellard 已提交
802 803
}

804
/* do_setsockopt() Must return target values and target errnos. */
805
static abi_long do_setsockopt(int sockfd, int level, int optname,
806
                              abi_ulong optval_addr, socklen_t optlen)
B
bellard 已提交
807
{
808
    abi_long ret;
809
    int val;
810

811 812
    switch(level) {
    case SOL_TCP:
B
bellard 已提交
813 814
        /* TCP options all take an 'int' value.  */
        if (optlen < sizeof(uint32_t))
815
            return -TARGET_EINVAL;
816

817 818
        if (get_user_u32(val, optval_addr))
            return -TARGET_EFAULT;
819 820 821 822
        ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
        break;
    case SOL_IP:
        switch(optname) {
B
bellard 已提交
823 824
        case IP_TOS:
        case IP_TTL:
825
        case IP_HDRINCL:
B
bellard 已提交
826 827 828 829 830 831 832 833 834 835 836 837
        case IP_ROUTER_ALERT:
        case IP_RECVOPTS:
        case IP_RETOPTS:
        case IP_PKTINFO:
        case IP_MTU_DISCOVER:
        case IP_RECVERR:
        case IP_RECVTOS:
#ifdef IP_FREEBIND
        case IP_FREEBIND:
#endif
        case IP_MULTICAST_TTL:
        case IP_MULTICAST_LOOP:
838 839
            val = 0;
            if (optlen >= sizeof(uint32_t)) {
840 841
                if (get_user_u32(val, optval_addr))
                    return -TARGET_EFAULT;
842
            } else if (optlen >= 1) {
843 844
                if (get_user_u8(val, optval_addr))
                    return -TARGET_EFAULT;
845 846 847 848 849 850 851
            }
            ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
            break;
        default:
            goto unimplemented;
        }
        break;
852
    case TARGET_SOL_SOCKET:
853 854
        switch (optname) {
            /* Options with 'int' argument.  */
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890
        case TARGET_SO_DEBUG:
		optname = SO_DEBUG;
		break;
        case TARGET_SO_REUSEADDR:
		optname = SO_REUSEADDR;
		break;
        case TARGET_SO_TYPE:
		optname = SO_TYPE;
		break;
        case TARGET_SO_ERROR:
		optname = SO_ERROR;
		break;
        case TARGET_SO_DONTROUTE:
		optname = SO_DONTROUTE;
		break;
        case TARGET_SO_BROADCAST:
		optname = SO_BROADCAST;
		break;
        case TARGET_SO_SNDBUF:
		optname = SO_SNDBUF;
		break;
        case TARGET_SO_RCVBUF:
		optname = SO_RCVBUF;
		break;
        case TARGET_SO_KEEPALIVE:
		optname = SO_KEEPALIVE;
		break;
        case TARGET_SO_OOBINLINE:
		optname = SO_OOBINLINE;
		break;
        case TARGET_SO_NO_CHECK:
		optname = SO_NO_CHECK;
		break;
        case TARGET_SO_PRIORITY:
		optname = SO_PRIORITY;
		break;
B
bellard 已提交
891
#ifdef SO_BSDCOMPAT
892 893 894
        case TARGET_SO_BSDCOMPAT:
		optname = SO_BSDCOMPAT;
		break;
B
bellard 已提交
895
#endif
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910
        case TARGET_SO_PASSCRED:
		optname = SO_PASSCRED;
		break;
        case TARGET_SO_TIMESTAMP:
		optname = SO_TIMESTAMP;
		break;
        case TARGET_SO_RCVLOWAT:
		optname = SO_RCVLOWAT;
		break;
        case TARGET_SO_RCVTIMEO:
		optname = SO_RCVTIMEO;
		break;
        case TARGET_SO_SNDTIMEO:
		optname = SO_SNDTIMEO;
		break;
911 912 913 914
            break;
        default:
            goto unimplemented;
        }
915
	if (optlen < sizeof(uint32_t))
916
            return -TARGET_EINVAL;
917

918 919
	if (get_user_u32(val, optval_addr))
            return -TARGET_EFAULT;
920
	ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
921
        break;
B
bellard 已提交
922
    default:
923 924
    unimplemented:
        gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
925
        ret = -TARGET_ENOPROTOOPT;
B
bellard 已提交
926
    }
927
    return ret;
B
bellard 已提交
928 929
}

930
/* do_getsockopt() Must return target values and target errnos. */
931
static abi_long do_getsockopt(int sockfd, int level, int optname,
932
                              abi_ulong optval_addr, abi_ulong optlen)
B
bellard 已提交
933
{
934
    abi_long ret;
935
    int len, lv, val;
936 937

    switch(level) {
938 939
    case TARGET_SOL_SOCKET:
    	level = SOL_SOCKET;
940
	switch (optname) {
941 942 943 944 945
	case TARGET_SO_LINGER:
	case TARGET_SO_RCVTIMEO:
	case TARGET_SO_SNDTIMEO:
	case TARGET_SO_PEERCRED:
	case TARGET_SO_PEERNAME:
946 947 948
	    /* These don't just return a single integer */
	    goto unimplemented;
        default:
B
bellard 已提交
949 950 951 952 953 954
            goto int_case;
        }
        break;
    case SOL_TCP:
        /* TCP options all take an 'int' value.  */
    int_case:
955 956
        if (get_user_u32(len, optlen))
            return -TARGET_EFAULT;
B
bellard 已提交
957
        if (len < 0)
958
            return -TARGET_EINVAL;
B
bellard 已提交
959 960 961 962 963 964 965
        lv = sizeof(int);
        ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
        if (ret < 0)
            return ret;
        val = tswap32(val);
        if (len > lv)
            len = lv;
966 967 968 969 970 971 972 973 974
        if (len == 4) {
            if (put_user_u32(val, optval_addr))
                return -TARGET_EFAULT;
        } else {
            if (put_user_u8(val, optval_addr))
                return -TARGET_EFAULT;
	}
        if (put_user_u32(len, optlen))
            return -TARGET_EFAULT;
B
bellard 已提交
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
        break;
    case SOL_IP:
        switch(optname) {
        case IP_TOS:
        case IP_TTL:
        case IP_HDRINCL:
        case IP_ROUTER_ALERT:
        case IP_RECVOPTS:
        case IP_RETOPTS:
        case IP_PKTINFO:
        case IP_MTU_DISCOVER:
        case IP_RECVERR:
        case IP_RECVTOS:
#ifdef IP_FREEBIND
        case IP_FREEBIND:
#endif
        case IP_MULTICAST_TTL:
        case IP_MULTICAST_LOOP:
993 994
            if (get_user_u32(len, optlen))
                return -TARGET_EFAULT;
995
            if (len < 0)
996
                return -TARGET_EINVAL;
997 998 999 1000
            lv = sizeof(int);
            ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
            if (ret < 0)
                return ret;
B
bellard 已提交
1001 1002
            if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
                len = 1;
1003 1004 1005
                if (put_user_u32(len, optlen)
                    || put_user_u8(val, optval_addr))
                    return -TARGET_EFAULT;
B
bellard 已提交
1006 1007 1008
            } else {
                if (len > sizeof(int))
                    len = sizeof(int);
1009 1010 1011
                if (put_user_u32(len, optlen)
                    || put_user_u32(val, optval_addr))
                    return -TARGET_EFAULT;
B
bellard 已提交
1012
            }
1013
            break;
B
bellard 已提交
1014
        default:
1015 1016
            ret = -TARGET_ENOPROTOOPT;
            break;
1017 1018 1019 1020 1021 1022
        }
        break;
    default:
    unimplemented:
        gemu_log("getsockopt level=%d optname=%d not yet supported\n",
                 level, optname);
1023
        ret = -TARGET_EOPNOTSUPP;
1024 1025 1026
        break;
    }
    return ret;
B
bellard 已提交
1027 1028
}

1029 1030 1031 1032 1033 1034
/* FIXME
 * lock_iovec()/unlock_iovec() have a return code of 0 for success where
 * other lock functions have a return code of 0 for failure.
 */
static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
                           int count, int copy)
1035 1036
{
    struct target_iovec *target_vec;
1037
    abi_ulong base;
1038
    int i, j;
1039

1040 1041 1042
    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
    if (!target_vec)
        return -TARGET_EFAULT;
1043 1044 1045
    for(i = 0;i < count; i++) {
        base = tswapl(target_vec[i].iov_base);
        vec[i].iov_len = tswapl(target_vec[i].iov_len);
B
bellard 已提交
1046 1047
        if (vec[i].iov_len != 0) {
            vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
1048
            if (!vec[i].iov_base && vec[i].iov_len) 
B
bellard 已提交
1049 1050 1051 1052 1053
                goto fail;
        } else {
            /* zero length pointer is ignored */
            vec[i].iov_base = NULL;
        }
1054 1055 1056 1057 1058 1059 1060 1061
    }
    unlock_user (target_vec, target_addr, 0);
    return 0;
 fail:
    /* failure - unwind locks */
    for (j = 0; j < i; j++) {
        base = tswapl(target_vec[j].iov_base);
        unlock_user(vec[j].iov_base, base, 0);
1062 1063
    }
    unlock_user (target_vec, target_addr, 0);
1064
    return -TARGET_EFAULT;
1065 1066
}

1067 1068
static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
                             int count, int copy)
1069 1070
{
    struct target_iovec *target_vec;
1071
    abi_ulong base;
1072 1073
    int i;

1074 1075 1076
    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
    if (!target_vec)
        return -TARGET_EFAULT;
1077 1078 1079 1080 1081
    for(i = 0;i < count; i++) {
        base = tswapl(target_vec[i].iov_base);
        unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
    }
    unlock_user (target_vec, target_addr, 0);
1082 1083

    return 0;
1084 1085
}

1086
/* do_socket() Must return target values and target errnos. */
1087
static abi_long do_socket(int domain, int type, int protocol)
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
{
#if defined(TARGET_MIPS)
    switch(type) {
    case TARGET_SOCK_DGRAM:
        type = SOCK_DGRAM;
        break;
    case TARGET_SOCK_STREAM:
        type = SOCK_STREAM;
        break;
    case TARGET_SOCK_RAW:
        type = SOCK_RAW;
        break;
    case TARGET_SOCK_RDM:
        type = SOCK_RDM;
        break;
    case TARGET_SOCK_SEQPACKET:
        type = SOCK_SEQPACKET;
        break;
    case TARGET_SOCK_PACKET:
        type = SOCK_PACKET;
        break;
    }
#endif
1111 1112
    if (domain == PF_NETLINK)
        return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
1113 1114 1115
    return get_errno(socket(domain, type, protocol));
}

1116
/* do_bind() Must return target values and target errnos. */
1117 1118
static abi_long do_bind(int sockfd, abi_ulong target_addr,
                        socklen_t addrlen)
1119 1120
{
    void *addr = alloca(addrlen);
1121

1122 1123 1124 1125
    target_to_host_sockaddr(addr, target_addr, addrlen);
    return get_errno(bind(sockfd, addr, addrlen));
}

1126
/* do_connect() Must return target values and target errnos. */
1127 1128
static abi_long do_connect(int sockfd, abi_ulong target_addr,
                           socklen_t addrlen)
1129 1130
{
    void *addr = alloca(addrlen);
1131

1132 1133 1134 1135
    target_to_host_sockaddr(addr, target_addr, addrlen);
    return get_errno(connect(sockfd, addr, addrlen));
}

1136
/* do_sendrecvmsg() Must return target values and target errnos. */
1137 1138
static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
                               int flags, int send)
1139
{
1140
    abi_long ret;
1141 1142 1143 1144
    struct target_msghdr *msgp;
    struct msghdr msg;
    int count;
    struct iovec *vec;
1145
    abi_ulong target_vec;
1146

1147 1148 1149 1150 1151 1152
    /* FIXME */
    if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
                          msgp,
                          target_msg,
                          send ? 1 : 0))
        return -TARGET_EFAULT;
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
    if (msgp->msg_name) {
        msg.msg_namelen = tswap32(msgp->msg_namelen);
        msg.msg_name = alloca(msg.msg_namelen);
        target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
                                msg.msg_namelen);
    } else {
        msg.msg_name = NULL;
        msg.msg_namelen = 0;
    }
    msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
    msg.msg_control = alloca(msg.msg_controllen);
    msg.msg_flags = tswap32(msgp->msg_flags);
1165

1166 1167 1168
    count = tswapl(msgp->msg_iovlen);
    vec = alloca(count * sizeof(struct iovec));
    target_vec = tswapl(msgp->msg_iov);
1169
    lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
1170 1171
    msg.msg_iovlen = count;
    msg.msg_iov = vec;
1172

1173
    if (send) {
1174 1175 1176
        ret = target_to_host_cmsg(&msg, msgp);
        if (ret == 0)
            ret = get_errno(sendmsg(fd, &msg, flags));
1177 1178 1179
    } else {
        ret = get_errno(recvmsg(fd, &msg, flags));
        if (!is_error(ret))
1180
            ret = host_to_target_cmsg(msgp, &msg);
1181 1182
    }
    unlock_iovec(vec, target_vec, count, !send);
1183
    unlock_user_struct(msgp, target_msg, send ? 0 : 1);
1184 1185 1186
    return ret;
}

1187
/* do_accept() Must return target values and target errnos. */
1188
static abi_long do_accept(int fd, abi_ulong target_addr,
1189
                          abi_ulong target_addrlen_addr)
P
pbrook 已提交
1190
{
1191 1192
    socklen_t addrlen;
    void *addr;
1193
    abi_long ret;
P
pbrook 已提交
1194

1195 1196 1197 1198 1199
    if (get_user_u32(addrlen, target_addrlen_addr))
        return -TARGET_EFAULT;

    addr = alloca(addrlen);

P
pbrook 已提交
1200 1201 1202
    ret = get_errno(accept(fd, addr, &addrlen));
    if (!is_error(ret)) {
        host_to_target_sockaddr(target_addr, addr, addrlen);
1203 1204
        if (put_user_u32(addrlen, target_addrlen_addr))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1205 1206 1207 1208
    }
    return ret;
}

1209
/* do_getpeername() Must return target values and target errnos. */
1210
static abi_long do_getpeername(int fd, abi_ulong target_addr,
1211
                               abi_ulong target_addrlen_addr)
P
pbrook 已提交
1212
{
1213 1214
    socklen_t addrlen;
    void *addr;
1215
    abi_long ret;
P
pbrook 已提交
1216

1217 1218 1219 1220 1221
    if (get_user_u32(addrlen, target_addrlen_addr))
        return -TARGET_EFAULT;

    addr = alloca(addrlen);

P
pbrook 已提交
1222 1223 1224
    ret = get_errno(getpeername(fd, addr, &addrlen));
    if (!is_error(ret)) {
        host_to_target_sockaddr(target_addr, addr, addrlen);
1225 1226
        if (put_user_u32(addrlen, target_addrlen_addr))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1227 1228 1229 1230
    }
    return ret;
}

1231
/* do_getsockname() Must return target values and target errnos. */
1232
static abi_long do_getsockname(int fd, abi_ulong target_addr,
1233
                               abi_ulong target_addrlen_addr)
P
pbrook 已提交
1234
{
1235 1236
    socklen_t addrlen;
    void *addr;
1237
    abi_long ret;
P
pbrook 已提交
1238

1239 1240 1241 1242 1243
    if (get_user_u32(addrlen, target_addrlen_addr))
        return -TARGET_EFAULT;

    addr = alloca(addrlen);

P
pbrook 已提交
1244 1245 1246
    ret = get_errno(getsockname(fd, addr, &addrlen));
    if (!is_error(ret)) {
        host_to_target_sockaddr(target_addr, addr, addrlen);
1247 1248
        if (put_user_u32(addrlen, target_addrlen_addr))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1249 1250 1251 1252
    }
    return ret;
}

1253
/* do_socketpair() Must return target values and target errnos. */
1254
static abi_long do_socketpair(int domain, int type, int protocol,
1255
                              abi_ulong target_tab_addr)
P
pbrook 已提交
1256 1257
{
    int tab[2];
1258
    abi_long ret;
P
pbrook 已提交
1259 1260 1261

    ret = get_errno(socketpair(domain, type, protocol, tab));
    if (!is_error(ret)) {
1262 1263 1264
        if (put_user_s32(tab[0], target_tab_addr)
            || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1265 1266 1267 1268
    }
    return ret;
}

1269
/* do_sendto() Must return target values and target errnos. */
1270 1271
static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
                          abi_ulong target_addr, socklen_t addrlen)
P
pbrook 已提交
1272 1273 1274
{
    void *addr;
    void *host_msg;
1275
    abi_long ret;
P
pbrook 已提交
1276

1277 1278 1279
    host_msg = lock_user(VERIFY_READ, msg, len, 1);
    if (!host_msg)
        return -TARGET_EFAULT;
P
pbrook 已提交
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
    if (target_addr) {
        addr = alloca(addrlen);
        target_to_host_sockaddr(addr, target_addr, addrlen);
        ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
    } else {
        ret = get_errno(send(fd, host_msg, len, flags));
    }
    unlock_user(host_msg, msg, 0);
    return ret;
}

1291
/* do_recvfrom() Must return target values and target errnos. */
1292 1293 1294
static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
                            abi_ulong target_addr,
                            abi_ulong target_addrlen)
P
pbrook 已提交
1295 1296 1297 1298
{
    socklen_t addrlen;
    void *addr;
    void *host_msg;
1299
    abi_long ret;
P
pbrook 已提交
1300

1301 1302 1303
    host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
    if (!host_msg)
        return -TARGET_EFAULT;
P
pbrook 已提交
1304
    if (target_addr) {
1305 1306 1307 1308
        if (get_user_u32(addrlen, target_addrlen)) {
            ret = -TARGET_EFAULT;
            goto fail;
        }
P
pbrook 已提交
1309 1310 1311 1312 1313 1314 1315 1316 1317
        addr = alloca(addrlen);
        ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
    } else {
        addr = NULL; /* To keep compiler quiet.  */
        ret = get_errno(recv(fd, host_msg, len, flags));
    }
    if (!is_error(ret)) {
        if (target_addr) {
            host_to_target_sockaddr(target_addr, addr, addrlen);
1318 1319 1320 1321
            if (put_user_u32(addrlen, target_addrlen)) {
                ret = -TARGET_EFAULT;
                goto fail;
            }
P
pbrook 已提交
1322 1323 1324
        }
        unlock_user(host_msg, msg, len);
    } else {
1325
fail:
P
pbrook 已提交
1326 1327 1328 1329 1330
        unlock_user(host_msg, msg, 0);
    }
    return ret;
}

1331
#ifdef TARGET_NR_socketcall
1332
/* do_socketcall() Must return target values and target errnos. */
1333
static abi_long do_socketcall(int num, abi_ulong vptr)
1334
{
1335 1336
    abi_long ret;
    const int n = sizeof(abi_ulong);
1337 1338 1339

    switch(num) {
    case SOCKOP_socket:
B
bellard 已提交
1340
	{
1341 1342 1343 1344 1345 1346 1347
            int domain, type, protocol;

            if (get_user_s32(domain, vptr)
                || get_user_s32(type, vptr + n)
                || get_user_s32(protocol, vptr + 2 * n))
                return -TARGET_EFAULT;

1348
            ret = do_socket(domain, type, protocol);
B
bellard 已提交
1349
	}
1350 1351
        break;
    case SOCKOP_bind:
B
bellard 已提交
1352
	{
1353 1354 1355 1356 1357 1358 1359 1360 1361
            int sockfd;
            abi_ulong target_addr;
            socklen_t addrlen;

            if (get_user_s32(sockfd, vptr)
                || get_user_ual(target_addr, vptr + n)
                || get_user_u32(addrlen, vptr + 2 * n))
                return -TARGET_EFAULT;

1362
            ret = do_bind(sockfd, target_addr, addrlen);
B
bellard 已提交
1363
        }
1364 1365
        break;
    case SOCKOP_connect:
B
bellard 已提交
1366
        {
1367 1368 1369 1370 1371 1372 1373 1374 1375
            int sockfd;
            abi_ulong target_addr;
            socklen_t addrlen;

            if (get_user_s32(sockfd, vptr)
                || get_user_ual(target_addr, vptr + n)
                || get_user_u32(addrlen, vptr + 2 * n))
                return -TARGET_EFAULT;

1376
            ret = do_connect(sockfd, target_addr, addrlen);
B
bellard 已提交
1377
        }
1378 1379
        break;
    case SOCKOP_listen:
B
bellard 已提交
1380
        {
1381 1382 1383 1384 1385 1386
            int sockfd, backlog;

            if (get_user_s32(sockfd, vptr)
                || get_user_s32(backlog, vptr + n))
                return -TARGET_EFAULT;

B
bellard 已提交
1387 1388
            ret = get_errno(listen(sockfd, backlog));
        }
1389 1390 1391
        break;
    case SOCKOP_accept:
        {
1392 1393 1394 1395 1396 1397 1398 1399
            int sockfd;
            abi_ulong target_addr, target_addrlen;

            if (get_user_s32(sockfd, vptr)
                || get_user_ual(target_addr, vptr + n)
                || get_user_u32(target_addrlen, vptr + 2 * n))
                return -TARGET_EFAULT;

P
pbrook 已提交
1400
            ret = do_accept(sockfd, target_addr, target_addrlen);
1401 1402 1403 1404
        }
        break;
    case SOCKOP_getsockname:
        {
1405 1406 1407 1408 1409 1410 1411 1412
            int sockfd;
            abi_ulong target_addr, target_addrlen;

            if (get_user_s32(sockfd, vptr)
                || get_user_ual(target_addr, vptr + n)
                || get_user_u32(target_addrlen, vptr + 2 * n))
                return -TARGET_EFAULT;

P
pbrook 已提交
1413
            ret = do_getsockname(sockfd, target_addr, target_addrlen);
1414 1415 1416 1417
        }
        break;
    case SOCKOP_getpeername:
        {
1418 1419 1420 1421 1422 1423 1424 1425
            int sockfd;
            abi_ulong target_addr, target_addrlen;

            if (get_user_s32(sockfd, vptr)
                || get_user_ual(target_addr, vptr + n)
                || get_user_u32(target_addrlen, vptr + 2 * n))
                return -TARGET_EFAULT;

P
pbrook 已提交
1426
            ret = do_getpeername(sockfd, target_addr, target_addrlen);
1427 1428 1429 1430
        }
        break;
    case SOCKOP_socketpair:
        {
1431 1432 1433 1434 1435 1436 1437 1438 1439
            int domain, type, protocol;
            abi_ulong tab;

            if (get_user_s32(domain, vptr)
                || get_user_s32(type, vptr + n)
                || get_user_s32(protocol, vptr + 2 * n)
                || get_user_ual(tab, vptr + 3 * n))
                return -TARGET_EFAULT;

P
pbrook 已提交
1440
            ret = do_socketpair(domain, type, protocol, tab);
1441 1442 1443
        }
        break;
    case SOCKOP_send:
B
bellard 已提交
1444
        {
1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455
            int sockfd;
            abi_ulong msg;
            size_t len;
            int flags;

            if (get_user_s32(sockfd, vptr)
                || get_user_ual(msg, vptr + n)
                || get_user_ual(len, vptr + 2 * n)
                || get_user_s32(flags, vptr + 3 * n))
                return -TARGET_EFAULT;

P
pbrook 已提交
1456
            ret = do_sendto(sockfd, msg, len, flags, 0, 0);
B
bellard 已提交
1457
        }
1458 1459
        break;
    case SOCKOP_recv:
B
bellard 已提交
1460
        {
1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471
            int sockfd;
            abi_ulong msg;
            size_t len;
            int flags;

            if (get_user_s32(sockfd, vptr)
                || get_user_ual(msg, vptr + n)
                || get_user_ual(len, vptr + 2 * n)
                || get_user_s32(flags, vptr + 3 * n))
                return -TARGET_EFAULT;

P
pbrook 已提交
1472
            ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
B
bellard 已提交
1473
        }
1474 1475
        break;
    case SOCKOP_sendto:
B
bellard 已提交
1476
        {
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
            int sockfd;
            abi_ulong msg;
            size_t len;
            int flags;
            abi_ulong addr;
            socklen_t addrlen;

            if (get_user_s32(sockfd, vptr)
                || get_user_ual(msg, vptr + n)
                || get_user_ual(len, vptr + 2 * n)
                || get_user_s32(flags, vptr + 3 * n)
                || get_user_ual(addr, vptr + 4 * n)
                || get_user_u32(addrlen, vptr + 5 * n))
                return -TARGET_EFAULT;

P
pbrook 已提交
1492
            ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
B
bellard 已提交
1493
        }
1494 1495 1496
        break;
    case SOCKOP_recvfrom:
        {
1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511
            int sockfd;
            abi_ulong msg;
            size_t len;
            int flags;
            abi_ulong addr;
            socklen_t addrlen;

            if (get_user_s32(sockfd, vptr)
                || get_user_ual(msg, vptr + n)
                || get_user_ual(len, vptr + 2 * n)
                || get_user_s32(flags, vptr + 3 * n)
                || get_user_ual(addr, vptr + 4 * n)
                || get_user_u32(addrlen, vptr + 5 * n))
                return -TARGET_EFAULT;

P
pbrook 已提交
1512
            ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
1513 1514 1515
        }
        break;
    case SOCKOP_shutdown:
B
bellard 已提交
1516
        {
1517 1518 1519 1520 1521
            int sockfd, how;

            if (get_user_s32(sockfd, vptr)
                || get_user_s32(how, vptr + n))
                return -TARGET_EFAULT;
B
bellard 已提交
1522 1523 1524

            ret = get_errno(shutdown(sockfd, how));
        }
1525 1526 1527
        break;
    case SOCKOP_sendmsg:
    case SOCKOP_recvmsg:
B
bellard 已提交
1528 1529
        {
            int fd;
1530
            abi_ulong target_msg;
1531
            int flags;
B
bellard 已提交
1532

1533 1534 1535 1536
            if (get_user_s32(fd, vptr)
                || get_user_ual(target_msg, vptr + n)
                || get_user_s32(flags, vptr + 2 * n))
                return -TARGET_EFAULT;
1537

1538
            ret = do_sendrecvmsg(fd, target_msg, flags,
1539
                                 (num == SOCKOP_sendmsg));
B
bellard 已提交
1540 1541
        }
        break;
1542
    case SOCKOP_setsockopt:
B
bellard 已提交
1543
        {
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
            int sockfd;
            int level;
            int optname;
            abi_ulong optval;
            socklen_t optlen;

            if (get_user_s32(sockfd, vptr)
                || get_user_s32(level, vptr + n)
                || get_user_s32(optname, vptr + 2 * n)
                || get_user_ual(optval, vptr + 3 * n)
                || get_user_u32(optlen, vptr + 4 * n))
                return -TARGET_EFAULT;
B
bellard 已提交
1556 1557 1558 1559

            ret = do_setsockopt(sockfd, level, optname, optval, optlen);
        }
        break;
1560
    case SOCKOP_getsockopt:
B
bellard 已提交
1561
        {
1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573
            int sockfd;
            int level;
            int optname;
            abi_ulong optval;
            socklen_t optlen;

            if (get_user_s32(sockfd, vptr)
                || get_user_s32(level, vptr + n)
                || get_user_s32(optname, vptr + 2 * n)
                || get_user_ual(optval, vptr + 3 * n)
                || get_user_u32(optlen, vptr + 4 * n))
                return -TARGET_EFAULT;
B
bellard 已提交
1574

1575
            ret = do_getsockopt(sockfd, level, optname, optval, optlen);
B
bellard 已提交
1576 1577
        }
        break;
1578 1579
    default:
        gemu_log("Unsupported socketcall: %d\n", num);
1580
        ret = -TARGET_ENOSYS;
1581 1582 1583 1584
        break;
    }
    return ret;
}
1585
#endif
1586

1587
#ifdef TARGET_NR_ipc
1588 1589 1590
#define N_SHM_REGIONS	32

static struct shm_region {
1591 1592
    abi_ulong	start;
    abi_ulong	size;
1593 1594
} shm_regions[N_SHM_REGIONS];

1595 1596
struct target_ipc_perm
{
1597 1598 1599 1600 1601
    abi_long __key;
    abi_ulong uid;
    abi_ulong gid;
    abi_ulong cuid;
    abi_ulong cgid;
1602 1603 1604 1605
    unsigned short int mode;
    unsigned short int __pad1;
    unsigned short int __seq;
    unsigned short int __pad2;
1606 1607
    abi_ulong __unused1;
    abi_ulong __unused2;
1608 1609 1610 1611 1612
};

struct target_semid_ds
{
  struct target_ipc_perm sem_perm;
1613 1614 1615 1616 1617 1618 1619
  abi_ulong sem_otime;
  abi_ulong __unused1;
  abi_ulong sem_ctime;
  abi_ulong __unused2;
  abi_ulong sem_nsems;
  abi_ulong __unused3;
  abi_ulong __unused4;
1620 1621
};

1622 1623
static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
                                               abi_ulong target_addr)
1624 1625 1626 1627
{
    struct target_ipc_perm *target_ip;
    struct target_semid_ds *target_sd;

1628 1629
    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
        return -TARGET_EFAULT;
1630 1631 1632 1633 1634 1635 1636 1637
    target_ip=&(target_sd->sem_perm);
    host_ip->__key = tswapl(target_ip->__key);
    host_ip->uid = tswapl(target_ip->uid);
    host_ip->gid = tswapl(target_ip->gid);
    host_ip->cuid = tswapl(target_ip->cuid);
    host_ip->cgid = tswapl(target_ip->cgid);
    host_ip->mode = tswapl(target_ip->mode);
    unlock_user_struct(target_sd, target_addr, 0);
1638
    return 0;
1639 1640
}

1641 1642
static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
                                               struct ipc_perm *host_ip)
1643 1644 1645 1646
{
    struct target_ipc_perm *target_ip;
    struct target_semid_ds *target_sd;

1647 1648
    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
        return -TARGET_EFAULT;
1649 1650 1651 1652 1653 1654 1655 1656
    target_ip = &(target_sd->sem_perm);
    target_ip->__key = tswapl(host_ip->__key);
    target_ip->uid = tswapl(host_ip->uid);
    target_ip->gid = tswapl(host_ip->gid);
    target_ip->cuid = tswapl(host_ip->cuid);
    target_ip->cgid = tswapl(host_ip->cgid);
    target_ip->mode = tswapl(host_ip->mode);
    unlock_user_struct(target_sd, target_addr, 1);
1657
    return 0;
1658 1659
}

1660 1661
static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
                                               abi_ulong target_addr)
1662 1663 1664
{
    struct target_semid_ds *target_sd;

1665 1666
    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
        return -TARGET_EFAULT;
1667 1668 1669 1670 1671
    target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr);
    host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
    host_sd->sem_otime = tswapl(target_sd->sem_otime);
    host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
    unlock_user_struct(target_sd, target_addr, 0);
1672
    return 0;
1673 1674
}

1675 1676
static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
                                               struct semid_ds *host_sd)
1677 1678 1679
{
    struct target_semid_ds *target_sd;

1680 1681
    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
        return -TARGET_EFAULT;
1682 1683 1684 1685 1686
    host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm));
    target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
    target_sd->sem_otime = tswapl(host_sd->sem_otime);
    target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
    unlock_user_struct(target_sd, target_addr, 1);
1687
    return 0;
1688 1689
}

1690 1691
union semun {
	int val;
1692
	struct semid_ds *buf;
1693 1694 1695
	unsigned short *array;
};

1696 1697
union target_semun {
	int val;
1698
	abi_long buf;
1699 1700 1701
	unsigned short int *array;
};

1702 1703 1704 1705
static inline abi_long target_to_host_semun(int cmd,
                                            union semun *host_su,
                                            abi_ulong target_addr,
                                            struct semid_ds *ds)
1706 1707 1708 1709 1710 1711
{
    union target_semun *target_su;

    switch( cmd ) {
	case IPC_STAT:
	case IPC_SET:
1712 1713
           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
               return -TARGET_EFAULT;
1714 1715 1716 1717 1718 1719
	   target_to_host_semid_ds(ds,target_su->buf);
	   host_su->buf = ds;
           unlock_user_struct(target_su, target_addr, 0);
	   break;
	case GETVAL:
	case SETVAL:
1720 1721
           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
               return -TARGET_EFAULT;
1722 1723 1724 1725 1726
	   host_su->val = tswapl(target_su->val);
           unlock_user_struct(target_su, target_addr, 0);
	   break;
	case GETALL:
	case SETALL:
1727 1728
           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
               return -TARGET_EFAULT;
1729 1730 1731 1732 1733 1734
	   *host_su->array = tswap16(*target_su->array);
           unlock_user_struct(target_su, target_addr, 0);
	   break;
	default:
           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
    }
1735
    return 0;
1736 1737
}

1738 1739 1740 1741
static inline abi_long host_to_target_semun(int cmd,
                                            abi_ulong target_addr,
                                            union semun *host_su,
                                            struct semid_ds *ds)
1742 1743 1744 1745 1746 1747
{
    union target_semun *target_su;

    switch( cmd ) {
	case IPC_STAT:
	case IPC_SET:
1748 1749
           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
               return -TARGET_EFAULT;
1750 1751 1752 1753 1754
	   host_to_target_semid_ds(target_su->buf,ds);
           unlock_user_struct(target_su, target_addr, 1);
	   break;
	case GETVAL:
	case SETVAL:
1755 1756
           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
               return -TARGET_EFAULT;
1757 1758 1759 1760 1761
	   target_su->val = tswapl(host_su->val);
           unlock_user_struct(target_su, target_addr, 1);
	   break;
	case GETALL:
	case SETALL:
1762 1763
           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
               return -TARGET_EFAULT;
1764 1765 1766 1767 1768 1769
	   *target_su->array = tswap16(*host_su->array);
           unlock_user_struct(target_su, target_addr, 1);
	   break;
        default:
           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
    }
1770
    return 0;
1771 1772
}

1773 1774
static inline abi_long do_semctl(int first, int second, int third,
                                 abi_long ptr)
1775 1776 1777 1778
{
    union semun arg;
    struct semid_ds dsarg;
    int cmd = third&0xff;
1779
    abi_long ret = 0;
1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818

    switch( cmd ) {
	case GETVAL:
            target_to_host_semun(cmd,&arg,ptr,&dsarg);
            ret = get_errno(semctl(first, second, cmd, arg));
            host_to_target_semun(cmd,ptr,&arg,&dsarg);
            break;
	case SETVAL:
            target_to_host_semun(cmd,&arg,ptr,&dsarg);
            ret = get_errno(semctl(first, second, cmd, arg));
            host_to_target_semun(cmd,ptr,&arg,&dsarg);
            break;
	case GETALL:
            target_to_host_semun(cmd,&arg,ptr,&dsarg);
            ret = get_errno(semctl(first, second, cmd, arg));
            host_to_target_semun(cmd,ptr,&arg,&dsarg);
            break;
	case SETALL:
            target_to_host_semun(cmd,&arg,ptr,&dsarg);
            ret = get_errno(semctl(first, second, cmd, arg));
            host_to_target_semun(cmd,ptr,&arg,&dsarg);
            break;
	case IPC_STAT:
            target_to_host_semun(cmd,&arg,ptr,&dsarg);
            ret = get_errno(semctl(first, second, cmd, arg));
            host_to_target_semun(cmd,ptr,&arg,&dsarg);
            break;
	case IPC_SET:
            target_to_host_semun(cmd,&arg,ptr,&dsarg);
            ret = get_errno(semctl(first, second, cmd, arg));
            host_to_target_semun(cmd,ptr,&arg,&dsarg);
            break;
    default:
            ret = get_errno(semctl(first, second, cmd, arg));
    }

    return ret;
}

T
ths 已提交
1819 1820 1821
struct target_msqid_ds
{
  struct target_ipc_perm msg_perm;
1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834
  abi_ulong msg_stime;
  abi_ulong __unused1;
  abi_ulong msg_rtime;
  abi_ulong __unused2;
  abi_ulong msg_ctime;
  abi_ulong __unused3;
  abi_ulong __msg_cbytes;
  abi_ulong msg_qnum;
  abi_ulong msg_qbytes;
  abi_ulong msg_lspid;
  abi_ulong msg_lrpid;
  abi_ulong __unused4;
  abi_ulong __unused5;
T
ths 已提交
1835 1836
};

1837 1838
static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
                                               abi_ulong target_addr)
T
ths 已提交
1839 1840 1841
{
    struct target_msqid_ds *target_md;

1842 1843
    if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
        return -TARGET_EFAULT;
T
ths 已提交
1844 1845 1846 1847 1848 1849 1850 1851 1852 1853
    target_to_host_ipc_perm(&(host_md->msg_perm),target_addr);
    host_md->msg_stime = tswapl(target_md->msg_stime);
    host_md->msg_rtime = tswapl(target_md->msg_rtime);
    host_md->msg_ctime = tswapl(target_md->msg_ctime);
    host_md->__msg_cbytes = tswapl(target_md->__msg_cbytes);
    host_md->msg_qnum = tswapl(target_md->msg_qnum);
    host_md->msg_qbytes = tswapl(target_md->msg_qbytes);
    host_md->msg_lspid = tswapl(target_md->msg_lspid);
    host_md->msg_lrpid = tswapl(target_md->msg_lrpid);
    unlock_user_struct(target_md, target_addr, 0);
1854
    return 0;
T
ths 已提交
1855 1856
}

1857 1858
static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
                                               struct msqid_ds *host_md)
T
ths 已提交
1859 1860 1861
{
    struct target_msqid_ds *target_md;

1862 1863
    if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
        return -TARGET_EFAULT;
T
ths 已提交
1864 1865 1866 1867 1868 1869 1870 1871 1872 1873
    host_to_target_ipc_perm(target_addr,&(host_md->msg_perm));
    target_md->msg_stime = tswapl(host_md->msg_stime);
    target_md->msg_rtime = tswapl(host_md->msg_rtime);
    target_md->msg_ctime = tswapl(host_md->msg_ctime);
    target_md->__msg_cbytes = tswapl(host_md->__msg_cbytes);
    target_md->msg_qnum = tswapl(host_md->msg_qnum);
    target_md->msg_qbytes = tswapl(host_md->msg_qbytes);
    target_md->msg_lspid = tswapl(host_md->msg_lspid);
    target_md->msg_lrpid = tswapl(host_md->msg_lrpid);
    unlock_user_struct(target_md, target_addr, 1);
1874
    return 0;
T
ths 已提交
1875 1876
}

1877
static inline abi_long do_msgctl(int first, int second, abi_long ptr)
T
ths 已提交
1878 1879 1880
{
    struct msqid_ds dsarg;
    int cmd = second&0xff;
1881
    abi_long ret = 0;
T
ths 已提交
1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894
    switch( cmd ) {
    case IPC_STAT:
    case IPC_SET:
        target_to_host_msqid_ds(&dsarg,ptr);
        ret = get_errno(msgctl(first, cmd, &dsarg));
        host_to_target_msqid_ds(ptr,&dsarg);
    default:
        ret = get_errno(msgctl(first, cmd, &dsarg));
    }
    return ret;
}

struct target_msgbuf {
1895
	abi_ulong mtype;
T
ths 已提交
1896 1897 1898
	char	mtext[1];
};

1899 1900
static inline abi_long do_msgsnd(int msqid, abi_long msgp,
                                 unsigned int msgsz, int msgflg)
T
ths 已提交
1901 1902 1903
{
    struct target_msgbuf *target_mb;
    struct msgbuf *host_mb;
1904
    abi_long ret = 0;
T
ths 已提交
1905

1906 1907
    if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
        return -TARGET_EFAULT;
T
ths 已提交
1908 1909 1910 1911 1912 1913 1914 1915 1916 1917
    host_mb = malloc(msgsz+sizeof(long));
    host_mb->mtype = tswapl(target_mb->mtype);
    memcpy(host_mb->mtext,target_mb->mtext,msgsz);
    ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
    free(host_mb);
    unlock_user_struct(target_mb, msgp, 0);

    return ret;
}

1918 1919 1920
static inline abi_long do_msgrcv(int msqid, abi_long msgp,
                                 unsigned int msgsz, int msgtype,
                                 int msgflg)
T
ths 已提交
1921 1922
{
    struct target_msgbuf *target_mb;
1923
    char *target_mtext;
T
ths 已提交
1924
    struct msgbuf *host_mb;
1925
    abi_long ret = 0;
T
ths 已提交
1926

1927 1928
    if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
        return -TARGET_EFAULT;
T
ths 已提交
1929 1930
    host_mb = malloc(msgsz+sizeof(long));
    ret = get_errno(msgrcv(msqid, host_mb, msgsz, 1, msgflg));
1931 1932 1933 1934 1935 1936 1937
    if (ret > 0) {
        abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
        target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
        if (!target_mtext) {
            ret = -TARGET_EFAULT;
            goto end;
        }
T
ths 已提交
1938
    	memcpy(target_mb->mtext, host_mb->mtext, ret);
1939 1940
        unlock_user(target_mtext, target_mtext_addr, ret);
    }
T
ths 已提交
1941 1942 1943
    target_mb->mtype = tswapl(host_mb->mtype);
    free(host_mb);

1944 1945 1946
end:
    if (target_mb)
        unlock_user_struct(target_mb, msgp, 1);
T
ths 已提交
1947 1948 1949
    return ret;
}

1950
/* ??? This only works with linear mappings.  */
1951
/* do_ipc() must return target values and target errnos. */
1952 1953 1954
static abi_long do_ipc(unsigned int call, int first,
                       int second, int third,
                       abi_long ptr, abi_long fifth)
1955 1956
{
    int version;
1957
    abi_long ret = 0;
1958 1959 1960 1961 1962 1963 1964
    struct shmid_ds shm_info;
    int i;

    version = call >> 16;
    call &= 0xffff;

    switch (call) {
1965
    case IPCOP_semop:
1966
        ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second));
1967 1968 1969 1970 1971 1972 1973
        break;

    case IPCOP_semget:
        ret = get_errno(semget(first, second, third));
        break;

    case IPCOP_semctl:
1974
        ret = do_semctl(first, second, third, ptr);
1975 1976 1977
        break;

    case IPCOP_semtimedop:
1978
        gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
1979
        ret = -TARGET_ENOSYS;
1980
        break;
1981 1982 1983 1984 1985 1986

	case IPCOP_msgget:
		ret = get_errno(msgget(first, second));
		break;

	case IPCOP_msgsnd:
T
ths 已提交
1987
		ret = do_msgsnd(first, ptr, second, third);
1988 1989 1990
		break;

	case IPCOP_msgctl:
T
ths 已提交
1991
        	ret = do_msgctl(first, second, ptr);
1992 1993 1994
		break;

	case IPCOP_msgrcv:
T
ths 已提交
1995
                {
1996
                      /* XXX: this code is not correct */
T
ths 已提交
1997 1998 1999 2000 2001
                      struct ipc_kludge
                      {
                              void *__unbounded msgp;
                              long int msgtyp;
                      };
2002

2003
                      struct ipc_kludge *foo = (struct ipc_kludge *)g2h(ptr);
T
ths 已提交
2004
                      struct msgbuf *msgp = (struct msgbuf *) foo->msgp;
2005

T
ths 已提交
2006
                      ret = do_msgrcv(first, (long)msgp, second, 0, third);
2007

T
ths 已提交
2008
                }
2009 2010
		break;

2011
    case IPCOP_shmat:
2012 2013 2014 2015 2016 2017 2018
        {
            abi_ulong raddr;
            void *host_addr;
            /* SHM_* flags are the same on all linux platforms */
            host_addr = shmat(first, (void *)g2h(ptr), second);
            if (host_addr == (void *)-1) {
                ret = get_errno((long)host_addr);
2019
                break;
2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039
            }
            raddr = h2g((unsigned long)host_addr);
            /* find out the length of the shared memory segment */
            
            ret = get_errno(shmctl(first, IPC_STAT, &shm_info));
            if (is_error(ret)) {
                /* can't get length, bail out */
                shmdt(host_addr);
                break;
            }
            page_set_flags(raddr, raddr + shm_info.shm_segsz,
                           PAGE_VALID | PAGE_READ |
                           ((second & SHM_RDONLY)? 0: PAGE_WRITE));
            for (i = 0; i < N_SHM_REGIONS; ++i) {
                if (shm_regions[i].start == 0) {
                    shm_regions[i].start = raddr;
                    shm_regions[i].size = shm_info.shm_segsz;
                    break;
                }
            }
2040
            if (put_user_ual(raddr, third))
2041 2042 2043
                return -TARGET_EFAULT;
            ret = 0;
        }
2044 2045 2046 2047 2048 2049 2050 2051 2052
	break;
    case IPCOP_shmdt:
	for (i = 0; i < N_SHM_REGIONS; ++i) {
	    if (shm_regions[i].start == ptr) {
		shm_regions[i].start = 0;
		page_set_flags(ptr, shm_regions[i].size, 0);
		break;
	    }
	}
2053
	ret = get_errno(shmdt((void *)g2h(ptr)));
2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074
	break;

    case IPCOP_shmget:
	/* IPC_* flag values are the same on all linux platforms */
	ret = get_errno(shmget(first, second, third));
	break;

	/* IPC_* and SHM_* command values are the same on all linux platforms */
    case IPCOP_shmctl:
        switch(second) {
        case IPC_RMID:
        case SHM_LOCK:
        case SHM_UNLOCK:
            ret = get_errno(shmctl(first, second, NULL));
            break;
        default:
            goto unimplemented;
        }
        break;
    default:
    unimplemented:
2075
	gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
2076
	ret = -TARGET_ENOSYS;
2077 2078 2079 2080
	break;
    }
    return ret;
}
2081
#endif
2082

2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100
/* kernel structure types definitions */
#define IFNAMSIZ        16

#define STRUCT(name, list...) STRUCT_ ## name,
#define STRUCT_SPECIAL(name) STRUCT_ ## name,
enum {
#include "syscall_types.h"
};
#undef STRUCT
#undef STRUCT_SPECIAL

#define STRUCT(name, list...) const argtype struct_ ## name ## _def[] = { list, TYPE_NULL };
#define STRUCT_SPECIAL(name)
#include "syscall_types.h"
#undef STRUCT
#undef STRUCT_SPECIAL

typedef struct IOCTLEntry {
2101 2102
    unsigned int target_cmd;
    unsigned int host_cmd;
2103 2104
    const char *name;
    int access;
B
bellard 已提交
2105
    const argtype arg_type[5];
2106 2107 2108 2109 2110 2111 2112 2113
} IOCTLEntry;

#define IOC_R 0x0001
#define IOC_W 0x0002
#define IOC_RW (IOC_R | IOC_W)

#define MAX_STRUCT_SIZE 4096

2114
IOCTLEntry ioctl_entries[] = {
2115 2116 2117 2118 2119 2120
#define IOCTL(cmd, access, types...) \
    { TARGET_ ## cmd, cmd, #cmd, access, { types } },
#include "ioctls.h"
    { 0, 0, },
};

2121
/* ??? Implement proper locking for ioctls.  */
2122
/* do_ioctl() Must return target values and target errnos. */
2123
static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
2124 2125 2126
{
    const IOCTLEntry *ie;
    const argtype *arg_type;
2127
    abi_long ret;
2128
    uint8_t buf_temp[MAX_STRUCT_SIZE];
2129 2130
    int target_size;
    void *argptr;
2131 2132 2133 2134

    ie = ioctl_entries;
    for(;;) {
        if (ie->target_cmd == 0) {
2135
            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
2136
            return -TARGET_ENOSYS;
2137 2138 2139 2140 2141 2142
        }
        if (ie->target_cmd == cmd)
            break;
        ie++;
    }
    arg_type = ie->arg_type;
B
bellard 已提交
2143
#if defined(DEBUG)
2144
    gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
B
bellard 已提交
2145
#endif
2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157
    switch(arg_type[0]) {
    case TYPE_NULL:
        /* no argument */
        ret = get_errno(ioctl(fd, ie->host_cmd));
        break;
    case TYPE_PTRVOID:
    case TYPE_INT:
        /* int argment */
        ret = get_errno(ioctl(fd, ie->host_cmd, arg));
        break;
    case TYPE_PTR:
        arg_type++;
2158
        target_size = thunk_type_size(arg_type, 0);
2159 2160 2161 2162
        switch(ie->access) {
        case IOC_R:
            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
            if (!is_error(ret)) {
2163 2164 2165
                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
                if (!argptr)
                    return -TARGET_EFAULT;
2166 2167
                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
                unlock_user(argptr, arg, target_size);
2168 2169 2170
            }
            break;
        case IOC_W:
2171 2172 2173
            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
            if (!argptr)
                return -TARGET_EFAULT;
2174 2175
            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
            unlock_user(argptr, arg, 0);
2176 2177 2178 2179
            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
            break;
        default:
        case IOC_RW:
2180 2181 2182
            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
            if (!argptr)
                return -TARGET_EFAULT;
2183 2184
            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
            unlock_user(argptr, arg, 0);
2185 2186
            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
            if (!is_error(ret)) {
2187 2188 2189
                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
                if (!argptr)
                    return -TARGET_EFAULT;
2190 2191
                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
                unlock_user(argptr, arg, target_size);
2192 2193 2194 2195 2196
            }
            break;
        }
        break;
    default:
2197 2198
        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
                 (long)cmd, arg_type[0]);
2199
        ret = -TARGET_ENOSYS;
2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308
        break;
    }
    return ret;
}

bitmask_transtbl iflag_tbl[] = {
        { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
        { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
        { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
        { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
        { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
        { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
        { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
        { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
        { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
        { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
        { TARGET_IXON, TARGET_IXON, IXON, IXON },
        { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
        { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
        { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
        { 0, 0, 0, 0 }
};

bitmask_transtbl oflag_tbl[] = {
	{ TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
	{ TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
	{ TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
	{ TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
	{ TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
	{ TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
	{ TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
	{ TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
	{ TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
	{ TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
	{ TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
	{ TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
	{ TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
	{ TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
	{ TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
	{ TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
	{ TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
	{ TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
	{ TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
	{ TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
	{ TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
	{ TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
	{ TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
	{ TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
	{ 0, 0, 0, 0 }
};

bitmask_transtbl cflag_tbl[] = {
	{ TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
	{ TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
	{ TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
	{ TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
	{ TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
	{ TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
	{ TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
	{ TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
	{ TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
	{ TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
	{ TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
	{ TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
	{ TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
	{ TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
	{ TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
	{ TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
	{ TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
	{ TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
	{ TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
	{ TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
	{ TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
	{ TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
	{ TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
	{ TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
	{ TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
	{ TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
	{ TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
	{ TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
	{ TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
	{ TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
	{ TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
	{ 0, 0, 0, 0 }
};

bitmask_transtbl lflag_tbl[] = {
	{ TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
	{ TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
	{ TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
	{ TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
	{ TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
	{ TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
	{ TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
	{ TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
	{ TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
	{ TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
	{ TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
	{ TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
	{ TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
	{ TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
	{ TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
	{ 0, 0, 0, 0 }
};

static void target_to_host_termios (void *dst, const void *src)
{
    struct host_termios *host = dst;
    const struct target_termios *target = src;
2309

2310
    host->c_iflag =
2311
        target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
2312
    host->c_oflag =
2313
        target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
2314
    host->c_cflag =
2315
        target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
2316
    host->c_lflag =
2317 2318
        target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
    host->c_line = target->c_line;
2319

2320 2321
    host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
    host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
2322
    host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
2323
    host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
2324
    host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
2325
    host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
2326
    host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
2327
    host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
2328
    host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
2329 2330
    host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
    host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
2331 2332 2333 2334 2335
    host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
    host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
    host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
    host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
    host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
2336
    host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
2337
}
2338

2339 2340 2341 2342 2343
static void host_to_target_termios (void *dst, const void *src)
{
    struct target_termios *target = dst;
    const struct host_termios *host = src;

2344
    target->c_iflag =
2345
        tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
2346
    target->c_oflag =
2347
        tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
2348
    target->c_cflag =
2349
        tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
2350
    target->c_lflag =
2351 2352
        tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
    target->c_line = host->c_line;
2353

2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378
    target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
    target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
    target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
    target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
    target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
    target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
    target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
    target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
    target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
    target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
    target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
    target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
    target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
    target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
    target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
    target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
    target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
}

StructEntry struct_termios_def = {
    .convert = { host_to_target_termios, target_to_host_termios },
    .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
    .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
};

B
bellard 已提交
2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390
static bitmask_transtbl mmap_flags_tbl[] = {
	{ TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
	{ TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
	{ TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
	{ TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
	{ TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
	{ TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
	{ TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
	{ TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
	{ 0, 0, 0, 0 }
};

B
bellard 已提交
2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404
static bitmask_transtbl fcntl_flags_tbl[] = {
	{ TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
	{ TARGET_O_ACCMODE,   TARGET_O_RDWR,      O_ACCMODE,   O_RDWR,      },
	{ TARGET_O_CREAT,     TARGET_O_CREAT,     O_CREAT,     O_CREAT,     },
	{ TARGET_O_EXCL,      TARGET_O_EXCL,      O_EXCL,      O_EXCL,      },
	{ TARGET_O_NOCTTY,    TARGET_O_NOCTTY,    O_NOCTTY,    O_NOCTTY,    },
	{ TARGET_O_TRUNC,     TARGET_O_TRUNC,     O_TRUNC,     O_TRUNC,     },
	{ TARGET_O_APPEND,    TARGET_O_APPEND,    O_APPEND,    O_APPEND,    },
	{ TARGET_O_NONBLOCK,  TARGET_O_NONBLOCK,  O_NONBLOCK,  O_NONBLOCK,  },
	{ TARGET_O_SYNC,      TARGET_O_SYNC,      O_SYNC,      O_SYNC,      },
	{ TARGET_FASYNC,      TARGET_FASYNC,      FASYNC,      FASYNC,      },
	{ TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
	{ TARGET_O_NOFOLLOW,  TARGET_O_NOFOLLOW,  O_NOFOLLOW,  O_NOFOLLOW,  },
	{ TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
B
bellard 已提交
2405
#if defined(O_DIRECT)
B
bellard 已提交
2406
	{ TARGET_O_DIRECT,    TARGET_O_DIRECT,    O_DIRECT,    O_DIRECT,    },
B
bellard 已提交
2407
#endif
B
bellard 已提交
2408 2409 2410
	{ 0, 0, 0, 0 }
};

2411
#if defined(TARGET_I386)
B
bellard 已提交
2412 2413 2414 2415

/* NOTE: there is really one LDT for all the threads */
uint8_t *ldt_table;

2416
static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
B
bellard 已提交
2417 2418
{
    int size;
2419
    void *p;
B
bellard 已提交
2420 2421 2422 2423 2424 2425

    if (!ldt_table)
        return 0;
    size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
    if (size > bytecount)
        size = bytecount;
2426 2427
    p = lock_user(VERIFY_WRITE, ptr, size, 0);
    if (!p)
2428
        return -TARGET_EFAULT;
2429
    /* ??? Should this by byteswapped?  */
2430 2431
    memcpy(p, ldt_table, size);
    unlock_user(p, ptr, size);
B
bellard 已提交
2432 2433 2434 2435
    return size;
}

/* XXX: add locking support */
2436 2437
static abi_long write_ldt(CPUX86State *env,
                          abi_ulong ptr, unsigned long bytecount, int oldmode)
B
bellard 已提交
2438 2439
{
    struct target_modify_ldt_ldt_s ldt_info;
2440
    struct target_modify_ldt_ldt_s *target_ldt_info;
B
bellard 已提交
2441
    int seg_32bit, contents, read_exec_only, limit_in_pages;
B
bellard 已提交
2442
    int seg_not_present, useable, lm;
B
bellard 已提交
2443 2444 2445
    uint32_t *lp, entry_1, entry_2;

    if (bytecount != sizeof(ldt_info))
2446
        return -TARGET_EINVAL;
2447
    if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
2448
        return -TARGET_EFAULT;
2449 2450 2451 2452 2453
    ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
    ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
    ldt_info.limit = tswap32(target_ldt_info->limit);
    ldt_info.flags = tswap32(target_ldt_info->flags);
    unlock_user_struct(target_ldt_info, ptr, 0);
2454

B
bellard 已提交
2455
    if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
2456
        return -TARGET_EINVAL;
B
bellard 已提交
2457 2458 2459 2460 2461 2462
    seg_32bit = ldt_info.flags & 1;
    contents = (ldt_info.flags >> 1) & 3;
    read_exec_only = (ldt_info.flags >> 3) & 1;
    limit_in_pages = (ldt_info.flags >> 4) & 1;
    seg_not_present = (ldt_info.flags >> 5) & 1;
    useable = (ldt_info.flags >> 6) & 1;
B
bellard 已提交
2463 2464 2465 2466 2467
#ifdef TARGET_ABI32
    lm = 0;
#else
    lm = (ldt_info.flags >> 7) & 1;
#endif
B
bellard 已提交
2468 2469
    if (contents == 3) {
        if (oldmode)
2470
            return -TARGET_EINVAL;
B
bellard 已提交
2471
        if (seg_not_present == 0)
2472
            return -TARGET_EINVAL;
B
bellard 已提交
2473 2474 2475 2476 2477
    }
    /* allocate the LDT */
    if (!ldt_table) {
        ldt_table = malloc(TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
        if (!ldt_table)
2478
            return -TARGET_ENOMEM;
B
bellard 已提交
2479
        memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
B
bellard 已提交
2480
        env->ldt.base = h2g((unsigned long)ldt_table);
B
bellard 已提交
2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498
        env->ldt.limit = 0xffff;
    }

    /* NOTE: same code as Linux kernel */
    /* Allow LDTs to be cleared by the user. */
    if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
        if (oldmode ||
            (contents == 0		&&
             read_exec_only == 1	&&
             seg_32bit == 0		&&
             limit_in_pages == 0	&&
             seg_not_present == 1	&&
             useable == 0 )) {
            entry_1 = 0;
            entry_2 = 0;
            goto install;
        }
    }
2499

B
bellard 已提交
2500 2501 2502 2503 2504 2505 2506 2507 2508 2509
    entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
        (ldt_info.limit & 0x0ffff);
    entry_2 = (ldt_info.base_addr & 0xff000000) |
        ((ldt_info.base_addr & 0x00ff0000) >> 16) |
        (ldt_info.limit & 0xf0000) |
        ((read_exec_only ^ 1) << 9) |
        (contents << 10) |
        ((seg_not_present ^ 1) << 15) |
        (seg_32bit << 22) |
        (limit_in_pages << 23) |
B
bellard 已提交
2510
        (lm << 21) |
B
bellard 已提交
2511 2512 2513
        0x7000;
    if (!oldmode)
        entry_2 |= (useable << 20);
B
bellard 已提交
2514

B
bellard 已提交
2515 2516 2517 2518 2519 2520 2521 2522 2523
    /* Install the new entry ...  */
install:
    lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
    lp[0] = tswap32(entry_1);
    lp[1] = tswap32(entry_2);
    return 0;
}

/* specific and weird i386 syscalls */
2524 2525
abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr, 
                       unsigned long bytecount)
B
bellard 已提交
2526
{
2527
    abi_long ret;
2528

B
bellard 已提交
2529 2530 2531 2532 2533 2534 2535 2536 2537 2538
    switch (func) {
    case 0:
        ret = read_ldt(ptr, bytecount);
        break;
    case 1:
        ret = write_ldt(env, ptr, bytecount, 1);
        break;
    case 0x11:
        ret = write_ldt(env, ptr, bytecount, 0);
        break;
2539 2540 2541
    default:
        ret = -TARGET_ENOSYS;
        break;
B
bellard 已提交
2542 2543 2544
    }
    return ret;
}
B
bellard 已提交
2545

B
bellard 已提交
2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677
abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
{
    uint64_t *gdt_table = g2h(env->gdt.base);
    struct target_modify_ldt_ldt_s ldt_info;
    struct target_modify_ldt_ldt_s *target_ldt_info;
    int seg_32bit, contents, read_exec_only, limit_in_pages;
    int seg_not_present, useable, lm;
    uint32_t *lp, entry_1, entry_2;
    int i;

    lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
    if (!target_ldt_info)
        return -TARGET_EFAULT;
    ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
    ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
    ldt_info.limit = tswap32(target_ldt_info->limit);
    ldt_info.flags = tswap32(target_ldt_info->flags);
    if (ldt_info.entry_number == -1) {
        for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
            if (gdt_table[i] == 0) {
                ldt_info.entry_number = i;
                target_ldt_info->entry_number = tswap32(i);
                break;
            }
        }
    }
    unlock_user_struct(target_ldt_info, ptr, 1);

    if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN || 
        ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
           return -TARGET_EINVAL;
    seg_32bit = ldt_info.flags & 1;
    contents = (ldt_info.flags >> 1) & 3;
    read_exec_only = (ldt_info.flags >> 3) & 1;
    limit_in_pages = (ldt_info.flags >> 4) & 1;
    seg_not_present = (ldt_info.flags >> 5) & 1;
    useable = (ldt_info.flags >> 6) & 1;
#ifdef TARGET_ABI32
    lm = 0;
#else
    lm = (ldt_info.flags >> 7) & 1;
#endif

    if (contents == 3) {
        if (seg_not_present == 0)
            return -TARGET_EINVAL;
    }

    /* NOTE: same code as Linux kernel */
    /* Allow LDTs to be cleared by the user. */
    if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
        if ((contents == 0             &&
             read_exec_only == 1       &&
             seg_32bit == 0            &&
             limit_in_pages == 0       &&
             seg_not_present == 1      &&
             useable == 0 )) {
            entry_1 = 0;
            entry_2 = 0;
            goto install;
        }
    }

    entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
        (ldt_info.limit & 0x0ffff);
    entry_2 = (ldt_info.base_addr & 0xff000000) |
        ((ldt_info.base_addr & 0x00ff0000) >> 16) |
        (ldt_info.limit & 0xf0000) |
        ((read_exec_only ^ 1) << 9) |
        (contents << 10) |
        ((seg_not_present ^ 1) << 15) |
        (seg_32bit << 22) |
        (limit_in_pages << 23) |
        (useable << 20) |
        (lm << 21) |
        0x7000;

    /* Install the new entry ...  */
install:
    lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
    lp[0] = tswap32(entry_1);
    lp[1] = tswap32(entry_2);
    return 0;
}

abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
{
    struct target_modify_ldt_ldt_s *target_ldt_info;
    uint64_t *gdt_table = g2h(env->gdt.base);
    uint32_t base_addr, limit, flags;
    int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
    int seg_not_present, useable, lm;
    uint32_t *lp, entry_1, entry_2;

    lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
    if (!target_ldt_info)
        return -TARGET_EFAULT;
    idx = tswap32(target_ldt_info->entry_number);
    if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
        idx > TARGET_GDT_ENTRY_TLS_MAX) {
        unlock_user_struct(target_ldt_info, ptr, 1);
        return -TARGET_EINVAL;
    }
    lp = (uint32_t *)(gdt_table + idx);
    entry_1 = tswap32(lp[0]);
    entry_2 = tswap32(lp[1]);
    
    read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
    contents = (entry_2 >> 10) & 3;
    seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
    seg_32bit = (entry_2 >> 22) & 1;
    limit_in_pages = (entry_2 >> 23) & 1;
    useable = (entry_2 >> 20) & 1;
#ifdef TARGET_ABI32
    lm = 0;
#else
    lm = (entry_2 >> 21) & 1;
#endif
    flags = (seg_32bit << 0) | (contents << 1) |
        (read_exec_only << 3) | (limit_in_pages << 4) |
        (seg_not_present << 5) | (useable << 6) | (lm << 7);
    limit = (entry_1 & 0xffff) | (entry_2  & 0xf0000);
    base_addr = (entry_1 >> 16) | 
        (entry_2 & 0xff000000) | 
        ((entry_2 & 0xff) << 16);
    target_ldt_info->base_addr = tswapl(base_addr);
    target_ldt_info->limit = tswap32(limit);
    target_ldt_info->flags = tswap32(flags);
    unlock_user_struct(target_ldt_info, ptr, 1);
    return 0;
}

B
bellard 已提交
2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712
#ifndef TARGET_ABI32
abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
{
    abi_long ret;
    abi_ulong val;
    int idx;
    
    switch(code) {
    case TARGET_ARCH_SET_GS:
    case TARGET_ARCH_SET_FS:
        if (code == TARGET_ARCH_SET_GS)
            idx = R_GS;
        else
            idx = R_FS;
        cpu_x86_load_seg(env, idx, 0);
        env->segs[idx].base = addr;
        break;
    case TARGET_ARCH_GET_GS:
    case TARGET_ARCH_GET_FS:
        if (code == TARGET_ARCH_GET_GS)
            idx = R_GS;
        else
            idx = R_FS;
        val = env->segs[idx].base;
        if (put_user(val, addr, abi_ulong))
            return -TARGET_EFAULT;
        break;
    default:
        ret = -TARGET_EINVAL;
        break;
    }
    return 0;
}
#endif

2713 2714
#endif /* defined(TARGET_I386) */

P
pbrook 已提交
2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756
#if defined(USE_NPTL)

#define NEW_STACK_SIZE PTHREAD_STACK_MIN

static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
typedef struct {
    CPUState *env;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    pthread_t thread;
    uint32_t tid;
    abi_ulong child_tidptr;
    abi_ulong parent_tidptr;
    sigset_t sigmask;
} new_thread_info;

static void *clone_func(void *arg)
{
    new_thread_info *info = arg;
    CPUState *env;

    env = info->env;
    thread_env = env;
    info->tid = gettid();
    if (info->child_tidptr)
        put_user_u32(info->tid, info->child_tidptr);
    if (info->parent_tidptr)
        put_user_u32(info->tid, info->parent_tidptr);
    /* Enable signals.  */
    sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
    /* Signal to the parent that we're ready.  */
    pthread_mutex_lock(&info->mutex);
    pthread_cond_broadcast(&info->cond);
    pthread_mutex_unlock(&info->mutex);
    /* Wait until the parent has finshed initializing the tls state.  */
    pthread_mutex_lock(&clone_lock);
    pthread_mutex_unlock(&clone_lock);
    cpu_loop(env);
    /* never exits */
    return NULL;
}
#else
B
bellard 已提交
2757 2758 2759 2760 2761 2762
/* this stack is the equivalent of the kernel stack associated with a
   thread/process */
#define NEW_STACK_SIZE 8192

static int clone_func(void *arg)
{
2763
    CPUState *env = arg;
B
bellard 已提交
2764 2765 2766 2767
    cpu_loop(env);
    /* never exits */
    return 0;
}
P
pbrook 已提交
2768
#endif
B
bellard 已提交
2769

2770 2771
/* do_fork() Must return host values and target errnos (unlike most
   do_*() functions). */
P
pbrook 已提交
2772 2773 2774
static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
                   abi_ulong parent_tidptr, target_ulong newtls,
                   abi_ulong child_tidptr)
B
bellard 已提交
2775 2776
{
    int ret;
B
bellard 已提交
2777
    TaskState *ts;
B
bellard 已提交
2778
    uint8_t *new_stack;
2779
    CPUState *new_env;
P
pbrook 已提交
2780 2781 2782 2783
#if defined(USE_NPTL)
    unsigned int nptl_flags;
    sigset_t sigmask;
#endif
2784

B
bellard 已提交
2785
    if (flags & CLONE_VM) {
2786
#if defined(USE_NPTL)
P
pbrook 已提交
2787 2788
        new_thread_info info;
        pthread_attr_t attr;
2789
#endif
2790
        ts = qemu_mallocz(sizeof(TaskState) + NEW_STACK_SIZE);
P
pbrook 已提交
2791
        init_task_state(ts);
B
bellard 已提交
2792
        new_stack = ts->stack;
B
bellard 已提交
2793
        /* we create a new CPU instance. */
2794
        new_env = cpu_copy(env);
2795 2796
        /* Init regs that differ from the parent.  */
        cpu_clone_regs(new_env, newsp);
B
bellard 已提交
2797
        new_env->opaque = ts;
P
pbrook 已提交
2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846
#if defined(USE_NPTL)
        nptl_flags = flags;
        flags &= ~CLONE_NPTL_FLAGS2;

        /* TODO: Implement CLONE_CHILD_CLEARTID.  */
        if (nptl_flags & CLONE_SETTLS)
            cpu_set_tls (new_env, newtls);

        /* Grab a mutex so that thread setup appears atomic.  */
        pthread_mutex_lock(&clone_lock);

        memset(&info, 0, sizeof(info));
        pthread_mutex_init(&info.mutex, NULL);
        pthread_mutex_lock(&info.mutex);
        pthread_cond_init(&info.cond, NULL);
        info.env = new_env;
        if (nptl_flags & CLONE_CHILD_SETTID)
            info.child_tidptr = child_tidptr;
        if (nptl_flags & CLONE_PARENT_SETTID)
            info.parent_tidptr = parent_tidptr;

        ret = pthread_attr_init(&attr);
        ret = pthread_attr_setstack(&attr, new_stack, NEW_STACK_SIZE);
        /* It is not safe to deliver signals until the child has finished
           initializing, so temporarily block all signals.  */
        sigfillset(&sigmask);
        sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);

        ret = pthread_create(&info.thread, &attr, clone_func, &info);

        sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
        pthread_attr_destroy(&attr);
        if (ret == 0) {
            /* Wait for the child to initialize.  */
            pthread_cond_wait(&info.cond, &info.mutex);
            ret = info.tid;
            if (flags & CLONE_PARENT_SETTID)
                put_user_u32(ret, parent_tidptr);
        } else {
            ret = -1;
        }
        pthread_mutex_unlock(&info.mutex);
        pthread_cond_destroy(&info.cond);
        pthread_mutex_destroy(&info.mutex);
        pthread_mutex_unlock(&clone_lock);
#else
        if (flags & CLONE_NPTL_FLAGS2)
            return -EINVAL;
        /* This is probably going to die very quickly, but do it anyway.  */
2847
#ifdef __ia64__
B
bellard 已提交
2848
        ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
2849 2850
#else
	ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
P
pbrook 已提交
2851
#endif
2852
#endif
B
bellard 已提交
2853 2854
    } else {
        /* if no CLONE_VM, we consider it is a fork */
P
pbrook 已提交
2855
        if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
B
bellard 已提交
2856
            return -EINVAL;
P
pbrook 已提交
2857
        fork_start();
B
bellard 已提交
2858
        ret = fork();
P
pbrook 已提交
2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881
#if defined(USE_NPTL)
        /* There is a race condition here.  The parent process could
           theoretically read the TID in the child process before the child
           tid is set.  This would require using either ptrace
           (not implemented) or having *_tidptr to point at a shared memory
           mapping.  We can't repeat the spinlock hack used above because
           the child process gets its own copy of the lock.  */
        if (ret == 0) {
            cpu_clone_regs(env, newsp);
            fork_end(1);
            /* Child Process.  */
            if (flags & CLONE_CHILD_SETTID)
                put_user_u32(gettid(), child_tidptr);
            if (flags & CLONE_PARENT_SETTID)
                put_user_u32(gettid(), parent_tidptr);
            ts = (TaskState *)env->opaque;
            if (flags & CLONE_SETTLS)
                cpu_set_tls (env, newtls);
            /* TODO: Implement CLONE_CHILD_CLEARTID.  */
        } else {
            fork_end(0);
        }
#else
2882 2883 2884
        if (ret == 0) {
            cpu_clone_regs(env, newsp);
        }
P
pbrook 已提交
2885
#endif
B
bellard 已提交
2886 2887 2888 2889
    }
    return ret;
}

2890
static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
B
bellard 已提交
2891 2892
{
    struct flock fl;
2893
    struct target_flock *target_fl;
2894 2895
    struct flock64 fl64;
    struct target_flock64 *target_fl64;
2896
    abi_long ret;
2897

B
bellard 已提交
2898 2899
    switch(cmd) {
    case TARGET_F_GETLK:
2900 2901
        if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
            return -TARGET_EFAULT;
T
ths 已提交
2902 2903 2904 2905 2906 2907
        fl.l_type = tswap16(target_fl->l_type);
        fl.l_whence = tswap16(target_fl->l_whence);
        fl.l_start = tswapl(target_fl->l_start);
        fl.l_len = tswapl(target_fl->l_len);
        fl.l_pid = tswapl(target_fl->l_pid);
        unlock_user_struct(target_fl, arg, 0);
B
bellard 已提交
2908
        ret = get_errno(fcntl(fd, cmd, &fl));
B
bellard 已提交
2909
        if (ret == 0) {
2910 2911
            if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
                return -TARGET_EFAULT;
B
bellard 已提交
2912 2913 2914 2915 2916
            target_fl->l_type = tswap16(fl.l_type);
            target_fl->l_whence = tswap16(fl.l_whence);
            target_fl->l_start = tswapl(fl.l_start);
            target_fl->l_len = tswapl(fl.l_len);
            target_fl->l_pid = tswapl(fl.l_pid);
2917
            unlock_user_struct(target_fl, arg, 1);
B
bellard 已提交
2918 2919
        }
        break;
2920

B
bellard 已提交
2921 2922
    case TARGET_F_SETLK:
    case TARGET_F_SETLKW:
2923 2924
        if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
            return -TARGET_EFAULT;
B
bellard 已提交
2925 2926 2927 2928 2929
        fl.l_type = tswap16(target_fl->l_type);
        fl.l_whence = tswap16(target_fl->l_whence);
        fl.l_start = tswapl(target_fl->l_start);
        fl.l_len = tswapl(target_fl->l_len);
        fl.l_pid = tswapl(target_fl->l_pid);
2930
        unlock_user_struct(target_fl, arg, 0);
B
bellard 已提交
2931
        ret = get_errno(fcntl(fd, cmd, &fl));
B
bellard 已提交
2932
        break;
2933

B
bellard 已提交
2934
    case TARGET_F_GETLK64:
2935 2936
        if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
            return -TARGET_EFAULT;
T
ths 已提交
2937 2938 2939 2940 2941 2942
        fl64.l_type = tswap16(target_fl64->l_type) >> 1;
        fl64.l_whence = tswap16(target_fl64->l_whence);
        fl64.l_start = tswapl(target_fl64->l_start);
        fl64.l_len = tswapl(target_fl64->l_len);
        fl64.l_pid = tswap16(target_fl64->l_pid);
        unlock_user_struct(target_fl64, arg, 0);
B
bellard 已提交
2943
        ret = get_errno(fcntl(fd, cmd >> 1, &fl64));
2944
        if (ret == 0) {
2945 2946
            if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
                return -TARGET_EFAULT;
2947 2948 2949 2950 2951 2952 2953
            target_fl64->l_type = tswap16(fl64.l_type) >> 1;
            target_fl64->l_whence = tswap16(fl64.l_whence);
            target_fl64->l_start = tswapl(fl64.l_start);
            target_fl64->l_len = tswapl(fl64.l_len);
            target_fl64->l_pid = tswapl(fl64.l_pid);
            unlock_user_struct(target_fl64, arg, 1);
        }
B
bellard 已提交
2954
        break;
B
bellard 已提交
2955 2956
    case TARGET_F_SETLK64:
    case TARGET_F_SETLKW64:
2957 2958
        if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
            return -TARGET_EFAULT;
2959 2960 2961 2962 2963 2964
        fl64.l_type = tswap16(target_fl64->l_type) >> 1;
        fl64.l_whence = tswap16(target_fl64->l_whence);
        fl64.l_start = tswapl(target_fl64->l_start);
        fl64.l_len = tswapl(target_fl64->l_len);
        fl64.l_pid = tswap16(target_fl64->l_pid);
        unlock_user_struct(target_fl64, arg, 0);
B
bellard 已提交
2965
        ret = get_errno(fcntl(fd, cmd >> 1, &fl64));
B
bellard 已提交
2966 2967
        break;

B
bellard 已提交
2968
    case F_GETFL:
B
bellard 已提交
2969 2970 2971 2972
        ret = get_errno(fcntl(fd, cmd, arg));
        if (ret >= 0) {
            ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
        }
B
bellard 已提交
2973 2974 2975
        break;

    case F_SETFL:
B
bellard 已提交
2976
        ret = get_errno(fcntl(fd, cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
B
bellard 已提交
2977 2978
        break;

B
bellard 已提交
2979
    default:
B
bellard 已提交
2980
        ret = get_errno(fcntl(fd, cmd, arg));
B
bellard 已提交
2981 2982 2983 2984 2985
        break;
    }
    return ret;
}

2986
#ifdef USE_UID16
B
bellard 已提交
2987

2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020
static inline int high2lowuid(int uid)
{
    if (uid > 65535)
        return 65534;
    else
        return uid;
}

static inline int high2lowgid(int gid)
{
    if (gid > 65535)
        return 65534;
    else
        return gid;
}

static inline int low2highuid(int uid)
{
    if ((int16_t)uid == -1)
        return -1;
    else
        return uid;
}

static inline int low2highgid(int gid)
{
    if ((int16_t)gid == -1)
        return -1;
    else
        return gid;
}

#endif /* USE_UID16 */
B
bellard 已提交
3021

3022 3023
void syscall_init(void)
{
3024 3025 3026
    IOCTLEntry *ie;
    const argtype *arg_type;
    int size;
3027
    int i;
3028

3029 3030
#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
3031 3032 3033
#include "syscall_types.h"
#undef STRUCT
#undef STRUCT_SPECIAL
3034 3035 3036 3037 3038 3039 3040 3041 3042

    /* we patch the ioctl size if necessary. We rely on the fact that
       no ioctl has all the bits at '1' in the size field */
    ie = ioctl_entries;
    while (ie->target_cmd != 0) {
        if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
            TARGET_IOC_SIZEMASK) {
            arg_type = ie->arg_type;
            if (arg_type[0] != TYPE_PTR) {
3043
                fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
3044 3045 3046 3047 3048
                        ie->target_cmd);
                exit(1);
            }
            arg_type++;
            size = thunk_type_size(arg_type, 0);
3049
            ie->target_cmd = (ie->target_cmd &
3050 3051 3052
                              ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
                (size << TARGET_IOC_SIZESHIFT);
        }
3053 3054 3055 3056 3057 3058

        /* Build target_to_host_errno_table[] table from
         * host_to_target_errno_table[]. */
        for (i=0; i < ERRNO_TABLE_SIZE; i++)
                target_to_host_errno_table[host_to_target_errno_table[i]] = i;

3059
        /* automatic consistency check if same arch */
B
bellard 已提交
3060
#if defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)
3061
        if (ie->target_cmd != ie->host_cmd) {
3062
            fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n",
3063 3064 3065 3066 3067
                    ie->target_cmd, ie->host_cmd);
        }
#endif
        ie++;
    }
3068
}
B
bellard 已提交
3069

3070
#if TARGET_ABI_BITS == 32
P
pbrook 已提交
3071 3072
static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
{
T
ths 已提交
3073
#ifdef TARGET_WORDS_BIGENDIAN
P
pbrook 已提交
3074 3075 3076 3077 3078
    return ((uint64_t)word0 << 32) | word1;
#else
    return ((uint64_t)word1 << 32) | word0;
#endif
}
3079
#else /* TARGET_ABI_BITS == 32 */
3080 3081 3082 3083
static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
{
    return word0;
}
3084
#endif /* TARGET_ABI_BITS != 32 */
P
pbrook 已提交
3085 3086

#ifdef TARGET_NR_truncate64
3087 3088 3089 3090
static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
                                         abi_long arg2,
                                         abi_long arg3,
                                         abi_long arg4)
P
pbrook 已提交
3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103
{
#ifdef TARGET_ARM
    if (((CPUARMState *)cpu_env)->eabi)
      {
        arg2 = arg3;
        arg3 = arg4;
      }
#endif
    return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
}
#endif

#ifdef TARGET_NR_ftruncate64
3104 3105 3106 3107
static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
                                          abi_long arg2,
                                          abi_long arg3,
                                          abi_long arg4)
P
pbrook 已提交
3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119
{
#ifdef TARGET_ARM
    if (((CPUARMState *)cpu_env)->eabi)
      {
        arg2 = arg3;
        arg3 = arg4;
      }
#endif
    return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
}
#endif

3120 3121
static inline abi_long target_to_host_timespec(struct timespec *host_ts,
                                               abi_ulong target_addr)
3122 3123 3124
{
    struct target_timespec *target_ts;

3125 3126
    if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
        return -TARGET_EFAULT;
3127 3128 3129
    host_ts->tv_sec = tswapl(target_ts->tv_sec);
    host_ts->tv_nsec = tswapl(target_ts->tv_nsec);
    unlock_user_struct(target_ts, target_addr, 0);
B
bellard 已提交
3130
    return 0;
3131 3132
}

3133 3134
static inline abi_long host_to_target_timespec(abi_ulong target_addr,
                                               struct timespec *host_ts)
3135 3136 3137
{
    struct target_timespec *target_ts;

3138 3139
    if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
        return -TARGET_EFAULT;
3140 3141 3142
    target_ts->tv_sec = tswapl(host_ts->tv_sec);
    target_ts->tv_nsec = tswapl(host_ts->tv_nsec);
    unlock_user_struct(target_ts, target_addr, 1);
B
bellard 已提交
3143
    return 0;
3144 3145
}

3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184
#if defined(USE_NPTL)
/* ??? Using host futex calls even when target atomic operations
   are not really atomic probably breaks things.  However implementing
   futexes locally would make futexes shared between multiple processes
   tricky.  However they're probably useless because guest atomic
   operations won't work either.  */
int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
             target_ulong uaddr2, int val3)
{
    struct timespec ts, *pts;

    /* ??? We assume FUTEX_* constants are the same on both host
       and target.  */
    switch (op) {
    case FUTEX_WAIT:
        if (timeout) {
            pts = &ts;
            target_to_host_timespec(pts, timeout);
        } else {
            pts = NULL;
        }
        return get_errno(sys_futex(g2h(uaddr), FUTEX_WAIT, tswap32(val),
                         pts, NULL, 0));
    case FUTEX_WAKE:
        return get_errno(sys_futex(g2h(uaddr), FUTEX_WAKE, val, NULL, NULL, 0));
    case FUTEX_FD:
        return get_errno(sys_futex(g2h(uaddr), FUTEX_FD, val, NULL, NULL, 0));
    case FUTEX_REQUEUE:
        return get_errno(sys_futex(g2h(uaddr), FUTEX_REQUEUE, val,
                         NULL, g2h(uaddr2), 0));
    case FUTEX_CMP_REQUEUE:
        return get_errno(sys_futex(g2h(uaddr), FUTEX_CMP_REQUEUE, val,
                         NULL, g2h(uaddr2), tswap32(val3)));
    default:
        return -TARGET_ENOSYS;
    }
}
#endif

P
pbrook 已提交
3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215
int get_osversion(void)
{
    static int osversion;
    struct new_utsname buf;
    const char *s;
    int i, n, tmp;
    if (osversion)
        return osversion;
    if (qemu_uname_release && *qemu_uname_release) {
        s = qemu_uname_release;
    } else {
        if (sys_uname(&buf))
            return 0;
        s = buf.release;
    }
    tmp = 0;
    for (i = 0; i < 3; i++) {
        n = 0;
        while (*s >= '0' && *s <= '9') {
            n *= 10;
            n += *s - '0';
            s++;
        }
        tmp = (tmp << 8) + n;
        if (*s == '.')
            s++;
    }
    osversion = tmp;
    return osversion;
}

3216 3217 3218
/* do_syscall() should always have a single exit point at the end so
   that actions, such as logging of syscall results, can be performed.
   All errnos that do_syscall() returns must be -TARGET_<errcode>. */
3219 3220 3221
abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                    abi_long arg2, abi_long arg3, abi_long arg4,
                    abi_long arg5, abi_long arg6)
3222
{
3223
    abi_long ret;
3224
    struct stat st;
B
bellard 已提交
3225
    struct statfs stfs;
3226
    void *p;
3227

B
bellard 已提交
3228
#ifdef DEBUG
B
bellard 已提交
3229
    gemu_log("syscall %d", num);
B
bellard 已提交
3230
#endif
3231 3232 3233
    if(do_strace)
        print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);

3234 3235
    switch(num) {
    case TARGET_NR_exit:
B
bellard 已提交
3236 3237 3238
#ifdef HAVE_GPROF
        _mcleanup();
#endif
3239
        gdb_exit(cpu_env, arg1);
B
bellard 已提交
3240
        /* XXX: should free thread stack and CPU env */
3241 3242 3243 3244
        _exit(arg1);
        ret = 0; /* avoid warning */
        break;
    case TARGET_NR_read:
3245 3246
        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
            goto efault;
3247 3248
        ret = get_errno(read(arg1, p, arg3));
        unlock_user(p, arg2, ret);
3249 3250
        break;
    case TARGET_NR_write:
3251 3252
        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
            goto efault;
3253 3254
        ret = get_errno(write(arg1, p, arg3));
        unlock_user(p, arg2, 0);
3255 3256
        break;
    case TARGET_NR_open:
3257 3258
        if (!(p = lock_user_string(arg1)))
            goto efault;
3259
        ret = get_errno(open(path(p),
B
bellard 已提交
3260 3261
                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
                             arg3));
3262
        unlock_user(p, arg1, 0);
3263
        break;
3264 3265
#if defined(TARGET_NR_openat) && defined(__NR_openat)
    case TARGET_NR_openat:
3266 3267 3268 3269 3270 3271 3272
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_openat(arg1,
                                   path(p),
                                   target_to_host_bitmask(arg3, fcntl_flags_tbl),
                                   arg4));
        unlock_user(p, arg2, 0);
3273 3274
        break;
#endif
3275 3276 3277 3278
    case TARGET_NR_close:
        ret = get_errno(close(arg1));
        break;
    case TARGET_NR_brk:
3279
        ret = do_brk(arg1);
3280 3281
        break;
    case TARGET_NR_fork:
P
pbrook 已提交
3282
        ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
3283
        break;
3284
#ifdef TARGET_NR_waitpid
3285 3286
    case TARGET_NR_waitpid:
        {
3287 3288
            int status;
            ret = get_errno(waitpid(arg1, &status, arg3));
3289 3290 3291
            if (!is_error(ret) && arg2
                && put_user_s32(status, arg2))
                goto efault;
3292 3293
        }
        break;
3294
#endif
P
pbrook 已提交
3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309
#ifdef TARGET_NR_waitid
    case TARGET_NR_waitid:
        {
            siginfo_t info;
            info.si_pid = 0;
            ret = get_errno(waitid(arg1, arg2, &info, arg4));
            if (!is_error(ret) && arg3 && info.si_pid != 0) {
                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
                    goto efault;
                host_to_target_siginfo(p, &info);
                unlock_user(p, arg3, sizeof(target_siginfo_t));
            }
        }
        break;
#endif
3310
#ifdef TARGET_NR_creat /* not on alpha */
3311
    case TARGET_NR_creat:
3312 3313
        if (!(p = lock_user_string(arg1)))
            goto efault;
3314 3315
        ret = get_errno(creat(p, arg2));
        unlock_user(p, arg1, 0);
3316
        break;
3317
#endif
3318
    case TARGET_NR_link:
3319 3320 3321 3322
        {
            void * p2;
            p = lock_user_string(arg1);
            p2 = lock_user_string(arg2);
3323 3324 3325 3326
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(link(p, p2));
3327 3328 3329
            unlock_user(p2, arg2, 0);
            unlock_user(p, arg1, 0);
        }
3330
        break;
3331 3332 3333 3334
#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
    case TARGET_NR_linkat:
        {
            void * p2 = NULL;
3335 3336
            if (!arg2 || !arg4)
                goto efault;
3337 3338
            p  = lock_user_string(arg2);
            p2 = lock_user_string(arg4);
3339
            if (!p || !p2)
3340
                ret = -TARGET_EFAULT;
3341 3342
            else
                ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
3343 3344
            unlock_user(p, arg2, 0);
            unlock_user(p2, arg4, 0);
3345 3346 3347
        }
        break;
#endif
3348
    case TARGET_NR_unlink:
3349 3350
        if (!(p = lock_user_string(arg1)))
            goto efault;
3351 3352
        ret = get_errno(unlink(p));
        unlock_user(p, arg1, 0);
3353
        break;
3354 3355
#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
    case TARGET_NR_unlinkat:
3356 3357 3358 3359
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_unlinkat(arg1, p, arg3));
        unlock_user(p, arg2, 0);
3360
        break;
3361
#endif
3362
    case TARGET_NR_execve:
B
bellard 已提交
3363 3364
        {
            char **argp, **envp;
B
bellard 已提交
3365
            int argc, envc;
3366 3367 3368 3369
            abi_ulong gp;
            abi_ulong guest_argp;
            abi_ulong guest_envp;
            abi_ulong addr;
B
bellard 已提交
3370 3371
            char **q;

B
bellard 已提交
3372
            argc = 0;
3373
            guest_argp = arg2;
3374
            for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
3375
                if (get_user_ual(addr, gp))
3376
                    goto efault;
3377
                if (!addr)
3378
                    break;
B
bellard 已提交
3379
                argc++;
3380
            }
B
bellard 已提交
3381
            envc = 0;
3382
            guest_envp = arg3;
3383
            for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
3384
                if (get_user_ual(addr, gp))
3385
                    goto efault;
3386
                if (!addr)
3387
                    break;
B
bellard 已提交
3388
                envc++;
3389
            }
B
bellard 已提交
3390

B
bellard 已提交
3391 3392
            argp = alloca((argc + 1) * sizeof(void *));
            envp = alloca((envc + 1) * sizeof(void *));
B
bellard 已提交
3393

3394
            for (gp = guest_argp, q = argp; gp;
3395
                  gp += sizeof(abi_ulong), q++) {
3396 3397
                if (get_user_ual(addr, gp))
                    goto execve_efault;
3398 3399
                if (!addr)
                    break;
3400 3401
                if (!(*q = lock_user_string(addr)))
                    goto execve_efault;
3402
            }
B
bellard 已提交
3403 3404
            *q = NULL;

3405
            for (gp = guest_envp, q = envp; gp;
3406
                  gp += sizeof(abi_ulong), q++) {
3407 3408
                if (get_user_ual(addr, gp))
                    goto execve_efault;
3409 3410
                if (!addr)
                    break;
3411 3412
                if (!(*q = lock_user_string(addr)))
                    goto execve_efault;
3413
            }
B
bellard 已提交
3414
            *q = NULL;
B
bellard 已提交
3415

3416 3417
            if (!(p = lock_user_string(arg1)))
                goto execve_efault;
3418 3419 3420
            ret = get_errno(execve(p, argp, envp));
            unlock_user(p, arg1, 0);

3421 3422 3423 3424 3425 3426
            goto execve_end;

        execve_efault:
            ret = -TARGET_EFAULT;

        execve_end:
3427
            for (gp = guest_argp, q = argp; *q;
3428
                  gp += sizeof(abi_ulong), q++) {
3429 3430 3431
                if (get_user_ual(addr, gp)
                    || !addr)
                    break;
3432 3433 3434
                unlock_user(*q, addr, 0);
            }
            for (gp = guest_envp, q = envp; *q;
3435
                  gp += sizeof(abi_ulong), q++) {
3436 3437 3438
                if (get_user_ual(addr, gp)
                    || !addr)
                    break;
3439 3440
                unlock_user(*q, addr, 0);
            }
B
bellard 已提交
3441
        }
3442 3443
        break;
    case TARGET_NR_chdir:
3444 3445
        if (!(p = lock_user_string(arg1)))
            goto efault;
3446 3447
        ret = get_errno(chdir(p));
        unlock_user(p, arg1, 0);
3448
        break;
B
bellard 已提交
3449
#ifdef TARGET_NR_time
3450 3451
    case TARGET_NR_time:
        {
3452 3453
            time_t host_time;
            ret = get_errno(time(&host_time));
3454 3455 3456 3457
            if (!is_error(ret)
                && arg1
                && put_user_sal(host_time, arg1))
                goto efault;
3458 3459
        }
        break;
B
bellard 已提交
3460
#endif
3461
    case TARGET_NR_mknod:
3462 3463
        if (!(p = lock_user_string(arg1)))
            goto efault;
3464 3465
        ret = get_errno(mknod(p, arg2, arg3));
        unlock_user(p, arg1, 0);
3466
        break;
3467 3468
#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
    case TARGET_NR_mknodat:
3469 3470 3471 3472
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
        unlock_user(p, arg2, 0);
3473 3474
        break;
#endif
3475
    case TARGET_NR_chmod:
3476 3477
        if (!(p = lock_user_string(arg1)))
            goto efault;
3478 3479
        ret = get_errno(chmod(p, arg2));
        unlock_user(p, arg1, 0);
3480
        break;
3481
#ifdef TARGET_NR_break
3482 3483
    case TARGET_NR_break:
        goto unimplemented;
3484 3485
#endif
#ifdef TARGET_NR_oldstat
3486 3487
    case TARGET_NR_oldstat:
        goto unimplemented;
3488
#endif
3489 3490 3491
    case TARGET_NR_lseek:
        ret = get_errno(lseek(arg1, arg2, arg3));
        break;
3492 3493 3494
#ifdef TARGET_NR_getxpid
    case TARGET_NR_getxpid:
#else
3495
    case TARGET_NR_getpid:
3496
#endif
3497 3498 3499
        ret = get_errno(getpid());
        break;
    case TARGET_NR_mount:
3500 3501 3502 3503 3504 3505
		{
			/* need to look at the data field */
			void *p2, *p3;
			p = lock_user_string(arg1);
			p2 = lock_user_string(arg2);
			p3 = lock_user_string(arg3);
3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516
                        if (!p || !p2 || !p3)
                            ret = -TARGET_EFAULT;
                        else
                            /* FIXME - arg5 should be locked, but it isn't clear how to
                             * do that since it's not guaranteed to be a NULL-terminated
                             * string.
                             */
                            ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
                        unlock_user(p, arg1, 0);
                        unlock_user(p2, arg2, 0);
                        unlock_user(p3, arg3, 0);
3517 3518
			break;
		}
3519
#ifdef TARGET_NR_umount
3520
    case TARGET_NR_umount:
3521 3522
        if (!(p = lock_user_string(arg1)))
            goto efault;
3523 3524
        ret = get_errno(umount(p));
        unlock_user(p, arg1, 0);
3525
        break;
3526
#endif
3527
#ifdef TARGET_NR_stime /* not on alpha */
3528 3529
    case TARGET_NR_stime:
        {
3530
            time_t host_time;
3531 3532
            if (get_user_sal(host_time, arg1))
                goto efault;
3533
            ret = get_errno(stime(&host_time));
3534 3535
        }
        break;
3536
#endif
3537 3538
    case TARGET_NR_ptrace:
        goto unimplemented;
3539
#ifdef TARGET_NR_alarm /* not on alpha */
3540 3541 3542
    case TARGET_NR_alarm:
        ret = alarm(arg1);
        break;
3543
#endif
3544
#ifdef TARGET_NR_oldfstat
3545 3546
    case TARGET_NR_oldfstat:
        goto unimplemented;
3547
#endif
3548
#ifdef TARGET_NR_pause /* not on alpha */
3549 3550 3551
    case TARGET_NR_pause:
        ret = get_errno(pause());
        break;
3552
#endif
3553
#ifdef TARGET_NR_utime
3554
    case TARGET_NR_utime:
3555
        {
3556 3557 3558
            struct utimbuf tbuf, *host_tbuf;
            struct target_utimbuf *target_tbuf;
            if (arg2) {
3559 3560
                if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
                    goto efault;
3561 3562 3563 3564
                tbuf.actime = tswapl(target_tbuf->actime);
                tbuf.modtime = tswapl(target_tbuf->modtime);
                unlock_user_struct(target_tbuf, arg2, 0);
                host_tbuf = &tbuf;
B
bellard 已提交
3565
            } else {
3566
                host_tbuf = NULL;
B
bellard 已提交
3567
            }
3568 3569
            if (!(p = lock_user_string(arg1)))
                goto efault;
3570 3571
            ret = get_errno(utime(p, host_tbuf));
            unlock_user(p, arg1, 0);
3572 3573
        }
        break;
3574
#endif
B
bellard 已提交
3575 3576 3577
    case TARGET_NR_utimes:
        {
            struct timeval *tvp, tv[2];
3578
            if (arg2) {
3579 3580 3581 3582
                if (copy_from_user_timeval(&tv[0], arg2)
                    || copy_from_user_timeval(&tv[1],
                                              arg2 + sizeof(struct target_timeval)))
                    goto efault;
B
bellard 已提交
3583 3584 3585 3586
                tvp = tv;
            } else {
                tvp = NULL;
            }
3587 3588
            if (!(p = lock_user_string(arg1)))
                goto efault;
3589 3590
            ret = get_errno(utimes(p, tvp));
            unlock_user(p, arg1, 0);
B
bellard 已提交
3591 3592
        }
        break;
3593
#ifdef TARGET_NR_stty
3594 3595
    case TARGET_NR_stty:
        goto unimplemented;
3596 3597
#endif
#ifdef TARGET_NR_gtty
3598 3599
    case TARGET_NR_gtty:
        goto unimplemented;
3600
#endif
3601
    case TARGET_NR_access:
3602 3603
        if (!(p = lock_user_string(arg1)))
            goto efault;
3604 3605
        ret = get_errno(access(p, arg2));
        unlock_user(p, arg1, 0);
3606
        break;
3607 3608
#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
    case TARGET_NR_faccessat:
3609 3610 3611 3612
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_faccessat(arg1, p, arg3, arg4));
        unlock_user(p, arg2, 0);
3613 3614
        break;
#endif
3615
#ifdef TARGET_NR_nice /* not on alpha */
3616 3617 3618
    case TARGET_NR_nice:
        ret = get_errno(nice(arg1));
        break;
3619
#endif
3620
#ifdef TARGET_NR_ftime
3621 3622
    case TARGET_NR_ftime:
        goto unimplemented;
3623
#endif
3624
    case TARGET_NR_sync:
B
bellard 已提交
3625 3626
        sync();
        ret = 0;
3627 3628
        break;
    case TARGET_NR_kill:
3629
        ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
3630 3631
        break;
    case TARGET_NR_rename:
3632 3633 3634 3635
        {
            void *p2;
            p = lock_user_string(arg1);
            p2 = lock_user_string(arg2);
3636 3637 3638 3639
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(rename(p, p2));
3640 3641 3642
            unlock_user(p2, arg2, 0);
            unlock_user(p, arg1, 0);
        }
3643
        break;
3644 3645 3646
#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
    case TARGET_NR_renameat:
        {
3647
            void *p2;
3648 3649
            p  = lock_user_string(arg2);
            p2 = lock_user_string(arg4);
3650
            if (!p || !p2)
3651
                ret = -TARGET_EFAULT;
3652 3653
            else
                ret = get_errno(sys_renameat(arg1, p, arg3, p2));
3654 3655
            unlock_user(p2, arg4, 0);
            unlock_user(p, arg2, 0);
3656 3657 3658
        }
        break;
#endif
3659
    case TARGET_NR_mkdir:
3660 3661
        if (!(p = lock_user_string(arg1)))
            goto efault;
3662 3663
        ret = get_errno(mkdir(p, arg2));
        unlock_user(p, arg1, 0);
3664
        break;
3665 3666
#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
    case TARGET_NR_mkdirat:
3667 3668 3669 3670
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_mkdirat(arg1, p, arg3));
        unlock_user(p, arg2, 0);
3671 3672
        break;
#endif
3673
    case TARGET_NR_rmdir:
3674 3675
        if (!(p = lock_user_string(arg1)))
            goto efault;
3676 3677
        ret = get_errno(rmdir(p));
        unlock_user(p, arg1, 0);
3678 3679 3680 3681 3682 3683
        break;
    case TARGET_NR_dup:
        ret = get_errno(dup(arg1));
        break;
    case TARGET_NR_pipe:
        {
3684 3685
            int host_pipe[2];
            ret = get_errno(pipe(host_pipe));
3686
            if (!is_error(ret)) {
3687
#if defined(TARGET_MIPS)
3688
                CPUMIPSState *env = (CPUMIPSState*)cpu_env;
3689
		env->active_tc.gpr[3] = host_pipe[1];
3690
		ret = host_pipe[0];
3691 3692 3693
#elif defined(TARGET_SH4)
		((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
		ret = host_pipe[0];
3694
#else
3695 3696 3697
                if (put_user_s32(host_pipe[0], arg1)
                    || put_user_s32(host_pipe[1], arg1 + sizeof(host_pipe[0])))
                    goto efault;
3698
#endif
3699 3700 3701 3702
            }
        }
        break;
    case TARGET_NR_times:
B
bellard 已提交
3703
        {
3704
            struct target_tms *tmsp;
B
bellard 已提交
3705 3706
            struct tms tms;
            ret = get_errno(times(&tms));
3707
            if (arg1) {
3708 3709 3710
                tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
                if (!tmsp)
                    goto efault;
B
bellard 已提交
3711 3712 3713 3714
                tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
                tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
                tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
                tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
B
bellard 已提交
3715
            }
B
bellard 已提交
3716 3717
            if (!is_error(ret))
                ret = host_to_target_clock_t(ret);
B
bellard 已提交
3718 3719
        }
        break;
3720
#ifdef TARGET_NR_prof
3721 3722
    case TARGET_NR_prof:
        goto unimplemented;
3723
#endif
3724
#ifdef TARGET_NR_signal
3725 3726
    case TARGET_NR_signal:
        goto unimplemented;
3727
#endif
3728
    case TARGET_NR_acct:
3729 3730
        if (!(p = lock_user_string(arg1)))
            goto efault;
3731 3732 3733
        ret = get_errno(acct(path(p)));
        unlock_user(p, arg1, 0);
        break;
3734
#ifdef TARGET_NR_umount2 /* not on alpha */
3735
    case TARGET_NR_umount2:
3736 3737
        if (!(p = lock_user_string(arg1)))
            goto efault;
3738 3739
        ret = get_errno(umount2(p, arg2));
        unlock_user(p, arg1, 0);
3740
        break;
3741
#endif
3742
#ifdef TARGET_NR_lock
3743 3744
    case TARGET_NR_lock:
        goto unimplemented;
3745
#endif
3746 3747 3748 3749
    case TARGET_NR_ioctl:
        ret = do_ioctl(arg1, arg2, arg3);
        break;
    case TARGET_NR_fcntl:
B
bellard 已提交
3750
        ret = do_fcntl(arg1, arg2, arg3);
3751
        break;
3752
#ifdef TARGET_NR_mpx
3753 3754
    case TARGET_NR_mpx:
        goto unimplemented;
3755
#endif
3756 3757 3758
    case TARGET_NR_setpgid:
        ret = get_errno(setpgid(arg1, arg2));
        break;
3759
#ifdef TARGET_NR_ulimit
3760 3761
    case TARGET_NR_ulimit:
        goto unimplemented;
3762 3763
#endif
#ifdef TARGET_NR_oldolduname
3764 3765
    case TARGET_NR_oldolduname:
        goto unimplemented;
3766
#endif
3767 3768 3769 3770
    case TARGET_NR_umask:
        ret = get_errno(umask(arg1));
        break;
    case TARGET_NR_chroot:
3771 3772
        if (!(p = lock_user_string(arg1)))
            goto efault;
3773 3774
        ret = get_errno(chroot(p));
        unlock_user(p, arg1, 0);
3775 3776 3777 3778 3779 3780
        break;
    case TARGET_NR_ustat:
        goto unimplemented;
    case TARGET_NR_dup2:
        ret = get_errno(dup2(arg1, arg2));
        break;
3781
#ifdef TARGET_NR_getppid /* not on alpha */
3782 3783 3784
    case TARGET_NR_getppid:
        ret = get_errno(getppid());
        break;
3785
#endif
3786 3787 3788 3789 3790 3791
    case TARGET_NR_getpgrp:
        ret = get_errno(getpgrp());
        break;
    case TARGET_NR_setsid:
        ret = get_errno(setsid());
        break;
3792
#ifdef TARGET_NR_sigaction
3793 3794
    case TARGET_NR_sigaction:
        {
T
ths 已提交
3795
#if !defined(TARGET_MIPS)
3796
            struct target_old_sigaction *old_act;
B
bellard 已提交
3797
            struct target_sigaction act, oact, *pact;
3798
            if (arg2) {
3799 3800
                if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
                    goto efault;
B
bellard 已提交
3801 3802 3803 3804
                act._sa_handler = old_act->_sa_handler;
                target_siginitset(&act.sa_mask, old_act->sa_mask);
                act.sa_flags = old_act->sa_flags;
                act.sa_restorer = old_act->sa_restorer;
3805
                unlock_user_struct(old_act, arg2, 0);
B
bellard 已提交
3806 3807 3808 3809 3810
                pact = &act;
            } else {
                pact = NULL;
            }
            ret = get_errno(do_sigaction(arg1, pact, &oact));
3811
            if (!is_error(ret) && arg3) {
3812 3813
                if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
                    goto efault;
3814 3815 3816 3817 3818
                old_act->_sa_handler = oact._sa_handler;
                old_act->sa_mask = oact.sa_mask.sig[0];
                old_act->sa_flags = oact.sa_flags;
                old_act->sa_restorer = oact.sa_restorer;
                unlock_user_struct(old_act, arg3, 1);
B
bellard 已提交
3819
            }
T
ths 已提交
3820
#else
3821 3822 3823
	    struct target_sigaction act, oact, *pact, *old_act;

	    if (arg2) {
3824 3825
                if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
                    goto efault;
3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837
		act._sa_handler = old_act->_sa_handler;
		target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
		act.sa_flags = old_act->sa_flags;
		unlock_user_struct(old_act, arg2, 0);
		pact = &act;
	    } else {
		pact = NULL;
	    }

	    ret = get_errno(do_sigaction(arg1, pact, &oact));

	    if (!is_error(ret) && arg3) {
3838 3839
                if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
                    goto efault;
3840 3841 3842 3843 3844 3845 3846 3847
		old_act->_sa_handler = oact._sa_handler;
		old_act->sa_flags = oact.sa_flags;
		old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
		old_act->sa_mask.sig[1] = 0;
		old_act->sa_mask.sig[2] = 0;
		old_act->sa_mask.sig[3] = 0;
		unlock_user_struct(old_act, arg3, 1);
	    }
T
ths 已提交
3848
#endif
3849 3850
        }
        break;
3851
#endif
B
bellard 已提交
3852
    case TARGET_NR_rt_sigaction:
3853 3854 3855 3856
        {
            struct target_sigaction *act;
            struct target_sigaction *oact;

3857 3858 3859 3860
            if (arg2) {
                if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
                    goto efault;
            } else
3861
                act = NULL;
3862 3863 3864 3865 3866 3867
            if (arg3) {
                if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
                    ret = -TARGET_EFAULT;
                    goto rt_sigaction_fail;
                }
            } else
3868 3869
                oact = NULL;
            ret = get_errno(do_sigaction(arg1, act, oact));
3870 3871
	rt_sigaction_fail:
            if (act)
3872
                unlock_user_struct(act, arg2, 0);
3873
            if (oact)
3874 3875
                unlock_user_struct(oact, arg3, 1);
        }
B
bellard 已提交
3876
        break;
3877
#ifdef TARGET_NR_sgetmask /* not on alpha */
3878
    case TARGET_NR_sgetmask:
B
bellard 已提交
3879 3880
        {
            sigset_t cur_set;
3881
            abi_ulong target_set;
B
bellard 已提交
3882 3883 3884 3885 3886
            sigprocmask(0, NULL, &cur_set);
            host_to_target_old_sigset(&target_set, &cur_set);
            ret = target_set;
        }
        break;
3887 3888
#endif
#ifdef TARGET_NR_ssetmask /* not on alpha */
3889
    case TARGET_NR_ssetmask:
B
bellard 已提交
3890 3891
        {
            sigset_t set, oset, cur_set;
3892
            abi_ulong target_set = arg1;
B
bellard 已提交
3893 3894 3895 3896 3897 3898 3899 3900
            sigprocmask(0, NULL, &cur_set);
            target_to_host_old_sigset(&set, &target_set);
            sigorset(&set, &set, &cur_set);
            sigprocmask(SIG_SETMASK, &set, &oset);
            host_to_target_old_sigset(&target_set, &oset);
            ret = target_set;
        }
        break;
3901
#endif
3902
#ifdef TARGET_NR_sigprocmask
B
bellard 已提交
3903 3904 3905 3906
    case TARGET_NR_sigprocmask:
        {
            int how = arg1;
            sigset_t set, oldset, *set_ptr;
3907

3908
            if (arg2) {
B
bellard 已提交
3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919
                switch(how) {
                case TARGET_SIG_BLOCK:
                    how = SIG_BLOCK;
                    break;
                case TARGET_SIG_UNBLOCK:
                    how = SIG_UNBLOCK;
                    break;
                case TARGET_SIG_SETMASK:
                    how = SIG_SETMASK;
                    break;
                default:
3920
                    ret = -TARGET_EINVAL;
B
bellard 已提交
3921 3922
                    goto fail;
                }
3923 3924
                if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
                    goto efault;
3925 3926
                target_to_host_old_sigset(&set, p);
                unlock_user(p, arg2, 0);
B
bellard 已提交
3927 3928 3929 3930 3931 3932
                set_ptr = &set;
            } else {
                how = 0;
                set_ptr = NULL;
            }
            ret = get_errno(sigprocmask(arg1, set_ptr, &oldset));
3933
            if (!is_error(ret) && arg3) {
3934 3935
                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
                    goto efault;
3936 3937
                host_to_target_old_sigset(p, &oldset);
                unlock_user(p, arg3, sizeof(target_sigset_t));
B
bellard 已提交
3938 3939 3940
            }
        }
        break;
3941
#endif
B
bellard 已提交
3942 3943 3944 3945
    case TARGET_NR_rt_sigprocmask:
        {
            int how = arg1;
            sigset_t set, oldset, *set_ptr;
3946

3947
            if (arg2) {
B
bellard 已提交
3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958
                switch(how) {
                case TARGET_SIG_BLOCK:
                    how = SIG_BLOCK;
                    break;
                case TARGET_SIG_UNBLOCK:
                    how = SIG_UNBLOCK;
                    break;
                case TARGET_SIG_SETMASK:
                    how = SIG_SETMASK;
                    break;
                default:
3959
                    ret = -TARGET_EINVAL;
B
bellard 已提交
3960 3961
                    goto fail;
                }
3962 3963
                if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
                    goto efault;
3964 3965
                target_to_host_sigset(&set, p);
                unlock_user(p, arg2, 0);
B
bellard 已提交
3966 3967 3968 3969 3970 3971
                set_ptr = &set;
            } else {
                how = 0;
                set_ptr = NULL;
            }
            ret = get_errno(sigprocmask(how, set_ptr, &oldset));
3972
            if (!is_error(ret) && arg3) {
3973 3974
                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
                    goto efault;
3975 3976
                host_to_target_sigset(p, &oldset);
                unlock_user(p, arg3, sizeof(target_sigset_t));
B
bellard 已提交
3977 3978 3979
            }
        }
        break;
3980
#ifdef TARGET_NR_sigpending
B
bellard 已提交
3981 3982 3983 3984 3985
    case TARGET_NR_sigpending:
        {
            sigset_t set;
            ret = get_errno(sigpending(&set));
            if (!is_error(ret)) {
3986 3987
                if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
                    goto efault;
3988 3989
                host_to_target_old_sigset(p, &set);
                unlock_user(p, arg1, sizeof(target_sigset_t));
B
bellard 已提交
3990 3991 3992
            }
        }
        break;
3993
#endif
B
bellard 已提交
3994 3995 3996 3997 3998
    case TARGET_NR_rt_sigpending:
        {
            sigset_t set;
            ret = get_errno(sigpending(&set));
            if (!is_error(ret)) {
3999 4000
                if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
                    goto efault;
4001 4002
                host_to_target_sigset(p, &set);
                unlock_user(p, arg1, sizeof(target_sigset_t));
B
bellard 已提交
4003 4004 4005
            }
        }
        break;
4006
#ifdef TARGET_NR_sigsuspend
B
bellard 已提交
4007 4008 4009
    case TARGET_NR_sigsuspend:
        {
            sigset_t set;
4010 4011
            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
                goto efault;
4012 4013
            target_to_host_old_sigset(&set, p);
            unlock_user(p, arg1, 0);
B
bellard 已提交
4014 4015 4016
            ret = get_errno(sigsuspend(&set));
        }
        break;
4017
#endif
B
bellard 已提交
4018 4019 4020
    case TARGET_NR_rt_sigsuspend:
        {
            sigset_t set;
4021 4022
            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
                goto efault;
4023 4024
            target_to_host_sigset(&set, p);
            unlock_user(p, arg1, 0);
B
bellard 已提交
4025 4026 4027 4028 4029 4030 4031 4032
            ret = get_errno(sigsuspend(&set));
        }
        break;
    case TARGET_NR_rt_sigtimedwait:
        {
            sigset_t set;
            struct timespec uts, *puts;
            siginfo_t uinfo;
4033

4034 4035
            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
                goto efault;
4036 4037 4038
            target_to_host_sigset(&set, p);
            unlock_user(p, arg1, 0);
            if (arg3) {
B
bellard 已提交
4039
                puts = &uts;
4040
                target_to_host_timespec(puts, arg3);
B
bellard 已提交
4041 4042 4043 4044
            } else {
                puts = NULL;
            }
            ret = get_errno(sigtimedwait(&set, &uinfo, puts));
4045
            if (!is_error(ret) && arg2) {
4046
                if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
4047
                    goto efault;
4048
                host_to_target_siginfo(p, &uinfo);
4049
                unlock_user(p, arg2, sizeof(target_siginfo_t));
B
bellard 已提交
4050 4051 4052 4053 4054 4055
            }
        }
        break;
    case TARGET_NR_rt_sigqueueinfo:
        {
            siginfo_t uinfo;
4056 4057
            if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
                goto efault;
4058 4059
            target_to_host_siginfo(&uinfo, p);
            unlock_user(p, arg1, 0);
B
bellard 已提交
4060 4061 4062
            ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
        }
        break;
4063
#ifdef TARGET_NR_sigreturn
B
bellard 已提交
4064 4065 4066 4067
    case TARGET_NR_sigreturn:
        /* NOTE: ret is eax, so not transcoding must be done */
        ret = do_sigreturn(cpu_env);
        break;
4068
#endif
B
bellard 已提交
4069 4070 4071 4072
    case TARGET_NR_rt_sigreturn:
        /* NOTE: ret is eax, so not transcoding must be done */
        ret = do_rt_sigreturn(cpu_env);
        break;
4073
    case TARGET_NR_sethostname:
4074 4075
        if (!(p = lock_user_string(arg1)))
            goto efault;
4076 4077
        ret = get_errno(sethostname(p, arg2));
        unlock_user(p, arg1, 0);
4078 4079
        break;
    case TARGET_NR_setrlimit:
B
bellard 已提交
4080 4081 4082
        {
            /* XXX: convert resource ? */
            int resource = arg1;
4083
            struct target_rlimit *target_rlim;
B
bellard 已提交
4084
            struct rlimit rlim;
4085 4086
            if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
                goto efault;
B
bellard 已提交
4087 4088
            rlim.rlim_cur = tswapl(target_rlim->rlim_cur);
            rlim.rlim_max = tswapl(target_rlim->rlim_max);
4089
            unlock_user_struct(target_rlim, arg2, 0);
B
bellard 已提交
4090 4091 4092
            ret = get_errno(setrlimit(resource, &rlim));
        }
        break;
4093
    case TARGET_NR_getrlimit:
B
bellard 已提交
4094 4095 4096
        {
            /* XXX: convert resource ? */
            int resource = arg1;
4097
            struct target_rlimit *target_rlim;
B
bellard 已提交
4098
            struct rlimit rlim;
4099

B
bellard 已提交
4100 4101
            ret = get_errno(getrlimit(resource, &rlim));
            if (!is_error(ret)) {
4102 4103
                if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
                    goto efault;
4104 4105 4106
                rlim.rlim_cur = tswapl(target_rlim->rlim_cur);
                rlim.rlim_max = tswapl(target_rlim->rlim_max);
                unlock_user_struct(target_rlim, arg2, 1);
B
bellard 已提交
4107 4108 4109
            }
        }
        break;
4110
    case TARGET_NR_getrusage:
B
bellard 已提交
4111 4112 4113 4114
        {
            struct rusage rusage;
            ret = get_errno(getrusage(arg1, &rusage));
            if (!is_error(ret)) {
4115
                host_to_target_rusage(arg2, &rusage);
B
bellard 已提交
4116 4117 4118
            }
        }
        break;
4119 4120 4121 4122 4123
    case TARGET_NR_gettimeofday:
        {
            struct timeval tv;
            ret = get_errno(gettimeofday(&tv, NULL));
            if (!is_error(ret)) {
4124 4125
                if (copy_to_user_timeval(arg1, &tv))
                    goto efault;
4126 4127 4128 4129 4130 4131
            }
        }
        break;
    case TARGET_NR_settimeofday:
        {
            struct timeval tv;
4132 4133
            if (copy_from_user_timeval(&tv, arg1))
                goto efault;
4134 4135 4136
            ret = get_errno(settimeofday(&tv, NULL));
        }
        break;
B
bellard 已提交
4137
#ifdef TARGET_NR_select
4138
    case TARGET_NR_select:
B
bellard 已提交
4139
        {
4140
            struct target_sel_arg_struct *sel;
4141
            abi_ulong inp, outp, exp, tvp;
4142 4143
            long nsel;

4144 4145
            if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
                goto efault;
4146 4147 4148 4149 4150 4151 4152
            nsel = tswapl(sel->n);
            inp = tswapl(sel->inp);
            outp = tswapl(sel->outp);
            exp = tswapl(sel->exp);
            tvp = tswapl(sel->tvp);
            unlock_user_struct(sel, arg1, 0);
            ret = do_select(nsel, inp, outp, exp, tvp);
B
bellard 已提交
4153 4154
        }
        break;
B
bellard 已提交
4155
#endif
4156
    case TARGET_NR_symlink:
4157 4158 4159 4160
        {
            void *p2;
            p = lock_user_string(arg1);
            p2 = lock_user_string(arg2);
4161 4162 4163 4164
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(symlink(p, p2));
4165 4166 4167
            unlock_user(p2, arg2, 0);
            unlock_user(p, arg1, 0);
        }
4168
        break;
4169 4170 4171
#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
    case TARGET_NR_symlinkat:
        {
4172
            void *p2;
4173 4174
            p  = lock_user_string(arg1);
            p2 = lock_user_string(arg3);
4175
            if (!p || !p2)
4176
                ret = -TARGET_EFAULT;
4177 4178
            else
                ret = get_errno(sys_symlinkat(p, arg2, p2));
4179 4180
            unlock_user(p2, arg3, 0);
            unlock_user(p, arg1, 0);
4181 4182 4183
        }
        break;
#endif
4184
#ifdef TARGET_NR_oldlstat
4185 4186
    case TARGET_NR_oldlstat:
        goto unimplemented;
4187
#endif
4188
    case TARGET_NR_readlink:
4189 4190 4191
        {
            void *p2;
            p = lock_user_string(arg1);
4192 4193 4194 4195 4196
            p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(readlink(path(p), p2, arg3));
4197 4198 4199
            unlock_user(p2, arg2, ret);
            unlock_user(p, arg1, 0);
        }
4200
        break;
4201 4202 4203
#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
    case TARGET_NR_readlinkat:
        {
4204
            void *p2;
4205
            p  = lock_user_string(arg2);
4206 4207
            p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
            if (!p || !p2)
4208
        	ret = -TARGET_EFAULT;
4209 4210
            else
                ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
4211 4212
            unlock_user(p2, arg3, ret);
            unlock_user(p, arg2, 0);
4213 4214 4215
        }
        break;
#endif
4216
#ifdef TARGET_NR_uselib
4217 4218
    case TARGET_NR_uselib:
        goto unimplemented;
4219 4220
#endif
#ifdef TARGET_NR_swapon
4221
    case TARGET_NR_swapon:
4222 4223
        if (!(p = lock_user_string(arg1)))
            goto efault;
4224 4225
        ret = get_errno(swapon(p, arg2));
        unlock_user(p, arg1, 0);
4226
        break;
4227
#endif
4228 4229
    case TARGET_NR_reboot:
        goto unimplemented;
4230
#ifdef TARGET_NR_readdir
4231 4232
    case TARGET_NR_readdir:
        goto unimplemented;
4233 4234
#endif
#ifdef TARGET_NR_mmap
4235
    case TARGET_NR_mmap:
B
bellard 已提交
4236
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS)
4237
        {
4238 4239
            abi_ulong *v;
            abi_ulong v1, v2, v3, v4, v5, v6;
4240 4241
            if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
                goto efault;
4242 4243 4244 4245 4246 4247 4248
            v1 = tswapl(v[0]);
            v2 = tswapl(v[1]);
            v3 = tswapl(v[2]);
            v4 = tswapl(v[3]);
            v5 = tswapl(v[4]);
            v6 = tswapl(v[5]);
            unlock_user(v, arg1, 0);
4249
            ret = get_errno(target_mmap(v1, v2, v3,
B
bellard 已提交
4250 4251
                                        target_to_host_bitmask(v4, mmap_flags_tbl),
                                        v5, v6));
4252 4253
        }
#else
4254 4255
        ret = get_errno(target_mmap(arg1, arg2, arg3,
                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
B
bellard 已提交
4256 4257
                                    arg5,
                                    arg6));
4258
#endif
B
bellard 已提交
4259
        break;
4260
#endif
B
bellard 已提交
4261
#ifdef TARGET_NR_mmap2
B
bellard 已提交
4262
    case TARGET_NR_mmap2:
P
pbrook 已提交
4263
#ifndef MMAP_SHIFT
B
bellard 已提交
4264 4265
#define MMAP_SHIFT 12
#endif
4266 4267
        ret = get_errno(target_mmap(arg1, arg2, arg3,
                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
B
bellard 已提交
4268
                                    arg5,
B
bellard 已提交
4269
                                    arg6 << MMAP_SHIFT));
4270
        break;
B
bellard 已提交
4271
#endif
4272
    case TARGET_NR_munmap:
B
bellard 已提交
4273
        ret = get_errno(target_munmap(arg1, arg2));
4274
        break;
B
bellard 已提交
4275
    case TARGET_NR_mprotect:
B
bellard 已提交
4276
        ret = get_errno(target_mprotect(arg1, arg2, arg3));
B
bellard 已提交
4277
        break;
4278
#ifdef TARGET_NR_mremap
B
bellard 已提交
4279
    case TARGET_NR_mremap:
B
bellard 已提交
4280
        ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
B
bellard 已提交
4281
        break;
4282
#endif
4283
        /* ??? msync/mlock/munlock are broken for softmmu.  */
4284
#ifdef TARGET_NR_msync
B
bellard 已提交
4285
    case TARGET_NR_msync:
4286
        ret = get_errno(msync(g2h(arg1), arg2, arg3));
B
bellard 已提交
4287
        break;
4288 4289
#endif
#ifdef TARGET_NR_mlock
B
bellard 已提交
4290
    case TARGET_NR_mlock:
4291
        ret = get_errno(mlock(g2h(arg1), arg2));
B
bellard 已提交
4292
        break;
4293 4294
#endif
#ifdef TARGET_NR_munlock
B
bellard 已提交
4295
    case TARGET_NR_munlock:
4296
        ret = get_errno(munlock(g2h(arg1), arg2));
B
bellard 已提交
4297
        break;
4298 4299
#endif
#ifdef TARGET_NR_mlockall
B
bellard 已提交
4300 4301 4302
    case TARGET_NR_mlockall:
        ret = get_errno(mlockall(arg1));
        break;
4303 4304
#endif
#ifdef TARGET_NR_munlockall
B
bellard 已提交
4305 4306 4307
    case TARGET_NR_munlockall:
        ret = get_errno(munlockall());
        break;
4308
#endif
4309
    case TARGET_NR_truncate:
4310 4311
        if (!(p = lock_user_string(arg1)))
            goto efault;
4312 4313
        ret = get_errno(truncate(p, arg2));
        unlock_user(p, arg1, 0);
4314 4315 4316 4317 4318 4319 4320
        break;
    case TARGET_NR_ftruncate:
        ret = get_errno(ftruncate(arg1, arg2));
        break;
    case TARGET_NR_fchmod:
        ret = get_errno(fchmod(arg1, arg2));
        break;
4321 4322
#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
    case TARGET_NR_fchmodat:
4323 4324 4325 4326
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4));
        unlock_user(p, arg2, 0);
4327 4328
        break;
#endif
4329
    case TARGET_NR_getpriority:
4330 4331 4332 4333
        /* libc does special remapping of the return value of
         * sys_getpriority() so it's just easiest to call
         * sys_getpriority() directly rather than through libc. */
        ret = sys_getpriority(arg1, arg2);
4334 4335 4336 4337
        break;
    case TARGET_NR_setpriority:
        ret = get_errno(setpriority(arg1, arg2, arg3));
        break;
4338
#ifdef TARGET_NR_profil
4339 4340
    case TARGET_NR_profil:
        goto unimplemented;
4341
#endif
4342
    case TARGET_NR_statfs:
4343 4344
        if (!(p = lock_user_string(arg1)))
            goto efault;
4345 4346
        ret = get_errno(statfs(path(p), &stfs));
        unlock_user(p, arg1, 0);
4347 4348
    convert_statfs:
        if (!is_error(ret)) {
4349
            struct target_statfs *target_stfs;
4350

4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362
            if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
                goto efault;
            __put_user(stfs.f_type, &target_stfs->f_type);
            __put_user(stfs.f_bsize, &target_stfs->f_bsize);
            __put_user(stfs.f_blocks, &target_stfs->f_blocks);
            __put_user(stfs.f_bfree, &target_stfs->f_bfree);
            __put_user(stfs.f_bavail, &target_stfs->f_bavail);
            __put_user(stfs.f_files, &target_stfs->f_files);
            __put_user(stfs.f_ffree, &target_stfs->f_ffree);
            __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
            __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
            __put_user(stfs.f_namelen, &target_stfs->f_namelen);
4363
            unlock_user_struct(target_stfs, arg2, 1);
4364 4365 4366
        }
        break;
    case TARGET_NR_fstatfs:
B
bellard 已提交
4367
        ret = get_errno(fstatfs(arg1, &stfs));
4368
        goto convert_statfs;
B
bellard 已提交
4369 4370
#ifdef TARGET_NR_statfs64
    case TARGET_NR_statfs64:
4371 4372
        if (!(p = lock_user_string(arg1)))
            goto efault;
4373 4374
        ret = get_errno(statfs(path(p), &stfs));
        unlock_user(p, arg1, 0);
B
bellard 已提交
4375 4376
    convert_statfs64:
        if (!is_error(ret)) {
4377
            struct target_statfs64 *target_stfs;
4378

4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391
            if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
                goto efault;
            __put_user(stfs.f_type, &target_stfs->f_type);
            __put_user(stfs.f_bsize, &target_stfs->f_bsize);
            __put_user(stfs.f_blocks, &target_stfs->f_blocks);
            __put_user(stfs.f_bfree, &target_stfs->f_bfree);
            __put_user(stfs.f_bavail, &target_stfs->f_bavail);
            __put_user(stfs.f_files, &target_stfs->f_files);
            __put_user(stfs.f_ffree, &target_stfs->f_ffree);
            __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
            __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
            __put_user(stfs.f_namelen, &target_stfs->f_namelen);
            unlock_user_struct(target_stfs, arg3, 1);
B
bellard 已提交
4392 4393 4394 4395 4396 4397
        }
        break;
    case TARGET_NR_fstatfs64:
        ret = get_errno(fstatfs(arg1, &stfs));
        goto convert_statfs64;
#endif
4398
#ifdef TARGET_NR_ioperm
4399 4400
    case TARGET_NR_ioperm:
        goto unimplemented;
4401
#endif
4402
#ifdef TARGET_NR_socketcall
4403
    case TARGET_NR_socketcall:
4404
        ret = do_socketcall(arg1, arg2);
4405
        break;
4406
#endif
4407 4408
#ifdef TARGET_NR_accept
    case TARGET_NR_accept:
P
pbrook 已提交
4409
        ret = do_accept(arg1, arg2, arg3);
4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423
        break;
#endif
#ifdef TARGET_NR_bind
    case TARGET_NR_bind:
        ret = do_bind(arg1, arg2, arg3);
        break;
#endif
#ifdef TARGET_NR_connect
    case TARGET_NR_connect:
        ret = do_connect(arg1, arg2, arg3);
        break;
#endif
#ifdef TARGET_NR_getpeername
    case TARGET_NR_getpeername:
P
pbrook 已提交
4424
        ret = do_getpeername(arg1, arg2, arg3);
4425 4426 4427 4428
        break;
#endif
#ifdef TARGET_NR_getsockname
    case TARGET_NR_getsockname:
P
pbrook 已提交
4429
        ret = do_getsockname(arg1, arg2, arg3);
4430 4431 4432 4433 4434 4435 4436 4437 4438
        break;
#endif
#ifdef TARGET_NR_getsockopt
    case TARGET_NR_getsockopt:
        ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
        break;
#endif
#ifdef TARGET_NR_listen
    case TARGET_NR_listen:
P
pbrook 已提交
4439
        ret = get_errno(listen(arg1, arg2));
4440 4441 4442 4443
        break;
#endif
#ifdef TARGET_NR_recv
    case TARGET_NR_recv:
P
pbrook 已提交
4444
        ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
4445 4446 4447 4448
        break;
#endif
#ifdef TARGET_NR_recvfrom
    case TARGET_NR_recvfrom:
P
pbrook 已提交
4449
        ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
4450 4451 4452 4453 4454 4455 4456 4457 4458
        break;
#endif
#ifdef TARGET_NR_recvmsg
    case TARGET_NR_recvmsg:
        ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
        break;
#endif
#ifdef TARGET_NR_send
    case TARGET_NR_send:
P
pbrook 已提交
4459
        ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
4460 4461 4462 4463 4464 4465 4466 4467 4468
        break;
#endif
#ifdef TARGET_NR_sendmsg
    case TARGET_NR_sendmsg:
        ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
        break;
#endif
#ifdef TARGET_NR_sendto
    case TARGET_NR_sendto:
P
pbrook 已提交
4469
        ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
4470 4471 4472 4473
        break;
#endif
#ifdef TARGET_NR_shutdown
    case TARGET_NR_shutdown:
P
pbrook 已提交
4474
        ret = get_errno(shutdown(arg1, arg2));
4475 4476 4477 4478 4479 4480 4481 4482 4483
        break;
#endif
#ifdef TARGET_NR_socket
    case TARGET_NR_socket:
        ret = do_socket(arg1, arg2, arg3);
        break;
#endif
#ifdef TARGET_NR_socketpair
    case TARGET_NR_socketpair:
P
pbrook 已提交
4484
        ret = do_socketpair(arg1, arg2, arg3, arg4);
4485 4486 4487 4488 4489 4490 4491
        break;
#endif
#ifdef TARGET_NR_setsockopt
    case TARGET_NR_setsockopt:
        ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
        break;
#endif
4492

4493
    case TARGET_NR_syslog:
4494 4495
        if (!(p = lock_user_string(arg2)))
            goto efault;
4496 4497
        ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
        unlock_user(p, arg2, 0);
4498 4499
        break;

4500
    case TARGET_NR_setitimer:
B
bellard 已提交
4501 4502 4503
        {
            struct itimerval value, ovalue, *pvalue;

4504
            if (arg2) {
B
bellard 已提交
4505
                pvalue = &value;
4506 4507 4508 4509
                if (copy_from_user_timeval(&pvalue->it_interval, arg2)
                    || copy_from_user_timeval(&pvalue->it_value,
                                              arg2 + sizeof(struct target_timeval)))
                    goto efault;
B
bellard 已提交
4510 4511 4512 4513
            } else {
                pvalue = NULL;
            }
            ret = get_errno(setitimer(arg1, pvalue, &ovalue));
4514
            if (!is_error(ret) && arg3) {
4515 4516 4517 4518 4519
                if (copy_to_user_timeval(arg3,
                                         &ovalue.it_interval)
                    || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
                                            &ovalue.it_value))
                    goto efault;
B
bellard 已提交
4520 4521 4522
            }
        }
        break;
4523
    case TARGET_NR_getitimer:
B
bellard 已提交
4524 4525
        {
            struct itimerval value;
4526

B
bellard 已提交
4527
            ret = get_errno(getitimer(arg1, &value));
4528
            if (!is_error(ret) && arg2) {
4529 4530 4531 4532 4533
                if (copy_to_user_timeval(arg2,
                                         &value.it_interval)
                    || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
                                            &value.it_value))
                    goto efault;
B
bellard 已提交
4534 4535 4536
            }
        }
        break;
4537
    case TARGET_NR_stat:
4538 4539
        if (!(p = lock_user_string(arg1)))
            goto efault;
4540 4541
        ret = get_errno(stat(path(p), &st));
        unlock_user(p, arg1, 0);
4542 4543
        goto do_stat;
    case TARGET_NR_lstat:
4544 4545
        if (!(p = lock_user_string(arg1)))
            goto efault;
4546 4547
        ret = get_errno(lstat(path(p), &st));
        unlock_user(p, arg1, 0);
4548 4549 4550 4551 4552 4553
        goto do_stat;
    case TARGET_NR_fstat:
        {
            ret = get_errno(fstat(arg1, &st));
        do_stat:
            if (!is_error(ret)) {
4554
                struct target_stat *target_st;
4555

4556 4557
                if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
                    goto efault;
B
bellard 已提交
4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570
                __put_user(st.st_dev, &target_st->st_dev);
                __put_user(st.st_ino, &target_st->st_ino);
                __put_user(st.st_mode, &target_st->st_mode);
                __put_user(st.st_uid, &target_st->st_uid);
                __put_user(st.st_gid, &target_st->st_gid);
                __put_user(st.st_nlink, &target_st->st_nlink);
                __put_user(st.st_rdev, &target_st->st_rdev);
                __put_user(st.st_size, &target_st->st_size);
                __put_user(st.st_blksize, &target_st->st_blksize);
                __put_user(st.st_blocks, &target_st->st_blocks);
                __put_user(st.st_atime, &target_st->target_st_atime);
                __put_user(st.st_mtime, &target_st->target_st_mtime);
                __put_user(st.st_ctime, &target_st->target_st_ctime);
4571
                unlock_user_struct(target_st, arg2, 1);
4572 4573 4574
            }
        }
        break;
4575
#ifdef TARGET_NR_olduname
4576 4577
    case TARGET_NR_olduname:
        goto unimplemented;
4578 4579
#endif
#ifdef TARGET_NR_iopl
4580 4581
    case TARGET_NR_iopl:
        goto unimplemented;
4582
#endif
4583 4584 4585
    case TARGET_NR_vhangup:
        ret = get_errno(vhangup());
        break;
4586
#ifdef TARGET_NR_idle
4587 4588
    case TARGET_NR_idle:
        goto unimplemented;
B
bellard 已提交
4589 4590 4591 4592 4593
#endif
#ifdef TARGET_NR_syscall
    case TARGET_NR_syscall:
    	ret = do_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
    	break;
4594
#endif
4595 4596 4597
    case TARGET_NR_wait4:
        {
            int status;
4598
            abi_long status_ptr = arg2;
4599
            struct rusage rusage, *rusage_ptr;
4600
            abi_ulong target_rusage = arg4;
4601 4602 4603 4604 4605 4606
            if (target_rusage)
                rusage_ptr = &rusage;
            else
                rusage_ptr = NULL;
            ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
            if (!is_error(ret)) {
4607 4608 4609
                if (status_ptr) {
                    if (put_user_s32(status, status_ptr))
                        goto efault;
4610
                }
4611 4612
                if (target_rusage)
                    host_to_target_rusage(target_rusage, &rusage);
4613 4614 4615
            }
        }
        break;
4616
#ifdef TARGET_NR_swapoff
4617
    case TARGET_NR_swapoff:
4618 4619
        if (!(p = lock_user_string(arg1)))
            goto efault;
4620 4621
        ret = get_errno(swapoff(p));
        unlock_user(p, arg1, 0);
4622
        break;
4623
#endif
4624
    case TARGET_NR_sysinfo:
B
bellard 已提交
4625
        {
4626
            struct target_sysinfo *target_value;
B
bellard 已提交
4627 4628
            struct sysinfo value;
            ret = get_errno(sysinfo(&value));
4629
            if (!is_error(ret) && arg1)
B
bellard 已提交
4630
            {
4631 4632
                if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
                    goto efault;
B
bellard 已提交
4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646
                __put_user(value.uptime, &target_value->uptime);
                __put_user(value.loads[0], &target_value->loads[0]);
                __put_user(value.loads[1], &target_value->loads[1]);
                __put_user(value.loads[2], &target_value->loads[2]);
                __put_user(value.totalram, &target_value->totalram);
                __put_user(value.freeram, &target_value->freeram);
                __put_user(value.sharedram, &target_value->sharedram);
                __put_user(value.bufferram, &target_value->bufferram);
                __put_user(value.totalswap, &target_value->totalswap);
                __put_user(value.freeswap, &target_value->freeswap);
                __put_user(value.procs, &target_value->procs);
                __put_user(value.totalhigh, &target_value->totalhigh);
                __put_user(value.freehigh, &target_value->freehigh);
                __put_user(value.mem_unit, &target_value->mem_unit);
4647
                unlock_user_struct(target_value, arg1, 1);
B
bellard 已提交
4648 4649 4650
            }
        }
        break;
4651
#ifdef TARGET_NR_ipc
4652
    case TARGET_NR_ipc:
4653 4654
	ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
	break;
4655
#endif
4656 4657 4658 4659
    case TARGET_NR_fsync:
        ret = get_errno(fsync(arg1));
        break;
    case TARGET_NR_clone:
P
pbrook 已提交
4660
        ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
B
bellard 已提交
4661
        break;
4662 4663 4664
#ifdef __NR_exit_group
        /* new thread calls */
    case TARGET_NR_exit_group:
4665
        gdb_exit(cpu_env, arg1);
4666 4667 4668
        ret = get_errno(exit_group(arg1));
        break;
#endif
4669
    case TARGET_NR_setdomainname:
4670 4671
        if (!(p = lock_user_string(arg1)))
            goto efault;
4672 4673
        ret = get_errno(setdomainname(p, arg2));
        unlock_user(p, arg1, 0);
4674 4675 4676
        break;
    case TARGET_NR_uname:
        /* no need to transcode because we use the linux syscall */
B
bellard 已提交
4677 4678
        {
            struct new_utsname * buf;
4679

4680 4681
            if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
                goto efault;
B
bellard 已提交
4682 4683 4684 4685 4686
            ret = get_errno(sys_uname(buf));
            if (!is_error(ret)) {
                /* Overrite the native machine name with whatever is being
                   emulated. */
                strcpy (buf->machine, UNAME_MACHINE);
4687 4688 4689
                /* Allow the user to override the reported release.  */
                if (qemu_uname_release && *qemu_uname_release)
                  strcpy (buf->release, qemu_uname_release);
B
bellard 已提交
4690
            }
4691
            unlock_user_struct(buf, arg1, 1);
B
bellard 已提交
4692
        }
4693
        break;
B
bellard 已提交
4694
#ifdef TARGET_I386
4695
    case TARGET_NR_modify_ldt:
4696
        ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
B
bellard 已提交
4697
        break;
4698
#if !defined(TARGET_X86_64)
B
bellard 已提交
4699 4700 4701
    case TARGET_NR_vm86old:
        goto unimplemented;
    case TARGET_NR_vm86:
4702
        ret = do_vm86(cpu_env, arg1, arg2);
B
bellard 已提交
4703
        break;
4704
#endif
B
bellard 已提交
4705
#endif
4706 4707
    case TARGET_NR_adjtimex:
        goto unimplemented;
4708
#ifdef TARGET_NR_create_module
4709
    case TARGET_NR_create_module:
4710
#endif
4711 4712
    case TARGET_NR_init_module:
    case TARGET_NR_delete_module:
4713
#ifdef TARGET_NR_get_kernel_syms
4714
    case TARGET_NR_get_kernel_syms:
4715
#endif
4716 4717 4718 4719 4720 4721 4722 4723 4724
        goto unimplemented;
    case TARGET_NR_quotactl:
        goto unimplemented;
    case TARGET_NR_getpgid:
        ret = get_errno(getpgid(arg1));
        break;
    case TARGET_NR_fchdir:
        ret = get_errno(fchdir(arg1));
        break;
4725
#ifdef TARGET_NR_bdflush /* not on x86_64 */
4726 4727
    case TARGET_NR_bdflush:
        goto unimplemented;
4728
#endif
4729
#ifdef TARGET_NR_sysfs
4730 4731
    case TARGET_NR_sysfs:
        goto unimplemented;
4732
#endif
4733
    case TARGET_NR_personality:
B
bellard 已提交
4734
        ret = get_errno(personality(arg1));
4735
        break;
4736
#ifdef TARGET_NR_afs_syscall
4737 4738
    case TARGET_NR_afs_syscall:
        goto unimplemented;
4739
#endif
4740
#ifdef TARGET_NR__llseek /* Not on alpha */
4741 4742
    case TARGET_NR__llseek:
        {
B
bellard 已提交
4743 4744
#if defined (__x86_64__)
            ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5));
4745 4746
            if (put_user_s64(ret, arg4))
                goto efault;
B
bellard 已提交
4747
#else
4748 4749
            int64_t res;
            ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
4750 4751
            if (put_user_s64(res, arg4))
                goto efault;
B
bellard 已提交
4752
#endif
4753 4754
        }
        break;
4755
#endif
4756
    case TARGET_NR_getdents:
4757
#if TARGET_ABI_BITS != 32
4758
        goto unimplemented;
4759
#elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
B
bellard 已提交
4760
        {
4761
            struct target_dirent *target_dirp;
B
bellard 已提交
4762
            struct dirent *dirp;
4763
            abi_long count = arg3;
B
bellard 已提交
4764 4765

	    dirp = malloc(count);
4766
	    if (!dirp) {
4767
                ret = -TARGET_ENOMEM;
4768 4769
                goto fail;
            }
4770

B
bellard 已提交
4771 4772 4773 4774 4775 4776 4777 4778 4779 4780
            ret = get_errno(sys_getdents(arg1, dirp, count));
            if (!is_error(ret)) {
                struct dirent *de;
		struct target_dirent *tde;
                int len = ret;
                int reclen, treclen;
		int count1, tnamelen;

		count1 = 0;
                de = dirp;
4781 4782
                if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
                    goto efault;
B
bellard 已提交
4783 4784 4785
		tde = target_dirp;
                while (len > 0) {
                    reclen = de->d_reclen;
4786
		    treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
B
bellard 已提交
4787 4788 4789
                    tde->d_reclen = tswap16(treclen);
                    tde->d_ino = tswapl(de->d_ino);
                    tde->d_off = tswapl(de->d_off);
4790
		    tnamelen = treclen - (2 * sizeof(abi_long) + 2);
B
bellard 已提交
4791 4792
		    if (tnamelen > 256)
                        tnamelen = 256;
B
bellard 已提交
4793
                    /* XXX: may not be correct */
B
bellard 已提交
4794 4795 4796
		    strncpy(tde->d_name, de->d_name, tnamelen);
                    de = (struct dirent *)((char *)de + reclen);
                    len -= reclen;
J
j_mayer 已提交
4797
                    tde = (struct target_dirent *)((char *)tde + treclen);
B
bellard 已提交
4798 4799 4800
		    count1 += treclen;
                }
		ret = count1;
4801
                unlock_user(target_dirp, arg2, ret);
B
bellard 已提交
4802 4803 4804 4805
            }
	    free(dirp);
        }
#else
4806
        {
4807
            struct dirent *dirp;
4808
            abi_long count = arg3;
B
bellard 已提交
4809

4810 4811
            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
                goto efault;
B
bellard 已提交
4812
            ret = get_errno(sys_getdents(arg1, dirp, count));
4813 4814 4815 4816 4817 4818
            if (!is_error(ret)) {
                struct dirent *de;
                int len = ret;
                int reclen;
                de = dirp;
                while (len > 0) {
B
bellard 已提交
4819
                    reclen = de->d_reclen;
4820 4821
                    if (reclen > len)
                        break;
B
bellard 已提交
4822
                    de->d_reclen = tswap16(reclen);
4823 4824 4825 4826 4827 4828
                    tswapls(&de->d_ino);
                    tswapls(&de->d_off);
                    de = (struct dirent *)((char *)de + reclen);
                    len -= reclen;
                }
            }
4829
            unlock_user(dirp, arg2, ret);
4830
        }
B
bellard 已提交
4831
#endif
4832
        break;
T
ths 已提交
4833
#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
B
bellard 已提交
4834 4835
    case TARGET_NR_getdents64:
        {
4836
            struct dirent64 *dirp;
4837
            abi_long count = arg3;
4838 4839
            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
                goto efault;
B
bellard 已提交
4840 4841 4842 4843 4844 4845 4846
            ret = get_errno(sys_getdents64(arg1, dirp, count));
            if (!is_error(ret)) {
                struct dirent64 *de;
                int len = ret;
                int reclen;
                de = dirp;
                while (len > 0) {
B
bellard 已提交
4847
                    reclen = de->d_reclen;
B
bellard 已提交
4848 4849
                    if (reclen > len)
                        break;
B
bellard 已提交
4850
                    de->d_reclen = tswap16(reclen);
B
bellard 已提交
4851 4852
                    tswap64s((uint64_t *)&de->d_ino);
                    tswap64s((uint64_t *)&de->d_off);
B
bellard 已提交
4853 4854 4855 4856
                    de = (struct dirent64 *)((char *)de + reclen);
                    len -= reclen;
                }
            }
4857
            unlock_user(dirp, arg2, ret);
B
bellard 已提交
4858 4859
        }
        break;
4860
#endif /* TARGET_NR_getdents64 */
4861
#ifdef TARGET_NR__newselect
4862
    case TARGET_NR__newselect:
4863
        ret = do_select(arg1, arg2, arg3, arg4, arg5);
4864
        break;
4865 4866
#endif
#ifdef TARGET_NR_poll
B
bellard 已提交
4867 4868
    case TARGET_NR_poll:
        {
4869
            struct target_pollfd *target_pfd;
B
bellard 已提交
4870 4871 4872
            unsigned int nfds = arg2;
            int timeout = arg3;
            struct pollfd *pfd;
B
bellard 已提交
4873
            unsigned int i;
B
bellard 已提交
4874

4875 4876 4877
            target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
            if (!target_pfd)
                goto efault;
B
bellard 已提交
4878 4879
            pfd = alloca(sizeof(struct pollfd) * nfds);
            for(i = 0; i < nfds; i++) {
B
bellard 已提交
4880 4881
                pfd[i].fd = tswap32(target_pfd[i].fd);
                pfd[i].events = tswap16(target_pfd[i].events);
B
bellard 已提交
4882 4883 4884 4885
            }
            ret = get_errno(poll(pfd, nfds, timeout));
            if (!is_error(ret)) {
                for(i = 0; i < nfds; i++) {
B
bellard 已提交
4886
                    target_pfd[i].revents = tswap16(pfd[i].revents);
B
bellard 已提交
4887
                }
4888 4889
                ret += nfds * (sizeof(struct target_pollfd)
                               - sizeof(struct pollfd));
B
bellard 已提交
4890
            }
4891
            unlock_user(target_pfd, arg1, ret);
B
bellard 已提交
4892 4893
        }
        break;
4894
#endif
4895
    case TARGET_NR_flock:
B
bellard 已提交
4896 4897 4898
        /* NOTE: the flock constant seems to be the same for every
           Linux platform */
        ret = get_errno(flock(arg1, arg2));
4899 4900 4901 4902 4903 4904 4905
        break;
    case TARGET_NR_readv:
        {
            int count = arg3;
            struct iovec *vec;

            vec = alloca(count * sizeof(struct iovec));
B
bellard 已提交
4906 4907
            if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
                goto efault;
4908
            ret = get_errno(readv(arg1, vec, count));
4909
            unlock_iovec(vec, arg2, count, 1);
4910 4911 4912 4913 4914 4915 4916 4917
        }
        break;
    case TARGET_NR_writev:
        {
            int count = arg3;
            struct iovec *vec;

            vec = alloca(count * sizeof(struct iovec));
B
bellard 已提交
4918 4919
            if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
                goto efault;
4920
            ret = get_errno(writev(arg1, vec, count));
4921
            unlock_iovec(vec, arg2, count, 0);
4922 4923 4924 4925 4926
        }
        break;
    case TARGET_NR_getsid:
        ret = get_errno(getsid(arg1));
        break;
4927
#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
4928
    case TARGET_NR_fdatasync:
B
bellard 已提交
4929 4930
        ret = get_errno(fdatasync(arg1));
        break;
4931
#endif
4932
    case TARGET_NR__sysctl:
4933
        /* We don't implement this, but ENOTDIR is always a safe
B
bellard 已提交
4934
           return value. */
4935 4936
        ret = -TARGET_ENOTDIR;
        break;
4937
    case TARGET_NR_sched_setparam:
B
bellard 已提交
4938
        {
4939
            struct sched_param *target_schp;
B
bellard 已提交
4940
            struct sched_param schp;
4941

4942 4943
            if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
                goto efault;
B
bellard 已提交
4944
            schp.sched_priority = tswap32(target_schp->sched_priority);
4945
            unlock_user_struct(target_schp, arg2, 0);
B
bellard 已提交
4946 4947 4948
            ret = get_errno(sched_setparam(arg1, &schp));
        }
        break;
4949
    case TARGET_NR_sched_getparam:
B
bellard 已提交
4950
        {
4951
            struct sched_param *target_schp;
B
bellard 已提交
4952 4953 4954
            struct sched_param schp;
            ret = get_errno(sched_getparam(arg1, &schp));
            if (!is_error(ret)) {
4955 4956
                if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
                    goto efault;
B
bellard 已提交
4957
                target_schp->sched_priority = tswap32(schp.sched_priority);
4958
                unlock_user_struct(target_schp, arg2, 1);
B
bellard 已提交
4959 4960 4961
            }
        }
        break;
4962
    case TARGET_NR_sched_setscheduler:
B
bellard 已提交
4963
        {
4964
            struct sched_param *target_schp;
B
bellard 已提交
4965
            struct sched_param schp;
4966 4967
            if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
                goto efault;
B
bellard 已提交
4968
            schp.sched_priority = tswap32(target_schp->sched_priority);
4969
            unlock_user_struct(target_schp, arg3, 0);
B
bellard 已提交
4970 4971 4972
            ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
        }
        break;
4973
    case TARGET_NR_sched_getscheduler:
B
bellard 已提交
4974 4975
        ret = get_errno(sched_getscheduler(arg1));
        break;
4976 4977 4978 4979
    case TARGET_NR_sched_yield:
        ret = get_errno(sched_yield());
        break;
    case TARGET_NR_sched_get_priority_max:
B
bellard 已提交
4980 4981
        ret = get_errno(sched_get_priority_max(arg1));
        break;
4982
    case TARGET_NR_sched_get_priority_min:
B
bellard 已提交
4983 4984
        ret = get_errno(sched_get_priority_min(arg1));
        break;
4985
    case TARGET_NR_sched_rr_get_interval:
B
bellard 已提交
4986 4987 4988 4989
        {
            struct timespec ts;
            ret = get_errno(sched_rr_get_interval(arg1, &ts));
            if (!is_error(ret)) {
4990
                host_to_target_timespec(arg2, &ts);
B
bellard 已提交
4991 4992 4993
            }
        }
        break;
4994
    case TARGET_NR_nanosleep:
B
bellard 已提交
4995 4996
        {
            struct timespec req, rem;
4997
            target_to_host_timespec(&req, arg1);
B
bellard 已提交
4998
            ret = get_errno(nanosleep(&req, &rem));
4999 5000
            if (is_error(ret) && arg2) {
                host_to_target_timespec(arg2, &rem);
B
bellard 已提交
5001 5002 5003
            }
        }
        break;
5004
#ifdef TARGET_NR_query_module
5005
    case TARGET_NR_query_module:
B
bellard 已提交
5006
        goto unimplemented;
5007 5008
#endif
#ifdef TARGET_NR_nfsservctl
5009
    case TARGET_NR_nfsservctl:
B
bellard 已提交
5010
        goto unimplemented;
5011
#endif
5012
    case TARGET_NR_prctl:
5013 5014 5015 5016 5017 5018
        switch (arg1)
            {
            case PR_GET_PDEATHSIG:
                {
                    int deathsig;
                    ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
5019 5020 5021
                    if (!is_error(ret) && arg2
                        && put_user_ual(deathsig, arg2))
                        goto efault;
5022 5023 5024 5025 5026 5027
                }
                break;
            default:
                ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
                break;
            }
5028
        break;
B
bellard 已提交
5029 5030 5031 5032 5033 5034 5035 5036 5037
#ifdef TARGET_NR_arch_prctl
    case TARGET_NR_arch_prctl:
#if defined(TARGET_I386) && !defined(TARGET_ABI32)
        ret = do_arch_prctl(cpu_env, arg1, arg2);
        break;
#else
        goto unimplemented;
#endif
#endif
5038
#ifdef TARGET_NR_pread
5039
    case TARGET_NR_pread:
5040 5041
        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
            goto efault;
5042 5043
        ret = get_errno(pread(arg1, p, arg3, arg4));
        unlock_user(p, arg2, ret);
5044
        break;
5045
    case TARGET_NR_pwrite:
5046 5047
        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
            goto efault;
5048 5049
        ret = get_errno(pwrite(arg1, p, arg3, arg4));
        unlock_user(p, arg2, 0);
5050
        break;
A
aurel32 已提交
5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064
#endif
#ifdef TARGET_NR_pread64
    case TARGET_NR_pread64:
        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
            goto efault;
        ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
        unlock_user(p, arg2, ret);
        break;
    case TARGET_NR_pwrite64:
        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
            goto efault;
        ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
        unlock_user(p, arg2, 0);
        break;
5065
#endif
5066
    case TARGET_NR_getcwd:
5067 5068
        if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
            goto efault;
5069 5070
        ret = get_errno(sys_getcwd1(p, arg2));
        unlock_user(p, arg1, ret);
5071 5072
        break;
    case TARGET_NR_capget:
B
bellard 已提交
5073
        goto unimplemented;
5074
    case TARGET_NR_capset:
B
bellard 已提交
5075
        goto unimplemented;
5076
    case TARGET_NR_sigaltstack:
5077 5078
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
    defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA)
5079
        ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env));
5080 5081
        break;
#else
B
bellard 已提交
5082
        goto unimplemented;
5083
#endif
5084
    case TARGET_NR_sendfile:
B
bellard 已提交
5085
        goto unimplemented;
5086
#ifdef TARGET_NR_getpmsg
5087
    case TARGET_NR_getpmsg:
B
bellard 已提交
5088
        goto unimplemented;
5089 5090
#endif
#ifdef TARGET_NR_putpmsg
5091
    case TARGET_NR_putpmsg:
B
bellard 已提交
5092
        goto unimplemented;
5093
#endif
B
bellard 已提交
5094
#ifdef TARGET_NR_vfork
5095
    case TARGET_NR_vfork:
P
pbrook 已提交
5096 5097
        ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
                        0, 0, 0, 0));
5098
        break;
B
bellard 已提交
5099
#endif
5100
#ifdef TARGET_NR_ugetrlimit
5101
    case TARGET_NR_ugetrlimit:
B
bellard 已提交
5102 5103 5104 5105
    {
	struct rlimit rlim;
	ret = get_errno(getrlimit(arg1, &rlim));
	if (!is_error(ret)) {
5106
	    struct target_rlimit *target_rlim;
5107 5108
            if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
                goto efault;
B
bellard 已提交
5109 5110
	    target_rlim->rlim_cur = tswapl(rlim.rlim_cur);
	    target_rlim->rlim_max = tswapl(rlim.rlim_max);
5111
            unlock_user_struct(target_rlim, arg2, 1);
B
bellard 已提交
5112 5113 5114
	}
	break;
    }
5115
#endif
B
bellard 已提交
5116
#ifdef TARGET_NR_truncate64
5117
    case TARGET_NR_truncate64:
5118 5119
        if (!(p = lock_user_string(arg1)))
            goto efault;
5120 5121
	ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
        unlock_user(p, arg1, 0);
B
bellard 已提交
5122
	break;
B
bellard 已提交
5123 5124
#endif
#ifdef TARGET_NR_ftruncate64
5125
    case TARGET_NR_ftruncate64:
P
pbrook 已提交
5126
	ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
B
bellard 已提交
5127
	break;
B
bellard 已提交
5128 5129
#endif
#ifdef TARGET_NR_stat64
5130
    case TARGET_NR_stat64:
5131 5132
        if (!(p = lock_user_string(arg1)))
            goto efault;
5133 5134
        ret = get_errno(stat(path(p), &st));
        unlock_user(p, arg1, 0);
B
bellard 已提交
5135
        goto do_stat64;
B
bellard 已提交
5136 5137
#endif
#ifdef TARGET_NR_lstat64
5138
    case TARGET_NR_lstat64:
5139 5140
        if (!(p = lock_user_string(arg1)))
            goto efault;
5141 5142
        ret = get_errno(lstat(path(p), &st));
        unlock_user(p, arg1, 0);
B
bellard 已提交
5143
        goto do_stat64;
B
bellard 已提交
5144 5145
#endif
#ifdef TARGET_NR_fstat64
5146
    case TARGET_NR_fstat64:
B
bellard 已提交
5147 5148 5149 5150
        {
            ret = get_errno(fstat(arg1, &st));
        do_stat64:
            if (!is_error(ret)) {
P
pbrook 已提交
5151 5152
#ifdef TARGET_ARM
                if (((CPUARMState *)cpu_env)->eabi) {
5153
                    struct target_eabi_stat64 *target_st;
5154 5155 5156

                    if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
                        goto efault;
P
pbrook 已提交
5157
                    memset(target_st, 0, sizeof(struct target_eabi_stat64));
5158 5159
                    __put_user(st.st_dev, &target_st->st_dev);
                    __put_user(st.st_ino, &target_st->st_ino);
P
pbrook 已提交
5160
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174
                    __put_user(st.st_ino, &target_st->__st_ino);
#endif
                    __put_user(st.st_mode, &target_st->st_mode);
                    __put_user(st.st_nlink, &target_st->st_nlink);
                    __put_user(st.st_uid, &target_st->st_uid);
                    __put_user(st.st_gid, &target_st->st_gid);
                    __put_user(st.st_rdev, &target_st->st_rdev);
                    __put_user(st.st_size, &target_st->st_size);
                    __put_user(st.st_blksize, &target_st->st_blksize);
                    __put_user(st.st_blocks, &target_st->st_blocks);
                    __put_user(st.st_atime, &target_st->target_st_atime);
                    __put_user(st.st_mtime, &target_st->target_st_mtime);
                    __put_user(st.st_ctime, &target_st->target_st_ctime);
                    unlock_user_struct(target_st, arg2, 1);
P
pbrook 已提交
5175 5176 5177
                } else
#endif
                {
5178
                    struct target_stat64 *target_st;
5179 5180 5181

                    if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
                        goto efault;
P
pbrook 已提交
5182
                    memset(target_st, 0, sizeof(struct target_stat64));
5183 5184
                    __put_user(st.st_dev, &target_st->st_dev);
                    __put_user(st.st_ino, &target_st->st_ino);
5185
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5186
                    __put_user(st.st_ino, &target_st->__st_ino);
P
pbrook 已提交
5187
#endif
5188 5189 5190 5191 5192
                    __put_user(st.st_mode, &target_st->st_mode);
                    __put_user(st.st_nlink, &target_st->st_nlink);
                    __put_user(st.st_uid, &target_st->st_uid);
                    __put_user(st.st_gid, &target_st->st_gid);
                    __put_user(st.st_rdev, &target_st->st_rdev);
P
pbrook 已提交
5193
                    /* XXX: better use of kernel struct */
5194 5195 5196 5197 5198 5199 5200
                    __put_user(st.st_size, &target_st->st_size);
                    __put_user(st.st_blksize, &target_st->st_blksize);
                    __put_user(st.st_blocks, &target_st->st_blocks);
                    __put_user(st.st_atime, &target_st->target_st_atime);
                    __put_user(st.st_mtime, &target_st->target_st_mtime);
                    __put_user(st.st_ctime, &target_st->target_st_ctime);
                    unlock_user_struct(target_st, arg2, 1);
P
pbrook 已提交
5201
                }
B
bellard 已提交
5202 5203 5204
            }
        }
        break;
B
bellard 已提交
5205
#endif
5206 5207
#ifdef USE_UID16
    case TARGET_NR_lchown:
5208 5209
        if (!(p = lock_user_string(arg1)))
            goto efault;
5210 5211
        ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
        unlock_user(p, arg1, 0);
5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233
        break;
    case TARGET_NR_getuid:
        ret = get_errno(high2lowuid(getuid()));
        break;
    case TARGET_NR_getgid:
        ret = get_errno(high2lowgid(getgid()));
        break;
    case TARGET_NR_geteuid:
        ret = get_errno(high2lowuid(geteuid()));
        break;
    case TARGET_NR_getegid:
        ret = get_errno(high2lowgid(getegid()));
        break;
    case TARGET_NR_setreuid:
        ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
        break;
    case TARGET_NR_setregid:
        ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
        break;
    case TARGET_NR_getgroups:
        {
            int gidsetsize = arg1;
5234
            uint16_t *target_grouplist;
5235 5236 5237 5238 5239 5240
            gid_t *grouplist;
            int i;

            grouplist = alloca(gidsetsize * sizeof(gid_t));
            ret = get_errno(getgroups(gidsetsize, grouplist));
            if (!is_error(ret)) {
5241 5242 5243
                target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
                if (!target_grouplist)
                    goto efault;
5244 5245
                for(i = 0;i < gidsetsize; i++)
                    target_grouplist[i] = tswap16(grouplist[i]);
5246
                unlock_user(target_grouplist, arg2, gidsetsize * 2);
5247 5248 5249 5250 5251 5252
            }
        }
        break;
    case TARGET_NR_setgroups:
        {
            int gidsetsize = arg1;
5253
            uint16_t *target_grouplist;
5254 5255 5256 5257
            gid_t *grouplist;
            int i;

            grouplist = alloca(gidsetsize * sizeof(gid_t));
5258 5259 5260 5261 5262
            target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
            if (!target_grouplist) {
                ret = -TARGET_EFAULT;
                goto fail;
            }
5263 5264
            for(i = 0;i < gidsetsize; i++)
                grouplist[i] = tswap16(target_grouplist[i]);
5265
            unlock_user(target_grouplist, arg2, 0);
5266 5267 5268 5269 5270 5271
            ret = get_errno(setgroups(gidsetsize, grouplist));
        }
        break;
    case TARGET_NR_fchown:
        ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
        break;
5272 5273
#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
    case TARGET_NR_fchownat:
5274 5275 5276 5277
        if (!(p = lock_user_string(arg2))) 
            goto efault;
        ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5));
        unlock_user(p, arg2, 0);
5278 5279
        break;
#endif
5280 5281
#ifdef TARGET_NR_setresuid
    case TARGET_NR_setresuid:
5282 5283
        ret = get_errno(setresuid(low2highuid(arg1),
                                  low2highuid(arg2),
5284 5285 5286 5287 5288 5289
                                  low2highuid(arg3)));
        break;
#endif
#ifdef TARGET_NR_getresuid
    case TARGET_NR_getresuid:
        {
5290
            uid_t ruid, euid, suid;
5291 5292
            ret = get_errno(getresuid(&ruid, &euid, &suid));
            if (!is_error(ret)) {
5293 5294 5295 5296
                if (put_user_u16(high2lowuid(ruid), arg1)
                    || put_user_u16(high2lowuid(euid), arg2)
                    || put_user_u16(high2lowuid(suid), arg3))
                    goto efault;
5297 5298 5299 5300 5301 5302
            }
        }
        break;
#endif
#ifdef TARGET_NR_getresgid
    case TARGET_NR_setresgid:
5303 5304
        ret = get_errno(setresgid(low2highgid(arg1),
                                  low2highgid(arg2),
5305 5306 5307 5308 5309 5310
                                  low2highgid(arg3)));
        break;
#endif
#ifdef TARGET_NR_getresgid
    case TARGET_NR_getresgid:
        {
5311
            gid_t rgid, egid, sgid;
5312 5313
            ret = get_errno(getresgid(&rgid, &egid, &sgid));
            if (!is_error(ret)) {
5314 5315 5316 5317
                if (put_user_u16(high2lowgid(rgid), arg1)
                    || put_user_u16(high2lowgid(egid), arg2)
                    || put_user_u16(high2lowgid(sgid), arg3))
                    goto efault;
5318 5319 5320 5321 5322
            }
        }
        break;
#endif
    case TARGET_NR_chown:
5323 5324
        if (!(p = lock_user_string(arg1)))
            goto efault;
5325 5326
        ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
        unlock_user(p, arg1, 0);
5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341
        break;
    case TARGET_NR_setuid:
        ret = get_errno(setuid(low2highuid(arg1)));
        break;
    case TARGET_NR_setgid:
        ret = get_errno(setgid(low2highgid(arg1)));
        break;
    case TARGET_NR_setfsuid:
        ret = get_errno(setfsuid(arg1));
        break;
    case TARGET_NR_setfsgid:
        ret = get_errno(setfsgid(arg1));
        break;
#endif /* USE_UID16 */

B
bellard 已提交
5342
#ifdef TARGET_NR_lchown32
5343
    case TARGET_NR_lchown32:
5344 5345
        if (!(p = lock_user_string(arg1)))
            goto efault;
5346 5347
        ret = get_errno(lchown(p, arg2, arg3));
        unlock_user(p, arg1, 0);
B
bellard 已提交
5348
        break;
B
bellard 已提交
5349 5350
#endif
#ifdef TARGET_NR_getuid32
5351
    case TARGET_NR_getuid32:
B
bellard 已提交
5352 5353
        ret = get_errno(getuid());
        break;
B
bellard 已提交
5354 5355
#endif
#ifdef TARGET_NR_getgid32
5356
    case TARGET_NR_getgid32:
B
bellard 已提交
5357 5358
        ret = get_errno(getgid());
        break;
B
bellard 已提交
5359 5360
#endif
#ifdef TARGET_NR_geteuid32
5361
    case TARGET_NR_geteuid32:
B
bellard 已提交
5362 5363
        ret = get_errno(geteuid());
        break;
B
bellard 已提交
5364 5365
#endif
#ifdef TARGET_NR_getegid32
5366
    case TARGET_NR_getegid32:
B
bellard 已提交
5367 5368
        ret = get_errno(getegid());
        break;
B
bellard 已提交
5369 5370
#endif
#ifdef TARGET_NR_setreuid32
5371
    case TARGET_NR_setreuid32:
B
bellard 已提交
5372 5373
        ret = get_errno(setreuid(arg1, arg2));
        break;
B
bellard 已提交
5374 5375
#endif
#ifdef TARGET_NR_setregid32
5376
    case TARGET_NR_setregid32:
B
bellard 已提交
5377 5378
        ret = get_errno(setregid(arg1, arg2));
        break;
B
bellard 已提交
5379 5380
#endif
#ifdef TARGET_NR_getgroups32
5381
    case TARGET_NR_getgroups32:
B
bellard 已提交
5382 5383
        {
            int gidsetsize = arg1;
5384
            uint32_t *target_grouplist;
B
bellard 已提交
5385 5386 5387 5388 5389 5390
            gid_t *grouplist;
            int i;

            grouplist = alloca(gidsetsize * sizeof(gid_t));
            ret = get_errno(getgroups(gidsetsize, grouplist));
            if (!is_error(ret)) {
5391 5392 5393 5394 5395
                target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
                if (!target_grouplist) {
                    ret = -TARGET_EFAULT;
                    goto fail;
                }
B
bellard 已提交
5396
                for(i = 0;i < gidsetsize; i++)
5397 5398
                    target_grouplist[i] = tswap32(grouplist[i]);
                unlock_user(target_grouplist, arg2, gidsetsize * 4);
B
bellard 已提交
5399 5400 5401
            }
        }
        break;
B
bellard 已提交
5402 5403
#endif
#ifdef TARGET_NR_setgroups32
5404
    case TARGET_NR_setgroups32:
B
bellard 已提交
5405 5406
        {
            int gidsetsize = arg1;
5407
            uint32_t *target_grouplist;
B
bellard 已提交
5408 5409
            gid_t *grouplist;
            int i;
5410

B
bellard 已提交
5411
            grouplist = alloca(gidsetsize * sizeof(gid_t));
5412 5413 5414 5415 5416
            target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
            if (!target_grouplist) {
                ret = -TARGET_EFAULT;
                goto fail;
            }
B
bellard 已提交
5417
            for(i = 0;i < gidsetsize; i++)
5418 5419
                grouplist[i] = tswap32(target_grouplist[i]);
            unlock_user(target_grouplist, arg2, 0);
B
bellard 已提交
5420 5421 5422
            ret = get_errno(setgroups(gidsetsize, grouplist));
        }
        break;
B
bellard 已提交
5423 5424
#endif
#ifdef TARGET_NR_fchown32
5425
    case TARGET_NR_fchown32:
B
bellard 已提交
5426 5427
        ret = get_errno(fchown(arg1, arg2, arg3));
        break;
B
bellard 已提交
5428 5429
#endif
#ifdef TARGET_NR_setresuid32
5430
    case TARGET_NR_setresuid32:
B
bellard 已提交
5431 5432
        ret = get_errno(setresuid(arg1, arg2, arg3));
        break;
B
bellard 已提交
5433 5434
#endif
#ifdef TARGET_NR_getresuid32
5435
    case TARGET_NR_getresuid32:
B
bellard 已提交
5436
        {
5437
            uid_t ruid, euid, suid;
B
bellard 已提交
5438 5439
            ret = get_errno(getresuid(&ruid, &euid, &suid));
            if (!is_error(ret)) {
5440 5441 5442 5443
                if (put_user_u32(ruid, arg1)
                    || put_user_u32(euid, arg2)
                    || put_user_u32(suid, arg3))
                    goto efault;
B
bellard 已提交
5444 5445 5446
            }
        }
        break;
B
bellard 已提交
5447 5448
#endif
#ifdef TARGET_NR_setresgid32
5449
    case TARGET_NR_setresgid32:
B
bellard 已提交
5450 5451
        ret = get_errno(setresgid(arg1, arg2, arg3));
        break;
B
bellard 已提交
5452 5453
#endif
#ifdef TARGET_NR_getresgid32
5454
    case TARGET_NR_getresgid32:
B
bellard 已提交
5455
        {
5456
            gid_t rgid, egid, sgid;
B
bellard 已提交
5457 5458
            ret = get_errno(getresgid(&rgid, &egid, &sgid));
            if (!is_error(ret)) {
5459 5460 5461 5462
                if (put_user_u32(rgid, arg1)
                    || put_user_u32(egid, arg2)
                    || put_user_u32(sgid, arg3))
                    goto efault;
B
bellard 已提交
5463 5464 5465
            }
        }
        break;
B
bellard 已提交
5466 5467
#endif
#ifdef TARGET_NR_chown32
5468
    case TARGET_NR_chown32:
5469 5470
        if (!(p = lock_user_string(arg1)))
            goto efault;
5471 5472
        ret = get_errno(chown(p, arg2, arg3));
        unlock_user(p, arg1, 0);
B
bellard 已提交
5473
        break;
B
bellard 已提交
5474 5475
#endif
#ifdef TARGET_NR_setuid32
5476
    case TARGET_NR_setuid32:
B
bellard 已提交
5477 5478
        ret = get_errno(setuid(arg1));
        break;
B
bellard 已提交
5479 5480
#endif
#ifdef TARGET_NR_setgid32
5481
    case TARGET_NR_setgid32:
B
bellard 已提交
5482 5483
        ret = get_errno(setgid(arg1));
        break;
B
bellard 已提交
5484 5485
#endif
#ifdef TARGET_NR_setfsuid32
5486
    case TARGET_NR_setfsuid32:
B
bellard 已提交
5487 5488
        ret = get_errno(setfsuid(arg1));
        break;
B
bellard 已提交
5489 5490
#endif
#ifdef TARGET_NR_setfsgid32
5491
    case TARGET_NR_setfsgid32:
B
bellard 已提交
5492 5493
        ret = get_errno(setfsgid(arg1));
        break;
B
bellard 已提交
5494
#endif
5495

5496
    case TARGET_NR_pivot_root:
B
bellard 已提交
5497
        goto unimplemented;
B
bellard 已提交
5498
#ifdef TARGET_NR_mincore
5499
    case TARGET_NR_mincore:
B
bellard 已提交
5500
        goto unimplemented;
B
bellard 已提交
5501 5502
#endif
#ifdef TARGET_NR_madvise
5503
    case TARGET_NR_madvise:
5504 5505 5506 5507 5508 5509
        /* A straight passthrough may not be safe because qemu sometimes
           turns private flie-backed mappings into anonymous mappings.
           This will break MADV_DONTNEED.
           This is a hint, so ignoring and returning success is ok.  */
        ret = get_errno(0);
        break;
B
bellard 已提交
5510
#endif
5511
#if TARGET_ABI_BITS == 32
5512
    case TARGET_NR_fcntl64:
B
bellard 已提交
5513
    {
T
ths 已提交
5514
	int cmd;
B
bellard 已提交
5515
	struct flock64 fl;
5516
	struct target_flock64 *target_fl;
P
pbrook 已提交
5517
#ifdef TARGET_ARM
5518
	struct target_eabi_flock64 *target_efl;
P
pbrook 已提交
5519
#endif
B
bellard 已提交
5520

T
ths 已提交
5521 5522 5523
        switch(arg2){
        case TARGET_F_GETLK64:
            cmd = F_GETLK64;
5524
            break;
T
ths 已提交
5525 5526
        case TARGET_F_SETLK64:
            cmd = F_SETLK64;
5527
            break;
T
ths 已提交
5528 5529
        case TARGET_F_SETLKW64:
            cmd = F_SETLK64;
5530
            break;
T
ths 已提交
5531 5532
        default:
            cmd = arg2;
5533
            break;
T
ths 已提交
5534 5535
        }

B
bellard 已提交
5536
        switch(arg2) {
T
ths 已提交
5537
        case TARGET_F_GETLK64:
T
ths 已提交
5538 5539
#ifdef TARGET_ARM
            if (((CPUARMState *)cpu_env)->eabi) {
B
bellard 已提交
5540 5541
                if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) 
                    goto efault;
T
ths 已提交
5542 5543 5544 5545 5546 5547 5548 5549 5550
                fl.l_type = tswap16(target_efl->l_type);
                fl.l_whence = tswap16(target_efl->l_whence);
                fl.l_start = tswap64(target_efl->l_start);
                fl.l_len = tswap64(target_efl->l_len);
                fl.l_pid = tswapl(target_efl->l_pid);
                unlock_user_struct(target_efl, arg3, 0);
            } else
#endif
            {
B
bellard 已提交
5551 5552
                if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) 
                    goto efault;
T
ths 已提交
5553 5554 5555 5556 5557 5558 5559
                fl.l_type = tswap16(target_fl->l_type);
                fl.l_whence = tswap16(target_fl->l_whence);
                fl.l_start = tswap64(target_fl->l_start);
                fl.l_len = tswap64(target_fl->l_len);
                fl.l_pid = tswapl(target_fl->l_pid);
                unlock_user_struct(target_fl, arg3, 0);
            }
T
ths 已提交
5560
            ret = get_errno(fcntl(arg1, cmd, &fl));
B
bellard 已提交
5561
	    if (ret == 0) {
P
pbrook 已提交
5562 5563
#ifdef TARGET_ARM
                if (((CPUARMState *)cpu_env)->eabi) {
B
bellard 已提交
5564 5565
                    if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) 
                        goto efault;
P
pbrook 已提交
5566 5567 5568 5569 5570
                    target_efl->l_type = tswap16(fl.l_type);
                    target_efl->l_whence = tswap16(fl.l_whence);
                    target_efl->l_start = tswap64(fl.l_start);
                    target_efl->l_len = tswap64(fl.l_len);
                    target_efl->l_pid = tswapl(fl.l_pid);
5571
                    unlock_user_struct(target_efl, arg3, 1);
P
pbrook 已提交
5572 5573 5574
                } else
#endif
                {
B
bellard 已提交
5575 5576
                    if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) 
                        goto efault;
P
pbrook 已提交
5577 5578 5579 5580 5581
                    target_fl->l_type = tswap16(fl.l_type);
                    target_fl->l_whence = tswap16(fl.l_whence);
                    target_fl->l_start = tswap64(fl.l_start);
                    target_fl->l_len = tswap64(fl.l_len);
                    target_fl->l_pid = tswapl(fl.l_pid);
5582
                    unlock_user_struct(target_fl, arg3, 1);
P
pbrook 已提交
5583
                }
B
bellard 已提交
5584 5585 5586
	    }
	    break;

T
ths 已提交
5587 5588
        case TARGET_F_SETLK64:
        case TARGET_F_SETLKW64:
P
pbrook 已提交
5589 5590
#ifdef TARGET_ARM
            if (((CPUARMState *)cpu_env)->eabi) {
B
bellard 已提交
5591 5592
                if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) 
                    goto efault;
P
pbrook 已提交
5593 5594 5595 5596 5597
                fl.l_type = tswap16(target_efl->l_type);
                fl.l_whence = tswap16(target_efl->l_whence);
                fl.l_start = tswap64(target_efl->l_start);
                fl.l_len = tswap64(target_efl->l_len);
                fl.l_pid = tswapl(target_efl->l_pid);
5598
                unlock_user_struct(target_efl, arg3, 0);
P
pbrook 已提交
5599 5600 5601
            } else
#endif
            {
B
bellard 已提交
5602 5603
                if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) 
                    goto efault;
P
pbrook 已提交
5604 5605 5606 5607 5608
                fl.l_type = tswap16(target_fl->l_type);
                fl.l_whence = tswap16(target_fl->l_whence);
                fl.l_start = tswap64(target_fl->l_start);
                fl.l_len = tswap64(target_fl->l_len);
                fl.l_pid = tswapl(target_fl->l_pid);
5609
                unlock_user_struct(target_fl, arg3, 0);
P
pbrook 已提交
5610
            }
T
ths 已提交
5611
            ret = get_errno(fcntl(arg1, cmd, &fl));
B
bellard 已提交
5612
	    break;
B
bellard 已提交
5613
        default:
B
bellard 已提交
5614
            ret = do_fcntl(arg1, cmd, arg3);
B
bellard 已提交
5615 5616
            break;
        }
B
bellard 已提交
5617 5618
	break;
    }
B
bellard 已提交
5619
#endif
5620 5621 5622 5623 5624 5625
#ifdef TARGET_NR_cacheflush
    case TARGET_NR_cacheflush:
        /* self-modifying code is handled automatically, so nothing needed */
        ret = 0;
        break;
#endif
5626
#ifdef TARGET_NR_security
5627 5628
    case TARGET_NR_security:
        goto unimplemented;
B
bellard 已提交
5629 5630 5631 5632 5633
#endif
#ifdef TARGET_NR_getpagesize
    case TARGET_NR_getpagesize:
        ret = TARGET_PAGE_SIZE;
        break;
5634
#endif
5635 5636 5637
    case TARGET_NR_gettid:
        ret = get_errno(gettid());
        break;
5638
#ifdef TARGET_NR_readahead
5639
    case TARGET_NR_readahead:
B
bellard 已提交
5640
        goto unimplemented;
5641
#endif
5642
#ifdef TARGET_NR_setxattr
5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654
    case TARGET_NR_setxattr:
    case TARGET_NR_lsetxattr:
    case TARGET_NR_fsetxattr:
    case TARGET_NR_getxattr:
    case TARGET_NR_lgetxattr:
    case TARGET_NR_fgetxattr:
    case TARGET_NR_listxattr:
    case TARGET_NR_llistxattr:
    case TARGET_NR_flistxattr:
    case TARGET_NR_removexattr:
    case TARGET_NR_lremovexattr:
    case TARGET_NR_fremovexattr:
B
bellard 已提交
5655
        goto unimplemented_nowarn;
5656 5657
#endif
#ifdef TARGET_NR_set_thread_area
B
bellard 已提交
5658
    case TARGET_NR_set_thread_area:
B
bellard 已提交
5659
#if defined(TARGET_MIPS)
5660 5661 5662
      ((CPUMIPSState *) cpu_env)->tls_value = arg1;
      ret = 0;
      break;
B
bellard 已提交
5663 5664 5665
#elif defined(TARGET_I386) && defined(TARGET_ABI32)
      ret = do_set_thread_area(cpu_env, arg1);
      break;
5666 5667 5668 5669 5670
#else
      goto unimplemented_nowarn;
#endif
#endif
#ifdef TARGET_NR_get_thread_area
B
bellard 已提交
5671
    case TARGET_NR_get_thread_area:
B
bellard 已提交
5672 5673 5674
#if defined(TARGET_I386) && defined(TARGET_ABI32)
        ret = do_get_thread_area(cpu_env, arg1);
#else
B
bellard 已提交
5675
        goto unimplemented_nowarn;
B
bellard 已提交
5676
#endif
B
bellard 已提交
5677
#endif
B
bellard 已提交
5678 5679 5680
#ifdef TARGET_NR_getdomainname
    case TARGET_NR_getdomainname:
        goto unimplemented_nowarn;
5681
#endif
5682

5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704
#ifdef TARGET_NR_clock_gettime
    case TARGET_NR_clock_gettime:
    {
        struct timespec ts;
        ret = get_errno(clock_gettime(arg1, &ts));
        if (!is_error(ret)) {
            host_to_target_timespec(arg2, &ts);
        }
        break;
    }
#endif
#ifdef TARGET_NR_clock_getres
    case TARGET_NR_clock_getres:
    {
        struct timespec ts;
        ret = get_errno(clock_getres(arg1, &ts));
        if (!is_error(ret)) {
            host_to_target_timespec(arg2, &ts);
        }
        break;
    }
#endif
P
pbrook 已提交
5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715
#ifdef TARGET_NR_clock_nanosleep
    case TARGET_NR_clock_nanosleep:
    {
        struct timespec ts;
        target_to_host_timespec(&ts, arg3);
        ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
        if (arg4)
            host_to_target_timespec(arg4, &ts);
        break;
    }
#endif
5716

5717 5718
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
    case TARGET_NR_set_tid_address:
5719 5720
        ret = get_errno(set_tid_address((int *)g2h(arg1)));
        break;
5721 5722
#endif

T
ths 已提交
5723
#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
T
ths 已提交
5724
    case TARGET_NR_tkill:
5725
        ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
T
ths 已提交
5726 5727 5728
        break;
#endif

T
ths 已提交
5729
#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
T
ths 已提交
5730
    case TARGET_NR_tgkill:
5731 5732
	ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
                        target_to_host_signal(arg3)));
T
ths 已提交
5733 5734 5735
	break;
#endif

5736 5737 5738 5739 5740
#ifdef TARGET_NR_set_robust_list
    case TARGET_NR_set_robust_list:
	goto unimplemented_nowarn;
#endif

5741 5742 5743 5744 5745 5746 5747 5748 5749
#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
    case TARGET_NR_utimensat:
        {
            struct timespec ts[2];
            target_to_host_timespec(ts, arg3);
            target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
            if (!arg2)
                ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4));
            else {
5750
                if (!(p = lock_user_string(arg2))) {
5751
                    ret = -TARGET_EFAULT;
5752 5753 5754 5755
                    goto fail;
                }
                ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4));
                unlock_user(p, arg2, 0);
5756 5757 5758 5759
            }
        }
	break;
#endif
5760 5761 5762 5763 5764
#if defined(USE_NPTL)
    case TARGET_NR_futex:
        ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
        break;
#endif
5765

5766 5767
    default:
    unimplemented:
B
bellard 已提交
5768
        gemu_log("qemu: Unsupported syscall: %d\n", num);
5769
#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list)
B
bellard 已提交
5770
    unimplemented_nowarn:
B
bellard 已提交
5771
#endif
5772
        ret = -TARGET_ENOSYS;
5773 5774
        break;
    }
5775
fail:
B
bellard 已提交
5776 5777 5778
#ifdef DEBUG
    gemu_log(" = %ld\n", ret);
#endif
5779 5780
    if(do_strace)
        print_syscall_ret(num, ret);
5781
    return ret;
5782 5783 5784
efault:
    ret = -TARGET_EFAULT;
    goto fail;
5785
}