syscall.c 202.2 KB
Newer Older
1 2
/*
 *  Linux syscalls
3
 *
4 5 6 7 8 9 10 11 12 13 14 15 16 17
 *  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
B
blueswir1 已提交
18 19
 *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
 *  MA 02110-1301, USA.
20 21 22 23
 */
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
B
bellard 已提交
24
#include <string.h>
25 26 27 28 29
#include <elf.h>
#include <endian.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
B
bellard 已提交
30
#include <time.h>
31
#include <limits.h>
32
#include <mqueue.h>
33
#include <sys/types.h>
T
ths 已提交
34 35
#include <sys/ipc.h>
#include <sys/msg.h>
36 37 38 39
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/mount.h>
40
#include <sys/prctl.h>
41 42 43 44 45 46
#include <sys/resource.h>
#include <sys/mman.h>
#include <sys/swap.h>
#include <signal.h>
#include <sched.h>
#include <sys/socket.h>
47
#include <sys/un.h>
48
#include <sys/uio.h>
B
bellard 已提交
49
#include <sys/poll.h>
B
bellard 已提交
50
#include <sys/times.h>
51
#include <sys/shm.h>
52
#include <sys/sem.h>
B
bellard 已提交
53
#include <sys/statfs.h>
54
#include <utime.h>
B
bellard 已提交
55
#include <sys/sysinfo.h>
56
#include <sys/utsname.h>
B
bellard 已提交
57
//#include <sys/user.h>
58
#include <netinet/ip.h>
B
bellard 已提交
59
#include <netinet/tcp.h>
A
aurel32 已提交
60
#include <qemu-common.h>
A
aurel32 已提交
61 62 63
#ifdef HAVE_GPROF
#include <sys/gmon.h>
#endif
64 65 66 67

#define termios host_termios
#define winsize host_winsize
#define termio host_termio
B
bellard 已提交
68 69 70
#define sgttyb host_sgttyb /* same as target */
#define tchars host_tchars /* same as target */
#define ltchars host_ltchars /* same as target */
71 72 73 74 75 76 77

#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 已提交
78
#include <linux/kd.h>
79
#include <linux/mtio.h>
80
#include "linux_loop.h"
81

B
bellard 已提交
82
#include "qemu.h"
83
#include "qemu-common.h"
84

P
pbrook 已提交
85 86
#if defined(USE_NPTL)
#include <linux/futex.h>
P
pbrook 已提交
87 88 89 90 91
#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 已提交
92 93
#endif

B
bellard 已提交
94
//#define DEBUG
95

P
pbrook 已提交
96
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
97
    || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
98 99 100 101
/* 16 bit uid wrappers emulation */
#define USE_UID16
#endif

B
bellard 已提交
102
//#include <linux/msdos_fs.h>
A
aurel32 已提交
103 104
#define	VFAT_IOCTL_READDIR_BOTH		_IOR('r', 1, struct linux_dirent [2])
#define	VFAT_IOCTL_READDIR_SHORT	_IOR('r', 2, struct linux_dirent [2])
B
bellard 已提交
105

106 107 108 109 110 111 112

#undef _syscall0
#undef _syscall1
#undef _syscall2
#undef _syscall3
#undef _syscall4
#undef _syscall5
B
bellard 已提交
113
#undef _syscall6
114

B
bellard 已提交
115
#define _syscall0(type,name)		\
116
static type name (void)			\
B
bellard 已提交
117 118 119
{					\
	return syscall(__NR_##name);	\
}
120

B
bellard 已提交
121
#define _syscall1(type,name,type1,arg1)		\
122
static type name (type1 arg1)			\
B
bellard 已提交
123 124
{						\
	return syscall(__NR_##name, arg1);	\
125 126
}

B
bellard 已提交
127
#define _syscall2(type,name,type1,arg1,type2,arg2)	\
128
static type name (type1 arg1,type2 arg2)		\
B
bellard 已提交
129 130
{							\
	return syscall(__NR_##name, arg1, arg2);	\
131 132
}

B
bellard 已提交
133
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)	\
134
static type name (type1 arg1,type2 arg2,type3 arg3)		\
B
bellard 已提交
135 136
{								\
	return syscall(__NR_##name, arg1, arg2, arg3);		\
137 138
}

B
bellard 已提交
139
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)	\
140
static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4)			\
B
bellard 已提交
141 142
{										\
	return syscall(__NR_##name, arg1, arg2, arg3, arg4);			\
143 144
}

B
bellard 已提交
145 146
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,	\
		  type5,arg5)							\
147
static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5)	\
B
bellard 已提交
148 149
{										\
	return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5);		\
150 151
}

B
bellard 已提交
152 153 154

#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,	\
		  type5,arg5,type6,arg6)					\
155 156
static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,	\
                  type6 arg6)							\
B
bellard 已提交
157 158
{										\
	return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6);	\
159
}
B
bellard 已提交
160

161

162
#define __NR_sys_uname __NR_uname
163
#define __NR_sys_faccessat __NR_faccessat
164
#define __NR_sys_fchmodat __NR_fchmodat
165
#define __NR_sys_fchownat __NR_fchownat
166
#define __NR_sys_fstatat64 __NR_fstatat64
167
#define __NR_sys_futimesat __NR_futimesat
B
bellard 已提交
168 169
#define __NR_sys_getcwd1 __NR_getcwd
#define __NR_sys_getdents __NR_getdents
B
bellard 已提交
170
#define __NR_sys_getdents64 __NR_getdents64
171
#define __NR_sys_getpriority __NR_getpriority
172
#define __NR_sys_linkat __NR_linkat
173
#define __NR_sys_mkdirat __NR_mkdirat
174
#define __NR_sys_mknodat __NR_mknodat
175
#define __NR_sys_newfstatat __NR_newfstatat
176
#define __NR_sys_openat __NR_openat
177
#define __NR_sys_readlinkat __NR_readlinkat
178
#define __NR_sys_renameat __NR_renameat
B
bellard 已提交
179
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
180
#define __NR_sys_symlinkat __NR_symlinkat
181
#define __NR_sys_syslog __NR_syslog
T
ths 已提交
182
#define __NR_sys_tgkill __NR_tgkill
T
ths 已提交
183
#define __NR_sys_tkill __NR_tkill
184
#define __NR_sys_unlinkat __NR_unlinkat
185
#define __NR_sys_utimensat __NR_utimensat
186
#define __NR_sys_futex __NR_futex
A
aurel32 已提交
187 188 189
#define __NR_sys_inotify_init __NR_inotify_init
#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
190

191
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
B
bellard 已提交
192 193 194
#define __NR__llseek __NR_lseek
#endif

B
bellard 已提交
195
#ifdef __NR_gettid
196
_syscall0(int, gettid)
B
bellard 已提交
197
#else
198 199
/* This is a replacement for the host gettid() and must return a host
   errno. */
B
bellard 已提交
200 201 202 203
static int gettid(void) {
    return -ENOSYS;
}
#endif
204 205 206 207 208 209 210
#if TARGET_ABI_BITS == 32
_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
#endif
#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
#endif
_syscall2(int, sys_getpriority, int, which, int, who);
211
#if defined(TARGET_NR__llseek) && !defined (__x86_64__)
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
_syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
          loff_t *, res, uint, wh);
#endif
_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
#endif
#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
_syscall2(int,sys_tkill,int,tid,int,sig)
#endif
#ifdef __NR_exit_group
_syscall1(int,exit_group,int,error_code)
#endif
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
_syscall1(int,set_tid_address,int *,tidptr)
#endif
#if defined(USE_NPTL)
#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
#endif

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, },
#if defined(O_DIRECT)
  { TARGET_O_DIRECT,    TARGET_O_DIRECT,    O_DIRECT,    O_DIRECT,    },
#endif
  { 0, 0, 0, 0 }
};

#define COPY_UTSNAME_FIELD(dest, src) \
  do { \
      /* __NEW_UTS_LEN doesn't include terminating null */ \
      (void) strncpy((dest), (src), __NEW_UTS_LEN); \
      (dest)[__NEW_UTS_LEN] = '\0'; \
  } while (0)

static int sys_uname(struct new_utsname *buf)
{
  struct utsname uts_buf;

  if (uname(&uts_buf) < 0)
      return (-1);

  /*
   * Just in case these have some differences, we
   * translate utsname to new_utsname (which is the
   * struct linux kernel uses).
   */

  bzero(buf, sizeof (*buf));
  COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
  COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
  COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
  COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
  COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
#ifdef _GNU_SOURCE
  COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
#endif
  return (0);

#undef COPY_UTSNAME_FIELD
}

static int sys_getcwd1(char *buf, size_t size)
{
  if (getcwd(buf, size) == NULL) {
      /* getcwd() sets errno */
      return (-1);
  }
A
aurel32 已提交
296
  return strlen(buf)+1;
297 298 299 300 301 302 303 304 305
}

#ifdef CONFIG_ATFILE
/*
 * Host system seems to have atfile syscall stubs available.  We
 * now enable them one by one as specified by target syscall_nr.h.
 */

#ifdef TARGET_NR_faccessat
306
static int sys_faccessat(int dirfd, const char *pathname, int mode)
307
{
308
  return (faccessat(dirfd, pathname, mode, 0));
309 310 311
}
#endif
#ifdef TARGET_NR_fchmodat
312
static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
313
{
314
  return (fchmodat(dirfd, pathname, mode, 0));
315 316
}
#endif
317
#if defined(TARGET_NR_fchownat) && defined(USE_UID16)
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 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
    gid_t group, int flags)
{
  return (fchownat(dirfd, pathname, owner, group, flags));
}
#endif
#ifdef __NR_fstatat64
static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
    int flags)
{
  return (fstatat(dirfd, pathname, buf, flags));
}
#endif
#ifdef __NR_newfstatat
static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
    int flags)
{
  return (fstatat(dirfd, pathname, buf, flags));
}
#endif
#ifdef TARGET_NR_futimesat
static int sys_futimesat(int dirfd, const char *pathname,
    const struct timeval times[2])
{
  return (futimesat(dirfd, pathname, times));
}
#endif
#ifdef TARGET_NR_linkat
static int sys_linkat(int olddirfd, const char *oldpath,
    int newdirfd, const char *newpath, int flags)
{
  return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
}
#endif
#ifdef TARGET_NR_mkdirat
static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
{
  return (mkdirat(dirfd, pathname, mode));
}
#endif
#ifdef TARGET_NR_mknodat
static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
    dev_t dev)
{
  return (mknodat(dirfd, pathname, mode, dev));
}
#endif
#ifdef TARGET_NR_openat
static int sys_openat(int dirfd, const char *pathname, int flags, ...)
{
  /*
   * open(2) has extra parameter 'mode' when called with
   * flag O_CREAT.
   */
  if ((flags & O_CREAT) != 0) {
      va_list ap;
      mode_t mode;

      /*
       * Get the 'mode' parameter and translate it to
       * host bits.
       */
      va_start(ap, flags);
      mode = va_arg(ap, mode_t);
      mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
      va_end(ap);

      return (openat(dirfd, pathname, flags, mode));
  }
  return (openat(dirfd, pathname, flags));
}
#endif
#ifdef TARGET_NR_readlinkat
static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
{
  return (readlinkat(dirfd, pathname, buf, bufsiz));
}
#endif
#ifdef TARGET_NR_renameat
static int sys_renameat(int olddirfd, const char *oldpath,
    int newdirfd, const char *newpath)
{
  return (renameat(olddirfd, oldpath, newdirfd, newpath));
}
#endif
#ifdef TARGET_NR_symlinkat
static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
{
  return (symlinkat(oldpath, newdirfd, newpath));
}
#endif
#ifdef TARGET_NR_unlinkat
static int sys_unlinkat(int dirfd, const char *pathname, int flags)
{
  return (unlinkat(dirfd, pathname, flags));
}
#endif
#ifdef TARGET_NR_utimensat
static int sys_utimensat(int dirfd, const char *pathname,
    const struct timespec times[2], int flags)
{
  return (utimensat(dirfd, pathname, times, flags));
}
#endif
#else /* !CONFIG_ATFILE */

/*
 * Try direct syscalls instead
 */
427
#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
428
_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
429
#endif
430
#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
431
_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
432
#endif
433
#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16)
434 435 436
_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
          uid_t,owner,gid_t,group,int,flags)
#endif
437 438
#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
        defined(__NR_fstatat64)
439 440 441
_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
          struct stat *,buf,int,flags)
#endif
442 443 444 445
#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
         const struct timeval *,times)
#endif
446 447 448 449
#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
        defined(__NR_newfstatat)
_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
          struct stat *,buf,int,flags)
450
#endif
451 452
#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
453
      int,newdirfd,const char *,newpath,int,flags)
454
#endif
455 456 457
#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
#endif
458 459 460 461
#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
          mode_t,mode,dev_t,dev)
#endif
462 463 464
#if defined(TARGET_NR_openat) && defined(__NR_openat)
_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
#endif
465 466 467 468
#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
          char *,buf,size_t,bufsize)
#endif
469 470 471 472
#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
          int,newdirfd,const char *,newpath)
#endif
473
#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
474 475 476
_syscall3(int,sys_symlinkat,const char *,oldpath,
          int,newdirfd,const char *,newpath)
#endif
477 478 479
#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
#endif
480 481 482 483
#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
          const struct timespec *,tsp,int,flags)
#endif
484 485 486 487

#endif /* CONFIG_ATFILE */

#ifdef CONFIG_INOTIFY
A
aurel32 已提交
488
#include <sys/inotify.h>
489

A
aurel32 已提交
490
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
491 492 493 494
static int sys_inotify_init(void)
{
  return (inotify_init());
}
A
aurel32 已提交
495 496
#endif
#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
497 498 499 500
static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
{
  return (inotify_add_watch(fd, pathname, mask));
}
A
aurel32 已提交
501 502
#endif
#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
503 504
static int sys_inotify_rm_watch(int fd, int32_t wd)
{
A
aurel32 已提交
505
  return (inotify_rm_watch(fd, wd));
506
}
507
#endif
508 509 510 511 512 513 514
#else
/* Userspace can usually survive runtime without inotify */
#undef TARGET_NR_inotify_init
#undef TARGET_NR_inotify_add_watch
#undef TARGET_NR_inotify_rm_watch
#endif /* CONFIG_INOTIFY  */

B
bellard 已提交
515 516

extern int personality(int);
B
bellard 已提交
517 518 519
extern int flock(int, int);
extern int setfsuid(int);
extern int setfsgid(int);
B
bellard 已提交
520
extern int setgroups(int, gid_t *);
521

522 523 524 525 526 527 528
#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] = {
};

529
/*
T
ths 已提交
530
 * This list is the union of errno values overridden in asm-<arch>/errno.h
531 532
 * minus the errnos that are not actually generic to all archs.
 */
533
static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
    [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 已提交
621
#ifdef ENOKEY
622
    [ENOKEY]		= TARGET_ENOKEY,
T
ths 已提交
623 624
#endif
#ifdef EKEYEXPIRED
625
    [EKEYEXPIRED]	= TARGET_EKEYEXPIRED,
T
ths 已提交
626 627
#endif
#ifdef EKEYREVOKED
628
    [EKEYREVOKED]	= TARGET_EKEYREVOKED,
T
ths 已提交
629 630
#endif
#ifdef EKEYREJECTED
631
    [EKEYREJECTED]	= TARGET_EKEYREJECTED,
T
ths 已提交
632 633
#endif
#ifdef EOWNERDEAD
634
    [EOWNERDEAD]	= TARGET_EOWNERDEAD,
T
ths 已提交
635 636
#endif
#ifdef ENOTRECOVERABLE
637
    [ENOTRECOVERABLE]	= TARGET_ENOTRECOVERABLE,
T
ths 已提交
638
#endif
639
};
640 641 642 643 644 645 646 647

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;
}

648 649 650 651 652 653 654
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;
}

655
static inline abi_long get_errno(abi_long ret)
656 657
{
    if (ret == -1)
658
        return -host_to_target_errno(errno);
659 660 661 662
    else
        return ret;
}

663
static inline int is_error(abi_long ret)
664
{
665
    return (abi_ulong)ret >= (abi_ulong)(-4096);
666 667
}

668 669 670 671 672
char *target_strerror(int err)
{
    return strerror(target_to_host_errno(err));
}

673 674
static abi_ulong target_brk;
static abi_ulong target_original_brk;
675

676
void target_set_brk(abi_ulong new_brk)
677
{
678
    target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
679 680
}

681
/* do_brk() must return target values and target errnos. */
682
abi_long do_brk(abi_ulong new_brk)
683
{
684 685
    abi_ulong brk_page;
    abi_long mapped_addr;
686 687 688
    int	new_alloc_size;

    if (!new_brk)
689
        return target_brk;
690
    if (new_brk < target_original_brk)
691
        return target_brk;
692

693
    brk_page = HOST_PAGE_ALIGN(target_brk);
694 695 696 697

    /* If the new brk is less than this, set it and we're done... */
    if (new_brk < brk_page) {
	target_brk = new_brk;
698
    	return target_brk;
699 700 701
    }

    /* We need to allocate more memory after the brk... */
B
bellard 已提交
702
    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
703
    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
B
bellard 已提交
704 705
                                        PROT_READ|PROT_WRITE,
                                        MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0));
706 707

    if (!is_error(mapped_addr))
708
	target_brk = new_brk;
709 710
    
    return target_brk;
711 712
}

713 714 715
static inline abi_long copy_from_user_fdset(fd_set *fds,
                                            abi_ulong target_fds_addr,
                                            int n)
716
{
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
    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++;
737 738
        }
    }
739 740 741 742

    unlock_user(target_fds, target_fds_addr, 0);

    return 0;
743 744
}

745 746 747
static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
                                          const fd_set *fds,
                                          int n)
748 749
{
    int i, nw, j, k;
750
    abi_long v;
751
    abi_ulong *target_fds;
752

753 754 755 756 757 758 759 760 761 762 763 764 765
    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++;
766
        }
767
        __put_user(v, &target_fds[i]);
768
    }
769 770 771 772

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

    return 0;
773 774
}

B
bellard 已提交
775 776 777 778 779 780
#if defined(__alpha__)
#define HOST_HZ 1024
#else
#define HOST_HZ 100
#endif

781
static inline abi_long host_to_target_clock_t(long ticks)
B
bellard 已提交
782 783 784 785 786 787 788 789
{
#if HOST_HZ == TARGET_HZ
    return ticks;
#else
    return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
#endif
}

790 791
static inline abi_long host_to_target_rusage(abi_ulong target_addr,
                                             const struct rusage *rusage)
B
bellard 已提交
792
{
793 794
    struct target_rusage *target_rusage;

795 796
    if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
        return -TARGET_EFAULT;
B
bellard 已提交
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814
    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);
815
    unlock_user_struct(target_rusage, target_addr, 1);
816 817

    return 0;
B
bellard 已提交
818 819
}

820 821
static inline abi_long copy_from_user_timeval(struct timeval *tv,
                                              abi_ulong target_tv_addr)
822
{
823 824
    struct target_timeval *target_tv;

825
    if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
826
        return -TARGET_EFAULT;
827 828 829 830 831

    __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);
832 833

    return 0;
834 835
}

836 837
static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
                                            const struct timeval *tv)
838
{
839 840
    struct target_timeval *target_tv;

841
    if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
842
        return -TARGET_EFAULT;
843 844 845 846 847

    __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);
848 849

    return 0;
850 851
}

852 853 854 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
static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
                                              abi_ulong target_mq_attr_addr)
{
    struct target_mq_attr *target_mq_attr;

    if (!lock_user_struct(VERIFY_READ, target_mq_attr,
                          target_mq_attr_addr, 1))
        return -TARGET_EFAULT;

    __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
    __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
    __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
    __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);

    unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);

    return 0;
}

static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
                                            const struct mq_attr *attr)
{
    struct target_mq_attr *target_mq_attr;

    if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
                          target_mq_attr_addr, 0))
        return -TARGET_EFAULT;

    __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
    __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
    __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
    __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);

    unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);

    return 0;
}
889

890
/* do_select() must return target values and target errnos. */
891
static abi_long do_select(int n,
892 893
                          abi_ulong rfd_addr, abi_ulong wfd_addr,
                          abi_ulong efd_addr, abi_ulong target_tv_addr)
894 895 896 897
{
    fd_set rfds, wfds, efds;
    fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
    struct timeval tv, *tv_ptr;
898
    abi_long ret;
899

900 901 902 903
    if (rfd_addr) {
        if (copy_from_user_fdset(&rfds, rfd_addr, n))
            return -TARGET_EFAULT;
        rfds_ptr = &rfds;
904 905 906
    } else {
        rfds_ptr = NULL;
    }
907 908 909 910
    if (wfd_addr) {
        if (copy_from_user_fdset(&wfds, wfd_addr, n))
            return -TARGET_EFAULT;
        wfds_ptr = &wfds;
911 912 913
    } else {
        wfds_ptr = NULL;
    }
914 915 916 917
    if (efd_addr) {
        if (copy_from_user_fdset(&efds, efd_addr, n))
            return -TARGET_EFAULT;
        efds_ptr = &efds;
918 919 920
    } else {
        efds_ptr = NULL;
    }
921

922
    if (target_tv_addr) {
923 924
        if (copy_from_user_timeval(&tv, target_tv_addr))
            return -TARGET_EFAULT;
925 926 927 928
        tv_ptr = &tv;
    } else {
        tv_ptr = NULL;
    }
929

930
    ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
931

932 933 934 935 936 937 938
    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;
939

940 941
        if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
            return -TARGET_EFAULT;
942
    }
943

944 945 946
    return ret;
}

947 948 949
static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
                                               abi_ulong target_addr,
                                               socklen_t len)
B
bellard 已提交
950
{
951 952
    const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
    sa_family_t sa_family;
953 954
    struct target_sockaddr *target_saddr;

955 956 957
    target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
    if (!target_saddr)
        return -TARGET_EFAULT;
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979

    sa_family = tswap16(target_saddr->sa_family);

    /* Oops. The caller might send a incomplete sun_path; sun_path
     * must be terminated by \0 (see the manual page), but
     * unfortunately it is quite common to specify sockaddr_un
     * length as "strlen(x->sun_path)" while it should be
     * "strlen(...) + 1". We'll fix that here if needed.
     * Linux kernel has a similar feature.
     */

    if (sa_family == AF_UNIX) {
        if (len < unix_maxlen && len > 0) {
            char *cp = (char*)target_saddr;

            if ( cp[len-1] && !cp[len] )
                len++;
        }
        if (len > unix_maxlen)
            len = unix_maxlen;
    }

980
    memcpy(addr, target_saddr, len);
981
    addr->sa_family = sa_family;
982
    unlock_user(target_saddr, target_addr, 0);
983 984

    return 0;
B
bellard 已提交
985 986
}

987 988 989
static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
                                               struct sockaddr *addr,
                                               socklen_t len)
B
bellard 已提交
990
{
991 992
    struct target_sockaddr *target_saddr;

993 994 995
    target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
    if (!target_saddr)
        return -TARGET_EFAULT;
996 997 998
    memcpy(target_saddr, addr, len);
    target_saddr->sa_family = tswap16(addr->sa_family);
    unlock_user(target_saddr, target_addr, len);
999 1000

    return 0;
B
bellard 已提交
1001 1002
}

1003
/* ??? Should this also swap msgh->name?  */
1004 1005
static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
                                           struct target_msghdr *target_msgh)
B
bellard 已提交
1006 1007
{
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
1008 1009 1010
    abi_long msg_controllen;
    abi_ulong target_cmsg_addr;
    struct target_cmsghdr *target_cmsg;
B
bellard 已提交
1011
    socklen_t space = 0;
1012 1013 1014 1015 1016 1017 1018 1019
    
    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 已提交
1020 1021 1022 1023 1024

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

1025
        int len = tswapl(target_cmsg->cmsg_len)
B
bellard 已提交
1026 1027 1028 1029 1030
                  - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));

        space += CMSG_SPACE(len);
        if (space > msgh->msg_controllen) {
            space -= CMSG_SPACE(len);
B
bellard 已提交
1031
            gemu_log("Host cmsg overflow\n");
B
bellard 已提交
1032 1033 1034 1035 1036 1037 1038
            break;
        }

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

1039
        if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
B
bellard 已提交
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
            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);
    }
1054 1055
    unlock_user(target_cmsg, target_cmsg_addr, 0);
 the_end:
B
bellard 已提交
1056
    msgh->msg_controllen = space;
1057
    return 0;
B
bellard 已提交
1058 1059
}

1060
/* ??? Should this also swap msgh->name?  */
1061 1062
static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
                                           struct msghdr *msgh)
B
bellard 已提交
1063 1064
{
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
1065 1066 1067
    abi_long msg_controllen;
    abi_ulong target_cmsg_addr;
    struct target_cmsghdr *target_cmsg;
B
bellard 已提交
1068 1069
    socklen_t space = 0;

1070 1071 1072 1073 1074 1075 1076 1077
    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 已提交
1078 1079 1080 1081 1082 1083 1084
    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);
1085
        if (space > msg_controllen) {
B
bellard 已提交
1086
            space -= TARGET_CMSG_SPACE(len);
B
bellard 已提交
1087
            gemu_log("Target cmsg overflow\n");
B
bellard 已提交
1088 1089 1090 1091 1092 1093 1094
            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));

1095
        if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
B
bellard 已提交
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
            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);
    }
1110 1111 1112 1113
    unlock_user(target_cmsg, target_cmsg_addr, space);
 the_end:
    target_msgh->msg_controllen = tswapl(space);
    return 0;
B
bellard 已提交
1114 1115
}

1116
/* do_setsockopt() Must return target values and target errnos. */
1117
static abi_long do_setsockopt(int sockfd, int level, int optname,
1118
                              abi_ulong optval_addr, socklen_t optlen)
B
bellard 已提交
1119
{
1120
    abi_long ret;
1121
    int val;
1122

1123 1124
    switch(level) {
    case SOL_TCP:
B
bellard 已提交
1125 1126
        /* TCP options all take an 'int' value.  */
        if (optlen < sizeof(uint32_t))
1127
            return -TARGET_EINVAL;
1128

1129 1130
        if (get_user_u32(val, optval_addr))
            return -TARGET_EFAULT;
1131 1132 1133 1134
        ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
        break;
    case SOL_IP:
        switch(optname) {
B
bellard 已提交
1135 1136
        case IP_TOS:
        case IP_TTL:
1137
        case IP_HDRINCL:
B
bellard 已提交
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
        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:
1150 1151
            val = 0;
            if (optlen >= sizeof(uint32_t)) {
1152 1153
                if (get_user_u32(val, optval_addr))
                    return -TARGET_EFAULT;
1154
            } else if (optlen >= 1) {
1155 1156
                if (get_user_u8(val, optval_addr))
                    return -TARGET_EFAULT;
1157 1158 1159 1160 1161 1162 1163
            }
            ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
            break;
        default:
            goto unimplemented;
        }
        break;
1164
    case TARGET_SOL_SOCKET:
1165 1166
        switch (optname) {
            /* Options with 'int' argument.  */
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202
        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 已提交
1203
#ifdef SO_BSDCOMPAT
1204 1205 1206
        case TARGET_SO_BSDCOMPAT:
		optname = SO_BSDCOMPAT;
		break;
B
bellard 已提交
1207
#endif
1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
        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;
1223 1224 1225 1226
            break;
        default:
            goto unimplemented;
        }
1227
	if (optlen < sizeof(uint32_t))
1228
            return -TARGET_EINVAL;
1229

1230 1231
	if (get_user_u32(val, optval_addr))
            return -TARGET_EFAULT;
1232
	ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
1233
        break;
B
bellard 已提交
1234
    default:
1235 1236
    unimplemented:
        gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
1237
        ret = -TARGET_ENOPROTOOPT;
B
bellard 已提交
1238
    }
1239
    return ret;
B
bellard 已提交
1240 1241
}

1242
/* do_getsockopt() Must return target values and target errnos. */
1243
static abi_long do_getsockopt(int sockfd, int level, int optname,
1244
                              abi_ulong optval_addr, abi_ulong optlen)
B
bellard 已提交
1245
{
1246
    abi_long ret;
1247 1248
    int len, val;
    socklen_t lv;
1249 1250

    switch(level) {
1251 1252
    case TARGET_SOL_SOCKET:
    	level = SOL_SOCKET;
1253
	switch (optname) {
1254 1255 1256 1257 1258
	case TARGET_SO_LINGER:
	case TARGET_SO_RCVTIMEO:
	case TARGET_SO_SNDTIMEO:
	case TARGET_SO_PEERCRED:
	case TARGET_SO_PEERNAME:
1259 1260 1261
	    /* These don't just return a single integer */
	    goto unimplemented;
        default:
B
bellard 已提交
1262 1263 1264 1265 1266 1267
            goto int_case;
        }
        break;
    case SOL_TCP:
        /* TCP options all take an 'int' value.  */
    int_case:
1268 1269
        if (get_user_u32(len, optlen))
            return -TARGET_EFAULT;
B
bellard 已提交
1270
        if (len < 0)
1271
            return -TARGET_EINVAL;
B
bellard 已提交
1272 1273 1274 1275 1276 1277 1278
        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;
1279 1280 1281 1282 1283 1284 1285 1286 1287
        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 已提交
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
        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:
1306 1307
            if (get_user_u32(len, optlen))
                return -TARGET_EFAULT;
1308
            if (len < 0)
1309
                return -TARGET_EINVAL;
1310 1311 1312 1313
            lv = sizeof(int);
            ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
            if (ret < 0)
                return ret;
B
bellard 已提交
1314 1315
            if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
                len = 1;
1316 1317 1318
                if (put_user_u32(len, optlen)
                    || put_user_u8(val, optval_addr))
                    return -TARGET_EFAULT;
B
bellard 已提交
1319 1320 1321
            } else {
                if (len > sizeof(int))
                    len = sizeof(int);
1322 1323 1324
                if (put_user_u32(len, optlen)
                    || put_user_u32(val, optval_addr))
                    return -TARGET_EFAULT;
B
bellard 已提交
1325
            }
1326
            break;
B
bellard 已提交
1327
        default:
1328 1329
            ret = -TARGET_ENOPROTOOPT;
            break;
1330 1331 1332 1333 1334 1335
        }
        break;
    default:
    unimplemented:
        gemu_log("getsockopt level=%d optname=%d not yet supported\n",
                 level, optname);
1336
        ret = -TARGET_EOPNOTSUPP;
1337 1338 1339
        break;
    }
    return ret;
B
bellard 已提交
1340 1341
}

1342 1343 1344 1345 1346 1347
/* 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)
1348 1349
{
    struct target_iovec *target_vec;
1350
    abi_ulong base;
1351
    int i;
1352

1353 1354 1355
    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
    if (!target_vec)
        return -TARGET_EFAULT;
1356 1357 1358
    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 已提交
1359 1360
        if (vec[i].iov_len != 0) {
            vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
1361 1362
            /* Don't check lock_user return value. We must call writev even
               if a element has invalid base address. */
B
bellard 已提交
1363 1364 1365 1366
        } else {
            /* zero length pointer is ignored */
            vec[i].iov_base = NULL;
        }
1367 1368 1369
    }
    unlock_user (target_vec, target_addr, 0);
    return 0;
1370 1371
}

1372 1373
static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
                             int count, int copy)
1374 1375
{
    struct target_iovec *target_vec;
1376
    abi_ulong base;
1377 1378
    int i;

1379 1380 1381
    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
    if (!target_vec)
        return -TARGET_EFAULT;
1382
    for(i = 0;i < count; i++) {
1383 1384 1385 1386
        if (target_vec[i].iov_base) {
            base = tswapl(target_vec[i].iov_base);
            unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
        }
1387 1388
    }
    unlock_user (target_vec, target_addr, 0);
1389 1390

    return 0;
1391 1392
}

1393
/* do_socket() Must return target values and target errnos. */
1394
static abi_long do_socket(int domain, int type, int protocol)
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
{
#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
1418 1419
    if (domain == PF_NETLINK)
        return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
1420 1421 1422
    return get_errno(socket(domain, type, protocol));
}

1423
/* do_bind() Must return target values and target errnos. */
1424 1425
static abi_long do_bind(int sockfd, abi_ulong target_addr,
                        socklen_t addrlen)
1426
{
1427 1428
    void *addr;

1429
    if (addrlen < 0)
1430 1431
        return -TARGET_EINVAL;

1432
    addr = alloca(addrlen+1);
1433

1434 1435 1436 1437
    target_to_host_sockaddr(addr, target_addr, addrlen);
    return get_errno(bind(sockfd, addr, addrlen));
}

1438
/* do_connect() Must return target values and target errnos. */
1439 1440
static abi_long do_connect(int sockfd, abi_ulong target_addr,
                           socklen_t addrlen)
1441
{
1442 1443
    void *addr;

1444
    if (addrlen < 0)
1445 1446 1447
        return -TARGET_EINVAL;

    addr = alloca(addrlen);
1448

1449 1450 1451 1452
    target_to_host_sockaddr(addr, target_addr, addrlen);
    return get_errno(connect(sockfd, addr, addrlen));
}

1453
/* do_sendrecvmsg() Must return target values and target errnos. */
1454 1455
static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
                               int flags, int send)
1456
{
1457
    abi_long ret, len;
1458 1459 1460 1461
    struct target_msghdr *msgp;
    struct msghdr msg;
    int count;
    struct iovec *vec;
1462
    abi_ulong target_vec;
1463

1464 1465 1466 1467 1468 1469
    /* FIXME */
    if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
                          msgp,
                          target_msg,
                          send ? 1 : 0))
        return -TARGET_EFAULT;
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
    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);
1482

1483 1484 1485
    count = tswapl(msgp->msg_iovlen);
    vec = alloca(count * sizeof(struct iovec));
    target_vec = tswapl(msgp->msg_iov);
1486
    lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
1487 1488
    msg.msg_iovlen = count;
    msg.msg_iov = vec;
1489

1490
    if (send) {
1491 1492 1493
        ret = target_to_host_cmsg(&msg, msgp);
        if (ret == 0)
            ret = get_errno(sendmsg(fd, &msg, flags));
1494 1495
    } else {
        ret = get_errno(recvmsg(fd, &msg, flags));
1496 1497
        if (!is_error(ret)) {
            len = ret;
1498
            ret = host_to_target_cmsg(msgp, &msg);
1499 1500 1501
            if (!is_error(ret))
                ret = len;
        }
1502 1503
    }
    unlock_iovec(vec, target_vec, count, !send);
1504
    unlock_user_struct(msgp, target_msg, send ? 0 : 1);
1505 1506 1507
    return ret;
}

1508
/* do_accept() Must return target values and target errnos. */
1509
static abi_long do_accept(int fd, abi_ulong target_addr,
1510
                          abi_ulong target_addrlen_addr)
P
pbrook 已提交
1511
{
1512 1513
    socklen_t addrlen;
    void *addr;
1514
    abi_long ret;
P
pbrook 已提交
1515

1516 1517 1518
    if (get_user_u32(addrlen, target_addrlen_addr))
        return -TARGET_EFAULT;

1519
    if (addrlen < 0)
1520 1521
        return -TARGET_EINVAL;

1522 1523
    addr = alloca(addrlen);

P
pbrook 已提交
1524 1525 1526
    ret = get_errno(accept(fd, addr, &addrlen));
    if (!is_error(ret)) {
        host_to_target_sockaddr(target_addr, addr, addrlen);
1527 1528
        if (put_user_u32(addrlen, target_addrlen_addr))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1529 1530 1531 1532
    }
    return ret;
}

1533
/* do_getpeername() Must return target values and target errnos. */
1534
static abi_long do_getpeername(int fd, abi_ulong target_addr,
1535
                               abi_ulong target_addrlen_addr)
P
pbrook 已提交
1536
{
1537 1538
    socklen_t addrlen;
    void *addr;
1539
    abi_long ret;
P
pbrook 已提交
1540

1541 1542 1543
    if (get_user_u32(addrlen, target_addrlen_addr))
        return -TARGET_EFAULT;

1544
    if (addrlen < 0)
1545 1546
        return -TARGET_EINVAL;

1547 1548
    addr = alloca(addrlen);

P
pbrook 已提交
1549 1550 1551
    ret = get_errno(getpeername(fd, addr, &addrlen));
    if (!is_error(ret)) {
        host_to_target_sockaddr(target_addr, addr, addrlen);
1552 1553
        if (put_user_u32(addrlen, target_addrlen_addr))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1554 1555 1556 1557
    }
    return ret;
}

1558
/* do_getsockname() Must return target values and target errnos. */
1559
static abi_long do_getsockname(int fd, abi_ulong target_addr,
1560
                               abi_ulong target_addrlen_addr)
P
pbrook 已提交
1561
{
1562 1563
    socklen_t addrlen;
    void *addr;
1564
    abi_long ret;
P
pbrook 已提交
1565

1566 1567 1568
    if (target_addr == 0)
       return get_errno(accept(fd, NULL, NULL));

1569 1570 1571
    if (get_user_u32(addrlen, target_addrlen_addr))
        return -TARGET_EFAULT;

1572
    if (addrlen < 0)
1573 1574
        return -TARGET_EINVAL;

1575 1576
    addr = alloca(addrlen);

P
pbrook 已提交
1577 1578 1579
    ret = get_errno(getsockname(fd, addr, &addrlen));
    if (!is_error(ret)) {
        host_to_target_sockaddr(target_addr, addr, addrlen);
1580 1581
        if (put_user_u32(addrlen, target_addrlen_addr))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1582 1583 1584 1585
    }
    return ret;
}

1586
/* do_socketpair() Must return target values and target errnos. */
1587
static abi_long do_socketpair(int domain, int type, int protocol,
1588
                              abi_ulong target_tab_addr)
P
pbrook 已提交
1589 1590
{
    int tab[2];
1591
    abi_long ret;
P
pbrook 已提交
1592 1593 1594

    ret = get_errno(socketpair(domain, type, protocol, tab));
    if (!is_error(ret)) {
1595 1596 1597
        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 已提交
1598 1599 1600 1601
    }
    return ret;
}

1602
/* do_sendto() Must return target values and target errnos. */
1603 1604
static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
                          abi_ulong target_addr, socklen_t addrlen)
P
pbrook 已提交
1605 1606 1607
{
    void *addr;
    void *host_msg;
1608
    abi_long ret;
P
pbrook 已提交
1609

1610
    if (addrlen < 0)
1611 1612
        return -TARGET_EINVAL;

1613 1614 1615
    host_msg = lock_user(VERIFY_READ, msg, len, 1);
    if (!host_msg)
        return -TARGET_EFAULT;
P
pbrook 已提交
1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626
    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;
}

1627
/* do_recvfrom() Must return target values and target errnos. */
1628 1629 1630
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 已提交
1631 1632 1633 1634
{
    socklen_t addrlen;
    void *addr;
    void *host_msg;
1635
    abi_long ret;
P
pbrook 已提交
1636

1637 1638 1639
    host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
    if (!host_msg)
        return -TARGET_EFAULT;
P
pbrook 已提交
1640
    if (target_addr) {
1641 1642 1643 1644
        if (get_user_u32(addrlen, target_addrlen)) {
            ret = -TARGET_EFAULT;
            goto fail;
        }
1645
        if (addrlen < 0) {
1646 1647 1648
            ret = -TARGET_EINVAL;
            goto fail;
        }
P
pbrook 已提交
1649 1650 1651 1652 1653 1654 1655 1656 1657
        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);
1658 1659 1660 1661
            if (put_user_u32(addrlen, target_addrlen)) {
                ret = -TARGET_EFAULT;
                goto fail;
            }
P
pbrook 已提交
1662 1663 1664
        }
        unlock_user(host_msg, msg, len);
    } else {
1665
fail:
P
pbrook 已提交
1666 1667 1668 1669 1670
        unlock_user(host_msg, msg, 0);
    }
    return ret;
}

1671
#ifdef TARGET_NR_socketcall
1672
/* do_socketcall() Must return target values and target errnos. */
1673
static abi_long do_socketcall(int num, abi_ulong vptr)
1674
{
1675 1676
    abi_long ret;
    const int n = sizeof(abi_ulong);
1677 1678 1679

    switch(num) {
    case SOCKOP_socket:
B
bellard 已提交
1680
	{
1681 1682 1683 1684 1685 1686 1687
            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;

1688
            ret = do_socket(domain, type, protocol);
B
bellard 已提交
1689
	}
1690 1691
        break;
    case SOCKOP_bind:
B
bellard 已提交
1692
	{
1693 1694 1695 1696 1697 1698 1699 1700 1701
            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;

1702
            ret = do_bind(sockfd, target_addr, addrlen);
B
bellard 已提交
1703
        }
1704 1705
        break;
    case SOCKOP_connect:
B
bellard 已提交
1706
        {
1707 1708 1709 1710 1711 1712 1713 1714 1715
            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;

1716
            ret = do_connect(sockfd, target_addr, addrlen);
B
bellard 已提交
1717
        }
1718 1719
        break;
    case SOCKOP_listen:
B
bellard 已提交
1720
        {
1721 1722 1723 1724 1725 1726
            int sockfd, backlog;

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

B
bellard 已提交
1727 1728
            ret = get_errno(listen(sockfd, backlog));
        }
1729 1730 1731
        break;
    case SOCKOP_accept:
        {
1732 1733 1734 1735 1736 1737 1738 1739
            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 已提交
1740
            ret = do_accept(sockfd, target_addr, target_addrlen);
1741 1742 1743 1744
        }
        break;
    case SOCKOP_getsockname:
        {
1745 1746 1747 1748 1749 1750 1751 1752
            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 已提交
1753
            ret = do_getsockname(sockfd, target_addr, target_addrlen);
1754 1755 1756 1757
        }
        break;
    case SOCKOP_getpeername:
        {
1758 1759 1760 1761 1762 1763 1764 1765
            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 已提交
1766
            ret = do_getpeername(sockfd, target_addr, target_addrlen);
1767 1768 1769 1770
        }
        break;
    case SOCKOP_socketpair:
        {
1771 1772 1773 1774 1775 1776 1777 1778 1779
            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 已提交
1780
            ret = do_socketpair(domain, type, protocol, tab);
1781 1782 1783
        }
        break;
    case SOCKOP_send:
B
bellard 已提交
1784
        {
1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795
            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 已提交
1796
            ret = do_sendto(sockfd, msg, len, flags, 0, 0);
B
bellard 已提交
1797
        }
1798 1799
        break;
    case SOCKOP_recv:
B
bellard 已提交
1800
        {
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811
            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 已提交
1812
            ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
B
bellard 已提交
1813
        }
1814 1815
        break;
    case SOCKOP_sendto:
B
bellard 已提交
1816
        {
1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831
            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 已提交
1832
            ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
B
bellard 已提交
1833
        }
1834 1835 1836
        break;
    case SOCKOP_recvfrom:
        {
1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851
            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 已提交
1852
            ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
1853 1854 1855
        }
        break;
    case SOCKOP_shutdown:
B
bellard 已提交
1856
        {
1857 1858 1859 1860 1861
            int sockfd, how;

            if (get_user_s32(sockfd, vptr)
                || get_user_s32(how, vptr + n))
                return -TARGET_EFAULT;
B
bellard 已提交
1862 1863 1864

            ret = get_errno(shutdown(sockfd, how));
        }
1865 1866 1867
        break;
    case SOCKOP_sendmsg:
    case SOCKOP_recvmsg:
B
bellard 已提交
1868 1869
        {
            int fd;
1870
            abi_ulong target_msg;
1871
            int flags;
B
bellard 已提交
1872

1873 1874 1875 1876
            if (get_user_s32(fd, vptr)
                || get_user_ual(target_msg, vptr + n)
                || get_user_s32(flags, vptr + 2 * n))
                return -TARGET_EFAULT;
1877

1878
            ret = do_sendrecvmsg(fd, target_msg, flags,
1879
                                 (num == SOCKOP_sendmsg));
B
bellard 已提交
1880 1881
        }
        break;
1882
    case SOCKOP_setsockopt:
B
bellard 已提交
1883
        {
1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895
            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 已提交
1896 1897 1898 1899

            ret = do_setsockopt(sockfd, level, optname, optval, optlen);
        }
        break;
1900
    case SOCKOP_getsockopt:
B
bellard 已提交
1901
        {
1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913
            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 已提交
1914

1915
            ret = do_getsockopt(sockfd, level, optname, optval, optlen);
B
bellard 已提交
1916 1917
        }
        break;
1918 1919
    default:
        gemu_log("Unsupported socketcall: %d\n", num);
1920
        ret = -TARGET_ENOSYS;
1921 1922 1923 1924
        break;
    }
    return ret;
}
1925
#endif
1926

B
blueswir1 已提交
1927
#ifdef TARGET_NR_ipc
1928 1929 1930
#define N_SHM_REGIONS	32

static struct shm_region {
1931 1932
    abi_ulong	start;
    abi_ulong	size;
1933
} shm_regions[N_SHM_REGIONS];
B
blueswir1 已提交
1934
#endif
1935

1936 1937
struct target_ipc_perm
{
1938 1939 1940 1941 1942
    abi_long __key;
    abi_ulong uid;
    abi_ulong gid;
    abi_ulong cuid;
    abi_ulong cgid;
1943 1944 1945 1946
    unsigned short int mode;
    unsigned short int __pad1;
    unsigned short int __seq;
    unsigned short int __pad2;
1947 1948
    abi_ulong __unused1;
    abi_ulong __unused2;
1949 1950 1951 1952 1953
};

struct target_semid_ds
{
  struct target_ipc_perm sem_perm;
1954 1955 1956 1957 1958 1959 1960
  abi_ulong sem_otime;
  abi_ulong __unused1;
  abi_ulong sem_ctime;
  abi_ulong __unused2;
  abi_ulong sem_nsems;
  abi_ulong __unused3;
  abi_ulong __unused4;
1961 1962
};

1963 1964
static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
                                               abi_ulong target_addr)
1965 1966 1967 1968
{
    struct target_ipc_perm *target_ip;
    struct target_semid_ds *target_sd;

1969 1970
    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
        return -TARGET_EFAULT;
1971 1972 1973 1974 1975 1976 1977 1978
    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);
1979
    return 0;
1980 1981
}

1982 1983
static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
                                               struct ipc_perm *host_ip)
1984 1985 1986 1987
{
    struct target_ipc_perm *target_ip;
    struct target_semid_ds *target_sd;

1988 1989
    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
        return -TARGET_EFAULT;
1990 1991 1992 1993 1994 1995 1996 1997
    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);
1998
    return 0;
1999 2000
}

2001 2002
static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
                                               abi_ulong target_addr)
2003 2004 2005
{
    struct target_semid_ds *target_sd;

2006 2007
    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
        return -TARGET_EFAULT;
2008 2009
    if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
        return -TARGET_EFAULT;
2010 2011 2012 2013
    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);
2014
    return 0;
2015 2016
}

2017 2018
static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
                                               struct semid_ds *host_sd)
2019 2020 2021
{
    struct target_semid_ds *target_sd;

2022 2023
    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
        return -TARGET_EFAULT;
2024 2025
    if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
        return -TARGET_EFAULT;;
2026 2027 2028 2029
    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);
2030
    return 0;
2031 2032
}

2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065
struct target_seminfo {
    int semmap;
    int semmni;
    int semmns;
    int semmnu;
    int semmsl;
    int semopm;
    int semume;
    int semusz;
    int semvmx;
    int semaem;
};

static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
                                              struct seminfo *host_seminfo)
{
    struct target_seminfo *target_seminfo;
    if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
        return -TARGET_EFAULT;
    __put_user(host_seminfo->semmap, &target_seminfo->semmap);
    __put_user(host_seminfo->semmni, &target_seminfo->semmni);
    __put_user(host_seminfo->semmns, &target_seminfo->semmns);
    __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
    __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
    __put_user(host_seminfo->semopm, &target_seminfo->semopm);
    __put_user(host_seminfo->semume, &target_seminfo->semume);
    __put_user(host_seminfo->semusz, &target_seminfo->semusz);
    __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
    __put_user(host_seminfo->semaem, &target_seminfo->semaem);
    unlock_user_struct(target_seminfo, target_addr, 1);
    return 0;
}

2066 2067
union semun {
	int val;
2068
	struct semid_ds *buf;
2069
	unsigned short *array;
2070
	struct seminfo *__buf;
2071 2072
};

2073 2074
union target_semun {
	int val;
2075 2076 2077
	abi_ulong buf;
	abi_ulong array;
	abi_ulong __buf;
2078 2079
};

2080 2081
static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
                                               abi_ulong target_addr)
2082
{
2083 2084 2085 2086 2087
    int nsems;
    unsigned short *array;
    union semun semun;
    struct semid_ds semid_ds;
    int i, ret;
2088

2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104
    semun.buf = &semid_ds;

    ret = semctl(semid, 0, IPC_STAT, semun);
    if (ret == -1)
        return get_errno(ret);

    nsems = semid_ds.sem_nsems;

    *host_array = malloc(nsems*sizeof(unsigned short));
    array = lock_user(VERIFY_READ, target_addr,
                      nsems*sizeof(unsigned short), 1);
    if (!array)
        return -TARGET_EFAULT;

    for(i=0; i<nsems; i++) {
        __get_user((*host_array)[i], &array[i]);
2105
    }
2106 2107
    unlock_user(array, target_addr, 0);

2108
    return 0;
2109 2110
}

2111 2112
static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
                                               unsigned short **host_array)
2113
{
2114 2115 2116 2117 2118
    int nsems;
    unsigned short *array;
    union semun semun;
    struct semid_ds semid_ds;
    int i, ret;
2119

2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134
    semun.buf = &semid_ds;

    ret = semctl(semid, 0, IPC_STAT, semun);
    if (ret == -1)
        return get_errno(ret);

    nsems = semid_ds.sem_nsems;

    array = lock_user(VERIFY_WRITE, target_addr,
                      nsems*sizeof(unsigned short), 0);
    if (!array)
        return -TARGET_EFAULT;

    for(i=0; i<nsems; i++) {
        __put_user((*host_array)[i], &array[i]);
2135
    }
2136 2137 2138
    free(*host_array);
    unlock_user(array, target_addr, 1);

2139
    return 0;
2140 2141
}

2142 2143
static inline abi_long do_semctl(int semid, int semnum, int cmd,
                                 union target_semun target_su)
2144 2145 2146
{
    union semun arg;
    struct semid_ds dsarg;
2147 2148 2149 2150 2151
    unsigned short *array;
    struct seminfo seminfo;
    abi_long ret = -TARGET_EINVAL;
    abi_long err;
    cmd &= 0xff;
2152 2153 2154 2155

    switch( cmd ) {
	case GETVAL:
	case SETVAL:
2156 2157 2158
            arg.val = tswapl(target_su.val);
            ret = get_errno(semctl(semid, semnum, cmd, arg));
            target_su.val = tswapl(arg.val);
2159 2160 2161
            break;
	case GETALL:
	case SETALL:
2162 2163 2164 2165 2166 2167 2168 2169
            err = target_to_host_semarray(semid, &array, target_su.array);
            if (err)
                return err;
            arg.array = array;
            ret = get_errno(semctl(semid, semnum, cmd, arg));
            err = host_to_target_semarray(semid, target_su.array, &array);
            if (err)
                return err;
2170 2171 2172
            break;
	case IPC_STAT:
	case IPC_SET:
2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195
	case SEM_STAT:
            err = target_to_host_semid_ds(&dsarg, target_su.buf);
            if (err)
                return err;
            arg.buf = &dsarg;
            ret = get_errno(semctl(semid, semnum, cmd, arg));
            err = host_to_target_semid_ds(target_su.buf, &dsarg);
            if (err)
                return err;
            break;
	case IPC_INFO:
	case SEM_INFO:
            arg.__buf = &seminfo;
            ret = get_errno(semctl(semid, semnum, cmd, arg));
            err = host_to_target_seminfo(target_su.__buf, &seminfo);
            if (err)
                return err;
            break;
	case IPC_RMID:
	case GETPID:
	case GETNCNT:
	case GETZCNT:
            ret = get_errno(semctl(semid, semnum, cmd, NULL));
2196 2197 2198 2199 2200 2201
            break;
    }

    return ret;
}

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
struct target_sembuf {
    unsigned short sem_num;
    short sem_op;
    short sem_flg;
};

static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
                                             abi_ulong target_addr,
                                             unsigned nsops)
{
    struct target_sembuf *target_sembuf;
    int i;

    target_sembuf = lock_user(VERIFY_READ, target_addr,
                              nsops*sizeof(struct target_sembuf), 1);
    if (!target_sembuf)
        return -TARGET_EFAULT;

    for(i=0; i<nsops; i++) {
        __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
        __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
        __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
    }

    unlock_user(target_sembuf, target_addr, 0);

    return 0;
}

static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
{
    struct sembuf sops[nsops];

    if (target_to_host_sembuf(sops, ptr, nsops))
        return -TARGET_EFAULT;

    return semop(semid, sops, nsops);
}

T
ths 已提交
2241 2242
struct target_msqid_ds
{
2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262
    struct target_ipc_perm msg_perm;
    abi_ulong msg_stime;
#if TARGET_ABI_BITS == 32
    abi_ulong __unused1;
#endif
    abi_ulong msg_rtime;
#if TARGET_ABI_BITS == 32
    abi_ulong __unused2;
#endif
    abi_ulong msg_ctime;
#if TARGET_ABI_BITS == 32
    abi_ulong __unused3;
#endif
    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 已提交
2263 2264
};

2265 2266
static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
                                               abi_ulong target_addr)
T
ths 已提交
2267 2268 2269
{
    struct target_msqid_ds *target_md;

2270 2271
    if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
        return -TARGET_EFAULT;
2272 2273
    if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
        return -TARGET_EFAULT;
T
ths 已提交
2274 2275 2276 2277 2278 2279 2280 2281 2282
    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);
2283
    return 0;
T
ths 已提交
2284 2285
}

2286 2287
static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
                                               struct msqid_ds *host_md)
T
ths 已提交
2288 2289 2290
{
    struct target_msqid_ds *target_md;

2291 2292
    if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
        return -TARGET_EFAULT;
2293 2294
    if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
        return -TARGET_EFAULT;
T
ths 已提交
2295 2296 2297 2298 2299 2300 2301 2302 2303
    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);
2304
    return 0;
T
ths 已提交
2305 2306
}

2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332
struct target_msginfo {
    int msgpool;
    int msgmap;
    int msgmax;
    int msgmnb;
    int msgmni;
    int msgssz;
    int msgtql;
    unsigned short int msgseg;
};

static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
                                              struct msginfo *host_msginfo)
{
    struct target_msginfo *target_msginfo;
    if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
        return -TARGET_EFAULT;
    __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
    __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
    __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
    __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
    __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
    __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
    __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
    __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
    unlock_user_struct(target_msginfo, target_addr, 1);
2333
    return 0;
2334 2335 2336
}

static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
T
ths 已提交
2337 2338
{
    struct msqid_ds dsarg;
2339 2340 2341 2342 2343 2344
    struct msginfo msginfo;
    abi_long ret = -TARGET_EINVAL;

    cmd &= 0xff;

    switch (cmd) {
T
ths 已提交
2345 2346
    case IPC_STAT:
    case IPC_SET:
2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362
    case MSG_STAT:
        if (target_to_host_msqid_ds(&dsarg,ptr))
            return -TARGET_EFAULT;
        ret = get_errno(msgctl(msgid, cmd, &dsarg));
        if (host_to_target_msqid_ds(ptr,&dsarg))
            return -TARGET_EFAULT;
        break;
    case IPC_RMID:
        ret = get_errno(msgctl(msgid, cmd, NULL));
        break;
    case IPC_INFO:
    case MSG_INFO:
        ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
        if (host_to_target_msginfo(ptr, &msginfo))
            return -TARGET_EFAULT;
        break;
T
ths 已提交
2363
    }
2364

T
ths 已提交
2365 2366 2367 2368
    return ret;
}

struct target_msgbuf {
2369 2370
    abi_long mtype;
    char	mtext[1];
T
ths 已提交
2371 2372
};

2373 2374
static inline abi_long do_msgsnd(int msqid, abi_long msgp,
                                 unsigned int msgsz, int msgflg)
T
ths 已提交
2375 2376 2377
{
    struct target_msgbuf *target_mb;
    struct msgbuf *host_mb;
2378
    abi_long ret = 0;
T
ths 已提交
2379

2380 2381
    if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
        return -TARGET_EFAULT;
T
ths 已提交
2382
    host_mb = malloc(msgsz+sizeof(long));
2383 2384
    host_mb->mtype = (abi_long) tswapl(target_mb->mtype);
    memcpy(host_mb->mtext, target_mb->mtext, msgsz);
T
ths 已提交
2385 2386 2387 2388 2389 2390 2391
    ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
    free(host_mb);
    unlock_user_struct(target_mb, msgp, 0);

    return ret;
}

2392
static inline abi_long do_msgrcv(int msqid, abi_long msgp,
2393
                                 unsigned int msgsz, abi_long msgtyp,
2394
                                 int msgflg)
T
ths 已提交
2395 2396
{
    struct target_msgbuf *target_mb;
2397
    char *target_mtext;
T
ths 已提交
2398
    struct msgbuf *host_mb;
2399
    abi_long ret = 0;
T
ths 已提交
2400

2401 2402
    if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
        return -TARGET_EFAULT;
2403

T
ths 已提交
2404
    host_mb = malloc(msgsz+sizeof(long));
2405 2406
    ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapl(msgtyp), msgflg));

2407 2408 2409 2410 2411 2412 2413
    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;
        }
2414
        memcpy(target_mb->mtext, host_mb->mtext, ret);
2415 2416
        unlock_user(target_mtext, target_mtext_addr, ret);
    }
2417

T
ths 已提交
2418 2419 2420
    target_mb->mtype = tswapl(host_mb->mtype);
    free(host_mb);

2421 2422 2423
end:
    if (target_mb)
        unlock_user_struct(target_mb, msgp, 1);
T
ths 已提交
2424 2425 2426
    return ret;
}

2427
#ifdef TARGET_NR_ipc
2428
/* ??? This only works with linear mappings.  */
2429
/* do_ipc() must return target values and target errnos. */
2430 2431 2432
static abi_long do_ipc(unsigned int call, int first,
                       int second, int third,
                       abi_long ptr, abi_long fifth)
2433 2434
{
    int version;
2435
    abi_long ret = 0;
2436 2437 2438 2439 2440 2441 2442
    struct shmid_ds shm_info;
    int i;

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

    switch (call) {
2443
    case IPCOP_semop:
2444
        ret = do_semop(first, ptr, second);
2445 2446 2447 2448 2449 2450 2451
        break;

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

    case IPCOP_semctl:
2452
        ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
2453
        break;
2454

2455 2456 2457
    case IPCOP_msgget:
        ret = get_errno(msgget(first, second));
        break;
2458

2459 2460 2461
    case IPCOP_msgsnd:
        ret = do_msgsnd(first, ptr, second, third);
        break;
2462

2463 2464 2465
    case IPCOP_msgctl:
        ret = do_msgctl(first, second, ptr);
        break;
2466

2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479
    case IPCOP_msgrcv:
        switch (version) {
        case 0:
            {
                struct target_ipc_kludge {
                    abi_long msgp;
                    abi_long msgtyp;
                } *tmp;

                if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
                    ret = -TARGET_EFAULT;
                    break;
                }
2480

2481
                ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
2482

2483 2484 2485 2486 2487 2488 2489
                unlock_user_struct(tmp, ptr, 0);
                break;
            }
        default:
            ret = do_msgrcv(first, ptr, second, fifth, third);
        }
        break;
2490

2491
    case IPCOP_shmat:
2492 2493 2494 2495 2496 2497 2498
        {
            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);
2499
                break;
2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519
            }
            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;
                }
            }
2520
            if (put_user_ual(raddr, third))
2521 2522 2523
                return -TARGET_EFAULT;
            ret = 0;
        }
2524 2525 2526 2527 2528 2529 2530 2531 2532
	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;
	    }
	}
2533
	ret = get_errno(shmdt((void *)g2h(ptr)));
2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554
	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:
2555
	gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
2556
	ret = -TARGET_ENOSYS;
2557 2558 2559 2560
	break;
    }
    return ret;
}
2561
#endif
2562

2563 2564 2565
/* kernel structure types definitions */
#define IFNAMSIZ        16

2566
#define STRUCT(name, ...) STRUCT_ ## name,
2567 2568 2569 2570 2571 2572 2573
#define STRUCT_SPECIAL(name) STRUCT_ ## name,
enum {
#include "syscall_types.h"
};
#undef STRUCT
#undef STRUCT_SPECIAL

2574
#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = {  __VA_ARGS__, TYPE_NULL };
2575 2576 2577 2578 2579 2580
#define STRUCT_SPECIAL(name)
#include "syscall_types.h"
#undef STRUCT
#undef STRUCT_SPECIAL

typedef struct IOCTLEntry {
2581 2582
    unsigned int target_cmd;
    unsigned int host_cmd;
2583 2584
    const char *name;
    int access;
B
bellard 已提交
2585
    const argtype arg_type[5];
2586 2587 2588 2589 2590 2591 2592 2593
} IOCTLEntry;

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

#define MAX_STRUCT_SIZE 4096

B
blueswir1 已提交
2594
static IOCTLEntry ioctl_entries[] = {
2595 2596
#define IOCTL(cmd, access, ...) \
    { TARGET_ ## cmd, cmd, #cmd, access, {  __VA_ARGS__ } },
2597 2598 2599 2600
#include "ioctls.h"
    { 0, 0, },
};

2601
/* ??? Implement proper locking for ioctls.  */
2602
/* do_ioctl() Must return target values and target errnos. */
2603
static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
2604 2605 2606
{
    const IOCTLEntry *ie;
    const argtype *arg_type;
2607
    abi_long ret;
2608
    uint8_t buf_temp[MAX_STRUCT_SIZE];
2609 2610
    int target_size;
    void *argptr;
2611 2612 2613 2614

    ie = ioctl_entries;
    for(;;) {
        if (ie->target_cmd == 0) {
2615
            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
2616
            return -TARGET_ENOSYS;
2617 2618 2619 2620 2621 2622
        }
        if (ie->target_cmd == cmd)
            break;
        ie++;
    }
    arg_type = ie->arg_type;
B
bellard 已提交
2623
#if defined(DEBUG)
2624
    gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
B
bellard 已提交
2625
#endif
2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637
    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++;
2638
        target_size = thunk_type_size(arg_type, 0);
2639 2640 2641 2642
        switch(ie->access) {
        case IOC_R:
            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
            if (!is_error(ret)) {
2643 2644 2645
                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
                if (!argptr)
                    return -TARGET_EFAULT;
2646 2647
                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
                unlock_user(argptr, arg, target_size);
2648 2649 2650
            }
            break;
        case IOC_W:
2651 2652 2653
            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
            if (!argptr)
                return -TARGET_EFAULT;
2654 2655
            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
            unlock_user(argptr, arg, 0);
2656 2657 2658 2659
            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
            break;
        default:
        case IOC_RW:
2660 2661 2662
            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
            if (!argptr)
                return -TARGET_EFAULT;
2663 2664
            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
            unlock_user(argptr, arg, 0);
2665 2666
            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
            if (!is_error(ret)) {
2667 2668 2669
                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
                if (!argptr)
                    return -TARGET_EFAULT;
2670 2671
                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
                unlock_user(argptr, arg, target_size);
2672 2673 2674 2675 2676
            }
            break;
        }
        break;
    default:
2677 2678
        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
                 (long)cmd, arg_type[0]);
2679
        ret = -TARGET_ENOSYS;
2680 2681 2682 2683 2684
        break;
    }
    return ret;
}

B
blueswir1 已提交
2685
static const bitmask_transtbl iflag_tbl[] = {
2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702
        { 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 }
};

B
blueswir1 已提交
2703
static const bitmask_transtbl oflag_tbl[] = {
2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730
	{ 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 }
};

B
blueswir1 已提交
2731
static const bitmask_transtbl cflag_tbl[] = {
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 2757 2758 2759 2760 2761 2762 2763 2764 2765
	{ 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 }
};

B
blueswir1 已提交
2766
static const bitmask_transtbl lflag_tbl[] = {
2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788
	{ 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;
2789

2790
    host->c_iflag =
2791
        target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
2792
    host->c_oflag =
2793
        target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
2794
    host->c_cflag =
2795
        target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
2796
    host->c_lflag =
2797 2798
        target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
    host->c_line = target->c_line;
2799

2800 2801
    host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
    host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
2802
    host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
2803
    host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
2804
    host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
2805
    host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
2806
    host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
2807
    host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
2808
    host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
2809 2810
    host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
    host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
2811 2812 2813 2814 2815
    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];
2816
    host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
2817
}
2818

2819 2820 2821 2822 2823
static void host_to_target_termios (void *dst, const void *src)
{
    struct target_termios *target = dst;
    const struct host_termios *host = src;

2824
    target->c_iflag =
2825
        tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
2826
    target->c_oflag =
2827
        tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
2828
    target->c_cflag =
2829
        tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
2830
    target->c_lflag =
2831 2832
        tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
    target->c_line = host->c_line;
2833

2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852
    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];
}

B
blueswir1 已提交
2853
static const StructEntry struct_termios_def = {
2854 2855 2856 2857 2858
    .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 已提交
2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870
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 }
};

2871
#if defined(TARGET_I386)
B
bellard 已提交
2872 2873

/* NOTE: there is really one LDT for all the threads */
2874
static uint8_t *ldt_table;
B
bellard 已提交
2875

2876
static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
B
bellard 已提交
2877 2878
{
    int size;
2879
    void *p;
B
bellard 已提交
2880 2881 2882 2883 2884 2885

    if (!ldt_table)
        return 0;
    size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
    if (size > bytecount)
        size = bytecount;
2886 2887
    p = lock_user(VERIFY_WRITE, ptr, size, 0);
    if (!p)
2888
        return -TARGET_EFAULT;
2889
    /* ??? Should this by byteswapped?  */
2890 2891
    memcpy(p, ldt_table, size);
    unlock_user(p, ptr, size);
B
bellard 已提交
2892 2893 2894 2895
    return size;
}

/* XXX: add locking support */
2896 2897
static abi_long write_ldt(CPUX86State *env,
                          abi_ulong ptr, unsigned long bytecount, int oldmode)
B
bellard 已提交
2898 2899
{
    struct target_modify_ldt_ldt_s ldt_info;
2900
    struct target_modify_ldt_ldt_s *target_ldt_info;
B
bellard 已提交
2901
    int seg_32bit, contents, read_exec_only, limit_in_pages;
B
bellard 已提交
2902
    int seg_not_present, useable, lm;
B
bellard 已提交
2903 2904 2905
    uint32_t *lp, entry_1, entry_2;

    if (bytecount != sizeof(ldt_info))
2906
        return -TARGET_EINVAL;
2907
    if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
2908
        return -TARGET_EFAULT;
2909 2910 2911 2912 2913
    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);
2914

B
bellard 已提交
2915
    if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
2916
        return -TARGET_EINVAL;
B
bellard 已提交
2917 2918 2919 2920 2921 2922
    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 已提交
2923 2924 2925 2926 2927
#ifdef TARGET_ABI32
    lm = 0;
#else
    lm = (ldt_info.flags >> 7) & 1;
#endif
B
bellard 已提交
2928 2929
    if (contents == 3) {
        if (oldmode)
2930
            return -TARGET_EINVAL;
B
bellard 已提交
2931
        if (seg_not_present == 0)
2932
            return -TARGET_EINVAL;
B
bellard 已提交
2933 2934 2935
    }
    /* allocate the LDT */
    if (!ldt_table) {
2936 2937 2938 2939 2940
        env->ldt.base = target_mmap(0,
                                    TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
                                    PROT_READ|PROT_WRITE,
                                    MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
        if (env->ldt.base == -1)
2941
            return -TARGET_ENOMEM;
2942 2943
        memset(g2h(env->ldt.base), 0,
               TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
B
bellard 已提交
2944
        env->ldt.limit = 0xffff;
2945
        ldt_table = g2h(env->ldt.base);
B
bellard 已提交
2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962
    }

    /* 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;
        }
    }
2963

B
bellard 已提交
2964 2965 2966 2967 2968 2969 2970 2971 2972 2973
    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 已提交
2974
        (lm << 21) |
B
bellard 已提交
2975 2976 2977
        0x7000;
    if (!oldmode)
        entry_2 |= (useable << 20);
B
bellard 已提交
2978

B
bellard 已提交
2979 2980 2981 2982 2983 2984 2985 2986 2987
    /* 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 */
2988 2989
static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
                              unsigned long bytecount)
B
bellard 已提交
2990
{
2991
    abi_long ret;
2992

B
bellard 已提交
2993 2994 2995 2996 2997 2998 2999 3000 3001 3002
    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;
3003 3004 3005
    default:
        ret = -TARGET_ENOSYS;
        break;
B
bellard 已提交
3006 3007 3008
    }
    return ret;
}
B
bellard 已提交
3009

3010
#if defined(TARGET_I386) && defined(TARGET_ABI32)
3011
static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
B
bellard 已提交
3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095
{
    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;
}

3096
static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
B
bellard 已提交
3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141
{
    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;
}
3142
#endif /* TARGET_I386 && TARGET_ABI32 */
B
bellard 已提交
3143

B
bellard 已提交
3144
#ifndef TARGET_ABI32
3145
static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
B
bellard 已提交
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
{
    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

3179 3180
#endif /* defined(TARGET_I386) */

P
pbrook 已提交
3181 3182 3183 3184 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 3216 3217 3218 3219 3220 3221 3222
#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 已提交
3223 3224 3225 3226 3227 3228
/* 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)
{
3229
    CPUState *env = arg;
B
bellard 已提交
3230 3231 3232 3233
    cpu_loop(env);
    /* never exits */
    return 0;
}
P
pbrook 已提交
3234
#endif
B
bellard 已提交
3235

3236 3237
/* do_fork() Must return host values and target errnos (unlike most
   do_*() functions). */
P
pbrook 已提交
3238 3239 3240
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 已提交
3241 3242
{
    int ret;
B
bellard 已提交
3243
    TaskState *ts;
B
bellard 已提交
3244
    uint8_t *new_stack;
3245
    CPUState *new_env;
P
pbrook 已提交
3246 3247 3248 3249
#if defined(USE_NPTL)
    unsigned int nptl_flags;
    sigset_t sigmask;
#endif
3250

3251 3252 3253 3254
    /* Emulate vfork() with fork() */
    if (flags & CLONE_VFORK)
        flags &= ~(CLONE_VFORK | CLONE_VM);

B
bellard 已提交
3255
    if (flags & CLONE_VM) {
3256
#if defined(USE_NPTL)
P
pbrook 已提交
3257 3258
        new_thread_info info;
        pthread_attr_t attr;
3259
#endif
3260
        ts = qemu_mallocz(sizeof(TaskState) + NEW_STACK_SIZE);
P
pbrook 已提交
3261
        init_task_state(ts);
B
bellard 已提交
3262
        new_stack = ts->stack;
B
bellard 已提交
3263
        /* we create a new CPU instance. */
3264
        new_env = cpu_copy(env);
3265 3266
        /* Init regs that differ from the parent.  */
        cpu_clone_regs(new_env, newsp);
B
bellard 已提交
3267
        new_env->opaque = ts;
P
pbrook 已提交
3268 3269 3270 3271
#if defined(USE_NPTL)
        nptl_flags = flags;
        flags &= ~CLONE_NPTL_FLAGS2;

3272 3273 3274 3275
        if (nptl_flags & CLONE_CHILD_CLEARTID) {
            ts->child_tidptr = child_tidptr;
        }

P
pbrook 已提交
3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299
        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);
3300
        /* TODO: Free new CPU state if thread creation failed.  */
P
pbrook 已提交
3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320

        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.  */
3321
#ifdef __ia64__
B
bellard 已提交
3322
        ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
3323 3324
#else
	ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
P
pbrook 已提交
3325
#endif
3326
#endif
B
bellard 已提交
3327 3328
    } else {
        /* if no CLONE_VM, we consider it is a fork */
P
pbrook 已提交
3329
        if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
B
bellard 已提交
3330
            return -EINVAL;
P
pbrook 已提交
3331
        fork_start();
B
bellard 已提交
3332
        ret = fork();
P
pbrook 已提交
3333
        if (ret == 0) {
3334
            /* Child Process.  */
P
pbrook 已提交
3335 3336
            cpu_clone_regs(env, newsp);
            fork_end(1);
3337 3338 3339 3340 3341 3342 3343
#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.  */
P
pbrook 已提交
3344 3345 3346 3347 3348 3349 3350
            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);
3351 3352
            if (flags & CLONE_CHILD_CLEARTID)
                ts->child_tidptr = child_tidptr;
3353
#endif
P
pbrook 已提交
3354 3355 3356
        } else {
            fork_end(0);
        }
B
bellard 已提交
3357 3358 3359 3360
    }
    return ret;
}

3361
static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
B
bellard 已提交
3362 3363
{
    struct flock fl;
3364
    struct target_flock *target_fl;
3365 3366
    struct flock64 fl64;
    struct target_flock64 *target_fl64;
3367
    abi_long ret;
3368

B
bellard 已提交
3369 3370
    switch(cmd) {
    case TARGET_F_GETLK:
3371 3372
        if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
            return -TARGET_EFAULT;
T
ths 已提交
3373 3374 3375 3376 3377 3378
        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 已提交
3379
        ret = get_errno(fcntl(fd, cmd, &fl));
B
bellard 已提交
3380
        if (ret == 0) {
3381 3382
            if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
                return -TARGET_EFAULT;
B
bellard 已提交
3383 3384 3385 3386 3387
            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);
3388
            unlock_user_struct(target_fl, arg, 1);
B
bellard 已提交
3389 3390
        }
        break;
3391

B
bellard 已提交
3392 3393
    case TARGET_F_SETLK:
    case TARGET_F_SETLKW:
3394 3395
        if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
            return -TARGET_EFAULT;
B
bellard 已提交
3396 3397 3398 3399 3400
        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);
3401
        unlock_user_struct(target_fl, arg, 0);
B
bellard 已提交
3402
        ret = get_errno(fcntl(fd, cmd, &fl));
B
bellard 已提交
3403
        break;
3404

B
bellard 已提交
3405
    case TARGET_F_GETLK64:
3406 3407
        if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
            return -TARGET_EFAULT;
T
ths 已提交
3408 3409 3410 3411 3412 3413
        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 已提交
3414
        ret = get_errno(fcntl(fd, cmd >> 1, &fl64));
3415
        if (ret == 0) {
3416 3417
            if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
                return -TARGET_EFAULT;
3418 3419 3420 3421 3422 3423 3424
            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 已提交
3425
        break;
B
bellard 已提交
3426 3427
    case TARGET_F_SETLK64:
    case TARGET_F_SETLKW64:
3428 3429
        if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
            return -TARGET_EFAULT;
3430 3431 3432 3433 3434 3435
        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 已提交
3436
        ret = get_errno(fcntl(fd, cmd >> 1, &fl64));
B
bellard 已提交
3437 3438
        break;

B
bellard 已提交
3439
    case F_GETFL:
B
bellard 已提交
3440 3441 3442 3443
        ret = get_errno(fcntl(fd, cmd, arg));
        if (ret >= 0) {
            ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
        }
B
bellard 已提交
3444 3445 3446
        break;

    case F_SETFL:
B
bellard 已提交
3447
        ret = get_errno(fcntl(fd, cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
B
bellard 已提交
3448 3449
        break;

B
bellard 已提交
3450
    default:
B
bellard 已提交
3451
        ret = get_errno(fcntl(fd, cmd, arg));
B
bellard 已提交
3452 3453 3454 3455 3456
        break;
    }
    return ret;
}

3457
#ifdef USE_UID16
B
bellard 已提交
3458

3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491
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 已提交
3492

3493 3494
void syscall_init(void)
{
3495 3496 3497
    IOCTLEntry *ie;
    const argtype *arg_type;
    int size;
3498
    int i;
3499

3500
#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
3501
#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
3502 3503 3504
#include "syscall_types.h"
#undef STRUCT
#undef STRUCT_SPECIAL
3505 3506 3507 3508 3509 3510 3511 3512 3513

    /* 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) {
3514
                fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
3515 3516 3517 3518 3519
                        ie->target_cmd);
                exit(1);
            }
            arg_type++;
            size = thunk_type_size(arg_type, 0);
3520
            ie->target_cmd = (ie->target_cmd &
3521 3522 3523
                              ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
                (size << TARGET_IOC_SIZESHIFT);
        }
3524 3525 3526 3527 3528 3529

        /* 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;

3530
        /* automatic consistency check if same arch */
3531 3532 3533 3534 3535
#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
    (defined(__x86_64__) && defined(TARGET_X86_64))
        if (unlikely(ie->target_cmd != ie->host_cmd)) {
            fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
                    ie->name, ie->target_cmd, ie->host_cmd);
3536 3537 3538 3539
        }
#endif
        ie++;
    }
3540
}
B
bellard 已提交
3541

3542
#if TARGET_ABI_BITS == 32
P
pbrook 已提交
3543 3544
static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
{
T
ths 已提交
3545
#ifdef TARGET_WORDS_BIGENDIAN
P
pbrook 已提交
3546 3547 3548 3549 3550
    return ((uint64_t)word0 << 32) | word1;
#else
    return ((uint64_t)word1 << 32) | word0;
#endif
}
3551
#else /* TARGET_ABI_BITS == 32 */
3552 3553 3554 3555
static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
{
    return word0;
}
3556
#endif /* TARGET_ABI_BITS != 32 */
P
pbrook 已提交
3557 3558

#ifdef TARGET_NR_truncate64
3559 3560 3561 3562
static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
                                         abi_long arg2,
                                         abi_long arg3,
                                         abi_long arg4)
P
pbrook 已提交
3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575
{
#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
3576 3577 3578 3579
static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
                                          abi_long arg2,
                                          abi_long arg3,
                                          abi_long arg4)
P
pbrook 已提交
3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591
{
#ifdef TARGET_ARM
    if (((CPUARMState *)cpu_env)->eabi)
      {
        arg2 = arg3;
        arg3 = arg4;
      }
#endif
    return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
}
#endif

3592 3593
static inline abi_long target_to_host_timespec(struct timespec *host_ts,
                                               abi_ulong target_addr)
3594 3595 3596
{
    struct target_timespec *target_ts;

3597 3598
    if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
        return -TARGET_EFAULT;
3599 3600 3601
    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 已提交
3602
    return 0;
3603 3604
}

3605 3606
static inline abi_long host_to_target_timespec(abi_ulong target_addr,
                                               struct timespec *host_ts)
3607 3608 3609
{
    struct target_timespec *target_ts;

3610 3611
    if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
        return -TARGET_EFAULT;
3612 3613 3614
    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 已提交
3615
    return 0;
3616 3617
}

3618
#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649
static inline abi_long host_to_target_stat64(void *cpu_env,
                                             abi_ulong target_addr,
                                             struct stat *host_st)
{
#ifdef TARGET_ARM
    if (((CPUARMState *)cpu_env)->eabi) {
        struct target_eabi_stat64 *target_st;

        if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
            return -TARGET_EFAULT;
        memset(target_st, 0, sizeof(struct target_eabi_stat64));
        __put_user(host_st->st_dev, &target_st->st_dev);
        __put_user(host_st->st_ino, &target_st->st_ino);
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
        __put_user(host_st->st_ino, &target_st->__st_ino);
#endif
        __put_user(host_st->st_mode, &target_st->st_mode);
        __put_user(host_st->st_nlink, &target_st->st_nlink);
        __put_user(host_st->st_uid, &target_st->st_uid);
        __put_user(host_st->st_gid, &target_st->st_gid);
        __put_user(host_st->st_rdev, &target_st->st_rdev);
        __put_user(host_st->st_size, &target_st->st_size);
        __put_user(host_st->st_blksize, &target_st->st_blksize);
        __put_user(host_st->st_blocks, &target_st->st_blocks);
        __put_user(host_st->st_atime, &target_st->target_st_atime);
        __put_user(host_st->st_mtime, &target_st->target_st_mtime);
        __put_user(host_st->st_ctime, &target_st->target_st_ctime);
        unlock_user_struct(target_st, target_addr, 1);
    } else
#endif
    {
3650 3651 3652
#if TARGET_LONG_BITS == 64
        struct target_stat *target_st;
#else
3653
        struct target_stat64 *target_st;
3654
#endif
3655 3656 3657

        if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
            return -TARGET_EFAULT;
3658
        memset(target_st, 0, sizeof(*target_st));
3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682
        __put_user(host_st->st_dev, &target_st->st_dev);
        __put_user(host_st->st_ino, &target_st->st_ino);
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
        __put_user(host_st->st_ino, &target_st->__st_ino);
#endif
        __put_user(host_st->st_mode, &target_st->st_mode);
        __put_user(host_st->st_nlink, &target_st->st_nlink);
        __put_user(host_st->st_uid, &target_st->st_uid);
        __put_user(host_st->st_gid, &target_st->st_gid);
        __put_user(host_st->st_rdev, &target_st->st_rdev);
        /* XXX: better use of kernel struct */
        __put_user(host_st->st_size, &target_st->st_size);
        __put_user(host_st->st_blksize, &target_st->st_blksize);
        __put_user(host_st->st_blocks, &target_st->st_blocks);
        __put_user(host_st->st_atime, &target_st->target_st_atime);
        __put_user(host_st->st_mtime, &target_st->target_st_mtime);
        __put_user(host_st->st_ctime, &target_st->target_st_ctime);
        unlock_user_struct(target_st, target_addr, 1);
    }

    return 0;
}
#endif

3683 3684 3685 3686 3687 3688
#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.  */
3689 3690
static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
                    target_ulong uaddr2, int val3)
3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721
{
    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 已提交
3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735
/* Map host to target signal numbers for the wait family of syscalls.
   Assume all other status bits are the same.  */
static int host_to_target_waitstatus(int status)
{
    if (WIFSIGNALED(status)) {
        return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
    }
    if (WIFSTOPPED(status)) {
        return (host_to_target_signal(WSTOPSIG(status)) << 8)
               | (status & 0xff);
    }
    return status;
}

P
pbrook 已提交
3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766
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;
}

3767 3768 3769
/* 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>. */
3770 3771 3772
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)
3773
{
3774
    abi_long ret;
3775
    struct stat st;
B
bellard 已提交
3776
    struct statfs stfs;
3777
    void *p;
3778

B
bellard 已提交
3779
#ifdef DEBUG
B
bellard 已提交
3780
    gemu_log("syscall %d", num);
B
bellard 已提交
3781
#endif
3782 3783 3784
    if(do_strace)
        print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);

3785 3786
    switch(num) {
    case TARGET_NR_exit:
3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821
#ifdef USE_NPTL
      /* In old applications this may be used to implement _exit(2).
         However in threaded applictions it is used for thread termination,
         and _exit_group is used for application termination.
         Do thread termination if we have more then one thread.  */
      /* FIXME: This probably breaks if a signal arrives.  We should probably
         be disabling signals.  */
      if (first_cpu->next_cpu) {
          CPUState **lastp;
          CPUState *p;

          cpu_list_lock();
          lastp = &first_cpu;
          p = first_cpu;
          while (p && p != (CPUState *)cpu_env) {
              lastp = &p->next_cpu;
              p = p->next_cpu;
          }
          /* If we didn't find the CPU for this thread then something is
             horribly wrong.  */
          if (!p)
              abort();
          /* Remove the CPU from the list.  */
          *lastp = p->next_cpu;
          cpu_list_unlock();
          TaskState *ts = ((CPUState *)cpu_env)->opaque;
          if (ts->child_tidptr) {
              put_user_u32(0, ts->child_tidptr);
              sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
                        NULL, NULL, 0);
          }
          /* TODO: Free CPU state.  */
          pthread_exit(NULL);
      }
#endif
B
bellard 已提交
3822 3823 3824
#ifdef HAVE_GPROF
        _mcleanup();
#endif
3825
        gdb_exit(cpu_env, arg1);
3826
        _exit(arg1);
3827 3828 3829
        ret = 0; /* avoid warning */
        break;
    case TARGET_NR_read:
3830 3831 3832 3833 3834 3835 3836 3837
        if (arg3 == 0)
            ret = 0;
        else {
            if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
                goto efault;
            ret = get_errno(read(arg1, p, arg3));
            unlock_user(p, arg2, ret);
        }
3838 3839
        break;
    case TARGET_NR_write:
3840 3841
        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
            goto efault;
3842 3843
        ret = get_errno(write(arg1, p, arg3));
        unlock_user(p, arg2, 0);
3844 3845
        break;
    case TARGET_NR_open:
3846 3847
        if (!(p = lock_user_string(arg1)))
            goto efault;
3848
        ret = get_errno(open(path(p),
B
bellard 已提交
3849 3850
                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
                             arg3));
3851
        unlock_user(p, arg1, 0);
3852
        break;
3853 3854
#if defined(TARGET_NR_openat) && defined(__NR_openat)
    case TARGET_NR_openat:
3855 3856 3857 3858 3859 3860 3861
        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);
3862 3863
        break;
#endif
3864 3865 3866 3867
    case TARGET_NR_close:
        ret = get_errno(close(arg1));
        break;
    case TARGET_NR_brk:
3868
        ret = do_brk(arg1);
3869 3870
        break;
    case TARGET_NR_fork:
P
pbrook 已提交
3871
        ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
3872
        break;
3873
#ifdef TARGET_NR_waitpid
3874 3875
    case TARGET_NR_waitpid:
        {
3876 3877
            int status;
            ret = get_errno(waitpid(arg1, &status, arg3));
3878
            if (!is_error(ret) && arg2
P
pbrook 已提交
3879
                && put_user_s32(host_to_target_waitstatus(status), arg2))
3880
                goto efault;
3881 3882
        }
        break;
3883
#endif
P
pbrook 已提交
3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898
#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
3899
#ifdef TARGET_NR_creat /* not on alpha */
3900
    case TARGET_NR_creat:
3901 3902
        if (!(p = lock_user_string(arg1)))
            goto efault;
3903 3904
        ret = get_errno(creat(p, arg2));
        unlock_user(p, arg1, 0);
3905
        break;
3906
#endif
3907
    case TARGET_NR_link:
3908 3909 3910 3911
        {
            void * p2;
            p = lock_user_string(arg1);
            p2 = lock_user_string(arg2);
3912 3913 3914 3915
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(link(p, p2));
3916 3917 3918
            unlock_user(p2, arg2, 0);
            unlock_user(p, arg1, 0);
        }
3919
        break;
3920 3921 3922 3923
#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
    case TARGET_NR_linkat:
        {
            void * p2 = NULL;
3924 3925
            if (!arg2 || !arg4)
                goto efault;
3926 3927
            p  = lock_user_string(arg2);
            p2 = lock_user_string(arg4);
3928
            if (!p || !p2)
3929
                ret = -TARGET_EFAULT;
3930 3931
            else
                ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
3932 3933
            unlock_user(p, arg2, 0);
            unlock_user(p2, arg4, 0);
3934 3935 3936
        }
        break;
#endif
3937
    case TARGET_NR_unlink:
3938 3939
        if (!(p = lock_user_string(arg1)))
            goto efault;
3940 3941
        ret = get_errno(unlink(p));
        unlock_user(p, arg1, 0);
3942
        break;
3943 3944
#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
    case TARGET_NR_unlinkat:
3945 3946 3947 3948
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_unlinkat(arg1, p, arg3));
        unlock_user(p, arg2, 0);
3949
        break;
3950
#endif
3951
    case TARGET_NR_execve:
B
bellard 已提交
3952 3953
        {
            char **argp, **envp;
B
bellard 已提交
3954
            int argc, envc;
3955 3956 3957 3958
            abi_ulong gp;
            abi_ulong guest_argp;
            abi_ulong guest_envp;
            abi_ulong addr;
B
bellard 已提交
3959 3960
            char **q;

B
bellard 已提交
3961
            argc = 0;
3962
            guest_argp = arg2;
3963
            for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
3964
                if (get_user_ual(addr, gp))
3965
                    goto efault;
3966
                if (!addr)
3967
                    break;
B
bellard 已提交
3968
                argc++;
3969
            }
B
bellard 已提交
3970
            envc = 0;
3971
            guest_envp = arg3;
3972
            for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
3973
                if (get_user_ual(addr, gp))
3974
                    goto efault;
3975
                if (!addr)
3976
                    break;
B
bellard 已提交
3977
                envc++;
3978
            }
B
bellard 已提交
3979

B
bellard 已提交
3980 3981
            argp = alloca((argc + 1) * sizeof(void *));
            envp = alloca((envc + 1) * sizeof(void *));
B
bellard 已提交
3982

3983
            for (gp = guest_argp, q = argp; gp;
3984
                  gp += sizeof(abi_ulong), q++) {
3985 3986
                if (get_user_ual(addr, gp))
                    goto execve_efault;
3987 3988
                if (!addr)
                    break;
3989 3990
                if (!(*q = lock_user_string(addr)))
                    goto execve_efault;
3991
            }
B
bellard 已提交
3992 3993
            *q = NULL;

3994
            for (gp = guest_envp, q = envp; gp;
3995
                  gp += sizeof(abi_ulong), q++) {
3996 3997
                if (get_user_ual(addr, gp))
                    goto execve_efault;
3998 3999
                if (!addr)
                    break;
4000 4001
                if (!(*q = lock_user_string(addr)))
                    goto execve_efault;
4002
            }
B
bellard 已提交
4003
            *q = NULL;
B
bellard 已提交
4004

4005 4006
            if (!(p = lock_user_string(arg1)))
                goto execve_efault;
4007 4008 4009
            ret = get_errno(execve(p, argp, envp));
            unlock_user(p, arg1, 0);

4010 4011 4012 4013 4014 4015
            goto execve_end;

        execve_efault:
            ret = -TARGET_EFAULT;

        execve_end:
4016
            for (gp = guest_argp, q = argp; *q;
4017
                  gp += sizeof(abi_ulong), q++) {
4018 4019 4020
                if (get_user_ual(addr, gp)
                    || !addr)
                    break;
4021 4022 4023
                unlock_user(*q, addr, 0);
            }
            for (gp = guest_envp, q = envp; *q;
4024
                  gp += sizeof(abi_ulong), q++) {
4025 4026 4027
                if (get_user_ual(addr, gp)
                    || !addr)
                    break;
4028 4029
                unlock_user(*q, addr, 0);
            }
B
bellard 已提交
4030
        }
4031 4032
        break;
    case TARGET_NR_chdir:
4033 4034
        if (!(p = lock_user_string(arg1)))
            goto efault;
4035 4036
        ret = get_errno(chdir(p));
        unlock_user(p, arg1, 0);
4037
        break;
B
bellard 已提交
4038
#ifdef TARGET_NR_time
4039 4040
    case TARGET_NR_time:
        {
4041 4042
            time_t host_time;
            ret = get_errno(time(&host_time));
4043 4044 4045 4046
            if (!is_error(ret)
                && arg1
                && put_user_sal(host_time, arg1))
                goto efault;
4047 4048
        }
        break;
B
bellard 已提交
4049
#endif
4050
    case TARGET_NR_mknod:
4051 4052
        if (!(p = lock_user_string(arg1)))
            goto efault;
4053 4054
        ret = get_errno(mknod(p, arg2, arg3));
        unlock_user(p, arg1, 0);
4055
        break;
4056 4057
#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
    case TARGET_NR_mknodat:
4058 4059 4060 4061
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
        unlock_user(p, arg2, 0);
4062 4063
        break;
#endif
4064
    case TARGET_NR_chmod:
4065 4066
        if (!(p = lock_user_string(arg1)))
            goto efault;
4067 4068
        ret = get_errno(chmod(p, arg2));
        unlock_user(p, arg1, 0);
4069
        break;
4070
#ifdef TARGET_NR_break
4071 4072
    case TARGET_NR_break:
        goto unimplemented;
4073 4074
#endif
#ifdef TARGET_NR_oldstat
4075 4076
    case TARGET_NR_oldstat:
        goto unimplemented;
4077
#endif
4078 4079 4080
    case TARGET_NR_lseek:
        ret = get_errno(lseek(arg1, arg2, arg3));
        break;
4081 4082 4083
#ifdef TARGET_NR_getxpid
    case TARGET_NR_getxpid:
#else
4084
    case TARGET_NR_getpid:
4085
#endif
4086 4087 4088
        ret = get_errno(getpid());
        break;
    case TARGET_NR_mount:
4089 4090 4091 4092 4093 4094
		{
			/* 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);
4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105
                        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);
4106 4107
			break;
		}
4108
#ifdef TARGET_NR_umount
4109
    case TARGET_NR_umount:
4110 4111
        if (!(p = lock_user_string(arg1)))
            goto efault;
4112 4113
        ret = get_errno(umount(p));
        unlock_user(p, arg1, 0);
4114
        break;
4115
#endif
4116
#ifdef TARGET_NR_stime /* not on alpha */
4117 4118
    case TARGET_NR_stime:
        {
4119
            time_t host_time;
4120 4121
            if (get_user_sal(host_time, arg1))
                goto efault;
4122
            ret = get_errno(stime(&host_time));
4123 4124
        }
        break;
4125
#endif
4126 4127
    case TARGET_NR_ptrace:
        goto unimplemented;
4128
#ifdef TARGET_NR_alarm /* not on alpha */
4129 4130 4131
    case TARGET_NR_alarm:
        ret = alarm(arg1);
        break;
4132
#endif
4133
#ifdef TARGET_NR_oldfstat
4134 4135
    case TARGET_NR_oldfstat:
        goto unimplemented;
4136
#endif
4137
#ifdef TARGET_NR_pause /* not on alpha */
4138 4139 4140
    case TARGET_NR_pause:
        ret = get_errno(pause());
        break;
4141
#endif
4142
#ifdef TARGET_NR_utime
4143
    case TARGET_NR_utime:
4144
        {
4145 4146 4147
            struct utimbuf tbuf, *host_tbuf;
            struct target_utimbuf *target_tbuf;
            if (arg2) {
4148 4149
                if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
                    goto efault;
4150 4151 4152 4153
                tbuf.actime = tswapl(target_tbuf->actime);
                tbuf.modtime = tswapl(target_tbuf->modtime);
                unlock_user_struct(target_tbuf, arg2, 0);
                host_tbuf = &tbuf;
B
bellard 已提交
4154
            } else {
4155
                host_tbuf = NULL;
B
bellard 已提交
4156
            }
4157 4158
            if (!(p = lock_user_string(arg1)))
                goto efault;
4159 4160
            ret = get_errno(utime(p, host_tbuf));
            unlock_user(p, arg1, 0);
4161 4162
        }
        break;
4163
#endif
B
bellard 已提交
4164 4165 4166
    case TARGET_NR_utimes:
        {
            struct timeval *tvp, tv[2];
4167
            if (arg2) {
4168 4169 4170 4171
                if (copy_from_user_timeval(&tv[0], arg2)
                    || copy_from_user_timeval(&tv[1],
                                              arg2 + sizeof(struct target_timeval)))
                    goto efault;
B
bellard 已提交
4172 4173 4174 4175
                tvp = tv;
            } else {
                tvp = NULL;
            }
4176 4177
            if (!(p = lock_user_string(arg1)))
                goto efault;
4178 4179
            ret = get_errno(utimes(p, tvp));
            unlock_user(p, arg1, 0);
B
bellard 已提交
4180 4181
        }
        break;
4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201
#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
    case TARGET_NR_futimesat:
        {
            struct timeval *tvp, tv[2];
            if (arg3) {
                if (copy_from_user_timeval(&tv[0], arg3)
                    || copy_from_user_timeval(&tv[1],
                                              arg3 + sizeof(struct target_timeval)))
                    goto efault;
                tvp = tv;
            } else {
                tvp = NULL;
            }
            if (!(p = lock_user_string(arg2)))
                goto efault;
            ret = get_errno(sys_futimesat(arg1, path(p), tvp));
            unlock_user(p, arg2, 0);
        }
        break;
#endif
4202
#ifdef TARGET_NR_stty
4203 4204
    case TARGET_NR_stty:
        goto unimplemented;
4205 4206
#endif
#ifdef TARGET_NR_gtty
4207 4208
    case TARGET_NR_gtty:
        goto unimplemented;
4209
#endif
4210
    case TARGET_NR_access:
4211 4212
        if (!(p = lock_user_string(arg1)))
            goto efault;
4213 4214
        ret = get_errno(access(p, arg2));
        unlock_user(p, arg1, 0);
4215
        break;
4216 4217
#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
    case TARGET_NR_faccessat:
4218 4219
        if (!(p = lock_user_string(arg2)))
            goto efault;
4220
        ret = get_errno(sys_faccessat(arg1, p, arg3));
4221
        unlock_user(p, arg2, 0);
4222 4223
        break;
#endif
4224
#ifdef TARGET_NR_nice /* not on alpha */
4225 4226 4227
    case TARGET_NR_nice:
        ret = get_errno(nice(arg1));
        break;
4228
#endif
4229
#ifdef TARGET_NR_ftime
4230 4231
    case TARGET_NR_ftime:
        goto unimplemented;
4232
#endif
4233
    case TARGET_NR_sync:
B
bellard 已提交
4234 4235
        sync();
        ret = 0;
4236 4237
        break;
    case TARGET_NR_kill:
4238
        ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
4239 4240
        break;
    case TARGET_NR_rename:
4241 4242 4243 4244
        {
            void *p2;
            p = lock_user_string(arg1);
            p2 = lock_user_string(arg2);
4245 4246 4247 4248
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(rename(p, p2));
4249 4250 4251
            unlock_user(p2, arg2, 0);
            unlock_user(p, arg1, 0);
        }
4252
        break;
4253 4254 4255
#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
    case TARGET_NR_renameat:
        {
4256
            void *p2;
4257 4258
            p  = lock_user_string(arg2);
            p2 = lock_user_string(arg4);
4259
            if (!p || !p2)
4260
                ret = -TARGET_EFAULT;
4261 4262
            else
                ret = get_errno(sys_renameat(arg1, p, arg3, p2));
4263 4264
            unlock_user(p2, arg4, 0);
            unlock_user(p, arg2, 0);
4265 4266 4267
        }
        break;
#endif
4268
    case TARGET_NR_mkdir:
4269 4270
        if (!(p = lock_user_string(arg1)))
            goto efault;
4271 4272
        ret = get_errno(mkdir(p, arg2));
        unlock_user(p, arg1, 0);
4273
        break;
4274 4275
#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
    case TARGET_NR_mkdirat:
4276 4277 4278 4279
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_mkdirat(arg1, p, arg3));
        unlock_user(p, arg2, 0);
4280 4281
        break;
#endif
4282
    case TARGET_NR_rmdir:
4283 4284
        if (!(p = lock_user_string(arg1)))
            goto efault;
4285 4286
        ret = get_errno(rmdir(p));
        unlock_user(p, arg1, 0);
4287 4288 4289 4290 4291 4292
        break;
    case TARGET_NR_dup:
        ret = get_errno(dup(arg1));
        break;
    case TARGET_NR_pipe:
        {
4293 4294
            int host_pipe[2];
            ret = get_errno(pipe(host_pipe));
4295
            if (!is_error(ret)) {
4296
#if defined(TARGET_MIPS)
4297
                CPUMIPSState *env = (CPUMIPSState*)cpu_env;
4298
		env->active_tc.gpr[3] = host_pipe[1];
4299
		ret = host_pipe[0];
4300 4301 4302
#elif defined(TARGET_SH4)
		((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
		ret = host_pipe[0];
4303
#else
4304 4305 4306
                if (put_user_s32(host_pipe[0], arg1)
                    || put_user_s32(host_pipe[1], arg1 + sizeof(host_pipe[0])))
                    goto efault;
4307
#endif
4308 4309 4310 4311
            }
        }
        break;
    case TARGET_NR_times:
B
bellard 已提交
4312
        {
4313
            struct target_tms *tmsp;
B
bellard 已提交
4314 4315
            struct tms tms;
            ret = get_errno(times(&tms));
4316
            if (arg1) {
4317 4318 4319
                tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
                if (!tmsp)
                    goto efault;
B
bellard 已提交
4320 4321 4322 4323
                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 已提交
4324
            }
B
bellard 已提交
4325 4326
            if (!is_error(ret))
                ret = host_to_target_clock_t(ret);
B
bellard 已提交
4327 4328
        }
        break;
4329
#ifdef TARGET_NR_prof
4330 4331
    case TARGET_NR_prof:
        goto unimplemented;
4332
#endif
4333
#ifdef TARGET_NR_signal
4334 4335
    case TARGET_NR_signal:
        goto unimplemented;
4336
#endif
4337
    case TARGET_NR_acct:
4338 4339 4340 4341 4342 4343 4344 4345
        if (arg1 == 0) {
            ret = get_errno(acct(NULL));
        } else {
            if (!(p = lock_user_string(arg1)))
                goto efault;
            ret = get_errno(acct(path(p)));
            unlock_user(p, arg1, 0);
        }
4346
        break;
4347
#ifdef TARGET_NR_umount2 /* not on alpha */
4348
    case TARGET_NR_umount2:
4349 4350
        if (!(p = lock_user_string(arg1)))
            goto efault;
4351 4352
        ret = get_errno(umount2(p, arg2));
        unlock_user(p, arg1, 0);
4353
        break;
4354
#endif
4355
#ifdef TARGET_NR_lock
4356 4357
    case TARGET_NR_lock:
        goto unimplemented;
4358
#endif
4359 4360 4361 4362
    case TARGET_NR_ioctl:
        ret = do_ioctl(arg1, arg2, arg3);
        break;
    case TARGET_NR_fcntl:
B
bellard 已提交
4363
        ret = do_fcntl(arg1, arg2, arg3);
4364
        break;
4365
#ifdef TARGET_NR_mpx
4366 4367
    case TARGET_NR_mpx:
        goto unimplemented;
4368
#endif
4369 4370 4371
    case TARGET_NR_setpgid:
        ret = get_errno(setpgid(arg1, arg2));
        break;
4372
#ifdef TARGET_NR_ulimit
4373 4374
    case TARGET_NR_ulimit:
        goto unimplemented;
4375 4376
#endif
#ifdef TARGET_NR_oldolduname
4377 4378
    case TARGET_NR_oldolduname:
        goto unimplemented;
4379
#endif
4380 4381 4382 4383
    case TARGET_NR_umask:
        ret = get_errno(umask(arg1));
        break;
    case TARGET_NR_chroot:
4384 4385
        if (!(p = lock_user_string(arg1)))
            goto efault;
4386 4387
        ret = get_errno(chroot(p));
        unlock_user(p, arg1, 0);
4388 4389 4390 4391 4392 4393
        break;
    case TARGET_NR_ustat:
        goto unimplemented;
    case TARGET_NR_dup2:
        ret = get_errno(dup2(arg1, arg2));
        break;
4394
#ifdef TARGET_NR_getppid /* not on alpha */
4395 4396 4397
    case TARGET_NR_getppid:
        ret = get_errno(getppid());
        break;
4398
#endif
4399 4400 4401 4402 4403 4404
    case TARGET_NR_getpgrp:
        ret = get_errno(getpgrp());
        break;
    case TARGET_NR_setsid:
        ret = get_errno(setsid());
        break;
4405
#ifdef TARGET_NR_sigaction
4406 4407
    case TARGET_NR_sigaction:
        {
T
ths 已提交
4408
#if !defined(TARGET_MIPS)
4409
            struct target_old_sigaction *old_act;
B
bellard 已提交
4410
            struct target_sigaction act, oact, *pact;
4411
            if (arg2) {
4412 4413
                if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
                    goto efault;
B
bellard 已提交
4414 4415 4416 4417
                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;
4418
                unlock_user_struct(old_act, arg2, 0);
B
bellard 已提交
4419 4420 4421 4422 4423
                pact = &act;
            } else {
                pact = NULL;
            }
            ret = get_errno(do_sigaction(arg1, pact, &oact));
4424
            if (!is_error(ret) && arg3) {
4425 4426
                if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
                    goto efault;
4427 4428 4429 4430 4431
                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 已提交
4432
            }
T
ths 已提交
4433
#else
4434 4435 4436
	    struct target_sigaction act, oact, *pact, *old_act;

	    if (arg2) {
4437 4438
                if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
                    goto efault;
4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450
		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) {
4451 4452
                if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
                    goto efault;
4453 4454 4455 4456 4457 4458 4459 4460
		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 已提交
4461
#endif
4462 4463
        }
        break;
4464
#endif
B
bellard 已提交
4465
    case TARGET_NR_rt_sigaction:
4466 4467 4468 4469
        {
            struct target_sigaction *act;
            struct target_sigaction *oact;

4470 4471 4472 4473
            if (arg2) {
                if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
                    goto efault;
            } else
4474
                act = NULL;
4475 4476 4477 4478 4479 4480
            if (arg3) {
                if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
                    ret = -TARGET_EFAULT;
                    goto rt_sigaction_fail;
                }
            } else
4481 4482
                oact = NULL;
            ret = get_errno(do_sigaction(arg1, act, oact));
4483 4484
	rt_sigaction_fail:
            if (act)
4485
                unlock_user_struct(act, arg2, 0);
4486
            if (oact)
4487 4488
                unlock_user_struct(oact, arg3, 1);
        }
B
bellard 已提交
4489
        break;
4490
#ifdef TARGET_NR_sgetmask /* not on alpha */
4491
    case TARGET_NR_sgetmask:
B
bellard 已提交
4492 4493
        {
            sigset_t cur_set;
4494
            abi_ulong target_set;
B
bellard 已提交
4495 4496 4497 4498 4499
            sigprocmask(0, NULL, &cur_set);
            host_to_target_old_sigset(&target_set, &cur_set);
            ret = target_set;
        }
        break;
4500 4501
#endif
#ifdef TARGET_NR_ssetmask /* not on alpha */
4502
    case TARGET_NR_ssetmask:
B
bellard 已提交
4503 4504
        {
            sigset_t set, oset, cur_set;
4505
            abi_ulong target_set = arg1;
B
bellard 已提交
4506 4507 4508 4509 4510 4511 4512 4513
            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;
4514
#endif
4515
#ifdef TARGET_NR_sigprocmask
B
bellard 已提交
4516 4517 4518 4519
    case TARGET_NR_sigprocmask:
        {
            int how = arg1;
            sigset_t set, oldset, *set_ptr;
4520

4521
            if (arg2) {
B
bellard 已提交
4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532
                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:
4533
                    ret = -TARGET_EINVAL;
B
bellard 已提交
4534 4535
                    goto fail;
                }
4536 4537
                if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
                    goto efault;
4538 4539
                target_to_host_old_sigset(&set, p);
                unlock_user(p, arg2, 0);
B
bellard 已提交
4540 4541 4542 4543 4544 4545
                set_ptr = &set;
            } else {
                how = 0;
                set_ptr = NULL;
            }
            ret = get_errno(sigprocmask(arg1, set_ptr, &oldset));
4546
            if (!is_error(ret) && arg3) {
4547 4548
                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
                    goto efault;
4549 4550
                host_to_target_old_sigset(p, &oldset);
                unlock_user(p, arg3, sizeof(target_sigset_t));
B
bellard 已提交
4551 4552 4553
            }
        }
        break;
4554
#endif
B
bellard 已提交
4555 4556 4557 4558
    case TARGET_NR_rt_sigprocmask:
        {
            int how = arg1;
            sigset_t set, oldset, *set_ptr;
4559

4560
            if (arg2) {
B
bellard 已提交
4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571
                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:
4572
                    ret = -TARGET_EINVAL;
B
bellard 已提交
4573 4574
                    goto fail;
                }
4575 4576
                if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
                    goto efault;
4577 4578
                target_to_host_sigset(&set, p);
                unlock_user(p, arg2, 0);
B
bellard 已提交
4579 4580 4581 4582 4583 4584
                set_ptr = &set;
            } else {
                how = 0;
                set_ptr = NULL;
            }
            ret = get_errno(sigprocmask(how, set_ptr, &oldset));
4585
            if (!is_error(ret) && arg3) {
4586 4587
                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
                    goto efault;
4588 4589
                host_to_target_sigset(p, &oldset);
                unlock_user(p, arg3, sizeof(target_sigset_t));
B
bellard 已提交
4590 4591 4592
            }
        }
        break;
4593
#ifdef TARGET_NR_sigpending
B
bellard 已提交
4594 4595 4596 4597 4598
    case TARGET_NR_sigpending:
        {
            sigset_t set;
            ret = get_errno(sigpending(&set));
            if (!is_error(ret)) {
4599 4600
                if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
                    goto efault;
4601 4602
                host_to_target_old_sigset(p, &set);
                unlock_user(p, arg1, sizeof(target_sigset_t));
B
bellard 已提交
4603 4604 4605
            }
        }
        break;
4606
#endif
B
bellard 已提交
4607 4608 4609 4610 4611
    case TARGET_NR_rt_sigpending:
        {
            sigset_t set;
            ret = get_errno(sigpending(&set));
            if (!is_error(ret)) {
4612 4613
                if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
                    goto efault;
4614 4615
                host_to_target_sigset(p, &set);
                unlock_user(p, arg1, sizeof(target_sigset_t));
B
bellard 已提交
4616 4617 4618
            }
        }
        break;
4619
#ifdef TARGET_NR_sigsuspend
B
bellard 已提交
4620 4621 4622
    case TARGET_NR_sigsuspend:
        {
            sigset_t set;
4623 4624
            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
                goto efault;
4625 4626
            target_to_host_old_sigset(&set, p);
            unlock_user(p, arg1, 0);
B
bellard 已提交
4627 4628 4629
            ret = get_errno(sigsuspend(&set));
        }
        break;
4630
#endif
B
bellard 已提交
4631 4632 4633
    case TARGET_NR_rt_sigsuspend:
        {
            sigset_t set;
4634 4635
            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
                goto efault;
4636 4637
            target_to_host_sigset(&set, p);
            unlock_user(p, arg1, 0);
B
bellard 已提交
4638 4639 4640 4641 4642 4643 4644 4645
            ret = get_errno(sigsuspend(&set));
        }
        break;
    case TARGET_NR_rt_sigtimedwait:
        {
            sigset_t set;
            struct timespec uts, *puts;
            siginfo_t uinfo;
4646

4647 4648
            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
                goto efault;
4649 4650 4651
            target_to_host_sigset(&set, p);
            unlock_user(p, arg1, 0);
            if (arg3) {
B
bellard 已提交
4652
                puts = &uts;
4653
                target_to_host_timespec(puts, arg3);
B
bellard 已提交
4654 4655 4656 4657
            } else {
                puts = NULL;
            }
            ret = get_errno(sigtimedwait(&set, &uinfo, puts));
4658
            if (!is_error(ret) && arg2) {
4659
                if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
4660
                    goto efault;
4661
                host_to_target_siginfo(p, &uinfo);
4662
                unlock_user(p, arg2, sizeof(target_siginfo_t));
B
bellard 已提交
4663 4664 4665 4666 4667 4668
            }
        }
        break;
    case TARGET_NR_rt_sigqueueinfo:
        {
            siginfo_t uinfo;
4669 4670
            if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
                goto efault;
4671 4672
            target_to_host_siginfo(&uinfo, p);
            unlock_user(p, arg1, 0);
B
bellard 已提交
4673 4674 4675
            ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
        }
        break;
4676
#ifdef TARGET_NR_sigreturn
B
bellard 已提交
4677 4678 4679 4680
    case TARGET_NR_sigreturn:
        /* NOTE: ret is eax, so not transcoding must be done */
        ret = do_sigreturn(cpu_env);
        break;
4681
#endif
B
bellard 已提交
4682 4683 4684 4685
    case TARGET_NR_rt_sigreturn:
        /* NOTE: ret is eax, so not transcoding must be done */
        ret = do_rt_sigreturn(cpu_env);
        break;
4686
    case TARGET_NR_sethostname:
4687 4688
        if (!(p = lock_user_string(arg1)))
            goto efault;
4689 4690
        ret = get_errno(sethostname(p, arg2));
        unlock_user(p, arg1, 0);
4691 4692
        break;
    case TARGET_NR_setrlimit:
B
bellard 已提交
4693 4694 4695
        {
            /* XXX: convert resource ? */
            int resource = arg1;
4696
            struct target_rlimit *target_rlim;
B
bellard 已提交
4697
            struct rlimit rlim;
4698 4699
            if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
                goto efault;
B
bellard 已提交
4700 4701
            rlim.rlim_cur = tswapl(target_rlim->rlim_cur);
            rlim.rlim_max = tswapl(target_rlim->rlim_max);
4702
            unlock_user_struct(target_rlim, arg2, 0);
B
bellard 已提交
4703 4704 4705
            ret = get_errno(setrlimit(resource, &rlim));
        }
        break;
4706
    case TARGET_NR_getrlimit:
B
bellard 已提交
4707 4708 4709
        {
            /* XXX: convert resource ? */
            int resource = arg1;
4710
            struct target_rlimit *target_rlim;
B
bellard 已提交
4711
            struct rlimit rlim;
4712

B
bellard 已提交
4713 4714
            ret = get_errno(getrlimit(resource, &rlim));
            if (!is_error(ret)) {
4715 4716
                if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
                    goto efault;
4717 4718 4719
                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 已提交
4720 4721 4722
            }
        }
        break;
4723
    case TARGET_NR_getrusage:
B
bellard 已提交
4724 4725 4726 4727
        {
            struct rusage rusage;
            ret = get_errno(getrusage(arg1, &rusage));
            if (!is_error(ret)) {
4728
                host_to_target_rusage(arg2, &rusage);
B
bellard 已提交
4729 4730 4731
            }
        }
        break;
4732 4733 4734 4735 4736
    case TARGET_NR_gettimeofday:
        {
            struct timeval tv;
            ret = get_errno(gettimeofday(&tv, NULL));
            if (!is_error(ret)) {
4737 4738
                if (copy_to_user_timeval(arg1, &tv))
                    goto efault;
4739 4740 4741 4742 4743 4744
            }
        }
        break;
    case TARGET_NR_settimeofday:
        {
            struct timeval tv;
4745 4746
            if (copy_from_user_timeval(&tv, arg1))
                goto efault;
4747 4748 4749
            ret = get_errno(settimeofday(&tv, NULL));
        }
        break;
B
bellard 已提交
4750
#ifdef TARGET_NR_select
4751
    case TARGET_NR_select:
B
bellard 已提交
4752
        {
4753
            struct target_sel_arg_struct *sel;
4754
            abi_ulong inp, outp, exp, tvp;
4755 4756
            long nsel;

4757 4758
            if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
                goto efault;
4759 4760 4761 4762 4763 4764 4765
            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 已提交
4766 4767
        }
        break;
B
bellard 已提交
4768
#endif
4769
    case TARGET_NR_symlink:
4770 4771 4772 4773
        {
            void *p2;
            p = lock_user_string(arg1);
            p2 = lock_user_string(arg2);
4774 4775 4776 4777
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(symlink(p, p2));
4778 4779 4780
            unlock_user(p2, arg2, 0);
            unlock_user(p, arg1, 0);
        }
4781
        break;
4782 4783 4784
#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
    case TARGET_NR_symlinkat:
        {
4785
            void *p2;
4786 4787
            p  = lock_user_string(arg1);
            p2 = lock_user_string(arg3);
4788
            if (!p || !p2)
4789
                ret = -TARGET_EFAULT;
4790 4791
            else
                ret = get_errno(sys_symlinkat(p, arg2, p2));
4792 4793
            unlock_user(p2, arg3, 0);
            unlock_user(p, arg1, 0);
4794 4795 4796
        }
        break;
#endif
4797
#ifdef TARGET_NR_oldlstat
4798 4799
    case TARGET_NR_oldlstat:
        goto unimplemented;
4800
#endif
4801
    case TARGET_NR_readlink:
4802
        {
4803
            void *p2, *temp;
4804
            p = lock_user_string(arg1);
4805 4806 4807
            p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
            if (!p || !p2)
                ret = -TARGET_EFAULT;
4808 4809 4810 4811 4812 4813 4814 4815 4816 4817
            else {
                if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
                    char real[PATH_MAX];
                    temp = realpath(exec_path,real);
                    ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
                    snprintf((char *)p2, arg3, "%s", real);
                    }
                else
                    ret = get_errno(readlink(path(p), p2, arg3));
            }
4818 4819 4820
            unlock_user(p2, arg2, ret);
            unlock_user(p, arg1, 0);
        }
4821
        break;
4822 4823 4824
#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
    case TARGET_NR_readlinkat:
        {
4825
            void *p2;
4826
            p  = lock_user_string(arg2);
4827 4828
            p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
            if (!p || !p2)
4829
        	ret = -TARGET_EFAULT;
4830 4831
            else
                ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
4832 4833
            unlock_user(p2, arg3, ret);
            unlock_user(p, arg2, 0);
4834 4835 4836
        }
        break;
#endif
4837
#ifdef TARGET_NR_uselib
4838 4839
    case TARGET_NR_uselib:
        goto unimplemented;
4840 4841
#endif
#ifdef TARGET_NR_swapon
4842
    case TARGET_NR_swapon:
4843 4844
        if (!(p = lock_user_string(arg1)))
            goto efault;
4845 4846
        ret = get_errno(swapon(p, arg2));
        unlock_user(p, arg1, 0);
4847
        break;
4848
#endif
4849 4850
    case TARGET_NR_reboot:
        goto unimplemented;
4851
#ifdef TARGET_NR_readdir
4852 4853
    case TARGET_NR_readdir:
        goto unimplemented;
4854 4855
#endif
#ifdef TARGET_NR_mmap
4856
    case TARGET_NR_mmap:
B
bellard 已提交
4857
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS)
4858
        {
4859 4860
            abi_ulong *v;
            abi_ulong v1, v2, v3, v4, v5, v6;
4861 4862
            if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
                goto efault;
4863 4864 4865 4866 4867 4868 4869
            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);
4870
            ret = get_errno(target_mmap(v1, v2, v3,
B
bellard 已提交
4871 4872
                                        target_to_host_bitmask(v4, mmap_flags_tbl),
                                        v5, v6));
4873 4874
        }
#else
4875 4876
        ret = get_errno(target_mmap(arg1, arg2, arg3,
                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
B
bellard 已提交
4877 4878
                                    arg5,
                                    arg6));
4879
#endif
B
bellard 已提交
4880
        break;
4881
#endif
B
bellard 已提交
4882
#ifdef TARGET_NR_mmap2
B
bellard 已提交
4883
    case TARGET_NR_mmap2:
P
pbrook 已提交
4884
#ifndef MMAP_SHIFT
B
bellard 已提交
4885 4886
#define MMAP_SHIFT 12
#endif
4887 4888
        ret = get_errno(target_mmap(arg1, arg2, arg3,
                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
B
bellard 已提交
4889
                                    arg5,
B
bellard 已提交
4890
                                    arg6 << MMAP_SHIFT));
4891
        break;
B
bellard 已提交
4892
#endif
4893
    case TARGET_NR_munmap:
B
bellard 已提交
4894
        ret = get_errno(target_munmap(arg1, arg2));
4895
        break;
B
bellard 已提交
4896
    case TARGET_NR_mprotect:
B
bellard 已提交
4897
        ret = get_errno(target_mprotect(arg1, arg2, arg3));
B
bellard 已提交
4898
        break;
4899
#ifdef TARGET_NR_mremap
B
bellard 已提交
4900
    case TARGET_NR_mremap:
B
bellard 已提交
4901
        ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
B
bellard 已提交
4902
        break;
4903
#endif
4904
        /* ??? msync/mlock/munlock are broken for softmmu.  */
4905
#ifdef TARGET_NR_msync
B
bellard 已提交
4906
    case TARGET_NR_msync:
4907
        ret = get_errno(msync(g2h(arg1), arg2, arg3));
B
bellard 已提交
4908
        break;
4909 4910
#endif
#ifdef TARGET_NR_mlock
B
bellard 已提交
4911
    case TARGET_NR_mlock:
4912
        ret = get_errno(mlock(g2h(arg1), arg2));
B
bellard 已提交
4913
        break;
4914 4915
#endif
#ifdef TARGET_NR_munlock
B
bellard 已提交
4916
    case TARGET_NR_munlock:
4917
        ret = get_errno(munlock(g2h(arg1), arg2));
B
bellard 已提交
4918
        break;
4919 4920
#endif
#ifdef TARGET_NR_mlockall
B
bellard 已提交
4921 4922 4923
    case TARGET_NR_mlockall:
        ret = get_errno(mlockall(arg1));
        break;
4924 4925
#endif
#ifdef TARGET_NR_munlockall
B
bellard 已提交
4926 4927 4928
    case TARGET_NR_munlockall:
        ret = get_errno(munlockall());
        break;
4929
#endif
4930
    case TARGET_NR_truncate:
4931 4932
        if (!(p = lock_user_string(arg1)))
            goto efault;
4933 4934
        ret = get_errno(truncate(p, arg2));
        unlock_user(p, arg1, 0);
4935 4936 4937 4938 4939 4940 4941
        break;
    case TARGET_NR_ftruncate:
        ret = get_errno(ftruncate(arg1, arg2));
        break;
    case TARGET_NR_fchmod:
        ret = get_errno(fchmod(arg1, arg2));
        break;
4942 4943
#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
    case TARGET_NR_fchmodat:
4944 4945
        if (!(p = lock_user_string(arg2)))
            goto efault;
4946
        ret = get_errno(sys_fchmodat(arg1, p, arg3));
4947
        unlock_user(p, arg2, 0);
4948 4949
        break;
#endif
4950
    case TARGET_NR_getpriority:
4951 4952 4953 4954
        /* 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);
4955 4956 4957 4958
        break;
    case TARGET_NR_setpriority:
        ret = get_errno(setpriority(arg1, arg2, arg3));
        break;
4959
#ifdef TARGET_NR_profil
4960 4961
    case TARGET_NR_profil:
        goto unimplemented;
4962
#endif
4963
    case TARGET_NR_statfs:
4964 4965
        if (!(p = lock_user_string(arg1)))
            goto efault;
4966 4967
        ret = get_errno(statfs(path(p), &stfs));
        unlock_user(p, arg1, 0);
4968 4969
    convert_statfs:
        if (!is_error(ret)) {
4970
            struct target_statfs *target_stfs;
4971

4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983
            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);
4984
            unlock_user_struct(target_stfs, arg2, 1);
4985 4986 4987
        }
        break;
    case TARGET_NR_fstatfs:
B
bellard 已提交
4988
        ret = get_errno(fstatfs(arg1, &stfs));
4989
        goto convert_statfs;
B
bellard 已提交
4990 4991
#ifdef TARGET_NR_statfs64
    case TARGET_NR_statfs64:
4992 4993
        if (!(p = lock_user_string(arg1)))
            goto efault;
4994 4995
        ret = get_errno(statfs(path(p), &stfs));
        unlock_user(p, arg1, 0);
B
bellard 已提交
4996 4997
    convert_statfs64:
        if (!is_error(ret)) {
4998
            struct target_statfs64 *target_stfs;
4999

5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012
            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 已提交
5013 5014 5015 5016 5017 5018
        }
        break;
    case TARGET_NR_fstatfs64:
        ret = get_errno(fstatfs(arg1, &stfs));
        goto convert_statfs64;
#endif
5019
#ifdef TARGET_NR_ioperm
5020 5021
    case TARGET_NR_ioperm:
        goto unimplemented;
5022
#endif
5023
#ifdef TARGET_NR_socketcall
5024
    case TARGET_NR_socketcall:
5025
        ret = do_socketcall(arg1, arg2);
5026
        break;
5027
#endif
5028 5029
#ifdef TARGET_NR_accept
    case TARGET_NR_accept:
P
pbrook 已提交
5030
        ret = do_accept(arg1, arg2, arg3);
5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044
        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 已提交
5045
        ret = do_getpeername(arg1, arg2, arg3);
5046 5047 5048 5049
        break;
#endif
#ifdef TARGET_NR_getsockname
    case TARGET_NR_getsockname:
P
pbrook 已提交
5050
        ret = do_getsockname(arg1, arg2, arg3);
5051 5052 5053 5054 5055 5056 5057 5058 5059
        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 已提交
5060
        ret = get_errno(listen(arg1, arg2));
5061 5062 5063 5064
        break;
#endif
#ifdef TARGET_NR_recv
    case TARGET_NR_recv:
P
pbrook 已提交
5065
        ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
5066 5067 5068 5069
        break;
#endif
#ifdef TARGET_NR_recvfrom
    case TARGET_NR_recvfrom:
P
pbrook 已提交
5070
        ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
5071 5072 5073 5074 5075 5076 5077 5078 5079
        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 已提交
5080
        ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
5081 5082 5083 5084 5085 5086 5087 5088 5089
        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 已提交
5090
        ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
5091 5092 5093 5094
        break;
#endif
#ifdef TARGET_NR_shutdown
    case TARGET_NR_shutdown:
P
pbrook 已提交
5095
        ret = get_errno(shutdown(arg1, arg2));
5096 5097 5098 5099 5100 5101 5102 5103 5104
        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 已提交
5105
        ret = do_socketpair(arg1, arg2, arg3, arg4);
5106 5107 5108 5109 5110 5111 5112
        break;
#endif
#ifdef TARGET_NR_setsockopt
    case TARGET_NR_setsockopt:
        ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
        break;
#endif
5113

5114
    case TARGET_NR_syslog:
5115 5116
        if (!(p = lock_user_string(arg2)))
            goto efault;
5117 5118
        ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
        unlock_user(p, arg2, 0);
5119 5120
        break;

5121
    case TARGET_NR_setitimer:
B
bellard 已提交
5122 5123 5124
        {
            struct itimerval value, ovalue, *pvalue;

5125
            if (arg2) {
B
bellard 已提交
5126
                pvalue = &value;
5127 5128 5129 5130
                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 已提交
5131 5132 5133 5134
            } else {
                pvalue = NULL;
            }
            ret = get_errno(setitimer(arg1, pvalue, &ovalue));
5135
            if (!is_error(ret) && arg3) {
5136 5137 5138 5139 5140
                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 已提交
5141 5142 5143
            }
        }
        break;
5144
    case TARGET_NR_getitimer:
B
bellard 已提交
5145 5146
        {
            struct itimerval value;
5147

B
bellard 已提交
5148
            ret = get_errno(getitimer(arg1, &value));
5149
            if (!is_error(ret) && arg2) {
5150 5151 5152 5153 5154
                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 已提交
5155 5156 5157
            }
        }
        break;
5158
    case TARGET_NR_stat:
5159 5160
        if (!(p = lock_user_string(arg1)))
            goto efault;
5161 5162
        ret = get_errno(stat(path(p), &st));
        unlock_user(p, arg1, 0);
5163 5164
        goto do_stat;
    case TARGET_NR_lstat:
5165 5166
        if (!(p = lock_user_string(arg1)))
            goto efault;
5167 5168
        ret = get_errno(lstat(path(p), &st));
        unlock_user(p, arg1, 0);
5169 5170 5171 5172 5173 5174
        goto do_stat;
    case TARGET_NR_fstat:
        {
            ret = get_errno(fstat(arg1, &st));
        do_stat:
            if (!is_error(ret)) {
5175
                struct target_stat *target_st;
5176

5177 5178
                if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
                    goto efault;
B
bellard 已提交
5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191
                __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);
5192
                unlock_user_struct(target_st, arg2, 1);
5193 5194 5195
            }
        }
        break;
5196
#ifdef TARGET_NR_olduname
5197 5198
    case TARGET_NR_olduname:
        goto unimplemented;
5199 5200
#endif
#ifdef TARGET_NR_iopl
5201 5202
    case TARGET_NR_iopl:
        goto unimplemented;
5203
#endif
5204 5205 5206
    case TARGET_NR_vhangup:
        ret = get_errno(vhangup());
        break;
5207
#ifdef TARGET_NR_idle
5208 5209
    case TARGET_NR_idle:
        goto unimplemented;
B
bellard 已提交
5210 5211 5212 5213 5214
#endif
#ifdef TARGET_NR_syscall
    case TARGET_NR_syscall:
    	ret = do_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
    	break;
5215
#endif
5216 5217 5218
    case TARGET_NR_wait4:
        {
            int status;
5219
            abi_long status_ptr = arg2;
5220
            struct rusage rusage, *rusage_ptr;
5221
            abi_ulong target_rusage = arg4;
5222 5223 5224 5225 5226 5227
            if (target_rusage)
                rusage_ptr = &rusage;
            else
                rusage_ptr = NULL;
            ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
            if (!is_error(ret)) {
5228
                if (status_ptr) {
P
pbrook 已提交
5229
                    status = host_to_target_waitstatus(status);
5230 5231
                    if (put_user_s32(status, status_ptr))
                        goto efault;
5232
                }
5233 5234
                if (target_rusage)
                    host_to_target_rusage(target_rusage, &rusage);
5235 5236 5237
            }
        }
        break;
5238
#ifdef TARGET_NR_swapoff
5239
    case TARGET_NR_swapoff:
5240 5241
        if (!(p = lock_user_string(arg1)))
            goto efault;
5242 5243
        ret = get_errno(swapoff(p));
        unlock_user(p, arg1, 0);
5244
        break;
5245
#endif
5246
    case TARGET_NR_sysinfo:
B
bellard 已提交
5247
        {
5248
            struct target_sysinfo *target_value;
B
bellard 已提交
5249 5250
            struct sysinfo value;
            ret = get_errno(sysinfo(&value));
5251
            if (!is_error(ret) && arg1)
B
bellard 已提交
5252
            {
5253 5254
                if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
                    goto efault;
B
bellard 已提交
5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268
                __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);
5269
                unlock_user_struct(target_value, arg1, 1);
B
bellard 已提交
5270 5271 5272
            }
        }
        break;
5273
#ifdef TARGET_NR_ipc
5274
    case TARGET_NR_ipc:
5275 5276
	ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
	break;
5277
#endif
5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292
#ifdef TARGET_NR_semget
    case TARGET_NR_semget:
        ret = get_errno(semget(arg1, arg2, arg3));
        break;
#endif
#ifdef TARGET_NR_semop
    case TARGET_NR_semop:
        ret = get_errno(do_semop(arg1, arg2, arg3));
        break;
#endif
#ifdef TARGET_NR_semctl
    case TARGET_NR_semctl:
        ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
        break;
#endif
A
aurel32 已提交
5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312
#ifdef TARGET_NR_msgctl
    case TARGET_NR_msgctl:
        ret = do_msgctl(arg1, arg2, arg3);
        break;
#endif
#ifdef TARGET_NR_msgget
    case TARGET_NR_msgget:
        ret = get_errno(msgget(arg1, arg2));
        break;
#endif
#ifdef TARGET_NR_msgrcv
    case TARGET_NR_msgrcv:
        ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
        break;
#endif
#ifdef TARGET_NR_msgsnd
    case TARGET_NR_msgsnd:
        ret = do_msgsnd(arg1, arg2, arg3, arg4);
        break;
#endif
5313 5314 5315 5316
    case TARGET_NR_fsync:
        ret = get_errno(fsync(arg1));
        break;
    case TARGET_NR_clone:
A
aurel32 已提交
5317 5318
#if defined(TARGET_SH4)
        ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
5319 5320
#elif defined(TARGET_CRIS)
        ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
A
aurel32 已提交
5321
#else
P
pbrook 已提交
5322
        ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
A
aurel32 已提交
5323
#endif
B
bellard 已提交
5324
        break;
5325 5326 5327
#ifdef __NR_exit_group
        /* new thread calls */
    case TARGET_NR_exit_group:
A
aurel32 已提交
5328 5329 5330
#ifdef HAVE_GPROF
        _mcleanup();
#endif
5331
        gdb_exit(cpu_env, arg1);
5332 5333 5334
        ret = get_errno(exit_group(arg1));
        break;
#endif
5335
    case TARGET_NR_setdomainname:
5336 5337
        if (!(p = lock_user_string(arg1)))
            goto efault;
5338 5339
        ret = get_errno(setdomainname(p, arg2));
        unlock_user(p, arg1, 0);
5340 5341 5342
        break;
    case TARGET_NR_uname:
        /* no need to transcode because we use the linux syscall */
B
bellard 已提交
5343 5344
        {
            struct new_utsname * buf;
5345

5346 5347
            if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
                goto efault;
B
bellard 已提交
5348 5349 5350 5351 5352
            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);
5353 5354 5355
                /* Allow the user to override the reported release.  */
                if (qemu_uname_release && *qemu_uname_release)
                  strcpy (buf->release, qemu_uname_release);
B
bellard 已提交
5356
            }
5357
            unlock_user_struct(buf, arg1, 1);
B
bellard 已提交
5358
        }
5359
        break;
B
bellard 已提交
5360
#ifdef TARGET_I386
5361
    case TARGET_NR_modify_ldt:
5362
        ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
B
bellard 已提交
5363
        break;
5364
#if !defined(TARGET_X86_64)
B
bellard 已提交
5365 5366 5367
    case TARGET_NR_vm86old:
        goto unimplemented;
    case TARGET_NR_vm86:
5368
        ret = do_vm86(cpu_env, arg1, arg2);
B
bellard 已提交
5369
        break;
5370
#endif
B
bellard 已提交
5371
#endif
5372 5373
    case TARGET_NR_adjtimex:
        goto unimplemented;
5374
#ifdef TARGET_NR_create_module
5375
    case TARGET_NR_create_module:
5376
#endif
5377 5378
    case TARGET_NR_init_module:
    case TARGET_NR_delete_module:
5379
#ifdef TARGET_NR_get_kernel_syms
5380
    case TARGET_NR_get_kernel_syms:
5381
#endif
5382 5383 5384 5385 5386 5387 5388 5389 5390
        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;
5391
#ifdef TARGET_NR_bdflush /* not on x86_64 */
5392 5393
    case TARGET_NR_bdflush:
        goto unimplemented;
5394
#endif
5395
#ifdef TARGET_NR_sysfs
5396 5397
    case TARGET_NR_sysfs:
        goto unimplemented;
5398
#endif
5399
    case TARGET_NR_personality:
B
bellard 已提交
5400
        ret = get_errno(personality(arg1));
5401
        break;
5402
#ifdef TARGET_NR_afs_syscall
5403 5404
    case TARGET_NR_afs_syscall:
        goto unimplemented;
5405
#endif
5406
#ifdef TARGET_NR__llseek /* Not on alpha */
5407 5408
    case TARGET_NR__llseek:
        {
B
bellard 已提交
5409 5410
#if defined (__x86_64__)
            ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5));
5411 5412
            if (put_user_s64(ret, arg4))
                goto efault;
B
bellard 已提交
5413
#else
5414 5415
            int64_t res;
            ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
5416 5417
            if (put_user_s64(res, arg4))
                goto efault;
B
bellard 已提交
5418
#endif
5419 5420
        }
        break;
5421
#endif
5422
    case TARGET_NR_getdents:
5423
#if TARGET_ABI_BITS != 32
5424
        goto unimplemented;
5425
#elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
B
bellard 已提交
5426
        {
5427
            struct target_dirent *target_dirp;
A
aurel32 已提交
5428
            struct linux_dirent *dirp;
5429
            abi_long count = arg3;
B
bellard 已提交
5430 5431

	    dirp = malloc(count);
5432
	    if (!dirp) {
5433
                ret = -TARGET_ENOMEM;
5434 5435
                goto fail;
            }
5436

B
bellard 已提交
5437 5438
            ret = get_errno(sys_getdents(arg1, dirp, count));
            if (!is_error(ret)) {
A
aurel32 已提交
5439
                struct linux_dirent *de;
B
bellard 已提交
5440 5441 5442 5443 5444 5445 5446
		struct target_dirent *tde;
                int len = ret;
                int reclen, treclen;
		int count1, tnamelen;

		count1 = 0;
                de = dirp;
5447 5448
                if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
                    goto efault;
B
bellard 已提交
5449 5450 5451
		tde = target_dirp;
                while (len > 0) {
                    reclen = de->d_reclen;
5452
		    treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
B
bellard 已提交
5453 5454 5455
                    tde->d_reclen = tswap16(treclen);
                    tde->d_ino = tswapl(de->d_ino);
                    tde->d_off = tswapl(de->d_off);
5456
		    tnamelen = treclen - (2 * sizeof(abi_long) + 2);
B
bellard 已提交
5457 5458
		    if (tnamelen > 256)
                        tnamelen = 256;
B
bellard 已提交
5459
                    /* XXX: may not be correct */
5460
                    pstrcpy(tde->d_name, tnamelen, de->d_name);
A
aurel32 已提交
5461
                    de = (struct linux_dirent *)((char *)de + reclen);
B
bellard 已提交
5462
                    len -= reclen;
J
j_mayer 已提交
5463
                    tde = (struct target_dirent *)((char *)tde + treclen);
B
bellard 已提交
5464 5465 5466
		    count1 += treclen;
                }
		ret = count1;
5467
                unlock_user(target_dirp, arg2, ret);
B
bellard 已提交
5468 5469 5470 5471
            }
	    free(dirp);
        }
#else
5472
        {
A
aurel32 已提交
5473
            struct linux_dirent *dirp;
5474
            abi_long count = arg3;
B
bellard 已提交
5475

5476 5477
            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
                goto efault;
B
bellard 已提交
5478
            ret = get_errno(sys_getdents(arg1, dirp, count));
5479
            if (!is_error(ret)) {
A
aurel32 已提交
5480
                struct linux_dirent *de;
5481 5482 5483 5484
                int len = ret;
                int reclen;
                de = dirp;
                while (len > 0) {
B
bellard 已提交
5485
                    reclen = de->d_reclen;
5486 5487
                    if (reclen > len)
                        break;
B
bellard 已提交
5488
                    de->d_reclen = tswap16(reclen);
5489 5490
                    tswapls(&de->d_ino);
                    tswapls(&de->d_off);
A
aurel32 已提交
5491
                    de = (struct linux_dirent *)((char *)de + reclen);
5492 5493 5494
                    len -= reclen;
                }
            }
5495
            unlock_user(dirp, arg2, ret);
5496
        }
B
bellard 已提交
5497
#endif
5498
        break;
T
ths 已提交
5499
#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
B
bellard 已提交
5500 5501
    case TARGET_NR_getdents64:
        {
A
aurel32 已提交
5502
            struct linux_dirent64 *dirp;
5503
            abi_long count = arg3;
5504 5505
            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
                goto efault;
B
bellard 已提交
5506 5507
            ret = get_errno(sys_getdents64(arg1, dirp, count));
            if (!is_error(ret)) {
A
aurel32 已提交
5508
                struct linux_dirent64 *de;
B
bellard 已提交
5509 5510 5511 5512
                int len = ret;
                int reclen;
                de = dirp;
                while (len > 0) {
B
bellard 已提交
5513
                    reclen = de->d_reclen;
B
bellard 已提交
5514 5515
                    if (reclen > len)
                        break;
B
bellard 已提交
5516
                    de->d_reclen = tswap16(reclen);
B
bellard 已提交
5517 5518
                    tswap64s((uint64_t *)&de->d_ino);
                    tswap64s((uint64_t *)&de->d_off);
A
aurel32 已提交
5519
                    de = (struct linux_dirent64 *)((char *)de + reclen);
B
bellard 已提交
5520 5521 5522
                    len -= reclen;
                }
            }
5523
            unlock_user(dirp, arg2, ret);
B
bellard 已提交
5524 5525
        }
        break;
5526
#endif /* TARGET_NR_getdents64 */
5527
#ifdef TARGET_NR__newselect
5528
    case TARGET_NR__newselect:
5529
        ret = do_select(arg1, arg2, arg3, arg4, arg5);
5530
        break;
5531 5532
#endif
#ifdef TARGET_NR_poll
B
bellard 已提交
5533 5534
    case TARGET_NR_poll:
        {
5535
            struct target_pollfd *target_pfd;
B
bellard 已提交
5536 5537 5538
            unsigned int nfds = arg2;
            int timeout = arg3;
            struct pollfd *pfd;
B
bellard 已提交
5539
            unsigned int i;
B
bellard 已提交
5540

5541 5542 5543
            target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
            if (!target_pfd)
                goto efault;
B
bellard 已提交
5544 5545
            pfd = alloca(sizeof(struct pollfd) * nfds);
            for(i = 0; i < nfds; i++) {
B
bellard 已提交
5546 5547
                pfd[i].fd = tswap32(target_pfd[i].fd);
                pfd[i].events = tswap16(target_pfd[i].events);
B
bellard 已提交
5548 5549 5550 5551
            }
            ret = get_errno(poll(pfd, nfds, timeout));
            if (!is_error(ret)) {
                for(i = 0; i < nfds; i++) {
B
bellard 已提交
5552
                    target_pfd[i].revents = tswap16(pfd[i].revents);
B
bellard 已提交
5553
                }
5554 5555
                ret += nfds * (sizeof(struct target_pollfd)
                               - sizeof(struct pollfd));
B
bellard 已提交
5556
            }
5557
            unlock_user(target_pfd, arg1, ret);
B
bellard 已提交
5558 5559
        }
        break;
5560
#endif
5561
    case TARGET_NR_flock:
B
bellard 已提交
5562 5563 5564
        /* NOTE: the flock constant seems to be the same for every
           Linux platform */
        ret = get_errno(flock(arg1, arg2));
5565 5566 5567 5568 5569 5570 5571
        break;
    case TARGET_NR_readv:
        {
            int count = arg3;
            struct iovec *vec;

            vec = alloca(count * sizeof(struct iovec));
B
bellard 已提交
5572 5573
            if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
                goto efault;
5574
            ret = get_errno(readv(arg1, vec, count));
5575
            unlock_iovec(vec, arg2, count, 1);
5576 5577 5578 5579 5580 5581 5582 5583
        }
        break;
    case TARGET_NR_writev:
        {
            int count = arg3;
            struct iovec *vec;

            vec = alloca(count * sizeof(struct iovec));
B
bellard 已提交
5584 5585
            if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
                goto efault;
5586
            ret = get_errno(writev(arg1, vec, count));
5587
            unlock_iovec(vec, arg2, count, 0);
5588 5589 5590 5591 5592
        }
        break;
    case TARGET_NR_getsid:
        ret = get_errno(getsid(arg1));
        break;
5593
#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
5594
    case TARGET_NR_fdatasync:
B
bellard 已提交
5595 5596
        ret = get_errno(fdatasync(arg1));
        break;
5597
#endif
5598
    case TARGET_NR__sysctl:
5599
        /* We don't implement this, but ENOTDIR is always a safe
B
bellard 已提交
5600
           return value. */
5601 5602
        ret = -TARGET_ENOTDIR;
        break;
5603
    case TARGET_NR_sched_setparam:
B
bellard 已提交
5604
        {
5605
            struct sched_param *target_schp;
B
bellard 已提交
5606
            struct sched_param schp;
5607

5608 5609
            if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
                goto efault;
B
bellard 已提交
5610
            schp.sched_priority = tswap32(target_schp->sched_priority);
5611
            unlock_user_struct(target_schp, arg2, 0);
B
bellard 已提交
5612 5613 5614
            ret = get_errno(sched_setparam(arg1, &schp));
        }
        break;
5615
    case TARGET_NR_sched_getparam:
B
bellard 已提交
5616
        {
5617
            struct sched_param *target_schp;
B
bellard 已提交
5618 5619 5620
            struct sched_param schp;
            ret = get_errno(sched_getparam(arg1, &schp));
            if (!is_error(ret)) {
5621 5622
                if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
                    goto efault;
B
bellard 已提交
5623
                target_schp->sched_priority = tswap32(schp.sched_priority);
5624
                unlock_user_struct(target_schp, arg2, 1);
B
bellard 已提交
5625 5626 5627
            }
        }
        break;
5628
    case TARGET_NR_sched_setscheduler:
B
bellard 已提交
5629
        {
5630
            struct sched_param *target_schp;
B
bellard 已提交
5631
            struct sched_param schp;
5632 5633
            if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
                goto efault;
B
bellard 已提交
5634
            schp.sched_priority = tswap32(target_schp->sched_priority);
5635
            unlock_user_struct(target_schp, arg3, 0);
B
bellard 已提交
5636 5637 5638
            ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
        }
        break;
5639
    case TARGET_NR_sched_getscheduler:
B
bellard 已提交
5640 5641
        ret = get_errno(sched_getscheduler(arg1));
        break;
5642 5643 5644 5645
    case TARGET_NR_sched_yield:
        ret = get_errno(sched_yield());
        break;
    case TARGET_NR_sched_get_priority_max:
B
bellard 已提交
5646 5647
        ret = get_errno(sched_get_priority_max(arg1));
        break;
5648
    case TARGET_NR_sched_get_priority_min:
B
bellard 已提交
5649 5650
        ret = get_errno(sched_get_priority_min(arg1));
        break;
5651
    case TARGET_NR_sched_rr_get_interval:
B
bellard 已提交
5652 5653 5654 5655
        {
            struct timespec ts;
            ret = get_errno(sched_rr_get_interval(arg1, &ts));
            if (!is_error(ret)) {
5656
                host_to_target_timespec(arg2, &ts);
B
bellard 已提交
5657 5658 5659
            }
        }
        break;
5660
    case TARGET_NR_nanosleep:
B
bellard 已提交
5661 5662
        {
            struct timespec req, rem;
5663
            target_to_host_timespec(&req, arg1);
B
bellard 已提交
5664
            ret = get_errno(nanosleep(&req, &rem));
5665 5666
            if (is_error(ret) && arg2) {
                host_to_target_timespec(arg2, &rem);
B
bellard 已提交
5667 5668 5669
            }
        }
        break;
5670
#ifdef TARGET_NR_query_module
5671
    case TARGET_NR_query_module:
B
bellard 已提交
5672
        goto unimplemented;
5673 5674
#endif
#ifdef TARGET_NR_nfsservctl
5675
    case TARGET_NR_nfsservctl:
B
bellard 已提交
5676
        goto unimplemented;
5677
#endif
5678
    case TARGET_NR_prctl:
5679 5680 5681 5682 5683 5684
        switch (arg1)
            {
            case PR_GET_PDEATHSIG:
                {
                    int deathsig;
                    ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
5685 5686 5687
                    if (!is_error(ret) && arg2
                        && put_user_ual(deathsig, arg2))
                        goto efault;
5688 5689 5690 5691 5692 5693
                }
                break;
            default:
                ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
                break;
            }
5694
        break;
B
bellard 已提交
5695 5696 5697 5698 5699 5700 5701 5702 5703
#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
5704
#ifdef TARGET_NR_pread
5705
    case TARGET_NR_pread:
5706 5707 5708 5709
#ifdef TARGET_ARM
        if (((CPUARMState *)cpu_env)->eabi)
            arg4 = arg5;
#endif
5710 5711
        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
            goto efault;
5712 5713
        ret = get_errno(pread(arg1, p, arg3, arg4));
        unlock_user(p, arg2, ret);
5714
        break;
5715
    case TARGET_NR_pwrite:
5716 5717 5718 5719
#ifdef TARGET_ARM
        if (((CPUARMState *)cpu_env)->eabi)
            arg4 = arg5;
#endif
5720 5721
        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
            goto efault;
5722 5723
        ret = get_errno(pwrite(arg1, p, arg3, arg4));
        unlock_user(p, arg2, 0);
5724
        break;
A
aurel32 已提交
5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738
#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;
5739
#endif
5740
    case TARGET_NR_getcwd:
5741 5742
        if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
            goto efault;
5743 5744
        ret = get_errno(sys_getcwd1(p, arg2));
        unlock_user(p, arg1, ret);
5745 5746
        break;
    case TARGET_NR_capget:
B
bellard 已提交
5747
        goto unimplemented;
5748
    case TARGET_NR_capset:
B
bellard 已提交
5749
        goto unimplemented;
5750
    case TARGET_NR_sigaltstack:
5751 5752
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
    defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA)
5753
        ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env));
5754 5755
        break;
#else
B
bellard 已提交
5756
        goto unimplemented;
5757
#endif
5758
    case TARGET_NR_sendfile:
B
bellard 已提交
5759
        goto unimplemented;
5760
#ifdef TARGET_NR_getpmsg
5761
    case TARGET_NR_getpmsg:
B
bellard 已提交
5762
        goto unimplemented;
5763 5764
#endif
#ifdef TARGET_NR_putpmsg
5765
    case TARGET_NR_putpmsg:
B
bellard 已提交
5766
        goto unimplemented;
5767
#endif
B
bellard 已提交
5768
#ifdef TARGET_NR_vfork
5769
    case TARGET_NR_vfork:
P
pbrook 已提交
5770 5771
        ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
                        0, 0, 0, 0));
5772
        break;
B
bellard 已提交
5773
#endif
5774
#ifdef TARGET_NR_ugetrlimit
5775
    case TARGET_NR_ugetrlimit:
B
bellard 已提交
5776 5777 5778 5779
    {
	struct rlimit rlim;
	ret = get_errno(getrlimit(arg1, &rlim));
	if (!is_error(ret)) {
5780
	    struct target_rlimit *target_rlim;
5781 5782
            if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
                goto efault;
B
bellard 已提交
5783 5784
	    target_rlim->rlim_cur = tswapl(rlim.rlim_cur);
	    target_rlim->rlim_max = tswapl(rlim.rlim_max);
5785
            unlock_user_struct(target_rlim, arg2, 1);
B
bellard 已提交
5786 5787 5788
	}
	break;
    }
5789
#endif
B
bellard 已提交
5790
#ifdef TARGET_NR_truncate64
5791
    case TARGET_NR_truncate64:
5792 5793
        if (!(p = lock_user_string(arg1)))
            goto efault;
5794 5795
	ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
        unlock_user(p, arg1, 0);
B
bellard 已提交
5796
	break;
B
bellard 已提交
5797 5798
#endif
#ifdef TARGET_NR_ftruncate64
5799
    case TARGET_NR_ftruncate64:
P
pbrook 已提交
5800
	ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
B
bellard 已提交
5801
	break;
B
bellard 已提交
5802 5803
#endif
#ifdef TARGET_NR_stat64
5804
    case TARGET_NR_stat64:
5805 5806
        if (!(p = lock_user_string(arg1)))
            goto efault;
5807 5808
        ret = get_errno(stat(path(p), &st));
        unlock_user(p, arg1, 0);
5809 5810 5811
        if (!is_error(ret))
            ret = host_to_target_stat64(cpu_env, arg2, &st);
        break;
B
bellard 已提交
5812 5813
#endif
#ifdef TARGET_NR_lstat64
5814
    case TARGET_NR_lstat64:
5815 5816
        if (!(p = lock_user_string(arg1)))
            goto efault;
5817 5818
        ret = get_errno(lstat(path(p), &st));
        unlock_user(p, arg1, 0);
5819 5820 5821
        if (!is_error(ret))
            ret = host_to_target_stat64(cpu_env, arg2, &st);
        break;
B
bellard 已提交
5822 5823
#endif
#ifdef TARGET_NR_fstat64
5824
    case TARGET_NR_fstat64:
5825 5826 5827 5828
        ret = get_errno(fstat(arg1, &st));
        if (!is_error(ret))
            ret = host_to_target_stat64(cpu_env, arg2, &st);
        break;
P
pbrook 已提交
5829
#endif
5830 5831 5832
#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
        (defined(__NR_fstatat64) || defined(__NR_newfstatat))
#ifdef TARGET_NR_fstatat64
5833
    case TARGET_NR_fstatat64:
5834 5835 5836 5837
#endif
#ifdef TARGET_NR_newfstatat
    case TARGET_NR_newfstatat:
#endif
5838 5839
        if (!(p = lock_user_string(arg2)))
            goto efault;
5840
#ifdef __NR_fstatat64
5841
        ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
5842 5843 5844
#else
        ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
#endif
5845 5846
        if (!is_error(ret))
            ret = host_to_target_stat64(cpu_env, arg3, &st);
B
bellard 已提交
5847
        break;
B
bellard 已提交
5848
#endif
5849 5850
#ifdef USE_UID16
    case TARGET_NR_lchown:
5851 5852
        if (!(p = lock_user_string(arg1)))
            goto efault;
5853 5854
        ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
        unlock_user(p, arg1, 0);
5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876
        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;
5877
            uint16_t *target_grouplist;
5878 5879 5880 5881 5882
            gid_t *grouplist;
            int i;

            grouplist = alloca(gidsetsize * sizeof(gid_t));
            ret = get_errno(getgroups(gidsetsize, grouplist));
5883 5884
            if (gidsetsize == 0)
                break;
5885
            if (!is_error(ret)) {
5886 5887 5888
                target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
                if (!target_grouplist)
                    goto efault;
5889
                for(i = 0;i < ret; i++)
5890
                    target_grouplist[i] = tswap16(grouplist[i]);
5891
                unlock_user(target_grouplist, arg2, gidsetsize * 2);
5892 5893 5894 5895 5896 5897
            }
        }
        break;
    case TARGET_NR_setgroups:
        {
            int gidsetsize = arg1;
5898
            uint16_t *target_grouplist;
5899 5900 5901 5902
            gid_t *grouplist;
            int i;

            grouplist = alloca(gidsetsize * sizeof(gid_t));
5903 5904 5905 5906 5907
            target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
            if (!target_grouplist) {
                ret = -TARGET_EFAULT;
                goto fail;
            }
5908 5909
            for(i = 0;i < gidsetsize; i++)
                grouplist[i] = tswap16(target_grouplist[i]);
5910
            unlock_user(target_grouplist, arg2, 0);
5911 5912 5913 5914 5915 5916
            ret = get_errno(setgroups(gidsetsize, grouplist));
        }
        break;
    case TARGET_NR_fchown:
        ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
        break;
5917 5918
#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
    case TARGET_NR_fchownat:
5919 5920 5921 5922
        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);
5923 5924
        break;
#endif
5925 5926
#ifdef TARGET_NR_setresuid
    case TARGET_NR_setresuid:
5927 5928
        ret = get_errno(setresuid(low2highuid(arg1),
                                  low2highuid(arg2),
5929 5930 5931 5932 5933 5934
                                  low2highuid(arg3)));
        break;
#endif
#ifdef TARGET_NR_getresuid
    case TARGET_NR_getresuid:
        {
5935
            uid_t ruid, euid, suid;
5936 5937
            ret = get_errno(getresuid(&ruid, &euid, &suid));
            if (!is_error(ret)) {
5938 5939 5940 5941
                if (put_user_u16(high2lowuid(ruid), arg1)
                    || put_user_u16(high2lowuid(euid), arg2)
                    || put_user_u16(high2lowuid(suid), arg3))
                    goto efault;
5942 5943 5944 5945 5946 5947
            }
        }
        break;
#endif
#ifdef TARGET_NR_getresgid
    case TARGET_NR_setresgid:
5948 5949
        ret = get_errno(setresgid(low2highgid(arg1),
                                  low2highgid(arg2),
5950 5951 5952 5953 5954 5955
                                  low2highgid(arg3)));
        break;
#endif
#ifdef TARGET_NR_getresgid
    case TARGET_NR_getresgid:
        {
5956
            gid_t rgid, egid, sgid;
5957 5958
            ret = get_errno(getresgid(&rgid, &egid, &sgid));
            if (!is_error(ret)) {
5959 5960 5961 5962
                if (put_user_u16(high2lowgid(rgid), arg1)
                    || put_user_u16(high2lowgid(egid), arg2)
                    || put_user_u16(high2lowgid(sgid), arg3))
                    goto efault;
5963 5964 5965 5966 5967
            }
        }
        break;
#endif
    case TARGET_NR_chown:
5968 5969
        if (!(p = lock_user_string(arg1)))
            goto efault;
5970 5971
        ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
        unlock_user(p, arg1, 0);
5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986
        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 已提交
5987
#ifdef TARGET_NR_lchown32
5988
    case TARGET_NR_lchown32:
5989 5990
        if (!(p = lock_user_string(arg1)))
            goto efault;
5991 5992
        ret = get_errno(lchown(p, arg2, arg3));
        unlock_user(p, arg1, 0);
B
bellard 已提交
5993
        break;
B
bellard 已提交
5994 5995
#endif
#ifdef TARGET_NR_getuid32
5996
    case TARGET_NR_getuid32:
B
bellard 已提交
5997 5998
        ret = get_errno(getuid());
        break;
B
bellard 已提交
5999
#endif
6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023

#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
   /* Alpha specific */
    case TARGET_NR_getxuid:
	 {
	    uid_t euid;
	    euid=geteuid();
	    ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
	 }
        ret = get_errno(getuid());
        break;
#endif
#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
   /* Alpha specific */
    case TARGET_NR_getxgid:
	 {
	    uid_t egid;
	    egid=getegid();
	    ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
	 }
        ret = get_errno(getgid());
        break;
#endif

B
bellard 已提交
6024
#ifdef TARGET_NR_getgid32
6025
    case TARGET_NR_getgid32:
B
bellard 已提交
6026 6027
        ret = get_errno(getgid());
        break;
B
bellard 已提交
6028 6029
#endif
#ifdef TARGET_NR_geteuid32
6030
    case TARGET_NR_geteuid32:
B
bellard 已提交
6031 6032
        ret = get_errno(geteuid());
        break;
B
bellard 已提交
6033 6034
#endif
#ifdef TARGET_NR_getegid32
6035
    case TARGET_NR_getegid32:
B
bellard 已提交
6036 6037
        ret = get_errno(getegid());
        break;
B
bellard 已提交
6038 6039
#endif
#ifdef TARGET_NR_setreuid32
6040
    case TARGET_NR_setreuid32:
B
bellard 已提交
6041 6042
        ret = get_errno(setreuid(arg1, arg2));
        break;
B
bellard 已提交
6043 6044
#endif
#ifdef TARGET_NR_setregid32
6045
    case TARGET_NR_setregid32:
B
bellard 已提交
6046 6047
        ret = get_errno(setregid(arg1, arg2));
        break;
B
bellard 已提交
6048 6049
#endif
#ifdef TARGET_NR_getgroups32
6050
    case TARGET_NR_getgroups32:
B
bellard 已提交
6051 6052
        {
            int gidsetsize = arg1;
6053
            uint32_t *target_grouplist;
B
bellard 已提交
6054 6055 6056 6057 6058
            gid_t *grouplist;
            int i;

            grouplist = alloca(gidsetsize * sizeof(gid_t));
            ret = get_errno(getgroups(gidsetsize, grouplist));
6059 6060
            if (gidsetsize == 0)
                break;
B
bellard 已提交
6061
            if (!is_error(ret)) {
6062 6063 6064 6065 6066
                target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
                if (!target_grouplist) {
                    ret = -TARGET_EFAULT;
                    goto fail;
                }
6067
                for(i = 0;i < ret; i++)
6068 6069
                    target_grouplist[i] = tswap32(grouplist[i]);
                unlock_user(target_grouplist, arg2, gidsetsize * 4);
B
bellard 已提交
6070 6071 6072
            }
        }
        break;
B
bellard 已提交
6073 6074
#endif
#ifdef TARGET_NR_setgroups32
6075
    case TARGET_NR_setgroups32:
B
bellard 已提交
6076 6077
        {
            int gidsetsize = arg1;
6078
            uint32_t *target_grouplist;
B
bellard 已提交
6079 6080
            gid_t *grouplist;
            int i;
6081

B
bellard 已提交
6082
            grouplist = alloca(gidsetsize * sizeof(gid_t));
6083 6084 6085 6086 6087
            target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
            if (!target_grouplist) {
                ret = -TARGET_EFAULT;
                goto fail;
            }
B
bellard 已提交
6088
            for(i = 0;i < gidsetsize; i++)
6089 6090
                grouplist[i] = tswap32(target_grouplist[i]);
            unlock_user(target_grouplist, arg2, 0);
B
bellard 已提交
6091 6092 6093
            ret = get_errno(setgroups(gidsetsize, grouplist));
        }
        break;
B
bellard 已提交
6094 6095
#endif
#ifdef TARGET_NR_fchown32
6096
    case TARGET_NR_fchown32:
B
bellard 已提交
6097 6098
        ret = get_errno(fchown(arg1, arg2, arg3));
        break;
B
bellard 已提交
6099 6100
#endif
#ifdef TARGET_NR_setresuid32
6101
    case TARGET_NR_setresuid32:
B
bellard 已提交
6102 6103
        ret = get_errno(setresuid(arg1, arg2, arg3));
        break;
B
bellard 已提交
6104 6105
#endif
#ifdef TARGET_NR_getresuid32
6106
    case TARGET_NR_getresuid32:
B
bellard 已提交
6107
        {
6108
            uid_t ruid, euid, suid;
B
bellard 已提交
6109 6110
            ret = get_errno(getresuid(&ruid, &euid, &suid));
            if (!is_error(ret)) {
6111 6112 6113 6114
                if (put_user_u32(ruid, arg1)
                    || put_user_u32(euid, arg2)
                    || put_user_u32(suid, arg3))
                    goto efault;
B
bellard 已提交
6115 6116 6117
            }
        }
        break;
B
bellard 已提交
6118 6119
#endif
#ifdef TARGET_NR_setresgid32
6120
    case TARGET_NR_setresgid32:
B
bellard 已提交
6121 6122
        ret = get_errno(setresgid(arg1, arg2, arg3));
        break;
B
bellard 已提交
6123 6124
#endif
#ifdef TARGET_NR_getresgid32
6125
    case TARGET_NR_getresgid32:
B
bellard 已提交
6126
        {
6127
            gid_t rgid, egid, sgid;
B
bellard 已提交
6128 6129
            ret = get_errno(getresgid(&rgid, &egid, &sgid));
            if (!is_error(ret)) {
6130 6131 6132 6133
                if (put_user_u32(rgid, arg1)
                    || put_user_u32(egid, arg2)
                    || put_user_u32(sgid, arg3))
                    goto efault;
B
bellard 已提交
6134 6135 6136
            }
        }
        break;
B
bellard 已提交
6137 6138
#endif
#ifdef TARGET_NR_chown32
6139
    case TARGET_NR_chown32:
6140 6141
        if (!(p = lock_user_string(arg1)))
            goto efault;
6142 6143
        ret = get_errno(chown(p, arg2, arg3));
        unlock_user(p, arg1, 0);
B
bellard 已提交
6144
        break;
B
bellard 已提交
6145 6146
#endif
#ifdef TARGET_NR_setuid32
6147
    case TARGET_NR_setuid32:
B
bellard 已提交
6148 6149
        ret = get_errno(setuid(arg1));
        break;
B
bellard 已提交
6150 6151
#endif
#ifdef TARGET_NR_setgid32
6152
    case TARGET_NR_setgid32:
B
bellard 已提交
6153 6154
        ret = get_errno(setgid(arg1));
        break;
B
bellard 已提交
6155 6156
#endif
#ifdef TARGET_NR_setfsuid32
6157
    case TARGET_NR_setfsuid32:
B
bellard 已提交
6158 6159
        ret = get_errno(setfsuid(arg1));
        break;
B
bellard 已提交
6160 6161
#endif
#ifdef TARGET_NR_setfsgid32
6162
    case TARGET_NR_setfsgid32:
B
bellard 已提交
6163 6164
        ret = get_errno(setfsgid(arg1));
        break;
B
bellard 已提交
6165
#endif
6166

6167
    case TARGET_NR_pivot_root:
B
bellard 已提交
6168
        goto unimplemented;
B
bellard 已提交
6169
#ifdef TARGET_NR_mincore
6170
    case TARGET_NR_mincore:
A
aurel32 已提交
6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183
        {
            void *a;
            ret = -TARGET_EFAULT;
            if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
                goto efault;
            if (!(p = lock_user_string(arg3)))
                goto mincore_fail;
            ret = get_errno(mincore(a, arg2, p));
            unlock_user(p, arg3, ret);
            mincore_fail:
            unlock_user(a, arg1, 0);
        }
        break;
B
bellard 已提交
6184
#endif
A
aurel32 已提交
6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205
#ifdef TARGET_NR_arm_fadvise64_64
    case TARGET_NR_arm_fadvise64_64:
	{
		/*
		 * arm_fadvise64_64 looks like fadvise64_64 but
		 * with different argument order
		 */
		abi_long temp;
		temp = arg3;
		arg3 = arg4;
		arg4 = temp;
	}
#endif
#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64)
#ifdef TARGET_NR_fadvise64_64
    case TARGET_NR_fadvise64_64:
#endif
        /* This is a hint, so ignoring and returning success is ok.  */
	ret = get_errno(0);
	break;
#endif
B
bellard 已提交
6206
#ifdef TARGET_NR_madvise
6207
    case TARGET_NR_madvise:
6208 6209 6210 6211 6212 6213
        /* 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 已提交
6214
#endif
6215
#if TARGET_ABI_BITS == 32
6216
    case TARGET_NR_fcntl64:
B
bellard 已提交
6217
    {
T
ths 已提交
6218
	int cmd;
B
bellard 已提交
6219
	struct flock64 fl;
6220
	struct target_flock64 *target_fl;
P
pbrook 已提交
6221
#ifdef TARGET_ARM
6222
	struct target_eabi_flock64 *target_efl;
P
pbrook 已提交
6223
#endif
B
bellard 已提交
6224

T
ths 已提交
6225 6226 6227
        switch(arg2){
        case TARGET_F_GETLK64:
            cmd = F_GETLK64;
6228
            break;
T
ths 已提交
6229 6230
        case TARGET_F_SETLK64:
            cmd = F_SETLK64;
6231
            break;
T
ths 已提交
6232 6233
        case TARGET_F_SETLKW64:
            cmd = F_SETLK64;
6234
            break;
T
ths 已提交
6235 6236
        default:
            cmd = arg2;
6237
            break;
T
ths 已提交
6238 6239
        }

B
bellard 已提交
6240
        switch(arg2) {
T
ths 已提交
6241
        case TARGET_F_GETLK64:
T
ths 已提交
6242 6243
#ifdef TARGET_ARM
            if (((CPUARMState *)cpu_env)->eabi) {
B
bellard 已提交
6244 6245
                if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) 
                    goto efault;
T
ths 已提交
6246 6247 6248 6249 6250 6251 6252 6253 6254
                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 已提交
6255 6256
                if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) 
                    goto efault;
T
ths 已提交
6257 6258 6259 6260 6261 6262 6263
                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 已提交
6264
            ret = get_errno(fcntl(arg1, cmd, &fl));
B
bellard 已提交
6265
	    if (ret == 0) {
P
pbrook 已提交
6266 6267
#ifdef TARGET_ARM
                if (((CPUARMState *)cpu_env)->eabi) {
B
bellard 已提交
6268 6269
                    if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) 
                        goto efault;
P
pbrook 已提交
6270 6271 6272 6273 6274
                    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);
6275
                    unlock_user_struct(target_efl, arg3, 1);
P
pbrook 已提交
6276 6277 6278
                } else
#endif
                {
B
bellard 已提交
6279 6280
                    if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) 
                        goto efault;
P
pbrook 已提交
6281 6282 6283 6284 6285
                    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);
6286
                    unlock_user_struct(target_fl, arg3, 1);
P
pbrook 已提交
6287
                }
B
bellard 已提交
6288 6289 6290
	    }
	    break;

T
ths 已提交
6291 6292
        case TARGET_F_SETLK64:
        case TARGET_F_SETLKW64:
P
pbrook 已提交
6293 6294
#ifdef TARGET_ARM
            if (((CPUARMState *)cpu_env)->eabi) {
B
bellard 已提交
6295 6296
                if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) 
                    goto efault;
P
pbrook 已提交
6297 6298 6299 6300 6301
                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);
6302
                unlock_user_struct(target_efl, arg3, 0);
P
pbrook 已提交
6303 6304 6305
            } else
#endif
            {
B
bellard 已提交
6306 6307
                if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) 
                    goto efault;
P
pbrook 已提交
6308 6309 6310 6311 6312
                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);
6313
                unlock_user_struct(target_fl, arg3, 0);
P
pbrook 已提交
6314
            }
T
ths 已提交
6315
            ret = get_errno(fcntl(arg1, cmd, &fl));
B
bellard 已提交
6316
	    break;
B
bellard 已提交
6317
        default:
B
bellard 已提交
6318
            ret = do_fcntl(arg1, cmd, arg3);
B
bellard 已提交
6319 6320
            break;
        }
B
bellard 已提交
6321 6322
	break;
    }
B
bellard 已提交
6323
#endif
6324 6325 6326 6327 6328 6329
#ifdef TARGET_NR_cacheflush
    case TARGET_NR_cacheflush:
        /* self-modifying code is handled automatically, so nothing needed */
        ret = 0;
        break;
#endif
6330
#ifdef TARGET_NR_security
6331 6332
    case TARGET_NR_security:
        goto unimplemented;
B
bellard 已提交
6333 6334 6335 6336 6337
#endif
#ifdef TARGET_NR_getpagesize
    case TARGET_NR_getpagesize:
        ret = TARGET_PAGE_SIZE;
        break;
6338
#endif
6339 6340 6341
    case TARGET_NR_gettid:
        ret = get_errno(gettid());
        break;
6342
#ifdef TARGET_NR_readahead
6343
    case TARGET_NR_readahead:
A
aurel32 已提交
6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357
#if TARGET_ABI_BITS == 32
#ifdef TARGET_ARM
        if (((CPUARMState *)cpu_env)->eabi)
        {
            arg2 = arg3;
            arg3 = arg4;
            arg4 = arg5;
        }
#endif
        ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
#else
        ret = get_errno(readahead(arg1, arg2, arg3));
#endif
        break;
6358
#endif
6359
#ifdef TARGET_NR_setxattr
6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371
    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 已提交
6372
        goto unimplemented_nowarn;
6373 6374
#endif
#ifdef TARGET_NR_set_thread_area
B
bellard 已提交
6375
    case TARGET_NR_set_thread_area:
B
bellard 已提交
6376
#if defined(TARGET_MIPS)
6377 6378 6379
      ((CPUMIPSState *) cpu_env)->tls_value = arg1;
      ret = 0;
      break;
6380 6381 6382 6383 6384 6385 6386 6387
#elif defined(TARGET_CRIS)
      if (arg1 & 0xff)
          ret = -TARGET_EINVAL;
      else {
          ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
          ret = 0;
      }
      break;
B
bellard 已提交
6388 6389 6390
#elif defined(TARGET_I386) && defined(TARGET_ABI32)
      ret = do_set_thread_area(cpu_env, arg1);
      break;
6391 6392 6393 6394 6395
#else
      goto unimplemented_nowarn;
#endif
#endif
#ifdef TARGET_NR_get_thread_area
B
bellard 已提交
6396
    case TARGET_NR_get_thread_area:
B
bellard 已提交
6397 6398 6399
#if defined(TARGET_I386) && defined(TARGET_ABI32)
        ret = do_get_thread_area(cpu_env, arg1);
#else
B
bellard 已提交
6400
        goto unimplemented_nowarn;
B
bellard 已提交
6401
#endif
B
bellard 已提交
6402
#endif
B
bellard 已提交
6403 6404 6405
#ifdef TARGET_NR_getdomainname
    case TARGET_NR_getdomainname:
        goto unimplemented_nowarn;
6406
#endif
6407

6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429
#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 已提交
6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440
#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
6441

6442 6443
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
    case TARGET_NR_set_tid_address:
6444 6445
        ret = get_errno(set_tid_address((int *)g2h(arg1)));
        break;
6446 6447
#endif

T
ths 已提交
6448
#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
T
ths 已提交
6449
    case TARGET_NR_tkill:
6450
        ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
T
ths 已提交
6451 6452 6453
        break;
#endif

T
ths 已提交
6454
#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
T
ths 已提交
6455
    case TARGET_NR_tgkill:
6456 6457
	ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
                        target_to_host_signal(arg3)));
T
ths 已提交
6458 6459 6460
	break;
#endif

6461 6462 6463 6464 6465
#ifdef TARGET_NR_set_robust_list
    case TARGET_NR_set_robust_list:
	goto unimplemented_nowarn;
#endif

6466 6467 6468 6469 6470 6471 6472 6473 6474
#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 {
6475
                if (!(p = lock_user_string(arg2))) {
6476
                    ret = -TARGET_EFAULT;
6477 6478 6479 6480
                    goto fail;
                }
                ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4));
                unlock_user(p, arg2, 0);
6481 6482 6483 6484
            }
        }
	break;
#endif
6485 6486 6487 6488 6489
#if defined(USE_NPTL)
    case TARGET_NR_futex:
        ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
        break;
#endif
6490
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
A
aurel32 已提交
6491 6492 6493 6494
    case TARGET_NR_inotify_init:
        ret = get_errno(sys_inotify_init());
        break;
#endif
6495
#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
A
aurel32 已提交
6496 6497 6498 6499 6500 6501
    case TARGET_NR_inotify_add_watch:
        p = lock_user_string(arg2);
        ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
        unlock_user(p, arg2, 0);
        break;
#endif
6502
#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
A
aurel32 已提交
6503 6504 6505 6506
    case TARGET_NR_inotify_rm_watch:
        ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
        break;
#endif
6507

6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582
#ifdef TARGET_NR_mq_open
    case TARGET_NR_mq_open:
        {
            struct mq_attr posix_mq_attr;

            p = lock_user_string(arg1 - 1);
            if (arg4 != 0)
                copy_from_user_mq_attr (&posix_mq_attr, arg4);
            ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
            unlock_user (p, arg1, 0);
        }
        break;

    case TARGET_NR_mq_unlink:
        p = lock_user_string(arg1 - 1);
        ret = get_errno(mq_unlink(p));
        unlock_user (p, arg1, 0);
        break;

    case TARGET_NR_mq_timedsend:
        {
            struct timespec ts;

            p = lock_user (VERIFY_READ, arg2, arg3, 1);
            if (arg5 != 0) {
                target_to_host_timespec(&ts, arg5);
                ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
                host_to_target_timespec(arg5, &ts);
            }
            else
                ret = get_errno(mq_send(arg1, p, arg3, arg4));
            unlock_user (p, arg2, arg3);
        }
        break;

    case TARGET_NR_mq_timedreceive:
        {
            struct timespec ts;
            unsigned int prio;

            p = lock_user (VERIFY_READ, arg2, arg3, 1);
            if (arg5 != 0) {
                target_to_host_timespec(&ts, arg5);
                ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
                host_to_target_timespec(arg5, &ts);
            }
            else
                ret = get_errno(mq_receive(arg1, p, arg3, &prio));
            unlock_user (p, arg2, arg3);
            if (arg4 != 0)
                put_user_u32(prio, arg4);
        }
        break;

    /* Not implemented for now... */
/*     case TARGET_NR_mq_notify: */
/*         break; */

    case TARGET_NR_mq_getsetattr:
        {
            struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
            ret = 0;
            if (arg3 != 0) {
                ret = mq_getattr(arg1, &posix_mq_attr_out);
                copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
            }
            if (arg2 != 0) {
                copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
                ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
            }

        }
        break;
#endif

6583 6584
    default:
    unimplemented:
B
bellard 已提交
6585
        gemu_log("qemu: Unsupported syscall: %d\n", num);
6586
#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list)
B
bellard 已提交
6587
    unimplemented_nowarn:
B
bellard 已提交
6588
#endif
6589
        ret = -TARGET_ENOSYS;
6590 6591
        break;
    }
6592
fail:
B
bellard 已提交
6593 6594 6595
#ifdef DEBUG
    gemu_log(" = %ld\n", ret);
#endif
6596 6597
    if(do_strace)
        print_syscall_ret(num, ret);
6598
    return ret;
6599 6600 6601
efault:
    ret = -TARGET_EFAULT;
    goto fail;
6602
}