syscall.c 214.0 KB
Newer Older
1 2
/*
 *  Linux syscalls
3
 *
4 5 6 7 8 9 10 11 12 13 14 15 16
 *  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
17
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18
 */
19
#define _ATFILE_SOURCE
20 21 22
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
B
bellard 已提交
23
#include <string.h>
24 25 26 27 28
#include <elf.h>
#include <endian.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
B
bellard 已提交
29
#include <time.h>
30
#include <limits.h>
31
#include <mqueue.h>
32
#include <sys/types.h>
T
ths 已提交
33 34
#include <sys/ipc.h>
#include <sys/msg.h>
35 36 37 38
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/mount.h>
39
#include <sys/prctl.h>
40 41 42 43 44 45
#include <sys/resource.h>
#include <sys/mman.h>
#include <sys/swap.h>
#include <signal.h>
#include <sched.h>
#include <sys/socket.h>
46
#include <sys/un.h>
47
#include <sys/uio.h>
B
bellard 已提交
48
#include <sys/poll.h>
B
bellard 已提交
49
#include <sys/times.h>
50
#include <sys/shm.h>
51
#include <sys/sem.h>
B
bellard 已提交
52
#include <sys/statfs.h>
53
#include <utime.h>
B
bellard 已提交
54
#include <sys/sysinfo.h>
55
#include <sys/utsname.h>
B
bellard 已提交
56
//#include <sys/user.h>
57
#include <netinet/ip.h>
B
bellard 已提交
58
#include <netinet/tcp.h>
A
aurel32 已提交
59
#include <qemu-common.h>
60
#ifdef TARGET_GPROF
A
aurel32 已提交
61 62
#include <sys/gmon.h>
#endif
R
Riku Voipio 已提交
63 64 65
#ifdef CONFIG_EVENTFD
#include <sys/eventfd.h>
#endif
66 67 68 69

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

#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 已提交
80
#include <linux/kd.h>
81
#include <linux/mtio.h>
M
Martin Mohring 已提交
82
#include <linux/fs.h>
83
#include "linux_loop.h"
84

B
bellard 已提交
85
#include "qemu.h"
86
#include "qemu-common.h"
87

88
#if defined(CONFIG_USE_NPTL)
P
pbrook 已提交
89 90 91 92 93
#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 已提交
94 95
#endif

B
bellard 已提交
96
//#define DEBUG
97

B
bellard 已提交
98
//#include <linux/msdos_fs.h>
A
aurel32 已提交
99 100
#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 已提交
101

102 103 104 105 106 107 108

#undef _syscall0
#undef _syscall1
#undef _syscall2
#undef _syscall3
#undef _syscall4
#undef _syscall5
B
bellard 已提交
109
#undef _syscall6
110

B
bellard 已提交
111
#define _syscall0(type,name)		\
112
static type name (void)			\
B
bellard 已提交
113 114 115
{					\
	return syscall(__NR_##name);	\
}
116

B
bellard 已提交
117
#define _syscall1(type,name,type1,arg1)		\
118
static type name (type1 arg1)			\
B
bellard 已提交
119 120
{						\
	return syscall(__NR_##name, arg1);	\
121 122
}

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

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

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

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

B
bellard 已提交
148 149 150

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

157

158
#define __NR_sys_uname __NR_uname
159
#define __NR_sys_faccessat __NR_faccessat
160
#define __NR_sys_fchmodat __NR_fchmodat
161
#define __NR_sys_fchownat __NR_fchownat
162
#define __NR_sys_fstatat64 __NR_fstatat64
163
#define __NR_sys_futimesat __NR_futimesat
B
bellard 已提交
164 165
#define __NR_sys_getcwd1 __NR_getcwd
#define __NR_sys_getdents __NR_getdents
B
bellard 已提交
166
#define __NR_sys_getdents64 __NR_getdents64
167
#define __NR_sys_getpriority __NR_getpriority
168
#define __NR_sys_linkat __NR_linkat
169
#define __NR_sys_mkdirat __NR_mkdirat
170
#define __NR_sys_mknodat __NR_mknodat
171
#define __NR_sys_newfstatat __NR_newfstatat
172
#define __NR_sys_openat __NR_openat
173
#define __NR_sys_readlinkat __NR_readlinkat
174
#define __NR_sys_renameat __NR_renameat
B
bellard 已提交
175
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
176
#define __NR_sys_symlinkat __NR_symlinkat
177
#define __NR_sys_syslog __NR_syslog
T
ths 已提交
178
#define __NR_sys_tgkill __NR_tgkill
T
ths 已提交
179
#define __NR_sys_tkill __NR_tkill
180
#define __NR_sys_unlinkat __NR_unlinkat
181
#define __NR_sys_utimensat __NR_utimensat
182
#define __NR_sys_futex __NR_futex
A
aurel32 已提交
183 184 185
#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
186

187
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
B
bellard 已提交
188 189 190
#define __NR__llseek __NR_lseek
#endif

B
bellard 已提交
191
#ifdef __NR_gettid
192
_syscall0(int, gettid)
B
bellard 已提交
193
#else
194 195
/* This is a replacement for the host gettid() and must return a host
   errno. */
B
bellard 已提交
196 197 198 199
static int gettid(void) {
    return -ENOSYS;
}
#endif
200 201 202 203 204 205 206
#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);
207
#if defined(TARGET_NR__llseek) && !defined (__x86_64__)
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
_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
225
#if defined(CONFIG_USE_NPTL)
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
#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 已提交
292
  return strlen(buf)+1;
293 294 295 296 297 298 299 300 301
}

#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
302
static int sys_faccessat(int dirfd, const char *pathname, int mode)
303
{
304
  return (faccessat(dirfd, pathname, mode, 0));
305 306 307
}
#endif
#ifdef TARGET_NR_fchmodat
308
static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
309
{
310
  return (fchmodat(dirfd, pathname, mode, 0));
311 312
}
#endif
313
#if defined(TARGET_NR_fchownat) && defined(USE_UID16)
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 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
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
#else /* !CONFIG_ATFILE */

/*
 * Try direct syscalls instead
 */
416
#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
417
_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
418
#endif
419
#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
420
_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
421
#endif
422
#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16)
423 424 425
_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
          uid_t,owner,gid_t,group,int,flags)
#endif
426 427
#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
        defined(__NR_fstatat64)
428 429 430
_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
          struct stat *,buf,int,flags)
#endif
431 432 433 434
#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
         const struct timeval *,times)
#endif
435 436 437 438
#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)
439
#endif
440 441
#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
442
      int,newdirfd,const char *,newpath,int,flags)
443
#endif
444 445 446
#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
#endif
447 448 449 450
#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
          mode_t,mode,dev_t,dev)
#endif
451 452 453
#if defined(TARGET_NR_openat) && defined(__NR_openat)
_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
#endif
454 455 456 457
#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
          char *,buf,size_t,bufsize)
#endif
458 459 460 461
#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
          int,newdirfd,const char *,newpath)
#endif
462
#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
463 464 465
_syscall3(int,sys_symlinkat,const char *,oldpath,
          int,newdirfd,const char *,newpath)
#endif
466 467 468
#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
#endif
R
Riku Voipio 已提交
469 470 471 472 473 474 475 476 477 478 479 480 481

#endif /* CONFIG_ATFILE */

#ifdef CONFIG_UTIMENSAT
static int sys_utimensat(int dirfd, const char *pathname,
    const struct timespec times[2], int flags)
{
    if (pathname == NULL)
        return futimens(dirfd, times);
    else
        return utimensat(dirfd, pathname, times, flags);
}
#else
482 483 484 485
#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
          const struct timespec *,tsp,int,flags)
#endif
R
Riku Voipio 已提交
486
#endif /* CONFIG_UTIMENSAT  */
487 488

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

A
aurel32 已提交
491
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
492 493 494 495
static int sys_inotify_init(void)
{
  return (inotify_init());
}
A
aurel32 已提交
496 497
#endif
#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
498 499 500 501
static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
{
  return (inotify_add_watch(fd, pathname, mask));
}
A
aurel32 已提交
502 503
#endif
#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
504 505
static int sys_inotify_rm_watch(int fd, int32_t wd)
{
A
aurel32 已提交
506
  return (inotify_rm_watch(fd, wd));
507
}
508
#endif
509 510 511 512 513 514 515
#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 已提交
516 517

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

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

530
/*
T
ths 已提交
531
 * This list is the union of errno values overridden in asm-<arch>/errno.h
532 533
 * minus the errnos that are not actually generic to all archs.
 */
534
static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
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 621
    [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 已提交
622
#ifdef ENOKEY
623
    [ENOKEY]		= TARGET_ENOKEY,
T
ths 已提交
624 625
#endif
#ifdef EKEYEXPIRED
626
    [EKEYEXPIRED]	= TARGET_EKEYEXPIRED,
T
ths 已提交
627 628
#endif
#ifdef EKEYREVOKED
629
    [EKEYREVOKED]	= TARGET_EKEYREVOKED,
T
ths 已提交
630 631
#endif
#ifdef EKEYREJECTED
632
    [EKEYREJECTED]	= TARGET_EKEYREJECTED,
T
ths 已提交
633 634
#endif
#ifdef EOWNERDEAD
635
    [EOWNERDEAD]	= TARGET_EOWNERDEAD,
T
ths 已提交
636 637
#endif
#ifdef ENOTRECOVERABLE
638
    [ENOTRECOVERABLE]	= TARGET_ENOTRECOVERABLE,
T
ths 已提交
639
#endif
640
};
641 642 643 644 645 646 647 648

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

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

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

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

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

674 675
static abi_ulong target_brk;
static abi_ulong target_original_brk;
676

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

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

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

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

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

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

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

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

    unlock_user(target_fds, target_fds_addr, 0);

    return 0;
744 745
}

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

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

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

    return 0;
774 775
}

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

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

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

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

    return 0;
B
bellard 已提交
819 820
}

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

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

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

    return 0;
835 836
}

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

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

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

    return 0;
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 889
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;
}
890

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

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

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

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

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

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

945 946 947
    return ret;
}

R
Riku Voipio 已提交
948 949 950 951 952 953 954 955 956
static abi_long do_pipe2(int host_pipe[], int flags)
{
#ifdef CONFIG_PIPE2
    return pipe2(host_pipe, flags);
#else
    return -ENOSYS;
#endif
}

957
static abi_long do_pipe(void *cpu_env, abi_ulong pipedes, int flags)
R
Riku Voipio 已提交
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
{
    int host_pipe[2];
    abi_long ret;
    ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);

    if (is_error(ret))
        return get_errno(ret);
#if defined(TARGET_MIPS)
    ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
    ret = host_pipe[0];
#elif defined(TARGET_SH4)
    ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
    ret = host_pipe[0];
#else
    if (put_user_s32(host_pipe[0], pipedes)
        || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
        return -TARGET_EFAULT;
#endif
    return get_errno(ret);
}

979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
                                              abi_ulong target_addr,
                                              socklen_t len)
{
    struct target_ip_mreqn *target_smreqn;

    target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
    if (!target_smreqn)
        return -TARGET_EFAULT;
    mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
    mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
    if (len == sizeof(struct target_ip_mreqn))
        mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex);
    unlock_user(target_smreqn, target_addr, 0);

    return 0;
}

997 998 999
static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
                                               abi_ulong target_addr,
                                               socklen_t len)
B
bellard 已提交
1000
{
1001 1002
    const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
    sa_family_t sa_family;
1003 1004
    struct target_sockaddr *target_saddr;

1005 1006 1007
    target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
    if (!target_saddr)
        return -TARGET_EFAULT;
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029

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

1030
    memcpy(addr, target_saddr, len);
1031
    addr->sa_family = sa_family;
1032
    unlock_user(target_saddr, target_addr, 0);
1033 1034

    return 0;
B
bellard 已提交
1035 1036
}

1037 1038 1039
static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
                                               struct sockaddr *addr,
                                               socklen_t len)
B
bellard 已提交
1040
{
1041 1042
    struct target_sockaddr *target_saddr;

1043 1044 1045
    target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
    if (!target_saddr)
        return -TARGET_EFAULT;
1046 1047 1048
    memcpy(target_saddr, addr, len);
    target_saddr->sa_family = tswap16(addr->sa_family);
    unlock_user(target_saddr, target_addr, len);
1049 1050

    return 0;
B
bellard 已提交
1051 1052
}

1053
/* ??? Should this also swap msgh->name?  */
1054 1055
static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
                                           struct target_msghdr *target_msgh)
B
bellard 已提交
1056 1057
{
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
1058 1059 1060
    abi_long msg_controllen;
    abi_ulong target_cmsg_addr;
    struct target_cmsghdr *target_cmsg;
B
bellard 已提交
1061
    socklen_t space = 0;
1062 1063 1064 1065 1066 1067 1068 1069
    
    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 已提交
1070 1071 1072 1073 1074

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

1075
        int len = tswapl(target_cmsg->cmsg_len)
B
bellard 已提交
1076 1077 1078 1079 1080
                  - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));

        space += CMSG_SPACE(len);
        if (space > msgh->msg_controllen) {
            space -= CMSG_SPACE(len);
B
bellard 已提交
1081
            gemu_log("Host cmsg overflow\n");
B
bellard 已提交
1082 1083 1084 1085 1086 1087 1088
            break;
        }

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

1089
        if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
B
bellard 已提交
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
            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);
    }
1104 1105
    unlock_user(target_cmsg, target_cmsg_addr, 0);
 the_end:
B
bellard 已提交
1106
    msgh->msg_controllen = space;
1107
    return 0;
B
bellard 已提交
1108 1109
}

1110
/* ??? Should this also swap msgh->name?  */
1111 1112
static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
                                           struct msghdr *msgh)
B
bellard 已提交
1113 1114
{
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
1115 1116 1117
    abi_long msg_controllen;
    abi_ulong target_cmsg_addr;
    struct target_cmsghdr *target_cmsg;
B
bellard 已提交
1118 1119
    socklen_t space = 0;

1120 1121 1122 1123 1124 1125 1126 1127
    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 已提交
1128 1129 1130 1131 1132 1133 1134
    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);
1135
        if (space > msg_controllen) {
B
bellard 已提交
1136
            space -= TARGET_CMSG_SPACE(len);
B
bellard 已提交
1137
            gemu_log("Target cmsg overflow\n");
B
bellard 已提交
1138 1139 1140 1141 1142 1143 1144
            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));

1145
        if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
B
bellard 已提交
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
            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);
    }
1160 1161 1162 1163
    unlock_user(target_cmsg, target_cmsg_addr, space);
 the_end:
    target_msgh->msg_controllen = tswapl(space);
    return 0;
B
bellard 已提交
1164 1165
}

1166
/* do_setsockopt() Must return target values and target errnos. */
1167
static abi_long do_setsockopt(int sockfd, int level, int optname,
1168
                              abi_ulong optval_addr, socklen_t optlen)
B
bellard 已提交
1169
{
1170
    abi_long ret;
1171
    int val;
1172
    struct ip_mreqn *ip_mreq;
1173
    struct ip_mreq_source *ip_mreq_source;
1174

1175 1176
    switch(level) {
    case SOL_TCP:
B
bellard 已提交
1177 1178
        /* TCP options all take an 'int' value.  */
        if (optlen < sizeof(uint32_t))
1179
            return -TARGET_EINVAL;
1180

1181 1182
        if (get_user_u32(val, optval_addr))
            return -TARGET_EFAULT;
1183 1184 1185 1186
        ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
        break;
    case SOL_IP:
        switch(optname) {
B
bellard 已提交
1187 1188
        case IP_TOS:
        case IP_TTL:
1189
        case IP_HDRINCL:
B
bellard 已提交
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
        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:
1202 1203
            val = 0;
            if (optlen >= sizeof(uint32_t)) {
1204 1205
                if (get_user_u32(val, optval_addr))
                    return -TARGET_EFAULT;
1206
            } else if (optlen >= 1) {
1207 1208
                if (get_user_u8(val, optval_addr))
                    return -TARGET_EFAULT;
1209 1210 1211
            }
            ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
            break;
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
        case IP_ADD_MEMBERSHIP:
        case IP_DROP_MEMBERSHIP:
            if (optlen < sizeof (struct target_ip_mreq) ||
                optlen > sizeof (struct target_ip_mreqn))
                return -TARGET_EINVAL;

            ip_mreq = (struct ip_mreqn *) alloca(optlen);
            target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
            ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
            break;

1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234
        case IP_BLOCK_SOURCE:
        case IP_UNBLOCK_SOURCE:
        case IP_ADD_SOURCE_MEMBERSHIP:
        case IP_DROP_SOURCE_MEMBERSHIP:
            if (optlen != sizeof (struct target_ip_mreq_source))
                return -TARGET_EINVAL;

            ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
            ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
            unlock_user (ip_mreq_source, optval_addr, 0);
            break;

1235 1236 1237 1238
        default:
            goto unimplemented;
        }
        break;
1239
    case TARGET_SOL_SOCKET:
1240 1241
        switch (optname) {
            /* Options with 'int' argument.  */
1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
        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 已提交
1278
#ifdef SO_BSDCOMPAT
1279 1280 1281
        case TARGET_SO_BSDCOMPAT:
		optname = SO_BSDCOMPAT;
		break;
B
bellard 已提交
1282
#endif
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
        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;
1298 1299 1300 1301
            break;
        default:
            goto unimplemented;
        }
1302
	if (optlen < sizeof(uint32_t))
1303
            return -TARGET_EINVAL;
1304

1305 1306
	if (get_user_u32(val, optval_addr))
            return -TARGET_EFAULT;
1307
	ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
1308
        break;
B
bellard 已提交
1309
    default:
1310 1311
    unimplemented:
        gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
1312
        ret = -TARGET_ENOPROTOOPT;
B
bellard 已提交
1313
    }
1314
    return ret;
B
bellard 已提交
1315 1316
}

1317
/* do_getsockopt() Must return target values and target errnos. */
1318
static abi_long do_getsockopt(int sockfd, int level, int optname,
1319
                              abi_ulong optval_addr, abi_ulong optlen)
B
bellard 已提交
1320
{
1321
    abi_long ret;
1322 1323
    int len, val;
    socklen_t lv;
1324 1325

    switch(level) {
1326 1327
    case TARGET_SOL_SOCKET:
    	level = SOL_SOCKET;
1328
	switch (optname) {
1329 1330 1331 1332 1333
	case TARGET_SO_LINGER:
	case TARGET_SO_RCVTIMEO:
	case TARGET_SO_SNDTIMEO:
	case TARGET_SO_PEERCRED:
	case TARGET_SO_PEERNAME:
1334 1335 1336
	    /* These don't just return a single integer */
	    goto unimplemented;
        default:
B
bellard 已提交
1337 1338 1339 1340 1341 1342
            goto int_case;
        }
        break;
    case SOL_TCP:
        /* TCP options all take an 'int' value.  */
    int_case:
1343 1344
        if (get_user_u32(len, optlen))
            return -TARGET_EFAULT;
B
bellard 已提交
1345
        if (len < 0)
1346
            return -TARGET_EINVAL;
B
bellard 已提交
1347 1348 1349 1350 1351 1352
        lv = sizeof(int);
        ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
        if (ret < 0)
            return ret;
        if (len > lv)
            len = lv;
1353 1354 1355 1356 1357 1358 1359 1360 1361
        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 已提交
1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379
        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:
1380 1381
            if (get_user_u32(len, optlen))
                return -TARGET_EFAULT;
1382
            if (len < 0)
1383
                return -TARGET_EINVAL;
1384 1385 1386 1387
            lv = sizeof(int);
            ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
            if (ret < 0)
                return ret;
B
bellard 已提交
1388 1389
            if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
                len = 1;
1390 1391 1392
                if (put_user_u32(len, optlen)
                    || put_user_u8(val, optval_addr))
                    return -TARGET_EFAULT;
B
bellard 已提交
1393 1394 1395
            } else {
                if (len > sizeof(int))
                    len = sizeof(int);
1396 1397 1398
                if (put_user_u32(len, optlen)
                    || put_user_u32(val, optval_addr))
                    return -TARGET_EFAULT;
B
bellard 已提交
1399
            }
1400
            break;
B
bellard 已提交
1401
        default:
1402 1403
            ret = -TARGET_ENOPROTOOPT;
            break;
1404 1405 1406 1407 1408 1409
        }
        break;
    default:
    unimplemented:
        gemu_log("getsockopt level=%d optname=%d not yet supported\n",
                 level, optname);
1410
        ret = -TARGET_EOPNOTSUPP;
1411 1412 1413
        break;
    }
    return ret;
B
bellard 已提交
1414 1415
}

1416 1417 1418 1419 1420 1421
/* 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)
1422 1423
{
    struct target_iovec *target_vec;
1424
    abi_ulong base;
1425
    int i;
1426

1427 1428 1429
    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
    if (!target_vec)
        return -TARGET_EFAULT;
1430 1431 1432
    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 已提交
1433 1434
        if (vec[i].iov_len != 0) {
            vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
1435 1436
            /* Don't check lock_user return value. We must call writev even
               if a element has invalid base address. */
B
bellard 已提交
1437 1438 1439 1440
        } else {
            /* zero length pointer is ignored */
            vec[i].iov_base = NULL;
        }
1441 1442 1443
    }
    unlock_user (target_vec, target_addr, 0);
    return 0;
1444 1445
}

1446 1447
static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
                             int count, int copy)
1448 1449
{
    struct target_iovec *target_vec;
1450
    abi_ulong base;
1451 1452
    int i;

1453 1454 1455
    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
    if (!target_vec)
        return -TARGET_EFAULT;
1456
    for(i = 0;i < count; i++) {
1457 1458 1459 1460
        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);
        }
1461 1462
    }
    unlock_user (target_vec, target_addr, 0);
1463 1464

    return 0;
1465 1466
}

1467
/* do_socket() Must return target values and target errnos. */
1468
static abi_long do_socket(int domain, int type, int protocol)
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
{
#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
1492 1493
    if (domain == PF_NETLINK)
        return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
1494 1495 1496
    return get_errno(socket(domain, type, protocol));
}

1497
/* do_bind() Must return target values and target errnos. */
1498 1499
static abi_long do_bind(int sockfd, abi_ulong target_addr,
                        socklen_t addrlen)
1500
{
1501
    void *addr;
1502
    abi_long ret;
1503

1504
    if (addrlen < 0)
1505 1506
        return -TARGET_EINVAL;

1507
    addr = alloca(addrlen+1);
1508

1509 1510 1511 1512
    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
    if (ret)
        return ret;

1513 1514 1515
    return get_errno(bind(sockfd, addr, addrlen));
}

1516
/* do_connect() Must return target values and target errnos. */
1517 1518
static abi_long do_connect(int sockfd, abi_ulong target_addr,
                           socklen_t addrlen)
1519
{
1520
    void *addr;
1521
    abi_long ret;
1522

1523
    if (addrlen < 0)
1524 1525 1526
        return -TARGET_EINVAL;

    addr = alloca(addrlen);
1527

1528 1529 1530 1531
    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
    if (ret)
        return ret;

1532 1533 1534
    return get_errno(connect(sockfd, addr, addrlen));
}

1535
/* do_sendrecvmsg() Must return target values and target errnos. */
1536 1537
static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
                               int flags, int send)
1538
{
1539
    abi_long ret, len;
1540 1541 1542 1543
    struct target_msghdr *msgp;
    struct msghdr msg;
    int count;
    struct iovec *vec;
1544
    abi_ulong target_vec;
1545

1546 1547 1548 1549 1550 1551
    /* FIXME */
    if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
                          msgp,
                          target_msg,
                          send ? 1 : 0))
        return -TARGET_EFAULT;
1552 1553 1554
    if (msgp->msg_name) {
        msg.msg_namelen = tswap32(msgp->msg_namelen);
        msg.msg_name = alloca(msg.msg_namelen);
1555
        ret = target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
1556
                                msg.msg_namelen);
1557 1558 1559 1560
        if (ret) {
            unlock_user_struct(msgp, target_msg, send ? 0 : 1);
            return ret;
        }
1561 1562 1563 1564 1565 1566 1567
    } 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);
1568

1569 1570 1571
    count = tswapl(msgp->msg_iovlen);
    vec = alloca(count * sizeof(struct iovec));
    target_vec = tswapl(msgp->msg_iov);
1572
    lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
1573 1574
    msg.msg_iovlen = count;
    msg.msg_iov = vec;
1575

1576
    if (send) {
1577 1578 1579
        ret = target_to_host_cmsg(&msg, msgp);
        if (ret == 0)
            ret = get_errno(sendmsg(fd, &msg, flags));
1580 1581
    } else {
        ret = get_errno(recvmsg(fd, &msg, flags));
1582 1583
        if (!is_error(ret)) {
            len = ret;
1584
            ret = host_to_target_cmsg(msgp, &msg);
1585 1586 1587
            if (!is_error(ret))
                ret = len;
        }
1588 1589
    }
    unlock_iovec(vec, target_vec, count, !send);
1590
    unlock_user_struct(msgp, target_msg, send ? 0 : 1);
1591 1592 1593
    return ret;
}

1594
/* do_accept() Must return target values and target errnos. */
1595
static abi_long do_accept(int fd, abi_ulong target_addr,
1596
                          abi_ulong target_addrlen_addr)
P
pbrook 已提交
1597
{
1598 1599
    socklen_t addrlen;
    void *addr;
1600
    abi_long ret;
P
pbrook 已提交
1601

1602 1603 1604 1605
    if (target_addr == 0)
       return get_errno(accept(fd, NULL, NULL));

    /* linux returns EINVAL if addrlen pointer is invalid */
1606
    if (get_user_u32(addrlen, target_addrlen_addr))
1607
        return -TARGET_EINVAL;
1608

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

1612 1613 1614
    if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
        return -TARGET_EINVAL;

1615 1616
    addr = alloca(addrlen);

P
pbrook 已提交
1617 1618 1619
    ret = get_errno(accept(fd, addr, &addrlen));
    if (!is_error(ret)) {
        host_to_target_sockaddr(target_addr, addr, addrlen);
1620 1621
        if (put_user_u32(addrlen, target_addrlen_addr))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1622 1623 1624 1625
    }
    return ret;
}

1626
/* do_getpeername() Must return target values and target errnos. */
1627
static abi_long do_getpeername(int fd, abi_ulong target_addr,
1628
                               abi_ulong target_addrlen_addr)
P
pbrook 已提交
1629
{
1630 1631
    socklen_t addrlen;
    void *addr;
1632
    abi_long ret;
P
pbrook 已提交
1633

1634 1635 1636
    if (get_user_u32(addrlen, target_addrlen_addr))
        return -TARGET_EFAULT;

1637
    if (addrlen < 0)
1638 1639
        return -TARGET_EINVAL;

1640 1641 1642
    if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
        return -TARGET_EFAULT;

1643 1644
    addr = alloca(addrlen);

P
pbrook 已提交
1645 1646 1647
    ret = get_errno(getpeername(fd, addr, &addrlen));
    if (!is_error(ret)) {
        host_to_target_sockaddr(target_addr, addr, addrlen);
1648 1649
        if (put_user_u32(addrlen, target_addrlen_addr))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1650 1651 1652 1653
    }
    return ret;
}

1654
/* do_getsockname() Must return target values and target errnos. */
1655
static abi_long do_getsockname(int fd, abi_ulong target_addr,
1656
                               abi_ulong target_addrlen_addr)
P
pbrook 已提交
1657
{
1658 1659
    socklen_t addrlen;
    void *addr;
1660
    abi_long ret;
P
pbrook 已提交
1661

1662 1663 1664
    if (get_user_u32(addrlen, target_addrlen_addr))
        return -TARGET_EFAULT;

1665
    if (addrlen < 0)
1666 1667
        return -TARGET_EINVAL;

1668 1669 1670
    if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
        return -TARGET_EFAULT;

1671 1672
    addr = alloca(addrlen);

P
pbrook 已提交
1673 1674 1675
    ret = get_errno(getsockname(fd, addr, &addrlen));
    if (!is_error(ret)) {
        host_to_target_sockaddr(target_addr, addr, addrlen);
1676 1677
        if (put_user_u32(addrlen, target_addrlen_addr))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1678 1679 1680 1681
    }
    return ret;
}

1682
/* do_socketpair() Must return target values and target errnos. */
1683
static abi_long do_socketpair(int domain, int type, int protocol,
1684
                              abi_ulong target_tab_addr)
P
pbrook 已提交
1685 1686
{
    int tab[2];
1687
    abi_long ret;
P
pbrook 已提交
1688 1689 1690

    ret = get_errno(socketpair(domain, type, protocol, tab));
    if (!is_error(ret)) {
1691 1692 1693
        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 已提交
1694 1695 1696 1697
    }
    return ret;
}

1698
/* do_sendto() Must return target values and target errnos. */
1699 1700
static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
                          abi_ulong target_addr, socklen_t addrlen)
P
pbrook 已提交
1701 1702 1703
{
    void *addr;
    void *host_msg;
1704
    abi_long ret;
P
pbrook 已提交
1705

1706
    if (addrlen < 0)
1707 1708
        return -TARGET_EINVAL;

1709 1710 1711
    host_msg = lock_user(VERIFY_READ, msg, len, 1);
    if (!host_msg)
        return -TARGET_EFAULT;
P
pbrook 已提交
1712 1713
    if (target_addr) {
        addr = alloca(addrlen);
1714 1715 1716 1717 1718
        ret = target_to_host_sockaddr(addr, target_addr, addrlen);
        if (ret) {
            unlock_user(host_msg, msg, 0);
            return ret;
        }
P
pbrook 已提交
1719 1720 1721 1722 1723 1724 1725 1726
        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;
}

1727
/* do_recvfrom() Must return target values and target errnos. */
1728 1729 1730
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 已提交
1731 1732 1733 1734
{
    socklen_t addrlen;
    void *addr;
    void *host_msg;
1735
    abi_long ret;
P
pbrook 已提交
1736

1737 1738 1739
    host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
    if (!host_msg)
        return -TARGET_EFAULT;
P
pbrook 已提交
1740
    if (target_addr) {
1741 1742 1743 1744
        if (get_user_u32(addrlen, target_addrlen)) {
            ret = -TARGET_EFAULT;
            goto fail;
        }
1745
        if (addrlen < 0) {
1746 1747 1748
            ret = -TARGET_EINVAL;
            goto fail;
        }
P
pbrook 已提交
1749 1750 1751 1752 1753 1754 1755 1756 1757
        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);
1758 1759 1760 1761
            if (put_user_u32(addrlen, target_addrlen)) {
                ret = -TARGET_EFAULT;
                goto fail;
            }
P
pbrook 已提交
1762 1763 1764
        }
        unlock_user(host_msg, msg, len);
    } else {
1765
fail:
P
pbrook 已提交
1766 1767 1768 1769 1770
        unlock_user(host_msg, msg, 0);
    }
    return ret;
}

1771
#ifdef TARGET_NR_socketcall
1772
/* do_socketcall() Must return target values and target errnos. */
1773
static abi_long do_socketcall(int num, abi_ulong vptr)
1774
{
1775 1776
    abi_long ret;
    const int n = sizeof(abi_ulong);
1777 1778 1779

    switch(num) {
    case SOCKOP_socket:
B
bellard 已提交
1780
	{
U
Ulrich Hecht 已提交
1781
            abi_ulong domain, type, protocol;
1782

U
Ulrich Hecht 已提交
1783 1784 1785
            if (get_user_ual(domain, vptr)
                || get_user_ual(type, vptr + n)
                || get_user_ual(protocol, vptr + 2 * n))
1786 1787
                return -TARGET_EFAULT;

1788
            ret = do_socket(domain, type, protocol);
B
bellard 已提交
1789
	}
1790 1791
        break;
    case SOCKOP_bind:
B
bellard 已提交
1792
	{
U
Ulrich Hecht 已提交
1793
            abi_ulong sockfd;
1794 1795 1796
            abi_ulong target_addr;
            socklen_t addrlen;

U
Ulrich Hecht 已提交
1797
            if (get_user_ual(sockfd, vptr)
1798
                || get_user_ual(target_addr, vptr + n)
U
Ulrich Hecht 已提交
1799
                || get_user_ual(addrlen, vptr + 2 * n))
1800 1801
                return -TARGET_EFAULT;

1802
            ret = do_bind(sockfd, target_addr, addrlen);
B
bellard 已提交
1803
        }
1804 1805
        break;
    case SOCKOP_connect:
B
bellard 已提交
1806
        {
U
Ulrich Hecht 已提交
1807
            abi_ulong sockfd;
1808 1809 1810
            abi_ulong target_addr;
            socklen_t addrlen;

U
Ulrich Hecht 已提交
1811
            if (get_user_ual(sockfd, vptr)
1812
                || get_user_ual(target_addr, vptr + n)
U
Ulrich Hecht 已提交
1813
                || get_user_ual(addrlen, vptr + 2 * n))
1814 1815
                return -TARGET_EFAULT;

1816
            ret = do_connect(sockfd, target_addr, addrlen);
B
bellard 已提交
1817
        }
1818 1819
        break;
    case SOCKOP_listen:
B
bellard 已提交
1820
        {
U
Ulrich Hecht 已提交
1821
            abi_ulong sockfd, backlog;
1822

U
Ulrich Hecht 已提交
1823 1824
            if (get_user_ual(sockfd, vptr)
                || get_user_ual(backlog, vptr + n))
1825 1826
                return -TARGET_EFAULT;

B
bellard 已提交
1827 1828
            ret = get_errno(listen(sockfd, backlog));
        }
1829 1830 1831
        break;
    case SOCKOP_accept:
        {
U
Ulrich Hecht 已提交
1832
            abi_ulong sockfd;
1833 1834
            abi_ulong target_addr, target_addrlen;

U
Ulrich Hecht 已提交
1835
            if (get_user_ual(sockfd, vptr)
1836
                || get_user_ual(target_addr, vptr + n)
U
Ulrich Hecht 已提交
1837
                || get_user_ual(target_addrlen, vptr + 2 * n))
1838 1839
                return -TARGET_EFAULT;

P
pbrook 已提交
1840
            ret = do_accept(sockfd, target_addr, target_addrlen);
1841 1842 1843 1844
        }
        break;
    case SOCKOP_getsockname:
        {
U
Ulrich Hecht 已提交
1845
            abi_ulong sockfd;
1846 1847
            abi_ulong target_addr, target_addrlen;

U
Ulrich Hecht 已提交
1848
            if (get_user_ual(sockfd, vptr)
1849
                || get_user_ual(target_addr, vptr + n)
U
Ulrich Hecht 已提交
1850
                || get_user_ual(target_addrlen, vptr + 2 * n))
1851 1852
                return -TARGET_EFAULT;

P
pbrook 已提交
1853
            ret = do_getsockname(sockfd, target_addr, target_addrlen);
1854 1855 1856 1857
        }
        break;
    case SOCKOP_getpeername:
        {
U
Ulrich Hecht 已提交
1858
            abi_ulong sockfd;
1859 1860
            abi_ulong target_addr, target_addrlen;

U
Ulrich Hecht 已提交
1861
            if (get_user_ual(sockfd, vptr)
1862
                || get_user_ual(target_addr, vptr + n)
U
Ulrich Hecht 已提交
1863
                || get_user_ual(target_addrlen, vptr + 2 * n))
1864 1865
                return -TARGET_EFAULT;

P
pbrook 已提交
1866
            ret = do_getpeername(sockfd, target_addr, target_addrlen);
1867 1868 1869 1870
        }
        break;
    case SOCKOP_socketpair:
        {
U
Ulrich Hecht 已提交
1871
            abi_ulong domain, type, protocol;
1872 1873
            abi_ulong tab;

U
Ulrich Hecht 已提交
1874 1875 1876
            if (get_user_ual(domain, vptr)
                || get_user_ual(type, vptr + n)
                || get_user_ual(protocol, vptr + 2 * n)
1877 1878 1879
                || get_user_ual(tab, vptr + 3 * n))
                return -TARGET_EFAULT;

P
pbrook 已提交
1880
            ret = do_socketpair(domain, type, protocol, tab);
1881 1882 1883
        }
        break;
    case SOCKOP_send:
B
bellard 已提交
1884
        {
U
Ulrich Hecht 已提交
1885
            abi_ulong sockfd;
1886 1887
            abi_ulong msg;
            size_t len;
U
Ulrich Hecht 已提交
1888
            abi_ulong flags;
1889

U
Ulrich Hecht 已提交
1890
            if (get_user_ual(sockfd, vptr)
1891 1892
                || get_user_ual(msg, vptr + n)
                || get_user_ual(len, vptr + 2 * n)
U
Ulrich Hecht 已提交
1893
                || get_user_ual(flags, vptr + 3 * n))
1894 1895
                return -TARGET_EFAULT;

P
pbrook 已提交
1896
            ret = do_sendto(sockfd, msg, len, flags, 0, 0);
B
bellard 已提交
1897
        }
1898 1899
        break;
    case SOCKOP_recv:
B
bellard 已提交
1900
        {
U
Ulrich Hecht 已提交
1901
            abi_ulong sockfd;
1902 1903
            abi_ulong msg;
            size_t len;
U
Ulrich Hecht 已提交
1904
            abi_ulong flags;
1905

U
Ulrich Hecht 已提交
1906
            if (get_user_ual(sockfd, vptr)
1907 1908
                || get_user_ual(msg, vptr + n)
                || get_user_ual(len, vptr + 2 * n)
U
Ulrich Hecht 已提交
1909
                || get_user_ual(flags, vptr + 3 * n))
1910 1911
                return -TARGET_EFAULT;

P
pbrook 已提交
1912
            ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
B
bellard 已提交
1913
        }
1914 1915
        break;
    case SOCKOP_sendto:
B
bellard 已提交
1916
        {
U
Ulrich Hecht 已提交
1917
            abi_ulong sockfd;
1918 1919
            abi_ulong msg;
            size_t len;
U
Ulrich Hecht 已提交
1920
            abi_ulong flags;
1921 1922 1923
            abi_ulong addr;
            socklen_t addrlen;

U
Ulrich Hecht 已提交
1924
            if (get_user_ual(sockfd, vptr)
1925 1926
                || get_user_ual(msg, vptr + n)
                || get_user_ual(len, vptr + 2 * n)
U
Ulrich Hecht 已提交
1927
                || get_user_ual(flags, vptr + 3 * n)
1928
                || get_user_ual(addr, vptr + 4 * n)
U
Ulrich Hecht 已提交
1929
                || get_user_ual(addrlen, vptr + 5 * n))
1930 1931
                return -TARGET_EFAULT;

P
pbrook 已提交
1932
            ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
B
bellard 已提交
1933
        }
1934 1935 1936
        break;
    case SOCKOP_recvfrom:
        {
U
Ulrich Hecht 已提交
1937
            abi_ulong sockfd;
1938 1939
            abi_ulong msg;
            size_t len;
U
Ulrich Hecht 已提交
1940
            abi_ulong flags;
1941 1942 1943
            abi_ulong addr;
            socklen_t addrlen;

U
Ulrich Hecht 已提交
1944
            if (get_user_ual(sockfd, vptr)
1945 1946
                || get_user_ual(msg, vptr + n)
                || get_user_ual(len, vptr + 2 * n)
U
Ulrich Hecht 已提交
1947
                || get_user_ual(flags, vptr + 3 * n)
1948
                || get_user_ual(addr, vptr + 4 * n)
U
Ulrich Hecht 已提交
1949
                || get_user_ual(addrlen, vptr + 5 * n))
1950 1951
                return -TARGET_EFAULT;

P
pbrook 已提交
1952
            ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
1953 1954 1955
        }
        break;
    case SOCKOP_shutdown:
B
bellard 已提交
1956
        {
U
Ulrich Hecht 已提交
1957
            abi_ulong sockfd, how;
1958

U
Ulrich Hecht 已提交
1959 1960
            if (get_user_ual(sockfd, vptr)
                || get_user_ual(how, vptr + n))
1961
                return -TARGET_EFAULT;
B
bellard 已提交
1962 1963 1964

            ret = get_errno(shutdown(sockfd, how));
        }
1965 1966 1967
        break;
    case SOCKOP_sendmsg:
    case SOCKOP_recvmsg:
B
bellard 已提交
1968
        {
U
Ulrich Hecht 已提交
1969
            abi_ulong fd;
1970
            abi_ulong target_msg;
U
Ulrich Hecht 已提交
1971
            abi_ulong flags;
B
bellard 已提交
1972

U
Ulrich Hecht 已提交
1973
            if (get_user_ual(fd, vptr)
1974
                || get_user_ual(target_msg, vptr + n)
U
Ulrich Hecht 已提交
1975
                || get_user_ual(flags, vptr + 2 * n))
1976
                return -TARGET_EFAULT;
1977

1978
            ret = do_sendrecvmsg(fd, target_msg, flags,
1979
                                 (num == SOCKOP_sendmsg));
B
bellard 已提交
1980 1981
        }
        break;
1982
    case SOCKOP_setsockopt:
B
bellard 已提交
1983
        {
U
Ulrich Hecht 已提交
1984 1985 1986
            abi_ulong sockfd;
            abi_ulong level;
            abi_ulong optname;
1987 1988 1989
            abi_ulong optval;
            socklen_t optlen;

U
Ulrich Hecht 已提交
1990 1991 1992
            if (get_user_ual(sockfd, vptr)
                || get_user_ual(level, vptr + n)
                || get_user_ual(optname, vptr + 2 * n)
1993
                || get_user_ual(optval, vptr + 3 * n)
U
Ulrich Hecht 已提交
1994
                || get_user_ual(optlen, vptr + 4 * n))
1995
                return -TARGET_EFAULT;
B
bellard 已提交
1996 1997 1998 1999

            ret = do_setsockopt(sockfd, level, optname, optval, optlen);
        }
        break;
2000
    case SOCKOP_getsockopt:
B
bellard 已提交
2001
        {
U
Ulrich Hecht 已提交
2002 2003 2004
            abi_ulong sockfd;
            abi_ulong level;
            abi_ulong optname;
2005 2006 2007
            abi_ulong optval;
            socklen_t optlen;

U
Ulrich Hecht 已提交
2008 2009 2010
            if (get_user_ual(sockfd, vptr)
                || get_user_ual(level, vptr + n)
                || get_user_ual(optname, vptr + 2 * n)
2011
                || get_user_ual(optval, vptr + 3 * n)
U
Ulrich Hecht 已提交
2012
                || get_user_ual(optlen, vptr + 4 * n))
2013
                return -TARGET_EFAULT;
B
bellard 已提交
2014

2015
            ret = do_getsockopt(sockfd, level, optname, optval, optlen);
B
bellard 已提交
2016 2017
        }
        break;
2018 2019
    default:
        gemu_log("Unsupported socketcall: %d\n", num);
2020
        ret = -TARGET_ENOSYS;
2021 2022 2023 2024
        break;
    }
    return ret;
}
2025
#endif
2026

2027 2028 2029
#define N_SHM_REGIONS	32

static struct shm_region {
2030 2031
    abi_ulong	start;
    abi_ulong	size;
2032 2033
} shm_regions[N_SHM_REGIONS];

2034 2035
struct target_ipc_perm
{
2036 2037 2038 2039 2040
    abi_long __key;
    abi_ulong uid;
    abi_ulong gid;
    abi_ulong cuid;
    abi_ulong cgid;
2041 2042 2043 2044
    unsigned short int mode;
    unsigned short int __pad1;
    unsigned short int __seq;
    unsigned short int __pad2;
2045 2046
    abi_ulong __unused1;
    abi_ulong __unused2;
2047 2048 2049 2050 2051
};

struct target_semid_ds
{
  struct target_ipc_perm sem_perm;
2052 2053 2054 2055 2056 2057 2058
  abi_ulong sem_otime;
  abi_ulong __unused1;
  abi_ulong sem_ctime;
  abi_ulong __unused2;
  abi_ulong sem_nsems;
  abi_ulong __unused3;
  abi_ulong __unused4;
2059 2060
};

2061 2062
static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
                                               abi_ulong target_addr)
2063 2064 2065 2066
{
    struct target_ipc_perm *target_ip;
    struct target_semid_ds *target_sd;

2067 2068
    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
        return -TARGET_EFAULT;
2069 2070 2071 2072 2073 2074 2075 2076
    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);
2077
    return 0;
2078 2079
}

2080 2081
static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
                                               struct ipc_perm *host_ip)
2082 2083 2084 2085
{
    struct target_ipc_perm *target_ip;
    struct target_semid_ds *target_sd;

2086 2087
    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
        return -TARGET_EFAULT;
2088 2089 2090 2091 2092 2093 2094 2095
    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);
2096
    return 0;
2097 2098
}

2099 2100
static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
                                               abi_ulong target_addr)
2101 2102 2103
{
    struct target_semid_ds *target_sd;

2104 2105
    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
        return -TARGET_EFAULT;
2106 2107
    if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
        return -TARGET_EFAULT;
2108 2109 2110 2111
    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);
2112
    return 0;
2113 2114
}

2115 2116
static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
                                               struct semid_ds *host_sd)
2117 2118 2119
{
    struct target_semid_ds *target_sd;

2120 2121
    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
        return -TARGET_EFAULT;
2122 2123
    if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
        return -TARGET_EFAULT;;
2124 2125 2126 2127
    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);
2128
    return 0;
2129 2130
}

2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163
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;
}

2164 2165
union semun {
	int val;
2166
	struct semid_ds *buf;
2167
	unsigned short *array;
2168
	struct seminfo *__buf;
2169 2170
};

2171 2172
union target_semun {
	int val;
2173 2174 2175
	abi_ulong buf;
	abi_ulong array;
	abi_ulong __buf;
2176 2177
};

2178 2179
static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
                                               abi_ulong target_addr)
2180
{
2181 2182 2183 2184 2185
    int nsems;
    unsigned short *array;
    union semun semun;
    struct semid_ds semid_ds;
    int i, ret;
2186

2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202
    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]);
2203
    }
2204 2205
    unlock_user(array, target_addr, 0);

2206
    return 0;
2207 2208
}

2209 2210
static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
                                               unsigned short **host_array)
2211
{
2212 2213 2214 2215 2216
    int nsems;
    unsigned short *array;
    union semun semun;
    struct semid_ds semid_ds;
    int i, ret;
2217

2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232
    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]);
2233
    }
2234 2235 2236
    free(*host_array);
    unlock_user(array, target_addr, 1);

2237
    return 0;
2238 2239
}

2240 2241
static inline abi_long do_semctl(int semid, int semnum, int cmd,
                                 union target_semun target_su)
2242 2243 2244
{
    union semun arg;
    struct semid_ds dsarg;
2245
    unsigned short *array = NULL;
2246 2247 2248 2249
    struct seminfo seminfo;
    abi_long ret = -TARGET_EINVAL;
    abi_long err;
    cmd &= 0xff;
2250 2251 2252 2253

    switch( cmd ) {
	case GETVAL:
	case SETVAL:
2254 2255 2256
            arg.val = tswapl(target_su.val);
            ret = get_errno(semctl(semid, semnum, cmd, arg));
            target_su.val = tswapl(arg.val);
2257 2258 2259
            break;
	case GETALL:
	case SETALL:
2260 2261 2262 2263 2264 2265 2266 2267
            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;
2268 2269 2270
            break;
	case IPC_STAT:
	case IPC_SET:
2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293
	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));
2294 2295 2296 2297 2298 2299
            break;
    }

    return ret;
}

2300 2301 2302 2303 2304 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 2333 2334 2335 2336 2337 2338
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 已提交
2339 2340
struct target_msqid_ds
{
2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360
    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 已提交
2361 2362
};

2363 2364
static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
                                               abi_ulong target_addr)
T
ths 已提交
2365 2366 2367
{
    struct target_msqid_ds *target_md;

2368 2369
    if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
        return -TARGET_EFAULT;
2370 2371
    if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
        return -TARGET_EFAULT;
T
ths 已提交
2372 2373 2374 2375 2376 2377 2378 2379 2380
    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);
2381
    return 0;
T
ths 已提交
2382 2383
}

2384 2385
static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
                                               struct msqid_ds *host_md)
T
ths 已提交
2386 2387 2388
{
    struct target_msqid_ds *target_md;

2389 2390
    if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
        return -TARGET_EFAULT;
2391 2392
    if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
        return -TARGET_EFAULT;
T
ths 已提交
2393 2394 2395 2396 2397 2398 2399 2400 2401
    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);
2402
    return 0;
T
ths 已提交
2403 2404
}

2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430
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);
2431
    return 0;
2432 2433 2434
}

static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
T
ths 已提交
2435 2436
{
    struct msqid_ds dsarg;
2437 2438 2439 2440 2441 2442
    struct msginfo msginfo;
    abi_long ret = -TARGET_EINVAL;

    cmd &= 0xff;

    switch (cmd) {
T
ths 已提交
2443 2444
    case IPC_STAT:
    case IPC_SET:
2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460
    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 已提交
2461
    }
2462

T
ths 已提交
2463 2464 2465 2466
    return ret;
}

struct target_msgbuf {
2467 2468
    abi_long mtype;
    char	mtext[1];
T
ths 已提交
2469 2470
};

2471 2472
static inline abi_long do_msgsnd(int msqid, abi_long msgp,
                                 unsigned int msgsz, int msgflg)
T
ths 已提交
2473 2474 2475
{
    struct target_msgbuf *target_mb;
    struct msgbuf *host_mb;
2476
    abi_long ret = 0;
T
ths 已提交
2477

2478 2479
    if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
        return -TARGET_EFAULT;
T
ths 已提交
2480
    host_mb = malloc(msgsz+sizeof(long));
2481 2482
    host_mb->mtype = (abi_long) tswapl(target_mb->mtype);
    memcpy(host_mb->mtext, target_mb->mtext, msgsz);
T
ths 已提交
2483 2484 2485 2486 2487 2488 2489
    ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
    free(host_mb);
    unlock_user_struct(target_mb, msgp, 0);

    return ret;
}

2490
static inline abi_long do_msgrcv(int msqid, abi_long msgp,
2491
                                 unsigned int msgsz, abi_long msgtyp,
2492
                                 int msgflg)
T
ths 已提交
2493 2494
{
    struct target_msgbuf *target_mb;
2495
    char *target_mtext;
T
ths 已提交
2496
    struct msgbuf *host_mb;
2497
    abi_long ret = 0;
T
ths 已提交
2498

2499 2500
    if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
        return -TARGET_EFAULT;
2501

T
ths 已提交
2502
    host_mb = malloc(msgsz+sizeof(long));
2503 2504
    ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapl(msgtyp), msgflg));

2505 2506 2507 2508 2509 2510 2511
    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;
        }
2512
        memcpy(target_mb->mtext, host_mb->mtext, ret);
2513 2514
        unlock_user(target_mtext, target_mtext_addr, ret);
    }
2515

T
ths 已提交
2516 2517 2518
    target_mb->mtype = tswapl(host_mb->mtype);
    free(host_mb);

2519 2520 2521
end:
    if (target_mb)
        unlock_user_struct(target_mb, msgp, 1);
T
ths 已提交
2522 2523 2524
    return ret;
}

2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742
struct target_shmid_ds
{
    struct target_ipc_perm shm_perm;
    abi_ulong shm_segsz;
    abi_ulong shm_atime;
#if TARGET_ABI_BITS == 32
    abi_ulong __unused1;
#endif
    abi_ulong shm_dtime;
#if TARGET_ABI_BITS == 32
    abi_ulong __unused2;
#endif
    abi_ulong shm_ctime;
#if TARGET_ABI_BITS == 32
    abi_ulong __unused3;
#endif
    int shm_cpid;
    int shm_lpid;
    abi_ulong shm_nattch;
    unsigned long int __unused4;
    unsigned long int __unused5;
};

static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
                                               abi_ulong target_addr)
{
    struct target_shmid_ds *target_sd;

    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
        return -TARGET_EFAULT;
    if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
        return -TARGET_EFAULT;
    __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
    __get_user(host_sd->shm_atime, &target_sd->shm_atime);
    __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
    __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
    __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
    __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
    __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
    unlock_user_struct(target_sd, target_addr, 0);
    return 0;
}

static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
                                               struct shmid_ds *host_sd)
{
    struct target_shmid_ds *target_sd;

    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
        return -TARGET_EFAULT;
    if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
        return -TARGET_EFAULT;
    __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
    __put_user(host_sd->shm_atime, &target_sd->shm_atime);
    __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
    __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
    __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
    __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
    __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
    unlock_user_struct(target_sd, target_addr, 1);
    return 0;
}

struct  target_shminfo {
    abi_ulong shmmax;
    abi_ulong shmmin;
    abi_ulong shmmni;
    abi_ulong shmseg;
    abi_ulong shmall;
};

static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
                                              struct shminfo *host_shminfo)
{
    struct target_shminfo *target_shminfo;
    if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
        return -TARGET_EFAULT;
    __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
    __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
    __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
    __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
    __put_user(host_shminfo->shmall, &target_shminfo->shmall);
    unlock_user_struct(target_shminfo, target_addr, 1);
    return 0;
}

struct target_shm_info {
    int used_ids;
    abi_ulong shm_tot;
    abi_ulong shm_rss;
    abi_ulong shm_swp;
    abi_ulong swap_attempts;
    abi_ulong swap_successes;
};

static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
                                               struct shm_info *host_shm_info)
{
    struct target_shm_info *target_shm_info;
    if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
        return -TARGET_EFAULT;
    __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
    __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
    __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
    __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
    __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
    __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
    unlock_user_struct(target_shm_info, target_addr, 1);
    return 0;
}

static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
{
    struct shmid_ds dsarg;
    struct shminfo shminfo;
    struct shm_info shm_info;
    abi_long ret = -TARGET_EINVAL;

    cmd &= 0xff;

    switch(cmd) {
    case IPC_STAT:
    case IPC_SET:
    case SHM_STAT:
        if (target_to_host_shmid_ds(&dsarg, buf))
            return -TARGET_EFAULT;
        ret = get_errno(shmctl(shmid, cmd, &dsarg));
        if (host_to_target_shmid_ds(buf, &dsarg))
            return -TARGET_EFAULT;
        break;
    case IPC_INFO:
        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
        if (host_to_target_shminfo(buf, &shminfo))
            return -TARGET_EFAULT;
        break;
    case SHM_INFO:
        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
        if (host_to_target_shm_info(buf, &shm_info))
            return -TARGET_EFAULT;
        break;
    case IPC_RMID:
    case SHM_LOCK:
    case SHM_UNLOCK:
        ret = get_errno(shmctl(shmid, cmd, NULL));
        break;
    }

    return ret;
}

static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
{
    abi_long raddr;
    void *host_raddr;
    struct shmid_ds shm_info;
    int i,ret;

    /* find out the length of the shared memory segment */
    ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
    if (is_error(ret)) {
        /* can't get length, bail out */
        return ret;
    }

    mmap_lock();

    if (shmaddr)
        host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
    else {
        abi_ulong mmap_start;

        mmap_start = mmap_find_vma(0, shm_info.shm_segsz);

        if (mmap_start == -1) {
            errno = ENOMEM;
            host_raddr = (void *)-1;
        } else
            host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
    }

    if (host_raddr == (void *)-1) {
        mmap_unlock();
        return get_errno((long)host_raddr);
    }
    raddr=h2g((unsigned long)host_raddr);

    page_set_flags(raddr, raddr + shm_info.shm_segsz,
                   PAGE_VALID | PAGE_READ |
                   ((shmflg & 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;
        }
    }

    mmap_unlock();
    return raddr;

}

static inline abi_long do_shmdt(abi_ulong shmaddr)
{
    int i;

    for (i = 0; i < N_SHM_REGIONS; ++i) {
        if (shm_regions[i].start == shmaddr) {
            shm_regions[i].start = 0;
            page_set_flags(shmaddr, shm_regions[i].size, 0);
            break;
        }
    }

    return get_errno(shmdt(g2h(shmaddr)));
}

2743
#ifdef TARGET_NR_ipc
2744
/* ??? This only works with linear mappings.  */
2745
/* do_ipc() must return target values and target errnos. */
2746 2747 2748
static abi_long do_ipc(unsigned int call, int first,
                       int second, int third,
                       abi_long ptr, abi_long fifth)
2749 2750
{
    int version;
2751
    abi_long ret = 0;
2752 2753 2754 2755 2756

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

    switch (call) {
2757
    case IPCOP_semop:
2758
        ret = do_semop(first, ptr, second);
2759 2760 2761 2762 2763 2764 2765
        break;

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

    case IPCOP_semctl:
2766
        ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
2767
        break;
2768

2769 2770 2771
    case IPCOP_msgget:
        ret = get_errno(msgget(first, second));
        break;
2772

2773 2774 2775
    case IPCOP_msgsnd:
        ret = do_msgsnd(first, ptr, second, third);
        break;
2776

2777 2778 2779
    case IPCOP_msgctl:
        ret = do_msgctl(first, second, ptr);
        break;
2780

2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793
    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;
                }
2794

2795
                ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
2796

2797 2798 2799 2800 2801 2802 2803
                unlock_user_struct(tmp, ptr, 0);
                break;
            }
        default:
            ret = do_msgrcv(first, ptr, second, fifth, third);
        }
        break;
2804

2805
    case IPCOP_shmat:
2806 2807
        switch (version) {
        default:
2808 2809
        {
            abi_ulong raddr;
2810 2811 2812
            raddr = do_shmat(first, ptr, second);
            if (is_error(raddr))
                return get_errno(raddr);
2813
            if (put_user_ual(raddr, third))
2814
                return -TARGET_EFAULT;
2815 2816 2817 2818 2819
            break;
        }
        case 1:
            ret = -TARGET_EINVAL;
            break;
2820
        }
2821 2822
	break;
    case IPCOP_shmdt:
2823
        ret = do_shmdt(ptr);
2824 2825 2826 2827 2828 2829 2830 2831 2832
	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:
2833
        ret = do_shmctl(first, second, third);
2834 2835
        break;
    default:
2836
	gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
2837
	ret = -TARGET_ENOSYS;
2838 2839 2840 2841
	break;
    }
    return ret;
}
2842
#endif
2843

2844 2845 2846
/* kernel structure types definitions */
#define IFNAMSIZ        16

2847
#define STRUCT(name, ...) STRUCT_ ## name,
2848 2849 2850 2851 2852 2853 2854
#define STRUCT_SPECIAL(name) STRUCT_ ## name,
enum {
#include "syscall_types.h"
};
#undef STRUCT
#undef STRUCT_SPECIAL

2855
#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = {  __VA_ARGS__, TYPE_NULL };
2856 2857 2858 2859 2860 2861
#define STRUCT_SPECIAL(name)
#include "syscall_types.h"
#undef STRUCT
#undef STRUCT_SPECIAL

typedef struct IOCTLEntry {
2862 2863
    unsigned int target_cmd;
    unsigned int host_cmd;
2864 2865
    const char *name;
    int access;
B
bellard 已提交
2866
    const argtype arg_type[5];
2867 2868 2869 2870 2871 2872 2873 2874
} IOCTLEntry;

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

#define MAX_STRUCT_SIZE 4096

B
blueswir1 已提交
2875
static IOCTLEntry ioctl_entries[] = {
2876 2877
#define IOCTL(cmd, access, ...) \
    { TARGET_ ## cmd, cmd, #cmd, access, {  __VA_ARGS__ } },
2878 2879 2880 2881
#include "ioctls.h"
    { 0, 0, },
};

2882
/* ??? Implement proper locking for ioctls.  */
2883
/* do_ioctl() Must return target values and target errnos. */
2884
static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
2885 2886 2887
{
    const IOCTLEntry *ie;
    const argtype *arg_type;
2888
    abi_long ret;
2889
    uint8_t buf_temp[MAX_STRUCT_SIZE];
2890 2891
    int target_size;
    void *argptr;
2892 2893 2894 2895

    ie = ioctl_entries;
    for(;;) {
        if (ie->target_cmd == 0) {
2896
            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
2897
            return -TARGET_ENOSYS;
2898 2899 2900 2901 2902 2903
        }
        if (ie->target_cmd == cmd)
            break;
        ie++;
    }
    arg_type = ie->arg_type;
B
bellard 已提交
2904
#if defined(DEBUG)
2905
    gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
B
bellard 已提交
2906
#endif
2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918
    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++;
2919
        target_size = thunk_type_size(arg_type, 0);
2920 2921 2922 2923
        switch(ie->access) {
        case IOC_R:
            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
            if (!is_error(ret)) {
2924 2925 2926
                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
                if (!argptr)
                    return -TARGET_EFAULT;
2927 2928
                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
                unlock_user(argptr, arg, target_size);
2929 2930 2931
            }
            break;
        case IOC_W:
2932 2933 2934
            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
            if (!argptr)
                return -TARGET_EFAULT;
2935 2936
            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
            unlock_user(argptr, arg, 0);
2937 2938 2939 2940
            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
            break;
        default:
        case IOC_RW:
2941 2942 2943
            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
            if (!argptr)
                return -TARGET_EFAULT;
2944 2945
            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
            unlock_user(argptr, arg, 0);
2946 2947
            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
            if (!is_error(ret)) {
2948 2949 2950
                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
                if (!argptr)
                    return -TARGET_EFAULT;
2951 2952
                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
                unlock_user(argptr, arg, target_size);
2953 2954 2955 2956 2957
            }
            break;
        }
        break;
    default:
2958 2959
        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
                 (long)cmd, arg_type[0]);
2960
        ret = -TARGET_ENOSYS;
2961 2962 2963 2964 2965
        break;
    }
    return ret;
}

B
blueswir1 已提交
2966
static const bitmask_transtbl iflag_tbl[] = {
2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983
        { 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 已提交
2984
static const bitmask_transtbl oflag_tbl[] = {
2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011
	{ 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 已提交
3012
static const bitmask_transtbl cflag_tbl[] = {
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
	{ 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 已提交
3047
static const bitmask_transtbl lflag_tbl[] = {
3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069
	{ 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;
3070

3071
    host->c_iflag =
3072
        target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
3073
    host->c_oflag =
3074
        target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
3075
    host->c_cflag =
3076
        target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
3077
    host->c_lflag =
3078 3079
        target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
    host->c_line = target->c_line;
3080

3081
    memset(host->c_cc, 0, sizeof(host->c_cc));
3082 3083
    host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
    host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
3084
    host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
3085
    host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
3086
    host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
3087
    host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
3088
    host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
3089
    host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
3090
    host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
3091 3092
    host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
    host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
3093 3094 3095 3096 3097
    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];
3098
    host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
3099
}
3100

3101 3102 3103 3104 3105
static void host_to_target_termios (void *dst, const void *src)
{
    struct target_termios *target = dst;
    const struct host_termios *host = src;

3106
    target->c_iflag =
3107
        tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
3108
    target->c_oflag =
3109
        tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
3110
    target->c_cflag =
3111
        tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
3112
    target->c_lflag =
3113 3114
        tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
    target->c_line = host->c_line;
3115

3116
    memset(target->c_cc, 0, sizeof(target->c_cc));
3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135
    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 已提交
3136
static const StructEntry struct_termios_def = {
3137 3138 3139 3140 3141
    .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 已提交
3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153
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 }
};

3154
#if defined(TARGET_I386)
B
bellard 已提交
3155 3156

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

3159
static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
B
bellard 已提交
3160 3161
{
    int size;
3162
    void *p;
B
bellard 已提交
3163 3164 3165 3166 3167 3168

    if (!ldt_table)
        return 0;
    size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
    if (size > bytecount)
        size = bytecount;
3169 3170
    p = lock_user(VERIFY_WRITE, ptr, size, 0);
    if (!p)
3171
        return -TARGET_EFAULT;
3172
    /* ??? Should this by byteswapped?  */
3173 3174
    memcpy(p, ldt_table, size);
    unlock_user(p, ptr, size);
B
bellard 已提交
3175 3176 3177 3178
    return size;
}

/* XXX: add locking support */
3179 3180
static abi_long write_ldt(CPUX86State *env,
                          abi_ulong ptr, unsigned long bytecount, int oldmode)
B
bellard 已提交
3181 3182
{
    struct target_modify_ldt_ldt_s ldt_info;
3183
    struct target_modify_ldt_ldt_s *target_ldt_info;
B
bellard 已提交
3184
    int seg_32bit, contents, read_exec_only, limit_in_pages;
B
bellard 已提交
3185
    int seg_not_present, useable, lm;
B
bellard 已提交
3186 3187 3188
    uint32_t *lp, entry_1, entry_2;

    if (bytecount != sizeof(ldt_info))
3189
        return -TARGET_EINVAL;
3190
    if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
3191
        return -TARGET_EFAULT;
3192 3193 3194 3195 3196
    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);
3197

B
bellard 已提交
3198
    if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
3199
        return -TARGET_EINVAL;
B
bellard 已提交
3200 3201 3202 3203 3204 3205
    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 已提交
3206 3207 3208 3209 3210
#ifdef TARGET_ABI32
    lm = 0;
#else
    lm = (ldt_info.flags >> 7) & 1;
#endif
B
bellard 已提交
3211 3212
    if (contents == 3) {
        if (oldmode)
3213
            return -TARGET_EINVAL;
B
bellard 已提交
3214
        if (seg_not_present == 0)
3215
            return -TARGET_EINVAL;
B
bellard 已提交
3216 3217 3218
    }
    /* allocate the LDT */
    if (!ldt_table) {
3219 3220 3221 3222 3223
        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)
3224
            return -TARGET_ENOMEM;
3225 3226
        memset(g2h(env->ldt.base), 0,
               TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
B
bellard 已提交
3227
        env->ldt.limit = 0xffff;
3228
        ldt_table = g2h(env->ldt.base);
B
bellard 已提交
3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245
    }

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

B
bellard 已提交
3247 3248 3249 3250 3251 3252 3253 3254 3255 3256
    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 已提交
3257
        (lm << 21) |
B
bellard 已提交
3258 3259 3260
        0x7000;
    if (!oldmode)
        entry_2 |= (useable << 20);
B
bellard 已提交
3261

B
bellard 已提交
3262 3263 3264 3265 3266 3267 3268 3269 3270
    /* 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 */
3271 3272
static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
                              unsigned long bytecount)
B
bellard 已提交
3273
{
3274
    abi_long ret;
3275

B
bellard 已提交
3276 3277 3278 3279 3280 3281 3282 3283 3284 3285
    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;
3286 3287 3288
    default:
        ret = -TARGET_ENOSYS;
        break;
B
bellard 已提交
3289 3290 3291
    }
    return ret;
}
B
bellard 已提交
3292

3293
#if defined(TARGET_I386) && defined(TARGET_ABI32)
3294
static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
B
bellard 已提交
3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378
{
    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;
}

3379
static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
B
bellard 已提交
3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424
{
    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;
}
3425
#endif /* TARGET_I386 && TARGET_ABI32 */
B
bellard 已提交
3426

B
bellard 已提交
3427
#ifndef TARGET_ABI32
3428
static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
B
bellard 已提交
3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461
{
    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

3462 3463
#endif /* defined(TARGET_I386) */

3464
#if defined(CONFIG_USE_NPTL)
P
pbrook 已提交
3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483

#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;
3484
    TaskState *ts;
P
pbrook 已提交
3485 3486 3487

    env = info->env;
    thread_env = env;
3488
    ts = (TaskState *)thread_env->opaque;
P
pbrook 已提交
3489
    info->tid = gettid();
3490
    env->host_tid = info->tid;
3491
    task_settid(ts);
P
pbrook 已提交
3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509
    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 已提交
3510 3511 3512 3513 3514 3515
/* 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)
{
3516
    CPUState *env = arg;
B
bellard 已提交
3517 3518 3519 3520
    cpu_loop(env);
    /* never exits */
    return 0;
}
P
pbrook 已提交
3521
#endif
B
bellard 已提交
3522

3523 3524
/* do_fork() Must return host values and target errnos (unlike most
   do_*() functions). */
P
pbrook 已提交
3525 3526 3527
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 已提交
3528 3529
{
    int ret;
B
bellard 已提交
3530
    TaskState *ts;
B
bellard 已提交
3531
    uint8_t *new_stack;
3532
    CPUState *new_env;
3533
#if defined(CONFIG_USE_NPTL)
P
pbrook 已提交
3534 3535 3536
    unsigned int nptl_flags;
    sigset_t sigmask;
#endif
3537

3538 3539 3540 3541
    /* Emulate vfork() with fork() */
    if (flags & CLONE_VFORK)
        flags &= ~(CLONE_VFORK | CLONE_VM);

B
bellard 已提交
3542
    if (flags & CLONE_VM) {
3543
        TaskState *parent_ts = (TaskState *)env->opaque;
3544
#if defined(CONFIG_USE_NPTL)
P
pbrook 已提交
3545 3546
        new_thread_info info;
        pthread_attr_t attr;
3547
#endif
3548
        ts = qemu_mallocz(sizeof(TaskState) + NEW_STACK_SIZE);
P
pbrook 已提交
3549
        init_task_state(ts);
B
bellard 已提交
3550
        new_stack = ts->stack;
B
bellard 已提交
3551
        /* we create a new CPU instance. */
3552
        new_env = cpu_copy(env);
3553 3554
        /* Init regs that differ from the parent.  */
        cpu_clone_regs(new_env, newsp);
B
bellard 已提交
3555
        new_env->opaque = ts;
3556 3557
        ts->bprm = parent_ts->bprm;
        ts->info = parent_ts->info;
3558
#if defined(CONFIG_USE_NPTL)
P
pbrook 已提交
3559 3560 3561
        nptl_flags = flags;
        flags &= ~CLONE_NPTL_FLAGS2;

3562 3563 3564 3565
        if (nptl_flags & CLONE_CHILD_CLEARTID) {
            ts->child_tidptr = child_tidptr;
        }

P
pbrook 已提交
3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589
        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);
3590
        /* TODO: Free new CPU state if thread creation failed.  */
P
pbrook 已提交
3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610

        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.  */
3611
#ifdef __ia64__
B
bellard 已提交
3612
        ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
3613 3614
#else
	ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
P
pbrook 已提交
3615
#endif
3616
#endif
B
bellard 已提交
3617 3618
    } else {
        /* if no CLONE_VM, we consider it is a fork */
P
pbrook 已提交
3619
        if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
B
bellard 已提交
3620
            return -EINVAL;
P
pbrook 已提交
3621
        fork_start();
B
bellard 已提交
3622
        ret = fork();
P
pbrook 已提交
3623
        if (ret == 0) {
3624
            /* Child Process.  */
P
pbrook 已提交
3625 3626
            cpu_clone_regs(env, newsp);
            fork_end(1);
3627
#if defined(CONFIG_USE_NPTL)
3628 3629 3630 3631 3632 3633
            /* 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 已提交
3634 3635 3636 3637 3638 3639 3640
            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);
3641 3642
            if (flags & CLONE_CHILD_CLEARTID)
                ts->child_tidptr = child_tidptr;
3643
#endif
P
pbrook 已提交
3644 3645 3646
        } else {
            fork_end(0);
        }
B
bellard 已提交
3647 3648 3649 3650
    }
    return ret;
}

3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688
/* warning : doesn't handle linux specific flags... */
static int target_to_host_fcntl_cmd(int cmd)
{
    switch(cmd) {
	case TARGET_F_DUPFD:
	case TARGET_F_GETFD:
	case TARGET_F_SETFD:
	case TARGET_F_GETFL:
	case TARGET_F_SETFL:
            return cmd;
        case TARGET_F_GETLK:
	    return F_GETLK;
	case TARGET_F_SETLK:
	    return F_SETLK;
	case TARGET_F_SETLKW:
	    return F_SETLKW;
	case TARGET_F_GETOWN:
	    return F_GETOWN;
	case TARGET_F_SETOWN:
	    return F_SETOWN;
	case TARGET_F_GETSIG:
	    return F_GETSIG;
	case TARGET_F_SETSIG:
	    return F_SETSIG;
#if TARGET_ABI_BITS == 32
        case TARGET_F_GETLK64:
	    return F_GETLK64;
	case TARGET_F_SETLK64:
	    return F_SETLK64;
	case TARGET_F_SETLKW64:
	    return F_SETLKW64;
#endif
	default:
            return -TARGET_EINVAL;
    }
    return -TARGET_EINVAL;
}

3689
static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
B
bellard 已提交
3690 3691
{
    struct flock fl;
3692
    struct target_flock *target_fl;
3693 3694
    struct flock64 fl64;
    struct target_flock64 *target_fl64;
3695
    abi_long ret;
3696 3697 3698 3699
    int host_cmd = target_to_host_fcntl_cmd(cmd);

    if (host_cmd == -TARGET_EINVAL)
	    return host_cmd;
3700

B
bellard 已提交
3701 3702
    switch(cmd) {
    case TARGET_F_GETLK:
3703 3704
        if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
            return -TARGET_EFAULT;
T
ths 已提交
3705 3706 3707 3708 3709 3710
        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);
3711
        ret = get_errno(fcntl(fd, host_cmd, &fl));
B
bellard 已提交
3712
        if (ret == 0) {
3713 3714
            if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
                return -TARGET_EFAULT;
B
bellard 已提交
3715 3716 3717 3718 3719
            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);
3720
            unlock_user_struct(target_fl, arg, 1);
B
bellard 已提交
3721 3722
        }
        break;
3723

B
bellard 已提交
3724 3725
    case TARGET_F_SETLK:
    case TARGET_F_SETLKW:
3726 3727
        if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
            return -TARGET_EFAULT;
B
bellard 已提交
3728 3729 3730 3731 3732
        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);
3733
        unlock_user_struct(target_fl, arg, 0);
3734
        ret = get_errno(fcntl(fd, host_cmd, &fl));
B
bellard 已提交
3735
        break;
3736

B
bellard 已提交
3737
    case TARGET_F_GETLK64:
3738 3739
        if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
            return -TARGET_EFAULT;
T
ths 已提交
3740 3741 3742 3743 3744 3745
        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);
3746
        ret = get_errno(fcntl(fd, host_cmd, &fl64));
3747
        if (ret == 0) {
3748 3749
            if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
                return -TARGET_EFAULT;
3750 3751 3752 3753 3754 3755 3756
            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 已提交
3757
        break;
B
bellard 已提交
3758 3759
    case TARGET_F_SETLK64:
    case TARGET_F_SETLKW64:
3760 3761
        if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
            return -TARGET_EFAULT;
3762 3763 3764 3765 3766 3767
        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);
3768
        ret = get_errno(fcntl(fd, host_cmd, &fl64));
B
bellard 已提交
3769 3770
        break;

3771 3772
    case TARGET_F_GETFL:
        ret = get_errno(fcntl(fd, host_cmd, arg));
B
bellard 已提交
3773 3774 3775
        if (ret >= 0) {
            ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
        }
B
bellard 已提交
3776 3777
        break;

3778 3779 3780 3781 3782 3783 3784 3785 3786
    case TARGET_F_SETFL:
        ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
        break;

    case TARGET_F_SETOWN:
    case TARGET_F_GETOWN:
    case TARGET_F_SETSIG:
    case TARGET_F_GETSIG:
        ret = get_errno(fcntl(fd, host_cmd, arg));
B
bellard 已提交
3787 3788
        break;

B
bellard 已提交
3789
    default:
B
bellard 已提交
3790
        ret = get_errno(fcntl(fd, cmd, arg));
B
bellard 已提交
3791 3792 3793 3794 3795
        break;
    }
    return ret;
}

3796
#ifdef USE_UID16
B
bellard 已提交
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 3822 3823 3824 3825 3826 3827 3828 3829 3830
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 已提交
3831

3832 3833
void syscall_init(void)
{
3834 3835 3836
    IOCTLEntry *ie;
    const argtype *arg_type;
    int size;
3837
    int i;
3838

3839
#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
3840
#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
3841 3842 3843
#include "syscall_types.h"
#undef STRUCT
#undef STRUCT_SPECIAL
3844 3845 3846 3847 3848 3849 3850 3851 3852

    /* 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) {
3853
                fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
3854 3855 3856 3857 3858
                        ie->target_cmd);
                exit(1);
            }
            arg_type++;
            size = thunk_type_size(arg_type, 0);
3859
            ie->target_cmd = (ie->target_cmd &
3860 3861 3862
                              ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
                (size << TARGET_IOC_SIZESHIFT);
        }
3863 3864 3865 3866 3867 3868

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

3869
        /* automatic consistency check if same arch */
3870 3871 3872 3873 3874
#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);
3875 3876 3877 3878
        }
#endif
        ie++;
    }
3879
}
B
bellard 已提交
3880

3881
#if TARGET_ABI_BITS == 32
P
pbrook 已提交
3882 3883
static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
{
T
ths 已提交
3884
#ifdef TARGET_WORDS_BIGENDIAN
P
pbrook 已提交
3885 3886 3887 3888 3889
    return ((uint64_t)word0 << 32) | word1;
#else
    return ((uint64_t)word1 << 32) | word0;
#endif
}
3890
#else /* TARGET_ABI_BITS == 32 */
3891 3892 3893 3894
static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
{
    return word0;
}
3895
#endif /* TARGET_ABI_BITS != 32 */
P
pbrook 已提交
3896 3897

#ifdef TARGET_NR_truncate64
3898 3899 3900 3901
static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
                                         abi_long arg2,
                                         abi_long arg3,
                                         abi_long arg4)
P
pbrook 已提交
3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914
{
#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
3915 3916 3917 3918
static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
                                          abi_long arg2,
                                          abi_long arg3,
                                          abi_long arg4)
P
pbrook 已提交
3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930
{
#ifdef TARGET_ARM
    if (((CPUARMState *)cpu_env)->eabi)
      {
        arg2 = arg3;
        arg3 = arg4;
      }
#endif
    return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
}
#endif

3931 3932
static inline abi_long target_to_host_timespec(struct timespec *host_ts,
                                               abi_ulong target_addr)
3933 3934 3935
{
    struct target_timespec *target_ts;

3936 3937
    if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
        return -TARGET_EFAULT;
3938 3939 3940
    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 已提交
3941
    return 0;
3942 3943
}

3944 3945
static inline abi_long host_to_target_timespec(abi_ulong target_addr,
                                               struct timespec *host_ts)
3946 3947 3948
{
    struct target_timespec *target_ts;

3949 3950
    if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
        return -TARGET_EFAULT;
3951 3952 3953
    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 已提交
3954
    return 0;
3955 3956
}

3957
#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988
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
    {
3989 3990 3991
#if TARGET_LONG_BITS == 64
        struct target_stat *target_st;
#else
3992
        struct target_stat64 *target_st;
3993
#endif
3994 3995 3996

        if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
            return -TARGET_EFAULT;
3997
        memset(target_st, 0, sizeof(*target_st));
3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021
        __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

4022
#if defined(CONFIG_USE_NPTL)
4023 4024 4025 4026 4027
/* ??? 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.  */
4028 4029
static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
                    target_ulong uaddr2, int val3)
4030 4031
{
    struct timespec ts, *pts;
4032
    int base_op;
4033 4034 4035

    /* ??? We assume FUTEX_* constants are the same on both host
       and target.  */
4036
#ifdef FUTEX_CMD_MASK
4037
    base_op = op & FUTEX_CMD_MASK;
4038
#else
4039
    base_op = op;
4040
#endif
4041
    switch (base_op) {
4042 4043 4044 4045 4046 4047 4048
    case FUTEX_WAIT:
        if (timeout) {
            pts = &ts;
            target_to_host_timespec(pts, timeout);
        } else {
            pts = NULL;
        }
4049
        return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
4050 4051
                         pts, NULL, 0));
    case FUTEX_WAKE:
4052
        return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
4053
    case FUTEX_FD:
4054
        return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
4055 4056
    case FUTEX_REQUEUE:
    case FUTEX_CMP_REQUEUE:
4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068
    case FUTEX_WAKE_OP:
        /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
           TIMEOUT parameter is interpreted as a uint32_t by the kernel.
           But the prototype takes a `struct timespec *'; insert casts
           to satisfy the compiler.  We do not need to tswap TIMEOUT
           since it's not compared to guest memory.  */
        pts = (struct timespec *)(uintptr_t) timeout;
        return get_errno(sys_futex(g2h(uaddr), op, val, pts,
                                   g2h(uaddr2),
                                   (base_op == FUTEX_CMP_REQUEUE
                                    ? tswap32(val3)
                                    : val3)));
4069 4070 4071 4072 4073 4074
    default:
        return -TARGET_ENOSYS;
    }
}
#endif

P
pbrook 已提交
4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088
/* 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 已提交
4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119
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;
}

4120 4121 4122
/* 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>. */
4123 4124 4125
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)
4126
{
4127
    abi_long ret;
4128
    struct stat st;
B
bellard 已提交
4129
    struct statfs stfs;
4130
    void *p;
4131

B
bellard 已提交
4132
#ifdef DEBUG
B
bellard 已提交
4133
    gemu_log("syscall %d", num);
B
bellard 已提交
4134
#endif
4135 4136 4137
    if(do_strace)
        print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);

4138 4139
    switch(num) {
    case TARGET_NR_exit:
4140
#ifdef CONFIG_USE_NPTL
4141 4142 4143 4144 4145 4146 4147
      /* 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) {
4148
          TaskState *ts;
4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165
          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();
4166
          ts = ((CPUState *)cpu_env)->opaque;
4167 4168 4169 4170 4171 4172 4173 4174 4175
          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
4176
#ifdef TARGET_GPROF
B
bellard 已提交
4177 4178
        _mcleanup();
#endif
4179
        gdb_exit(cpu_env, arg1);
4180
        _exit(arg1);
4181 4182 4183
        ret = 0; /* avoid warning */
        break;
    case TARGET_NR_read:
4184 4185 4186 4187 4188 4189 4190 4191
        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);
        }
4192 4193
        break;
    case TARGET_NR_write:
4194 4195
        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
            goto efault;
4196 4197
        ret = get_errno(write(arg1, p, arg3));
        unlock_user(p, arg2, 0);
4198 4199
        break;
    case TARGET_NR_open:
4200 4201
        if (!(p = lock_user_string(arg1)))
            goto efault;
4202
        ret = get_errno(open(path(p),
B
bellard 已提交
4203 4204
                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
                             arg3));
4205
        unlock_user(p, arg1, 0);
4206
        break;
4207 4208
#if defined(TARGET_NR_openat) && defined(__NR_openat)
    case TARGET_NR_openat:
4209 4210 4211 4212 4213 4214 4215
        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);
4216 4217
        break;
#endif
4218 4219 4220 4221
    case TARGET_NR_close:
        ret = get_errno(close(arg1));
        break;
    case TARGET_NR_brk:
4222
        ret = do_brk(arg1);
4223 4224
        break;
    case TARGET_NR_fork:
P
pbrook 已提交
4225
        ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
4226
        break;
4227
#ifdef TARGET_NR_waitpid
4228 4229
    case TARGET_NR_waitpid:
        {
4230 4231
            int status;
            ret = get_errno(waitpid(arg1, &status, arg3));
4232
            if (!is_error(ret) && arg2
P
pbrook 已提交
4233
                && put_user_s32(host_to_target_waitstatus(status), arg2))
4234
                goto efault;
4235 4236
        }
        break;
4237
#endif
P
pbrook 已提交
4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252
#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
4253
#ifdef TARGET_NR_creat /* not on alpha */
4254
    case TARGET_NR_creat:
4255 4256
        if (!(p = lock_user_string(arg1)))
            goto efault;
4257 4258
        ret = get_errno(creat(p, arg2));
        unlock_user(p, arg1, 0);
4259
        break;
4260
#endif
4261
    case TARGET_NR_link:
4262 4263 4264 4265
        {
            void * p2;
            p = lock_user_string(arg1);
            p2 = lock_user_string(arg2);
4266 4267 4268 4269
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(link(p, p2));
4270 4271 4272
            unlock_user(p2, arg2, 0);
            unlock_user(p, arg1, 0);
        }
4273
        break;
4274 4275 4276 4277
#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
    case TARGET_NR_linkat:
        {
            void * p2 = NULL;
4278 4279
            if (!arg2 || !arg4)
                goto efault;
4280 4281
            p  = lock_user_string(arg2);
            p2 = lock_user_string(arg4);
4282
            if (!p || !p2)
4283
                ret = -TARGET_EFAULT;
4284 4285
            else
                ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
4286 4287
            unlock_user(p, arg2, 0);
            unlock_user(p2, arg4, 0);
4288 4289 4290
        }
        break;
#endif
4291
    case TARGET_NR_unlink:
4292 4293
        if (!(p = lock_user_string(arg1)))
            goto efault;
4294 4295
        ret = get_errno(unlink(p));
        unlock_user(p, arg1, 0);
4296
        break;
4297 4298
#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
    case TARGET_NR_unlinkat:
4299 4300 4301 4302
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_unlinkat(arg1, p, arg3));
        unlock_user(p, arg2, 0);
4303
        break;
4304
#endif
4305
    case TARGET_NR_execve:
B
bellard 已提交
4306 4307
        {
            char **argp, **envp;
B
bellard 已提交
4308
            int argc, envc;
4309 4310 4311 4312
            abi_ulong gp;
            abi_ulong guest_argp;
            abi_ulong guest_envp;
            abi_ulong addr;
B
bellard 已提交
4313 4314
            char **q;

B
bellard 已提交
4315
            argc = 0;
4316
            guest_argp = arg2;
4317
            for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
4318
                if (get_user_ual(addr, gp))
4319
                    goto efault;
4320
                if (!addr)
4321
                    break;
B
bellard 已提交
4322
                argc++;
4323
            }
B
bellard 已提交
4324
            envc = 0;
4325
            guest_envp = arg3;
4326
            for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
4327
                if (get_user_ual(addr, gp))
4328
                    goto efault;
4329
                if (!addr)
4330
                    break;
B
bellard 已提交
4331
                envc++;
4332
            }
B
bellard 已提交
4333

B
bellard 已提交
4334 4335
            argp = alloca((argc + 1) * sizeof(void *));
            envp = alloca((envc + 1) * sizeof(void *));
B
bellard 已提交
4336

4337
            for (gp = guest_argp, q = argp; gp;
4338
                  gp += sizeof(abi_ulong), q++) {
4339 4340
                if (get_user_ual(addr, gp))
                    goto execve_efault;
4341 4342
                if (!addr)
                    break;
4343 4344
                if (!(*q = lock_user_string(addr)))
                    goto execve_efault;
4345
            }
B
bellard 已提交
4346 4347
            *q = NULL;

4348
            for (gp = guest_envp, q = envp; gp;
4349
                  gp += sizeof(abi_ulong), q++) {
4350 4351
                if (get_user_ual(addr, gp))
                    goto execve_efault;
4352 4353
                if (!addr)
                    break;
4354 4355
                if (!(*q = lock_user_string(addr)))
                    goto execve_efault;
4356
            }
B
bellard 已提交
4357
            *q = NULL;
B
bellard 已提交
4358

4359 4360
            if (!(p = lock_user_string(arg1)))
                goto execve_efault;
4361 4362 4363
            ret = get_errno(execve(p, argp, envp));
            unlock_user(p, arg1, 0);

4364 4365 4366 4367 4368 4369
            goto execve_end;

        execve_efault:
            ret = -TARGET_EFAULT;

        execve_end:
4370
            for (gp = guest_argp, q = argp; *q;
4371
                  gp += sizeof(abi_ulong), q++) {
4372 4373 4374
                if (get_user_ual(addr, gp)
                    || !addr)
                    break;
4375 4376 4377
                unlock_user(*q, addr, 0);
            }
            for (gp = guest_envp, q = envp; *q;
4378
                  gp += sizeof(abi_ulong), q++) {
4379 4380 4381
                if (get_user_ual(addr, gp)
                    || !addr)
                    break;
4382 4383
                unlock_user(*q, addr, 0);
            }
B
bellard 已提交
4384
        }
4385 4386
        break;
    case TARGET_NR_chdir:
4387 4388
        if (!(p = lock_user_string(arg1)))
            goto efault;
4389 4390
        ret = get_errno(chdir(p));
        unlock_user(p, arg1, 0);
4391
        break;
B
bellard 已提交
4392
#ifdef TARGET_NR_time
4393 4394
    case TARGET_NR_time:
        {
4395 4396
            time_t host_time;
            ret = get_errno(time(&host_time));
4397 4398 4399 4400
            if (!is_error(ret)
                && arg1
                && put_user_sal(host_time, arg1))
                goto efault;
4401 4402
        }
        break;
B
bellard 已提交
4403
#endif
4404
    case TARGET_NR_mknod:
4405 4406
        if (!(p = lock_user_string(arg1)))
            goto efault;
4407 4408
        ret = get_errno(mknod(p, arg2, arg3));
        unlock_user(p, arg1, 0);
4409
        break;
4410 4411
#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
    case TARGET_NR_mknodat:
4412 4413 4414 4415
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
        unlock_user(p, arg2, 0);
4416 4417
        break;
#endif
4418
    case TARGET_NR_chmod:
4419 4420
        if (!(p = lock_user_string(arg1)))
            goto efault;
4421 4422
        ret = get_errno(chmod(p, arg2));
        unlock_user(p, arg1, 0);
4423
        break;
4424
#ifdef TARGET_NR_break
4425 4426
    case TARGET_NR_break:
        goto unimplemented;
4427 4428
#endif
#ifdef TARGET_NR_oldstat
4429 4430
    case TARGET_NR_oldstat:
        goto unimplemented;
4431
#endif
4432 4433 4434
    case TARGET_NR_lseek:
        ret = get_errno(lseek(arg1, arg2, arg3));
        break;
4435 4436 4437
#ifdef TARGET_NR_getxpid
    case TARGET_NR_getxpid:
#else
4438
    case TARGET_NR_getpid:
4439
#endif
4440 4441 4442
        ret = get_errno(getpid());
        break;
    case TARGET_NR_mount:
4443 4444 4445 4446 4447 4448
		{
			/* 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);
4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459
                        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);
4460 4461
			break;
		}
4462
#ifdef TARGET_NR_umount
4463
    case TARGET_NR_umount:
4464 4465
        if (!(p = lock_user_string(arg1)))
            goto efault;
4466 4467
        ret = get_errno(umount(p));
        unlock_user(p, arg1, 0);
4468
        break;
4469
#endif
4470
#ifdef TARGET_NR_stime /* not on alpha */
4471 4472
    case TARGET_NR_stime:
        {
4473
            time_t host_time;
4474 4475
            if (get_user_sal(host_time, arg1))
                goto efault;
4476
            ret = get_errno(stime(&host_time));
4477 4478
        }
        break;
4479
#endif
4480 4481
    case TARGET_NR_ptrace:
        goto unimplemented;
4482
#ifdef TARGET_NR_alarm /* not on alpha */
4483 4484 4485
    case TARGET_NR_alarm:
        ret = alarm(arg1);
        break;
4486
#endif
4487
#ifdef TARGET_NR_oldfstat
4488 4489
    case TARGET_NR_oldfstat:
        goto unimplemented;
4490
#endif
4491
#ifdef TARGET_NR_pause /* not on alpha */
4492 4493 4494
    case TARGET_NR_pause:
        ret = get_errno(pause());
        break;
4495
#endif
4496
#ifdef TARGET_NR_utime
4497
    case TARGET_NR_utime:
4498
        {
4499 4500 4501
            struct utimbuf tbuf, *host_tbuf;
            struct target_utimbuf *target_tbuf;
            if (arg2) {
4502 4503
                if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
                    goto efault;
4504 4505 4506 4507
                tbuf.actime = tswapl(target_tbuf->actime);
                tbuf.modtime = tswapl(target_tbuf->modtime);
                unlock_user_struct(target_tbuf, arg2, 0);
                host_tbuf = &tbuf;
B
bellard 已提交
4508
            } else {
4509
                host_tbuf = NULL;
B
bellard 已提交
4510
            }
4511 4512
            if (!(p = lock_user_string(arg1)))
                goto efault;
4513 4514
            ret = get_errno(utime(p, host_tbuf));
            unlock_user(p, arg1, 0);
4515 4516
        }
        break;
4517
#endif
B
bellard 已提交
4518 4519 4520
    case TARGET_NR_utimes:
        {
            struct timeval *tvp, tv[2];
4521
            if (arg2) {
4522 4523 4524 4525
                if (copy_from_user_timeval(&tv[0], arg2)
                    || copy_from_user_timeval(&tv[1],
                                              arg2 + sizeof(struct target_timeval)))
                    goto efault;
B
bellard 已提交
4526 4527 4528 4529
                tvp = tv;
            } else {
                tvp = NULL;
            }
4530 4531
            if (!(p = lock_user_string(arg1)))
                goto efault;
4532 4533
            ret = get_errno(utimes(p, tvp));
            unlock_user(p, arg1, 0);
B
bellard 已提交
4534 4535
        }
        break;
4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555
#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
4556
#ifdef TARGET_NR_stty
4557 4558
    case TARGET_NR_stty:
        goto unimplemented;
4559 4560
#endif
#ifdef TARGET_NR_gtty
4561 4562
    case TARGET_NR_gtty:
        goto unimplemented;
4563
#endif
4564
    case TARGET_NR_access:
4565 4566
        if (!(p = lock_user_string(arg1)))
            goto efault;
U
Ulrich Hecht 已提交
4567
        ret = get_errno(access(path(p), arg2));
4568
        unlock_user(p, arg1, 0);
4569
        break;
4570 4571
#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
    case TARGET_NR_faccessat:
4572 4573
        if (!(p = lock_user_string(arg2)))
            goto efault;
4574
        ret = get_errno(sys_faccessat(arg1, p, arg3));
4575
        unlock_user(p, arg2, 0);
4576 4577
        break;
#endif
4578
#ifdef TARGET_NR_nice /* not on alpha */
4579 4580 4581
    case TARGET_NR_nice:
        ret = get_errno(nice(arg1));
        break;
4582
#endif
4583
#ifdef TARGET_NR_ftime
4584 4585
    case TARGET_NR_ftime:
        goto unimplemented;
4586
#endif
4587
    case TARGET_NR_sync:
B
bellard 已提交
4588 4589
        sync();
        ret = 0;
4590 4591
        break;
    case TARGET_NR_kill:
4592
        ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
4593 4594
        break;
    case TARGET_NR_rename:
4595 4596 4597 4598
        {
            void *p2;
            p = lock_user_string(arg1);
            p2 = lock_user_string(arg2);
4599 4600 4601 4602
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(rename(p, p2));
4603 4604 4605
            unlock_user(p2, arg2, 0);
            unlock_user(p, arg1, 0);
        }
4606
        break;
4607 4608 4609
#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
    case TARGET_NR_renameat:
        {
4610
            void *p2;
4611 4612
            p  = lock_user_string(arg2);
            p2 = lock_user_string(arg4);
4613
            if (!p || !p2)
4614
                ret = -TARGET_EFAULT;
4615 4616
            else
                ret = get_errno(sys_renameat(arg1, p, arg3, p2));
4617 4618
            unlock_user(p2, arg4, 0);
            unlock_user(p, arg2, 0);
4619 4620 4621
        }
        break;
#endif
4622
    case TARGET_NR_mkdir:
4623 4624
        if (!(p = lock_user_string(arg1)))
            goto efault;
4625 4626
        ret = get_errno(mkdir(p, arg2));
        unlock_user(p, arg1, 0);
4627
        break;
4628 4629
#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
    case TARGET_NR_mkdirat:
4630 4631 4632 4633
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_mkdirat(arg1, p, arg3));
        unlock_user(p, arg2, 0);
4634 4635
        break;
#endif
4636
    case TARGET_NR_rmdir:
4637 4638
        if (!(p = lock_user_string(arg1)))
            goto efault;
4639 4640
        ret = get_errno(rmdir(p));
        unlock_user(p, arg1, 0);
4641 4642 4643 4644 4645
        break;
    case TARGET_NR_dup:
        ret = get_errno(dup(arg1));
        break;
    case TARGET_NR_pipe:
R
Riku Voipio 已提交
4646 4647 4648 4649 4650
        ret = do_pipe(cpu_env, arg1, 0);
        break;
#ifdef TARGET_NR_pipe2
    case TARGET_NR_pipe2:
        ret = do_pipe(cpu_env, arg1, arg2);
4651
        break;
R
Riku Voipio 已提交
4652
#endif
4653
    case TARGET_NR_times:
B
bellard 已提交
4654
        {
4655
            struct target_tms *tmsp;
B
bellard 已提交
4656 4657
            struct tms tms;
            ret = get_errno(times(&tms));
4658
            if (arg1) {
4659 4660 4661
                tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
                if (!tmsp)
                    goto efault;
B
bellard 已提交
4662 4663 4664 4665
                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 已提交
4666
            }
B
bellard 已提交
4667 4668
            if (!is_error(ret))
                ret = host_to_target_clock_t(ret);
B
bellard 已提交
4669 4670
        }
        break;
4671
#ifdef TARGET_NR_prof
4672 4673
    case TARGET_NR_prof:
        goto unimplemented;
4674
#endif
4675
#ifdef TARGET_NR_signal
4676 4677
    case TARGET_NR_signal:
        goto unimplemented;
4678
#endif
4679
    case TARGET_NR_acct:
4680 4681 4682 4683 4684 4685 4686 4687
        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);
        }
4688
        break;
4689
#ifdef TARGET_NR_umount2 /* not on alpha */
4690
    case TARGET_NR_umount2:
4691 4692
        if (!(p = lock_user_string(arg1)))
            goto efault;
4693 4694
        ret = get_errno(umount2(p, arg2));
        unlock_user(p, arg1, 0);
4695
        break;
4696
#endif
4697
#ifdef TARGET_NR_lock
4698 4699
    case TARGET_NR_lock:
        goto unimplemented;
4700
#endif
4701 4702 4703 4704
    case TARGET_NR_ioctl:
        ret = do_ioctl(arg1, arg2, arg3);
        break;
    case TARGET_NR_fcntl:
B
bellard 已提交
4705
        ret = do_fcntl(arg1, arg2, arg3);
4706
        break;
4707
#ifdef TARGET_NR_mpx
4708 4709
    case TARGET_NR_mpx:
        goto unimplemented;
4710
#endif
4711 4712 4713
    case TARGET_NR_setpgid:
        ret = get_errno(setpgid(arg1, arg2));
        break;
4714
#ifdef TARGET_NR_ulimit
4715 4716
    case TARGET_NR_ulimit:
        goto unimplemented;
4717 4718
#endif
#ifdef TARGET_NR_oldolduname
4719 4720
    case TARGET_NR_oldolduname:
        goto unimplemented;
4721
#endif
4722 4723 4724 4725
    case TARGET_NR_umask:
        ret = get_errno(umask(arg1));
        break;
    case TARGET_NR_chroot:
4726 4727
        if (!(p = lock_user_string(arg1)))
            goto efault;
4728 4729
        ret = get_errno(chroot(p));
        unlock_user(p, arg1, 0);
4730 4731 4732 4733 4734 4735
        break;
    case TARGET_NR_ustat:
        goto unimplemented;
    case TARGET_NR_dup2:
        ret = get_errno(dup2(arg1, arg2));
        break;
4736
#ifdef TARGET_NR_getppid /* not on alpha */
4737 4738 4739
    case TARGET_NR_getppid:
        ret = get_errno(getppid());
        break;
4740
#endif
4741 4742 4743 4744 4745 4746
    case TARGET_NR_getpgrp:
        ret = get_errno(getpgrp());
        break;
    case TARGET_NR_setsid:
        ret = get_errno(setsid());
        break;
4747
#ifdef TARGET_NR_sigaction
4748 4749
    case TARGET_NR_sigaction:
        {
T
ths 已提交
4750
#if !defined(TARGET_MIPS)
4751
            struct target_old_sigaction *old_act;
B
bellard 已提交
4752
            struct target_sigaction act, oact, *pact;
4753
            if (arg2) {
4754 4755
                if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
                    goto efault;
B
bellard 已提交
4756 4757 4758 4759
                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;
4760
                unlock_user_struct(old_act, arg2, 0);
B
bellard 已提交
4761 4762 4763 4764 4765
                pact = &act;
            } else {
                pact = NULL;
            }
            ret = get_errno(do_sigaction(arg1, pact, &oact));
4766
            if (!is_error(ret) && arg3) {
4767 4768
                if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
                    goto efault;
4769 4770 4771 4772 4773
                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 已提交
4774
            }
T
ths 已提交
4775
#else
4776 4777 4778
	    struct target_sigaction act, oact, *pact, *old_act;

	    if (arg2) {
4779 4780
                if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
                    goto efault;
4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792
		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) {
4793 4794
                if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
                    goto efault;
4795 4796 4797 4798 4799 4800 4801 4802
		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 已提交
4803
#endif
4804 4805
        }
        break;
4806
#endif
B
bellard 已提交
4807
    case TARGET_NR_rt_sigaction:
4808 4809 4810 4811
        {
            struct target_sigaction *act;
            struct target_sigaction *oact;

4812 4813 4814 4815
            if (arg2) {
                if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
                    goto efault;
            } else
4816
                act = NULL;
4817 4818 4819 4820 4821 4822
            if (arg3) {
                if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
                    ret = -TARGET_EFAULT;
                    goto rt_sigaction_fail;
                }
            } else
4823 4824
                oact = NULL;
            ret = get_errno(do_sigaction(arg1, act, oact));
4825 4826
	rt_sigaction_fail:
            if (act)
4827
                unlock_user_struct(act, arg2, 0);
4828
            if (oact)
4829 4830
                unlock_user_struct(oact, arg3, 1);
        }
B
bellard 已提交
4831
        break;
4832
#ifdef TARGET_NR_sgetmask /* not on alpha */
4833
    case TARGET_NR_sgetmask:
B
bellard 已提交
4834 4835
        {
            sigset_t cur_set;
4836
            abi_ulong target_set;
B
bellard 已提交
4837 4838 4839 4840 4841
            sigprocmask(0, NULL, &cur_set);
            host_to_target_old_sigset(&target_set, &cur_set);
            ret = target_set;
        }
        break;
4842 4843
#endif
#ifdef TARGET_NR_ssetmask /* not on alpha */
4844
    case TARGET_NR_ssetmask:
B
bellard 已提交
4845 4846
        {
            sigset_t set, oset, cur_set;
4847
            abi_ulong target_set = arg1;
B
bellard 已提交
4848 4849 4850 4851 4852 4853 4854 4855
            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;
4856
#endif
4857
#ifdef TARGET_NR_sigprocmask
B
bellard 已提交
4858 4859 4860 4861
    case TARGET_NR_sigprocmask:
        {
            int how = arg1;
            sigset_t set, oldset, *set_ptr;
4862

4863
            if (arg2) {
B
bellard 已提交
4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874
                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:
4875
                    ret = -TARGET_EINVAL;
B
bellard 已提交
4876 4877
                    goto fail;
                }
4878 4879
                if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
                    goto efault;
4880 4881
                target_to_host_old_sigset(&set, p);
                unlock_user(p, arg2, 0);
B
bellard 已提交
4882 4883 4884 4885 4886 4887
                set_ptr = &set;
            } else {
                how = 0;
                set_ptr = NULL;
            }
            ret = get_errno(sigprocmask(arg1, set_ptr, &oldset));
4888
            if (!is_error(ret) && arg3) {
4889 4890
                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
                    goto efault;
4891 4892
                host_to_target_old_sigset(p, &oldset);
                unlock_user(p, arg3, sizeof(target_sigset_t));
B
bellard 已提交
4893 4894 4895
            }
        }
        break;
4896
#endif
B
bellard 已提交
4897 4898 4899 4900
    case TARGET_NR_rt_sigprocmask:
        {
            int how = arg1;
            sigset_t set, oldset, *set_ptr;
4901

4902
            if (arg2) {
B
bellard 已提交
4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913
                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:
4914
                    ret = -TARGET_EINVAL;
B
bellard 已提交
4915 4916
                    goto fail;
                }
4917 4918
                if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
                    goto efault;
4919 4920
                target_to_host_sigset(&set, p);
                unlock_user(p, arg2, 0);
B
bellard 已提交
4921 4922 4923 4924 4925 4926
                set_ptr = &set;
            } else {
                how = 0;
                set_ptr = NULL;
            }
            ret = get_errno(sigprocmask(how, set_ptr, &oldset));
4927
            if (!is_error(ret) && arg3) {
4928 4929
                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
                    goto efault;
4930 4931
                host_to_target_sigset(p, &oldset);
                unlock_user(p, arg3, sizeof(target_sigset_t));
B
bellard 已提交
4932 4933 4934
            }
        }
        break;
4935
#ifdef TARGET_NR_sigpending
B
bellard 已提交
4936 4937 4938 4939 4940
    case TARGET_NR_sigpending:
        {
            sigset_t set;
            ret = get_errno(sigpending(&set));
            if (!is_error(ret)) {
4941 4942
                if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
                    goto efault;
4943 4944
                host_to_target_old_sigset(p, &set);
                unlock_user(p, arg1, sizeof(target_sigset_t));
B
bellard 已提交
4945 4946 4947
            }
        }
        break;
4948
#endif
B
bellard 已提交
4949 4950 4951 4952 4953
    case TARGET_NR_rt_sigpending:
        {
            sigset_t set;
            ret = get_errno(sigpending(&set));
            if (!is_error(ret)) {
4954 4955
                if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
                    goto efault;
4956 4957
                host_to_target_sigset(p, &set);
                unlock_user(p, arg1, sizeof(target_sigset_t));
B
bellard 已提交
4958 4959 4960
            }
        }
        break;
4961
#ifdef TARGET_NR_sigsuspend
B
bellard 已提交
4962 4963 4964
    case TARGET_NR_sigsuspend:
        {
            sigset_t set;
4965 4966
            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
                goto efault;
4967 4968
            target_to_host_old_sigset(&set, p);
            unlock_user(p, arg1, 0);
B
bellard 已提交
4969 4970 4971
            ret = get_errno(sigsuspend(&set));
        }
        break;
4972
#endif
B
bellard 已提交
4973 4974 4975
    case TARGET_NR_rt_sigsuspend:
        {
            sigset_t set;
4976 4977
            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
                goto efault;
4978 4979
            target_to_host_sigset(&set, p);
            unlock_user(p, arg1, 0);
B
bellard 已提交
4980 4981 4982 4983 4984 4985 4986 4987
            ret = get_errno(sigsuspend(&set));
        }
        break;
    case TARGET_NR_rt_sigtimedwait:
        {
            sigset_t set;
            struct timespec uts, *puts;
            siginfo_t uinfo;
4988

4989 4990
            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
                goto efault;
4991 4992 4993
            target_to_host_sigset(&set, p);
            unlock_user(p, arg1, 0);
            if (arg3) {
B
bellard 已提交
4994
                puts = &uts;
4995
                target_to_host_timespec(puts, arg3);
B
bellard 已提交
4996 4997 4998 4999
            } else {
                puts = NULL;
            }
            ret = get_errno(sigtimedwait(&set, &uinfo, puts));
5000
            if (!is_error(ret) && arg2) {
5001
                if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
5002
                    goto efault;
5003
                host_to_target_siginfo(p, &uinfo);
5004
                unlock_user(p, arg2, sizeof(target_siginfo_t));
B
bellard 已提交
5005 5006 5007 5008 5009 5010
            }
        }
        break;
    case TARGET_NR_rt_sigqueueinfo:
        {
            siginfo_t uinfo;
5011 5012
            if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
                goto efault;
5013 5014
            target_to_host_siginfo(&uinfo, p);
            unlock_user(p, arg1, 0);
B
bellard 已提交
5015 5016 5017
            ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
        }
        break;
5018
#ifdef TARGET_NR_sigreturn
B
bellard 已提交
5019 5020 5021 5022
    case TARGET_NR_sigreturn:
        /* NOTE: ret is eax, so not transcoding must be done */
        ret = do_sigreturn(cpu_env);
        break;
5023
#endif
B
bellard 已提交
5024 5025 5026 5027
    case TARGET_NR_rt_sigreturn:
        /* NOTE: ret is eax, so not transcoding must be done */
        ret = do_rt_sigreturn(cpu_env);
        break;
5028
    case TARGET_NR_sethostname:
5029 5030
        if (!(p = lock_user_string(arg1)))
            goto efault;
5031 5032
        ret = get_errno(sethostname(p, arg2));
        unlock_user(p, arg1, 0);
5033 5034
        break;
    case TARGET_NR_setrlimit:
B
bellard 已提交
5035 5036 5037
        {
            /* XXX: convert resource ? */
            int resource = arg1;
5038
            struct target_rlimit *target_rlim;
B
bellard 已提交
5039
            struct rlimit rlim;
5040 5041
            if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
                goto efault;
B
bellard 已提交
5042 5043
            rlim.rlim_cur = tswapl(target_rlim->rlim_cur);
            rlim.rlim_max = tswapl(target_rlim->rlim_max);
5044
            unlock_user_struct(target_rlim, arg2, 0);
B
bellard 已提交
5045 5046 5047
            ret = get_errno(setrlimit(resource, &rlim));
        }
        break;
5048
    case TARGET_NR_getrlimit:
B
bellard 已提交
5049 5050 5051
        {
            /* XXX: convert resource ? */
            int resource = arg1;
5052
            struct target_rlimit *target_rlim;
B
bellard 已提交
5053
            struct rlimit rlim;
5054

B
bellard 已提交
5055 5056
            ret = get_errno(getrlimit(resource, &rlim));
            if (!is_error(ret)) {
5057 5058
                if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
                    goto efault;
U
Ulrich Hecht 已提交
5059 5060
                target_rlim->rlim_cur = tswapl(rlim.rlim_cur);
                target_rlim->rlim_max = tswapl(rlim.rlim_max);
5061
                unlock_user_struct(target_rlim, arg2, 1);
B
bellard 已提交
5062 5063 5064
            }
        }
        break;
5065
    case TARGET_NR_getrusage:
B
bellard 已提交
5066 5067 5068 5069
        {
            struct rusage rusage;
            ret = get_errno(getrusage(arg1, &rusage));
            if (!is_error(ret)) {
5070
                host_to_target_rusage(arg2, &rusage);
B
bellard 已提交
5071 5072 5073
            }
        }
        break;
5074 5075 5076 5077 5078
    case TARGET_NR_gettimeofday:
        {
            struct timeval tv;
            ret = get_errno(gettimeofday(&tv, NULL));
            if (!is_error(ret)) {
5079 5080
                if (copy_to_user_timeval(arg1, &tv))
                    goto efault;
5081 5082 5083 5084 5085 5086
            }
        }
        break;
    case TARGET_NR_settimeofday:
        {
            struct timeval tv;
5087 5088
            if (copy_from_user_timeval(&tv, arg1))
                goto efault;
5089 5090 5091
            ret = get_errno(settimeofday(&tv, NULL));
        }
        break;
B
bellard 已提交
5092
#ifdef TARGET_NR_select
5093
    case TARGET_NR_select:
B
bellard 已提交
5094
        {
5095
            struct target_sel_arg_struct *sel;
5096
            abi_ulong inp, outp, exp, tvp;
5097 5098
            long nsel;

5099 5100
            if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
                goto efault;
5101 5102 5103 5104 5105 5106 5107
            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 已提交
5108 5109
        }
        break;
B
bellard 已提交
5110
#endif
5111
    case TARGET_NR_symlink:
5112 5113 5114 5115
        {
            void *p2;
            p = lock_user_string(arg1);
            p2 = lock_user_string(arg2);
5116 5117 5118 5119
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(symlink(p, p2));
5120 5121 5122
            unlock_user(p2, arg2, 0);
            unlock_user(p, arg1, 0);
        }
5123
        break;
5124 5125 5126
#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
    case TARGET_NR_symlinkat:
        {
5127
            void *p2;
5128 5129
            p  = lock_user_string(arg1);
            p2 = lock_user_string(arg3);
5130
            if (!p || !p2)
5131
                ret = -TARGET_EFAULT;
5132 5133
            else
                ret = get_errno(sys_symlinkat(p, arg2, p2));
5134 5135
            unlock_user(p2, arg3, 0);
            unlock_user(p, arg1, 0);
5136 5137 5138
        }
        break;
#endif
5139
#ifdef TARGET_NR_oldlstat
5140 5141
    case TARGET_NR_oldlstat:
        goto unimplemented;
5142
#endif
5143
    case TARGET_NR_readlink:
5144
        {
5145
            void *p2, *temp;
5146
            p = lock_user_string(arg1);
5147 5148 5149
            p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
            if (!p || !p2)
                ret = -TARGET_EFAULT;
5150 5151 5152 5153 5154 5155 5156 5157 5158 5159
            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));
            }
5160 5161 5162
            unlock_user(p2, arg2, ret);
            unlock_user(p, arg1, 0);
        }
5163
        break;
5164 5165 5166
#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
    case TARGET_NR_readlinkat:
        {
5167
            void *p2;
5168
            p  = lock_user_string(arg2);
5169 5170
            p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
            if (!p || !p2)
5171
        	ret = -TARGET_EFAULT;
5172 5173
            else
                ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
5174 5175
            unlock_user(p2, arg3, ret);
            unlock_user(p, arg2, 0);
5176 5177 5178
        }
        break;
#endif
5179
#ifdef TARGET_NR_uselib
5180 5181
    case TARGET_NR_uselib:
        goto unimplemented;
5182 5183
#endif
#ifdef TARGET_NR_swapon
5184
    case TARGET_NR_swapon:
5185 5186
        if (!(p = lock_user_string(arg1)))
            goto efault;
5187 5188
        ret = get_errno(swapon(p, arg2));
        unlock_user(p, arg1, 0);
5189
        break;
5190
#endif
5191 5192
    case TARGET_NR_reboot:
        goto unimplemented;
5193
#ifdef TARGET_NR_readdir
5194 5195
    case TARGET_NR_readdir:
        goto unimplemented;
5196 5197
#endif
#ifdef TARGET_NR_mmap
5198
    case TARGET_NR_mmap:
5199
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE)
5200
        {
5201 5202
            abi_ulong *v;
            abi_ulong v1, v2, v3, v4, v5, v6;
5203 5204
            if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
                goto efault;
5205 5206 5207 5208 5209 5210 5211
            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);
5212
            ret = get_errno(target_mmap(v1, v2, v3,
B
bellard 已提交
5213 5214
                                        target_to_host_bitmask(v4, mmap_flags_tbl),
                                        v5, v6));
5215 5216
        }
#else
5217 5218
        ret = get_errno(target_mmap(arg1, arg2, arg3,
                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
B
bellard 已提交
5219 5220
                                    arg5,
                                    arg6));
5221
#endif
B
bellard 已提交
5222
        break;
5223
#endif
B
bellard 已提交
5224
#ifdef TARGET_NR_mmap2
B
bellard 已提交
5225
    case TARGET_NR_mmap2:
P
pbrook 已提交
5226
#ifndef MMAP_SHIFT
B
bellard 已提交
5227 5228
#define MMAP_SHIFT 12
#endif
5229 5230
        ret = get_errno(target_mmap(arg1, arg2, arg3,
                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
B
bellard 已提交
5231
                                    arg5,
B
bellard 已提交
5232
                                    arg6 << MMAP_SHIFT));
5233
        break;
B
bellard 已提交
5234
#endif
5235
    case TARGET_NR_munmap:
B
bellard 已提交
5236
        ret = get_errno(target_munmap(arg1, arg2));
5237
        break;
B
bellard 已提交
5238
    case TARGET_NR_mprotect:
B
bellard 已提交
5239
        ret = get_errno(target_mprotect(arg1, arg2, arg3));
B
bellard 已提交
5240
        break;
5241
#ifdef TARGET_NR_mremap
B
bellard 已提交
5242
    case TARGET_NR_mremap:
B
bellard 已提交
5243
        ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
B
bellard 已提交
5244
        break;
5245
#endif
5246
        /* ??? msync/mlock/munlock are broken for softmmu.  */
5247
#ifdef TARGET_NR_msync
B
bellard 已提交
5248
    case TARGET_NR_msync:
5249
        ret = get_errno(msync(g2h(arg1), arg2, arg3));
B
bellard 已提交
5250
        break;
5251 5252
#endif
#ifdef TARGET_NR_mlock
B
bellard 已提交
5253
    case TARGET_NR_mlock:
5254
        ret = get_errno(mlock(g2h(arg1), arg2));
B
bellard 已提交
5255
        break;
5256 5257
#endif
#ifdef TARGET_NR_munlock
B
bellard 已提交
5258
    case TARGET_NR_munlock:
5259
        ret = get_errno(munlock(g2h(arg1), arg2));
B
bellard 已提交
5260
        break;
5261 5262
#endif
#ifdef TARGET_NR_mlockall
B
bellard 已提交
5263 5264 5265
    case TARGET_NR_mlockall:
        ret = get_errno(mlockall(arg1));
        break;
5266 5267
#endif
#ifdef TARGET_NR_munlockall
B
bellard 已提交
5268 5269 5270
    case TARGET_NR_munlockall:
        ret = get_errno(munlockall());
        break;
5271
#endif
5272
    case TARGET_NR_truncate:
5273 5274
        if (!(p = lock_user_string(arg1)))
            goto efault;
5275 5276
        ret = get_errno(truncate(p, arg2));
        unlock_user(p, arg1, 0);
5277 5278 5279 5280 5281 5282 5283
        break;
    case TARGET_NR_ftruncate:
        ret = get_errno(ftruncate(arg1, arg2));
        break;
    case TARGET_NR_fchmod:
        ret = get_errno(fchmod(arg1, arg2));
        break;
5284 5285
#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
    case TARGET_NR_fchmodat:
5286 5287
        if (!(p = lock_user_string(arg2)))
            goto efault;
5288
        ret = get_errno(sys_fchmodat(arg1, p, arg3));
5289
        unlock_user(p, arg2, 0);
5290 5291
        break;
#endif
5292
    case TARGET_NR_getpriority:
5293 5294 5295 5296
        /* 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);
5297 5298 5299 5300
        break;
    case TARGET_NR_setpriority:
        ret = get_errno(setpriority(arg1, arg2, arg3));
        break;
5301
#ifdef TARGET_NR_profil
5302 5303
    case TARGET_NR_profil:
        goto unimplemented;
5304
#endif
5305
    case TARGET_NR_statfs:
5306 5307
        if (!(p = lock_user_string(arg1)))
            goto efault;
5308 5309
        ret = get_errno(statfs(path(p), &stfs));
        unlock_user(p, arg1, 0);
5310 5311
    convert_statfs:
        if (!is_error(ret)) {
5312
            struct target_statfs *target_stfs;
5313

5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325
            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);
5326
            unlock_user_struct(target_stfs, arg2, 1);
5327 5328 5329
        }
        break;
    case TARGET_NR_fstatfs:
B
bellard 已提交
5330
        ret = get_errno(fstatfs(arg1, &stfs));
5331
        goto convert_statfs;
B
bellard 已提交
5332 5333
#ifdef TARGET_NR_statfs64
    case TARGET_NR_statfs64:
5334 5335
        if (!(p = lock_user_string(arg1)))
            goto efault;
5336 5337
        ret = get_errno(statfs(path(p), &stfs));
        unlock_user(p, arg1, 0);
B
bellard 已提交
5338 5339
    convert_statfs64:
        if (!is_error(ret)) {
5340
            struct target_statfs64 *target_stfs;
5341

5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354
            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 已提交
5355 5356 5357 5358 5359 5360
        }
        break;
    case TARGET_NR_fstatfs64:
        ret = get_errno(fstatfs(arg1, &stfs));
        goto convert_statfs64;
#endif
5361
#ifdef TARGET_NR_ioperm
5362 5363
    case TARGET_NR_ioperm:
        goto unimplemented;
5364
#endif
5365
#ifdef TARGET_NR_socketcall
5366
    case TARGET_NR_socketcall:
5367
        ret = do_socketcall(arg1, arg2);
5368
        break;
5369
#endif
5370 5371
#ifdef TARGET_NR_accept
    case TARGET_NR_accept:
P
pbrook 已提交
5372
        ret = do_accept(arg1, arg2, arg3);
5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386
        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 已提交
5387
        ret = do_getpeername(arg1, arg2, arg3);
5388 5389 5390 5391
        break;
#endif
#ifdef TARGET_NR_getsockname
    case TARGET_NR_getsockname:
P
pbrook 已提交
5392
        ret = do_getsockname(arg1, arg2, arg3);
5393 5394 5395 5396 5397 5398 5399 5400 5401
        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 已提交
5402
        ret = get_errno(listen(arg1, arg2));
5403 5404 5405 5406
        break;
#endif
#ifdef TARGET_NR_recv
    case TARGET_NR_recv:
P
pbrook 已提交
5407
        ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
5408 5409 5410 5411
        break;
#endif
#ifdef TARGET_NR_recvfrom
    case TARGET_NR_recvfrom:
P
pbrook 已提交
5412
        ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
5413 5414 5415 5416 5417 5418 5419 5420 5421
        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 已提交
5422
        ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
5423 5424 5425 5426 5427 5428 5429 5430 5431
        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 已提交
5432
        ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
5433 5434 5435 5436
        break;
#endif
#ifdef TARGET_NR_shutdown
    case TARGET_NR_shutdown:
P
pbrook 已提交
5437
        ret = get_errno(shutdown(arg1, arg2));
5438 5439 5440 5441 5442 5443 5444 5445 5446
        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 已提交
5447
        ret = do_socketpair(arg1, arg2, arg3, arg4);
5448 5449 5450 5451 5452 5453 5454
        break;
#endif
#ifdef TARGET_NR_setsockopt
    case TARGET_NR_setsockopt:
        ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
        break;
#endif
5455

5456
    case TARGET_NR_syslog:
5457 5458
        if (!(p = lock_user_string(arg2)))
            goto efault;
5459 5460
        ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
        unlock_user(p, arg2, 0);
5461 5462
        break;

5463
    case TARGET_NR_setitimer:
B
bellard 已提交
5464 5465 5466
        {
            struct itimerval value, ovalue, *pvalue;

5467
            if (arg2) {
B
bellard 已提交
5468
                pvalue = &value;
5469 5470 5471 5472
                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 已提交
5473 5474 5475 5476
            } else {
                pvalue = NULL;
            }
            ret = get_errno(setitimer(arg1, pvalue, &ovalue));
5477
            if (!is_error(ret) && arg3) {
5478 5479 5480 5481 5482
                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 已提交
5483 5484 5485
            }
        }
        break;
5486
    case TARGET_NR_getitimer:
B
bellard 已提交
5487 5488
        {
            struct itimerval value;
5489

B
bellard 已提交
5490
            ret = get_errno(getitimer(arg1, &value));
5491
            if (!is_error(ret) && arg2) {
5492 5493 5494 5495 5496
                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 已提交
5497 5498 5499
            }
        }
        break;
5500
    case TARGET_NR_stat:
5501 5502
        if (!(p = lock_user_string(arg1)))
            goto efault;
5503 5504
        ret = get_errno(stat(path(p), &st));
        unlock_user(p, arg1, 0);
5505 5506
        goto do_stat;
    case TARGET_NR_lstat:
5507 5508
        if (!(p = lock_user_string(arg1)))
            goto efault;
5509 5510
        ret = get_errno(lstat(path(p), &st));
        unlock_user(p, arg1, 0);
5511 5512 5513 5514 5515 5516
        goto do_stat;
    case TARGET_NR_fstat:
        {
            ret = get_errno(fstat(arg1, &st));
        do_stat:
            if (!is_error(ret)) {
5517
                struct target_stat *target_st;
5518

5519 5520
                if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
                    goto efault;
B
bellard 已提交
5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533
                __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);
5534
                unlock_user_struct(target_st, arg2, 1);
5535 5536 5537
            }
        }
        break;
5538
#ifdef TARGET_NR_olduname
5539 5540
    case TARGET_NR_olduname:
        goto unimplemented;
5541 5542
#endif
#ifdef TARGET_NR_iopl
5543 5544
    case TARGET_NR_iopl:
        goto unimplemented;
5545
#endif
5546 5547 5548
    case TARGET_NR_vhangup:
        ret = get_errno(vhangup());
        break;
5549
#ifdef TARGET_NR_idle
5550 5551
    case TARGET_NR_idle:
        goto unimplemented;
B
bellard 已提交
5552 5553 5554 5555 5556
#endif
#ifdef TARGET_NR_syscall
    case TARGET_NR_syscall:
    	ret = do_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
    	break;
5557
#endif
5558 5559 5560
    case TARGET_NR_wait4:
        {
            int status;
5561
            abi_long status_ptr = arg2;
5562
            struct rusage rusage, *rusage_ptr;
5563
            abi_ulong target_rusage = arg4;
5564 5565 5566 5567 5568 5569
            if (target_rusage)
                rusage_ptr = &rusage;
            else
                rusage_ptr = NULL;
            ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
            if (!is_error(ret)) {
5570
                if (status_ptr) {
P
pbrook 已提交
5571
                    status = host_to_target_waitstatus(status);
5572 5573
                    if (put_user_s32(status, status_ptr))
                        goto efault;
5574
                }
5575 5576
                if (target_rusage)
                    host_to_target_rusage(target_rusage, &rusage);
5577 5578 5579
            }
        }
        break;
5580
#ifdef TARGET_NR_swapoff
5581
    case TARGET_NR_swapoff:
5582 5583
        if (!(p = lock_user_string(arg1)))
            goto efault;
5584 5585
        ret = get_errno(swapoff(p));
        unlock_user(p, arg1, 0);
5586
        break;
5587
#endif
5588
    case TARGET_NR_sysinfo:
B
bellard 已提交
5589
        {
5590
            struct target_sysinfo *target_value;
B
bellard 已提交
5591 5592
            struct sysinfo value;
            ret = get_errno(sysinfo(&value));
5593
            if (!is_error(ret) && arg1)
B
bellard 已提交
5594
            {
5595 5596
                if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
                    goto efault;
B
bellard 已提交
5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610
                __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);
5611
                unlock_user_struct(target_value, arg1, 1);
B
bellard 已提交
5612 5613 5614
            }
        }
        break;
5615
#ifdef TARGET_NR_ipc
5616
    case TARGET_NR_ipc:
5617 5618
	ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
	break;
5619
#endif
5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634
#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 已提交
5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653
#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;
5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673
#endif
#ifdef TARGET_NR_shmget
    case TARGET_NR_shmget:
        ret = get_errno(shmget(arg1, arg2, arg3));
        break;
#endif
#ifdef TARGET_NR_shmctl
    case TARGET_NR_shmctl:
        ret = do_shmctl(arg1, arg2, arg3);
        break;
#endif
#ifdef TARGET_NR_shmat
    case TARGET_NR_shmat:
        ret = do_shmat(arg1, arg2, arg3);
        break;
#endif
#ifdef TARGET_NR_shmdt
    case TARGET_NR_shmdt:
        ret = do_shmdt(arg1);
        break;
A
aurel32 已提交
5674
#endif
5675 5676 5677 5678
    case TARGET_NR_fsync:
        ret = get_errno(fsync(arg1));
        break;
    case TARGET_NR_clone:
A
aurel32 已提交
5679 5680
#if defined(TARGET_SH4)
        ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
5681 5682
#elif defined(TARGET_CRIS)
        ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
A
aurel32 已提交
5683
#else
P
pbrook 已提交
5684
        ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
A
aurel32 已提交
5685
#endif
B
bellard 已提交
5686
        break;
5687 5688 5689
#ifdef __NR_exit_group
        /* new thread calls */
    case TARGET_NR_exit_group:
5690
#ifdef TARGET_GPROF
A
aurel32 已提交
5691 5692
        _mcleanup();
#endif
5693
        gdb_exit(cpu_env, arg1);
5694 5695 5696
        ret = get_errno(exit_group(arg1));
        break;
#endif
5697
    case TARGET_NR_setdomainname:
5698 5699
        if (!(p = lock_user_string(arg1)))
            goto efault;
5700 5701
        ret = get_errno(setdomainname(p, arg2));
        unlock_user(p, arg1, 0);
5702 5703 5704
        break;
    case TARGET_NR_uname:
        /* no need to transcode because we use the linux syscall */
B
bellard 已提交
5705 5706
        {
            struct new_utsname * buf;
5707

5708 5709
            if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
                goto efault;
B
bellard 已提交
5710 5711 5712 5713 5714
            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);
5715 5716 5717
                /* Allow the user to override the reported release.  */
                if (qemu_uname_release && *qemu_uname_release)
                  strcpy (buf->release, qemu_uname_release);
B
bellard 已提交
5718
            }
5719
            unlock_user_struct(buf, arg1, 1);
B
bellard 已提交
5720
        }
5721
        break;
B
bellard 已提交
5722
#ifdef TARGET_I386
5723
    case TARGET_NR_modify_ldt:
5724
        ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
B
bellard 已提交
5725
        break;
5726
#if !defined(TARGET_X86_64)
B
bellard 已提交
5727 5728 5729
    case TARGET_NR_vm86old:
        goto unimplemented;
    case TARGET_NR_vm86:
5730
        ret = do_vm86(cpu_env, arg1, arg2);
B
bellard 已提交
5731
        break;
5732
#endif
B
bellard 已提交
5733
#endif
5734 5735
    case TARGET_NR_adjtimex:
        goto unimplemented;
5736
#ifdef TARGET_NR_create_module
5737
    case TARGET_NR_create_module:
5738
#endif
5739 5740
    case TARGET_NR_init_module:
    case TARGET_NR_delete_module:
5741
#ifdef TARGET_NR_get_kernel_syms
5742
    case TARGET_NR_get_kernel_syms:
5743
#endif
5744 5745 5746 5747 5748 5749 5750 5751 5752
        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;
5753
#ifdef TARGET_NR_bdflush /* not on x86_64 */
5754 5755
    case TARGET_NR_bdflush:
        goto unimplemented;
5756
#endif
5757
#ifdef TARGET_NR_sysfs
5758 5759
    case TARGET_NR_sysfs:
        goto unimplemented;
5760
#endif
5761
    case TARGET_NR_personality:
B
bellard 已提交
5762
        ret = get_errno(personality(arg1));
5763
        break;
5764
#ifdef TARGET_NR_afs_syscall
5765 5766
    case TARGET_NR_afs_syscall:
        goto unimplemented;
5767
#endif
5768
#ifdef TARGET_NR__llseek /* Not on alpha */
5769 5770
    case TARGET_NR__llseek:
        {
B
bellard 已提交
5771 5772
#if defined (__x86_64__)
            ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5));
5773 5774
            if (put_user_s64(ret, arg4))
                goto efault;
B
bellard 已提交
5775
#else
5776 5777
            int64_t res;
            ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
5778 5779
            if (put_user_s64(res, arg4))
                goto efault;
B
bellard 已提交
5780
#endif
5781 5782
        }
        break;
5783
#endif
5784
    case TARGET_NR_getdents:
5785
#if TARGET_ABI_BITS != 32
5786
        goto unimplemented;
5787
#elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
B
bellard 已提交
5788
        {
5789
            struct target_dirent *target_dirp;
A
aurel32 已提交
5790
            struct linux_dirent *dirp;
5791
            abi_long count = arg3;
B
bellard 已提交
5792 5793

	    dirp = malloc(count);
5794
	    if (!dirp) {
5795
                ret = -TARGET_ENOMEM;
5796 5797
                goto fail;
            }
5798

B
bellard 已提交
5799 5800
            ret = get_errno(sys_getdents(arg1, dirp, count));
            if (!is_error(ret)) {
A
aurel32 已提交
5801
                struct linux_dirent *de;
B
bellard 已提交
5802 5803 5804 5805 5806 5807 5808
		struct target_dirent *tde;
                int len = ret;
                int reclen, treclen;
		int count1, tnamelen;

		count1 = 0;
                de = dirp;
5809 5810
                if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
                    goto efault;
B
bellard 已提交
5811 5812 5813
		tde = target_dirp;
                while (len > 0) {
                    reclen = de->d_reclen;
5814
		    treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
B
bellard 已提交
5815 5816 5817
                    tde->d_reclen = tswap16(treclen);
                    tde->d_ino = tswapl(de->d_ino);
                    tde->d_off = tswapl(de->d_off);
5818
		    tnamelen = treclen - (2 * sizeof(abi_long) + 2);
B
bellard 已提交
5819 5820
		    if (tnamelen > 256)
                        tnamelen = 256;
B
bellard 已提交
5821
                    /* XXX: may not be correct */
5822
                    pstrcpy(tde->d_name, tnamelen, de->d_name);
A
aurel32 已提交
5823
                    de = (struct linux_dirent *)((char *)de + reclen);
B
bellard 已提交
5824
                    len -= reclen;
J
j_mayer 已提交
5825
                    tde = (struct target_dirent *)((char *)tde + treclen);
B
bellard 已提交
5826 5827 5828
		    count1 += treclen;
                }
		ret = count1;
5829
                unlock_user(target_dirp, arg2, ret);
B
bellard 已提交
5830 5831 5832 5833
            }
	    free(dirp);
        }
#else
5834
        {
A
aurel32 已提交
5835
            struct linux_dirent *dirp;
5836
            abi_long count = arg3;
B
bellard 已提交
5837

5838 5839
            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
                goto efault;
B
bellard 已提交
5840
            ret = get_errno(sys_getdents(arg1, dirp, count));
5841
            if (!is_error(ret)) {
A
aurel32 已提交
5842
                struct linux_dirent *de;
5843 5844 5845 5846
                int len = ret;
                int reclen;
                de = dirp;
                while (len > 0) {
B
bellard 已提交
5847
                    reclen = de->d_reclen;
5848 5849
                    if (reclen > len)
                        break;
B
bellard 已提交
5850
                    de->d_reclen = tswap16(reclen);
5851 5852
                    tswapls(&de->d_ino);
                    tswapls(&de->d_off);
A
aurel32 已提交
5853
                    de = (struct linux_dirent *)((char *)de + reclen);
5854 5855 5856
                    len -= reclen;
                }
            }
5857
            unlock_user(dirp, arg2, ret);
5858
        }
B
bellard 已提交
5859
#endif
5860
        break;
T
ths 已提交
5861
#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
B
bellard 已提交
5862 5863
    case TARGET_NR_getdents64:
        {
A
aurel32 已提交
5864
            struct linux_dirent64 *dirp;
5865
            abi_long count = arg3;
5866 5867
            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
                goto efault;
B
bellard 已提交
5868 5869
            ret = get_errno(sys_getdents64(arg1, dirp, count));
            if (!is_error(ret)) {
A
aurel32 已提交
5870
                struct linux_dirent64 *de;
B
bellard 已提交
5871 5872 5873 5874
                int len = ret;
                int reclen;
                de = dirp;
                while (len > 0) {
B
bellard 已提交
5875
                    reclen = de->d_reclen;
B
bellard 已提交
5876 5877
                    if (reclen > len)
                        break;
B
bellard 已提交
5878
                    de->d_reclen = tswap16(reclen);
B
bellard 已提交
5879 5880
                    tswap64s((uint64_t *)&de->d_ino);
                    tswap64s((uint64_t *)&de->d_off);
A
aurel32 已提交
5881
                    de = (struct linux_dirent64 *)((char *)de + reclen);
B
bellard 已提交
5882 5883 5884
                    len -= reclen;
                }
            }
5885
            unlock_user(dirp, arg2, ret);
B
bellard 已提交
5886 5887
        }
        break;
5888
#endif /* TARGET_NR_getdents64 */
5889
#ifdef TARGET_NR__newselect
5890
    case TARGET_NR__newselect:
5891
        ret = do_select(arg1, arg2, arg3, arg4, arg5);
5892
        break;
5893 5894
#endif
#ifdef TARGET_NR_poll
B
bellard 已提交
5895 5896
    case TARGET_NR_poll:
        {
5897
            struct target_pollfd *target_pfd;
B
bellard 已提交
5898 5899 5900
            unsigned int nfds = arg2;
            int timeout = arg3;
            struct pollfd *pfd;
B
bellard 已提交
5901
            unsigned int i;
B
bellard 已提交
5902

5903 5904 5905
            target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
            if (!target_pfd)
                goto efault;
B
bellard 已提交
5906 5907
            pfd = alloca(sizeof(struct pollfd) * nfds);
            for(i = 0; i < nfds; i++) {
B
bellard 已提交
5908 5909
                pfd[i].fd = tswap32(target_pfd[i].fd);
                pfd[i].events = tswap16(target_pfd[i].events);
B
bellard 已提交
5910 5911 5912 5913
            }
            ret = get_errno(poll(pfd, nfds, timeout));
            if (!is_error(ret)) {
                for(i = 0; i < nfds; i++) {
B
bellard 已提交
5914
                    target_pfd[i].revents = tswap16(pfd[i].revents);
B
bellard 已提交
5915
                }
5916 5917
                ret += nfds * (sizeof(struct target_pollfd)
                               - sizeof(struct pollfd));
B
bellard 已提交
5918
            }
5919
            unlock_user(target_pfd, arg1, ret);
B
bellard 已提交
5920 5921
        }
        break;
5922
#endif
5923
    case TARGET_NR_flock:
B
bellard 已提交
5924 5925 5926
        /* NOTE: the flock constant seems to be the same for every
           Linux platform */
        ret = get_errno(flock(arg1, arg2));
5927 5928 5929 5930 5931 5932 5933
        break;
    case TARGET_NR_readv:
        {
            int count = arg3;
            struct iovec *vec;

            vec = alloca(count * sizeof(struct iovec));
B
bellard 已提交
5934 5935
            if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
                goto efault;
5936
            ret = get_errno(readv(arg1, vec, count));
5937
            unlock_iovec(vec, arg2, count, 1);
5938 5939 5940 5941 5942 5943 5944 5945
        }
        break;
    case TARGET_NR_writev:
        {
            int count = arg3;
            struct iovec *vec;

            vec = alloca(count * sizeof(struct iovec));
B
bellard 已提交
5946 5947
            if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
                goto efault;
5948
            ret = get_errno(writev(arg1, vec, count));
5949
            unlock_iovec(vec, arg2, count, 0);
5950 5951 5952 5953 5954
        }
        break;
    case TARGET_NR_getsid:
        ret = get_errno(getsid(arg1));
        break;
5955
#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
5956
    case TARGET_NR_fdatasync:
B
bellard 已提交
5957 5958
        ret = get_errno(fdatasync(arg1));
        break;
5959
#endif
5960
    case TARGET_NR__sysctl:
5961
        /* We don't implement this, but ENOTDIR is always a safe
B
bellard 已提交
5962
           return value. */
5963 5964
        ret = -TARGET_ENOTDIR;
        break;
5965
    case TARGET_NR_sched_setparam:
B
bellard 已提交
5966
        {
5967
            struct sched_param *target_schp;
B
bellard 已提交
5968
            struct sched_param schp;
5969

5970 5971
            if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
                goto efault;
B
bellard 已提交
5972
            schp.sched_priority = tswap32(target_schp->sched_priority);
5973
            unlock_user_struct(target_schp, arg2, 0);
B
bellard 已提交
5974 5975 5976
            ret = get_errno(sched_setparam(arg1, &schp));
        }
        break;
5977
    case TARGET_NR_sched_getparam:
B
bellard 已提交
5978
        {
5979
            struct sched_param *target_schp;
B
bellard 已提交
5980 5981 5982
            struct sched_param schp;
            ret = get_errno(sched_getparam(arg1, &schp));
            if (!is_error(ret)) {
5983 5984
                if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
                    goto efault;
B
bellard 已提交
5985
                target_schp->sched_priority = tswap32(schp.sched_priority);
5986
                unlock_user_struct(target_schp, arg2, 1);
B
bellard 已提交
5987 5988 5989
            }
        }
        break;
5990
    case TARGET_NR_sched_setscheduler:
B
bellard 已提交
5991
        {
5992
            struct sched_param *target_schp;
B
bellard 已提交
5993
            struct sched_param schp;
5994 5995
            if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
                goto efault;
B
bellard 已提交
5996
            schp.sched_priority = tswap32(target_schp->sched_priority);
5997
            unlock_user_struct(target_schp, arg3, 0);
B
bellard 已提交
5998 5999 6000
            ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
        }
        break;
6001
    case TARGET_NR_sched_getscheduler:
B
bellard 已提交
6002 6003
        ret = get_errno(sched_getscheduler(arg1));
        break;
6004 6005 6006 6007
    case TARGET_NR_sched_yield:
        ret = get_errno(sched_yield());
        break;
    case TARGET_NR_sched_get_priority_max:
B
bellard 已提交
6008 6009
        ret = get_errno(sched_get_priority_max(arg1));
        break;
6010
    case TARGET_NR_sched_get_priority_min:
B
bellard 已提交
6011 6012
        ret = get_errno(sched_get_priority_min(arg1));
        break;
6013
    case TARGET_NR_sched_rr_get_interval:
B
bellard 已提交
6014 6015 6016 6017
        {
            struct timespec ts;
            ret = get_errno(sched_rr_get_interval(arg1, &ts));
            if (!is_error(ret)) {
6018
                host_to_target_timespec(arg2, &ts);
B
bellard 已提交
6019 6020 6021
            }
        }
        break;
6022
    case TARGET_NR_nanosleep:
B
bellard 已提交
6023 6024
        {
            struct timespec req, rem;
6025
            target_to_host_timespec(&req, arg1);
B
bellard 已提交
6026
            ret = get_errno(nanosleep(&req, &rem));
6027 6028
            if (is_error(ret) && arg2) {
                host_to_target_timespec(arg2, &rem);
B
bellard 已提交
6029 6030 6031
            }
        }
        break;
6032
#ifdef TARGET_NR_query_module
6033
    case TARGET_NR_query_module:
B
bellard 已提交
6034
        goto unimplemented;
6035 6036
#endif
#ifdef TARGET_NR_nfsservctl
6037
    case TARGET_NR_nfsservctl:
B
bellard 已提交
6038
        goto unimplemented;
6039
#endif
6040
    case TARGET_NR_prctl:
6041 6042 6043 6044 6045 6046
        switch (arg1)
            {
            case PR_GET_PDEATHSIG:
                {
                    int deathsig;
                    ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
6047 6048 6049
                    if (!is_error(ret) && arg2
                        && put_user_ual(deathsig, arg2))
                        goto efault;
6050 6051 6052 6053 6054 6055
                }
                break;
            default:
                ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
                break;
            }
6056
        break;
B
bellard 已提交
6057 6058 6059 6060 6061 6062 6063 6064 6065
#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
6066
#ifdef TARGET_NR_pread
6067
    case TARGET_NR_pread:
6068 6069 6070 6071
#ifdef TARGET_ARM
        if (((CPUARMState *)cpu_env)->eabi)
            arg4 = arg5;
#endif
6072 6073
        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
            goto efault;
6074 6075
        ret = get_errno(pread(arg1, p, arg3, arg4));
        unlock_user(p, arg2, ret);
6076
        break;
6077
    case TARGET_NR_pwrite:
6078 6079 6080 6081
#ifdef TARGET_ARM
        if (((CPUARMState *)cpu_env)->eabi)
            arg4 = arg5;
#endif
6082 6083
        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
            goto efault;
6084 6085
        ret = get_errno(pwrite(arg1, p, arg3, arg4));
        unlock_user(p, arg2, 0);
6086
        break;
A
aurel32 已提交
6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100
#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;
6101
#endif
6102
    case TARGET_NR_getcwd:
6103 6104
        if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
            goto efault;
6105 6106
        ret = get_errno(sys_getcwd1(p, arg2));
        unlock_user(p, arg1, ret);
6107 6108
        break;
    case TARGET_NR_capget:
B
bellard 已提交
6109
        goto unimplemented;
6110
    case TARGET_NR_capset:
B
bellard 已提交
6111
        goto unimplemented;
6112
    case TARGET_NR_sigaltstack:
6113 6114
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
    defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA)
6115
        ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env));
6116 6117
        break;
#else
B
bellard 已提交
6118
        goto unimplemented;
6119
#endif
6120
    case TARGET_NR_sendfile:
B
bellard 已提交
6121
        goto unimplemented;
6122
#ifdef TARGET_NR_getpmsg
6123
    case TARGET_NR_getpmsg:
B
bellard 已提交
6124
        goto unimplemented;
6125 6126
#endif
#ifdef TARGET_NR_putpmsg
6127
    case TARGET_NR_putpmsg:
B
bellard 已提交
6128
        goto unimplemented;
6129
#endif
B
bellard 已提交
6130
#ifdef TARGET_NR_vfork
6131
    case TARGET_NR_vfork:
P
pbrook 已提交
6132 6133
        ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
                        0, 0, 0, 0));
6134
        break;
B
bellard 已提交
6135
#endif
6136
#ifdef TARGET_NR_ugetrlimit
6137
    case TARGET_NR_ugetrlimit:
B
bellard 已提交
6138 6139 6140 6141
    {
	struct rlimit rlim;
	ret = get_errno(getrlimit(arg1, &rlim));
	if (!is_error(ret)) {
6142
	    struct target_rlimit *target_rlim;
6143 6144
            if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
                goto efault;
B
bellard 已提交
6145 6146
	    target_rlim->rlim_cur = tswapl(rlim.rlim_cur);
	    target_rlim->rlim_max = tswapl(rlim.rlim_max);
6147
            unlock_user_struct(target_rlim, arg2, 1);
B
bellard 已提交
6148 6149 6150
	}
	break;
    }
6151
#endif
B
bellard 已提交
6152
#ifdef TARGET_NR_truncate64
6153
    case TARGET_NR_truncate64:
6154 6155
        if (!(p = lock_user_string(arg1)))
            goto efault;
6156 6157
	ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
        unlock_user(p, arg1, 0);
B
bellard 已提交
6158
	break;
B
bellard 已提交
6159 6160
#endif
#ifdef TARGET_NR_ftruncate64
6161
    case TARGET_NR_ftruncate64:
P
pbrook 已提交
6162
	ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
B
bellard 已提交
6163
	break;
B
bellard 已提交
6164 6165
#endif
#ifdef TARGET_NR_stat64
6166
    case TARGET_NR_stat64:
6167 6168
        if (!(p = lock_user_string(arg1)))
            goto efault;
6169 6170
        ret = get_errno(stat(path(p), &st));
        unlock_user(p, arg1, 0);
6171 6172 6173
        if (!is_error(ret))
            ret = host_to_target_stat64(cpu_env, arg2, &st);
        break;
B
bellard 已提交
6174 6175
#endif
#ifdef TARGET_NR_lstat64
6176
    case TARGET_NR_lstat64:
6177 6178
        if (!(p = lock_user_string(arg1)))
            goto efault;
6179 6180
        ret = get_errno(lstat(path(p), &st));
        unlock_user(p, arg1, 0);
6181 6182 6183
        if (!is_error(ret))
            ret = host_to_target_stat64(cpu_env, arg2, &st);
        break;
B
bellard 已提交
6184 6185
#endif
#ifdef TARGET_NR_fstat64
6186
    case TARGET_NR_fstat64:
6187 6188 6189 6190
        ret = get_errno(fstat(arg1, &st));
        if (!is_error(ret))
            ret = host_to_target_stat64(cpu_env, arg2, &st);
        break;
P
pbrook 已提交
6191
#endif
6192 6193 6194
#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
        (defined(__NR_fstatat64) || defined(__NR_newfstatat))
#ifdef TARGET_NR_fstatat64
6195
    case TARGET_NR_fstatat64:
6196 6197 6198 6199
#endif
#ifdef TARGET_NR_newfstatat
    case TARGET_NR_newfstatat:
#endif
6200 6201
        if (!(p = lock_user_string(arg2)))
            goto efault;
6202
#ifdef __NR_fstatat64
6203
        ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
6204 6205 6206
#else
        ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
#endif
6207 6208
        if (!is_error(ret))
            ret = host_to_target_stat64(cpu_env, arg3, &st);
B
bellard 已提交
6209
        break;
B
bellard 已提交
6210
#endif
6211 6212
#ifdef USE_UID16
    case TARGET_NR_lchown:
6213 6214
        if (!(p = lock_user_string(arg1)))
            goto efault;
6215 6216
        ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
        unlock_user(p, arg1, 0);
6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238
        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;
6239
            uint16_t *target_grouplist;
6240 6241 6242 6243 6244
            gid_t *grouplist;
            int i;

            grouplist = alloca(gidsetsize * sizeof(gid_t));
            ret = get_errno(getgroups(gidsetsize, grouplist));
6245 6246
            if (gidsetsize == 0)
                break;
6247
            if (!is_error(ret)) {
6248 6249 6250
                target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
                if (!target_grouplist)
                    goto efault;
6251
                for(i = 0;i < ret; i++)
6252
                    target_grouplist[i] = tswap16(grouplist[i]);
6253
                unlock_user(target_grouplist, arg2, gidsetsize * 2);
6254 6255 6256 6257 6258 6259
            }
        }
        break;
    case TARGET_NR_setgroups:
        {
            int gidsetsize = arg1;
6260
            uint16_t *target_grouplist;
6261 6262 6263 6264
            gid_t *grouplist;
            int i;

            grouplist = alloca(gidsetsize * sizeof(gid_t));
6265 6266 6267 6268 6269
            target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
            if (!target_grouplist) {
                ret = -TARGET_EFAULT;
                goto fail;
            }
6270 6271
            for(i = 0;i < gidsetsize; i++)
                grouplist[i] = tswap16(target_grouplist[i]);
6272
            unlock_user(target_grouplist, arg2, 0);
6273 6274 6275 6276 6277 6278
            ret = get_errno(setgroups(gidsetsize, grouplist));
        }
        break;
    case TARGET_NR_fchown:
        ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
        break;
6279 6280
#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
    case TARGET_NR_fchownat:
6281 6282 6283 6284
        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);
6285 6286
        break;
#endif
6287 6288
#ifdef TARGET_NR_setresuid
    case TARGET_NR_setresuid:
6289 6290
        ret = get_errno(setresuid(low2highuid(arg1),
                                  low2highuid(arg2),
6291 6292 6293 6294 6295 6296
                                  low2highuid(arg3)));
        break;
#endif
#ifdef TARGET_NR_getresuid
    case TARGET_NR_getresuid:
        {
6297
            uid_t ruid, euid, suid;
6298 6299
            ret = get_errno(getresuid(&ruid, &euid, &suid));
            if (!is_error(ret)) {
6300 6301 6302 6303
                if (put_user_u16(high2lowuid(ruid), arg1)
                    || put_user_u16(high2lowuid(euid), arg2)
                    || put_user_u16(high2lowuid(suid), arg3))
                    goto efault;
6304 6305 6306 6307 6308 6309
            }
        }
        break;
#endif
#ifdef TARGET_NR_getresgid
    case TARGET_NR_setresgid:
6310 6311
        ret = get_errno(setresgid(low2highgid(arg1),
                                  low2highgid(arg2),
6312 6313 6314 6315 6316 6317
                                  low2highgid(arg3)));
        break;
#endif
#ifdef TARGET_NR_getresgid
    case TARGET_NR_getresgid:
        {
6318
            gid_t rgid, egid, sgid;
6319 6320
            ret = get_errno(getresgid(&rgid, &egid, &sgid));
            if (!is_error(ret)) {
6321 6322 6323 6324
                if (put_user_u16(high2lowgid(rgid), arg1)
                    || put_user_u16(high2lowgid(egid), arg2)
                    || put_user_u16(high2lowgid(sgid), arg3))
                    goto efault;
6325 6326 6327 6328 6329
            }
        }
        break;
#endif
    case TARGET_NR_chown:
6330 6331
        if (!(p = lock_user_string(arg1)))
            goto efault;
6332 6333
        ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
        unlock_user(p, arg1, 0);
6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348
        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 已提交
6349
#ifdef TARGET_NR_lchown32
6350
    case TARGET_NR_lchown32:
6351 6352
        if (!(p = lock_user_string(arg1)))
            goto efault;
6353 6354
        ret = get_errno(lchown(p, arg2, arg3));
        unlock_user(p, arg1, 0);
B
bellard 已提交
6355
        break;
B
bellard 已提交
6356 6357
#endif
#ifdef TARGET_NR_getuid32
6358
    case TARGET_NR_getuid32:
B
bellard 已提交
6359 6360
        ret = get_errno(getuid());
        break;
B
bellard 已提交
6361
#endif
6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385

#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 已提交
6386
#ifdef TARGET_NR_getgid32
6387
    case TARGET_NR_getgid32:
B
bellard 已提交
6388 6389
        ret = get_errno(getgid());
        break;
B
bellard 已提交
6390 6391
#endif
#ifdef TARGET_NR_geteuid32
6392
    case TARGET_NR_geteuid32:
B
bellard 已提交
6393 6394
        ret = get_errno(geteuid());
        break;
B
bellard 已提交
6395 6396
#endif
#ifdef TARGET_NR_getegid32
6397
    case TARGET_NR_getegid32:
B
bellard 已提交
6398 6399
        ret = get_errno(getegid());
        break;
B
bellard 已提交
6400 6401
#endif
#ifdef TARGET_NR_setreuid32
6402
    case TARGET_NR_setreuid32:
B
bellard 已提交
6403 6404
        ret = get_errno(setreuid(arg1, arg2));
        break;
B
bellard 已提交
6405 6406
#endif
#ifdef TARGET_NR_setregid32
6407
    case TARGET_NR_setregid32:
B
bellard 已提交
6408 6409
        ret = get_errno(setregid(arg1, arg2));
        break;
B
bellard 已提交
6410 6411
#endif
#ifdef TARGET_NR_getgroups32
6412
    case TARGET_NR_getgroups32:
B
bellard 已提交
6413 6414
        {
            int gidsetsize = arg1;
6415
            uint32_t *target_grouplist;
B
bellard 已提交
6416 6417 6418 6419 6420
            gid_t *grouplist;
            int i;

            grouplist = alloca(gidsetsize * sizeof(gid_t));
            ret = get_errno(getgroups(gidsetsize, grouplist));
6421 6422
            if (gidsetsize == 0)
                break;
B
bellard 已提交
6423
            if (!is_error(ret)) {
6424 6425 6426 6427 6428
                target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
                if (!target_grouplist) {
                    ret = -TARGET_EFAULT;
                    goto fail;
                }
6429
                for(i = 0;i < ret; i++)
6430 6431
                    target_grouplist[i] = tswap32(grouplist[i]);
                unlock_user(target_grouplist, arg2, gidsetsize * 4);
B
bellard 已提交
6432 6433 6434
            }
        }
        break;
B
bellard 已提交
6435 6436
#endif
#ifdef TARGET_NR_setgroups32
6437
    case TARGET_NR_setgroups32:
B
bellard 已提交
6438 6439
        {
            int gidsetsize = arg1;
6440
            uint32_t *target_grouplist;
B
bellard 已提交
6441 6442
            gid_t *grouplist;
            int i;
6443

B
bellard 已提交
6444
            grouplist = alloca(gidsetsize * sizeof(gid_t));
6445 6446 6447 6448 6449
            target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
            if (!target_grouplist) {
                ret = -TARGET_EFAULT;
                goto fail;
            }
B
bellard 已提交
6450
            for(i = 0;i < gidsetsize; i++)
6451 6452
                grouplist[i] = tswap32(target_grouplist[i]);
            unlock_user(target_grouplist, arg2, 0);
B
bellard 已提交
6453 6454 6455
            ret = get_errno(setgroups(gidsetsize, grouplist));
        }
        break;
B
bellard 已提交
6456 6457
#endif
#ifdef TARGET_NR_fchown32
6458
    case TARGET_NR_fchown32:
B
bellard 已提交
6459 6460
        ret = get_errno(fchown(arg1, arg2, arg3));
        break;
B
bellard 已提交
6461 6462
#endif
#ifdef TARGET_NR_setresuid32
6463
    case TARGET_NR_setresuid32:
B
bellard 已提交
6464 6465
        ret = get_errno(setresuid(arg1, arg2, arg3));
        break;
B
bellard 已提交
6466 6467
#endif
#ifdef TARGET_NR_getresuid32
6468
    case TARGET_NR_getresuid32:
B
bellard 已提交
6469
        {
6470
            uid_t ruid, euid, suid;
B
bellard 已提交
6471 6472
            ret = get_errno(getresuid(&ruid, &euid, &suid));
            if (!is_error(ret)) {
6473 6474 6475 6476
                if (put_user_u32(ruid, arg1)
                    || put_user_u32(euid, arg2)
                    || put_user_u32(suid, arg3))
                    goto efault;
B
bellard 已提交
6477 6478 6479
            }
        }
        break;
B
bellard 已提交
6480 6481
#endif
#ifdef TARGET_NR_setresgid32
6482
    case TARGET_NR_setresgid32:
B
bellard 已提交
6483 6484
        ret = get_errno(setresgid(arg1, arg2, arg3));
        break;
B
bellard 已提交
6485 6486
#endif
#ifdef TARGET_NR_getresgid32
6487
    case TARGET_NR_getresgid32:
B
bellard 已提交
6488
        {
6489
            gid_t rgid, egid, sgid;
B
bellard 已提交
6490 6491
            ret = get_errno(getresgid(&rgid, &egid, &sgid));
            if (!is_error(ret)) {
6492 6493 6494 6495
                if (put_user_u32(rgid, arg1)
                    || put_user_u32(egid, arg2)
                    || put_user_u32(sgid, arg3))
                    goto efault;
B
bellard 已提交
6496 6497 6498
            }
        }
        break;
B
bellard 已提交
6499 6500
#endif
#ifdef TARGET_NR_chown32
6501
    case TARGET_NR_chown32:
6502 6503
        if (!(p = lock_user_string(arg1)))
            goto efault;
6504 6505
        ret = get_errno(chown(p, arg2, arg3));
        unlock_user(p, arg1, 0);
B
bellard 已提交
6506
        break;
B
bellard 已提交
6507 6508
#endif
#ifdef TARGET_NR_setuid32
6509
    case TARGET_NR_setuid32:
B
bellard 已提交
6510 6511
        ret = get_errno(setuid(arg1));
        break;
B
bellard 已提交
6512 6513
#endif
#ifdef TARGET_NR_setgid32
6514
    case TARGET_NR_setgid32:
B
bellard 已提交
6515 6516
        ret = get_errno(setgid(arg1));
        break;
B
bellard 已提交
6517 6518
#endif
#ifdef TARGET_NR_setfsuid32
6519
    case TARGET_NR_setfsuid32:
B
bellard 已提交
6520 6521
        ret = get_errno(setfsuid(arg1));
        break;
B
bellard 已提交
6522 6523
#endif
#ifdef TARGET_NR_setfsgid32
6524
    case TARGET_NR_setfsgid32:
B
bellard 已提交
6525 6526
        ret = get_errno(setfsgid(arg1));
        break;
B
bellard 已提交
6527
#endif
6528

6529
    case TARGET_NR_pivot_root:
B
bellard 已提交
6530
        goto unimplemented;
B
bellard 已提交
6531
#ifdef TARGET_NR_mincore
6532
    case TARGET_NR_mincore:
A
aurel32 已提交
6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545
        {
            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 已提交
6546
#endif
A
aurel32 已提交
6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567
#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 已提交
6568
#ifdef TARGET_NR_madvise
6569
    case TARGET_NR_madvise:
6570 6571 6572 6573 6574 6575
        /* 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 已提交
6576
#endif
6577
#if TARGET_ABI_BITS == 32
6578
    case TARGET_NR_fcntl64:
B
bellard 已提交
6579
    {
T
ths 已提交
6580
	int cmd;
B
bellard 已提交
6581
	struct flock64 fl;
6582
	struct target_flock64 *target_fl;
P
pbrook 已提交
6583
#ifdef TARGET_ARM
6584
	struct target_eabi_flock64 *target_efl;
P
pbrook 已提交
6585
#endif
B
bellard 已提交
6586

6587 6588 6589
	cmd = target_to_host_fcntl_cmd(arg2);
	if (cmd == -TARGET_EINVAL)
		return cmd;
T
ths 已提交
6590

B
bellard 已提交
6591
        switch(arg2) {
T
ths 已提交
6592
        case TARGET_F_GETLK64:
T
ths 已提交
6593 6594
#ifdef TARGET_ARM
            if (((CPUARMState *)cpu_env)->eabi) {
B
bellard 已提交
6595 6596
                if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) 
                    goto efault;
T
ths 已提交
6597 6598 6599 6600 6601 6602 6603 6604 6605
                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 已提交
6606 6607
                if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) 
                    goto efault;
T
ths 已提交
6608 6609 6610 6611 6612 6613 6614
                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 已提交
6615
            ret = get_errno(fcntl(arg1, cmd, &fl));
B
bellard 已提交
6616
	    if (ret == 0) {
P
pbrook 已提交
6617 6618
#ifdef TARGET_ARM
                if (((CPUARMState *)cpu_env)->eabi) {
B
bellard 已提交
6619 6620
                    if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) 
                        goto efault;
P
pbrook 已提交
6621 6622 6623 6624 6625
                    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);
6626
                    unlock_user_struct(target_efl, arg3, 1);
P
pbrook 已提交
6627 6628 6629
                } else
#endif
                {
B
bellard 已提交
6630 6631
                    if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) 
                        goto efault;
P
pbrook 已提交
6632 6633 6634 6635 6636
                    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);
6637
                    unlock_user_struct(target_fl, arg3, 1);
P
pbrook 已提交
6638
                }
B
bellard 已提交
6639 6640 6641
	    }
	    break;

T
ths 已提交
6642 6643
        case TARGET_F_SETLK64:
        case TARGET_F_SETLKW64:
P
pbrook 已提交
6644 6645
#ifdef TARGET_ARM
            if (((CPUARMState *)cpu_env)->eabi) {
B
bellard 已提交
6646 6647
                if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) 
                    goto efault;
P
pbrook 已提交
6648 6649 6650 6651 6652
                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);
6653
                unlock_user_struct(target_efl, arg3, 0);
P
pbrook 已提交
6654 6655 6656
            } else
#endif
            {
B
bellard 已提交
6657 6658
                if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) 
                    goto efault;
P
pbrook 已提交
6659 6660 6661 6662 6663
                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);
6664
                unlock_user_struct(target_fl, arg3, 0);
P
pbrook 已提交
6665
            }
T
ths 已提交
6666
            ret = get_errno(fcntl(arg1, cmd, &fl));
B
bellard 已提交
6667
	    break;
B
bellard 已提交
6668
        default:
6669
            ret = do_fcntl(arg1, arg2, arg3);
B
bellard 已提交
6670 6671
            break;
        }
B
bellard 已提交
6672 6673
	break;
    }
B
bellard 已提交
6674
#endif
6675 6676 6677 6678 6679 6680
#ifdef TARGET_NR_cacheflush
    case TARGET_NR_cacheflush:
        /* self-modifying code is handled automatically, so nothing needed */
        ret = 0;
        break;
#endif
6681
#ifdef TARGET_NR_security
6682 6683
    case TARGET_NR_security:
        goto unimplemented;
B
bellard 已提交
6684 6685 6686 6687 6688
#endif
#ifdef TARGET_NR_getpagesize
    case TARGET_NR_getpagesize:
        ret = TARGET_PAGE_SIZE;
        break;
6689
#endif
6690 6691 6692
    case TARGET_NR_gettid:
        ret = get_errno(gettid());
        break;
6693
#ifdef TARGET_NR_readahead
6694
    case TARGET_NR_readahead:
A
aurel32 已提交
6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708
#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;
6709
#endif
6710
#ifdef TARGET_NR_setxattr
6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722
    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:
6723 6724
        ret = -TARGET_EOPNOTSUPP;
        break;
6725 6726
#endif
#ifdef TARGET_NR_set_thread_area
B
bellard 已提交
6727
    case TARGET_NR_set_thread_area:
B
bellard 已提交
6728
#if defined(TARGET_MIPS)
6729 6730 6731
      ((CPUMIPSState *) cpu_env)->tls_value = arg1;
      ret = 0;
      break;
6732 6733 6734 6735 6736 6737 6738 6739
#elif defined(TARGET_CRIS)
      if (arg1 & 0xff)
          ret = -TARGET_EINVAL;
      else {
          ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
          ret = 0;
      }
      break;
B
bellard 已提交
6740 6741 6742
#elif defined(TARGET_I386) && defined(TARGET_ABI32)
      ret = do_set_thread_area(cpu_env, arg1);
      break;
6743 6744 6745 6746 6747
#else
      goto unimplemented_nowarn;
#endif
#endif
#ifdef TARGET_NR_get_thread_area
B
bellard 已提交
6748
    case TARGET_NR_get_thread_area:
B
bellard 已提交
6749 6750 6751
#if defined(TARGET_I386) && defined(TARGET_ABI32)
        ret = do_get_thread_area(cpu_env, arg1);
#else
B
bellard 已提交
6752
        goto unimplemented_nowarn;
B
bellard 已提交
6753
#endif
B
bellard 已提交
6754
#endif
B
bellard 已提交
6755 6756 6757
#ifdef TARGET_NR_getdomainname
    case TARGET_NR_getdomainname:
        goto unimplemented_nowarn;
6758
#endif
6759

6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781
#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 已提交
6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792
#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
6793

6794 6795
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
    case TARGET_NR_set_tid_address:
6796 6797
        ret = get_errno(set_tid_address((int *)g2h(arg1)));
        break;
6798 6799
#endif

T
ths 已提交
6800
#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
T
ths 已提交
6801
    case TARGET_NR_tkill:
6802
        ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
T
ths 已提交
6803 6804 6805
        break;
#endif

T
ths 已提交
6806
#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
T
ths 已提交
6807
    case TARGET_NR_tgkill:
6808 6809
	ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
                        target_to_host_signal(arg3)));
T
ths 已提交
6810 6811 6812
	break;
#endif

6813 6814 6815 6816 6817
#ifdef TARGET_NR_set_robust_list
    case TARGET_NR_set_robust_list:
	goto unimplemented_nowarn;
#endif

6818 6819 6820
#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
    case TARGET_NR_utimensat:
        {
R
Riku Voipio 已提交
6821 6822 6823 6824 6825 6826 6827 6828
            struct timespec *tsp, ts[2];
            if (!arg3) {
                tsp = NULL;
            } else {
                target_to_host_timespec(ts, arg3);
                target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
                tsp = ts;
            }
6829
            if (!arg2)
R
Riku Voipio 已提交
6830
                ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
6831
            else {
6832
                if (!(p = lock_user_string(arg2))) {
6833
                    ret = -TARGET_EFAULT;
6834 6835
                    goto fail;
                }
R
Riku Voipio 已提交
6836
                ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
6837
                unlock_user(p, arg2, 0);
6838 6839 6840 6841
            }
        }
	break;
#endif
6842
#if defined(CONFIG_USE_NPTL)
6843 6844 6845 6846
    case TARGET_NR_futex:
        ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
        break;
#endif
6847
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
A
aurel32 已提交
6848 6849 6850 6851
    case TARGET_NR_inotify_init:
        ret = get_errno(sys_inotify_init());
        break;
#endif
6852
#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
A
aurel32 已提交
6853 6854 6855 6856 6857 6858
    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
6859
#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
A
aurel32 已提交
6860 6861 6862 6863
    case TARGET_NR_inotify_rm_watch:
        ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
        break;
#endif
6864

6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939
#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

6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979
#ifdef CONFIG_SPLICE
#ifdef TARGET_NR_tee
    case TARGET_NR_tee:
        {
            ret = get_errno(tee(arg1,arg2,arg3,arg4));
        }
        break;
#endif
#ifdef TARGET_NR_splice
    case TARGET_NR_splice:
        {
            loff_t loff_in, loff_out;
            loff_t *ploff_in = NULL, *ploff_out = NULL;
            if(arg2) {
                get_user_u64(loff_in, arg2);
                ploff_in = &loff_in;
            }
            if(arg4) {
                get_user_u64(loff_out, arg2);
                ploff_out = &loff_out;
            }
            ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
        }
        break;
#endif
#ifdef TARGET_NR_vmsplice
	case TARGET_NR_vmsplice:
        {
            int count = arg3;
            struct iovec *vec;

            vec = alloca(count * sizeof(struct iovec));
            if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
                goto efault;
            ret = get_errno(vmsplice(arg1, vec, count, arg4));
            unlock_iovec(vec, arg2, count, 0);
        }
        break;
#endif
#endif /* CONFIG_SPLICE */
R
Riku Voipio 已提交
6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991
#ifdef CONFIG_EVENTFD
#if defined(TARGET_NR_eventfd)
    case TARGET_NR_eventfd:
        ret = get_errno(eventfd(arg1, 0));
        break;
#endif
#if defined(TARGET_NR_eventfd2)
    case TARGET_NR_eventfd2:
        ret = get_errno(eventfd(arg1, arg2));
        break;
#endif
#endif /* CONFIG_EVENTFD  */
6992 6993
    default:
    unimplemented:
B
bellard 已提交
6994
        gemu_log("qemu: Unsupported syscall: %d\n", num);
6995
#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list)
B
bellard 已提交
6996
    unimplemented_nowarn:
B
bellard 已提交
6997
#endif
6998
        ret = -TARGET_ENOSYS;
6999 7000
        break;
    }
7001
fail:
B
bellard 已提交
7002
#ifdef DEBUG
7003
    gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
B
bellard 已提交
7004
#endif
7005 7006
    if(do_strace)
        print_syscall_ret(num, ret);
7007
    return ret;
7008 7009 7010
efault:
    ret = -TARGET_EFAULT;
    goto fail;
7011
}