syscall.c 268.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 <sys/types.h>
T
ths 已提交
32 33
#include <sys/ipc.h>
#include <sys/msg.h>
34 35 36 37
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/mount.h>
38
#include <sys/prctl.h>
39 40 41 42 43
#include <sys/resource.h>
#include <sys/mman.h>
#include <sys/swap.h>
#include <signal.h>
#include <sched.h>
44 45 46 47
#ifdef __ia64__
int __clone2(int (*fn)(void *), void *child_stack_base,
             size_t stack_size, int flags, void *arg, ...);
#endif
48
#include <sys/socket.h>
49
#include <sys/un.h>
50
#include <sys/uio.h>
B
bellard 已提交
51
#include <sys/poll.h>
B
bellard 已提交
52
#include <sys/times.h>
53
#include <sys/shm.h>
54
#include <sys/sem.h>
B
bellard 已提交
55
#include <sys/statfs.h>
56
#include <utime.h>
B
bellard 已提交
57
#include <sys/sysinfo.h>
58
#include <sys/utsname.h>
B
bellard 已提交
59
//#include <sys/user.h>
60
#include <netinet/ip.h>
B
bellard 已提交
61
#include <netinet/tcp.h>
62
#include <linux/wireless.h>
63
#include "qemu-common.h"
64
#ifdef TARGET_GPROF
A
aurel32 已提交
65 66
#include <sys/gmon.h>
#endif
R
Riku Voipio 已提交
67 68 69
#ifdef CONFIG_EVENTFD
#include <sys/eventfd.h>
#endif
70 71 72
#ifdef CONFIG_EPOLL
#include <sys/epoll.h>
#endif
73
#ifdef CONFIG_ATTR
74
#include "qemu-xattr.h"
75
#endif
76 77 78 79

#define termios host_termios
#define winsize host_winsize
#define termio host_termio
B
bellard 已提交
80 81 82
#define sgttyb host_sgttyb /* same as target */
#define tchars host_tchars /* same as target */
#define ltchars host_ltchars /* same as target */
83 84 85 86 87 88 89

#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 已提交
90
#include <linux/kd.h>
91
#include <linux/mtio.h>
M
Martin Mohring 已提交
92
#include <linux/fs.h>
93
#if defined(CONFIG_FIEMAP)
94
#include <linux/fiemap.h>
95
#endif
U
Ulrich Hecht 已提交
96 97
#include <linux/fb.h>
#include <linux/vt.h>
98
#include <linux/dm-ioctl.h>
99
#include "linux_loop.h"
100
#include "cpu-uname.h"
101

B
bellard 已提交
102
#include "qemu.h"
103

104
#if defined(CONFIG_USE_NPTL)
P
pbrook 已提交
105 106 107 108 109
#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 已提交
110 111
#endif

B
bellard 已提交
112
//#define DEBUG
113

B
bellard 已提交
114
//#include <linux/msdos_fs.h>
A
aurel32 已提交
115 116
#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 已提交
117

118 119 120 121 122 123 124

#undef _syscall0
#undef _syscall1
#undef _syscall2
#undef _syscall3
#undef _syscall4
#undef _syscall5
B
bellard 已提交
125
#undef _syscall6
126

B
bellard 已提交
127
#define _syscall0(type,name)		\
128
static type name (void)			\
B
bellard 已提交
129 130 131
{					\
	return syscall(__NR_##name);	\
}
132

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

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

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

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

B
bellard 已提交
157 158
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,	\
		  type5,arg5)							\
159
static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5)	\
B
bellard 已提交
160 161
{										\
	return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5);		\
162 163
}

B
bellard 已提交
164 165 166

#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,	\
		  type5,arg5,type6,arg6)					\
167 168
static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,	\
                  type6 arg6)							\
B
bellard 已提交
169 170
{										\
	return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6);	\
171
}
B
bellard 已提交
172

173

174
#define __NR_sys_uname __NR_uname
175
#define __NR_sys_faccessat __NR_faccessat
176
#define __NR_sys_fchmodat __NR_fchmodat
177
#define __NR_sys_fchownat __NR_fchownat
178
#define __NR_sys_fstatat64 __NR_fstatat64
179
#define __NR_sys_futimesat __NR_futimesat
B
bellard 已提交
180 181
#define __NR_sys_getcwd1 __NR_getcwd
#define __NR_sys_getdents __NR_getdents
B
bellard 已提交
182
#define __NR_sys_getdents64 __NR_getdents64
183
#define __NR_sys_getpriority __NR_getpriority
184
#define __NR_sys_linkat __NR_linkat
185
#define __NR_sys_mkdirat __NR_mkdirat
186
#define __NR_sys_mknodat __NR_mknodat
187
#define __NR_sys_newfstatat __NR_newfstatat
188
#define __NR_sys_openat __NR_openat
189
#define __NR_sys_readlinkat __NR_readlinkat
190
#define __NR_sys_renameat __NR_renameat
B
bellard 已提交
191
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
192
#define __NR_sys_symlinkat __NR_symlinkat
193
#define __NR_sys_syslog __NR_syslog
T
ths 已提交
194
#define __NR_sys_tgkill __NR_tgkill
T
ths 已提交
195
#define __NR_sys_tkill __NR_tkill
196
#define __NR_sys_unlinkat __NR_unlinkat
197
#define __NR_sys_utimensat __NR_utimensat
198
#define __NR_sys_futex __NR_futex
A
aurel32 已提交
199 200 201
#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
202

203 204
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
    defined(__s390x__)
B
bellard 已提交
205 206 207
#define __NR__llseek __NR_lseek
#endif

B
bellard 已提交
208
#ifdef __NR_gettid
209
_syscall0(int, gettid)
B
bellard 已提交
210
#else
211 212
/* This is a replacement for the host gettid() and must return a host
   errno. */
B
bellard 已提交
213 214 215 216
static int gettid(void) {
    return -ENOSYS;
}
#endif
217 218 219 220 221
_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
#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);
R
Richard Henderson 已提交
222
#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
_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
240
#if defined(CONFIG_USE_NPTL)
241 242 243 244 245
#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
246 247 248 249 250 251
#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
          unsigned long *, user_mask_ptr);
#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
          unsigned long *, user_mask_ptr);
252 253
_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
          void *, arg);
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

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).
   */

295
  memset(buf, 0, sizeof(*buf));
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
  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 已提交
315
  return strlen(buf)+1;
316 317 318 319 320 321 322 323 324
}

#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
325
static int sys_faccessat(int dirfd, const char *pathname, int mode)
326
{
327
  return (faccessat(dirfd, pathname, mode, 0));
328 329 330
}
#endif
#ifdef TARGET_NR_fchmodat
331
static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
332
{
333
  return (fchmodat(dirfd, pathname, mode, 0));
334 335
}
#endif
336
#if defined(TARGET_NR_fchownat)
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
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
A
Alexander Graf 已提交
385
static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
{
  /*
   * open(2) has extra parameter 'mode' when called with
   * flag O_CREAT.
   */
  if ((flags & O_CREAT) != 0) {
      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
 */
427
#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
428
_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
429
#endif
430
#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
431
_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
432
#endif
433
#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
434 435 436
_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
          uid_t,owner,gid_t,group,int,flags)
#endif
437 438
#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
        defined(__NR_fstatat64)
439 440 441
_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
          struct stat *,buf,int,flags)
#endif
442 443 444 445
#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
         const struct timeval *,times)
#endif
446 447 448 449
#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
        defined(__NR_newfstatat)
_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
          struct stat *,buf,int,flags)
450
#endif
451 452
#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
453
      int,newdirfd,const char *,newpath,int,flags)
454
#endif
455 456 457
#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
#endif
458 459 460 461
#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
          mode_t,mode,dev_t,dev)
#endif
462 463 464
#if defined(TARGET_NR_openat) && defined(__NR_openat)
_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
#endif
465 466 467 468
#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
          char *,buf,size_t,bufsize)
#endif
469 470 471 472
#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
          int,newdirfd,const char *,newpath)
#endif
473
#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
474 475 476
_syscall3(int,sys_symlinkat,const char *,oldpath,
          int,newdirfd,const char *,newpath)
#endif
477 478 479
#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
#endif
R
Riku Voipio 已提交
480 481 482 483 484 485 486 487 488 489 490 491 492

#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
493 494 495 496
#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 已提交
497
#endif /* CONFIG_UTIMENSAT  */
498 499

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

A
aurel32 已提交
502
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
503 504 505 506
static int sys_inotify_init(void)
{
  return (inotify_init());
}
A
aurel32 已提交
507 508
#endif
#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
509 510 511 512
static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
{
  return (inotify_add_watch(fd, pathname, mask));
}
A
aurel32 已提交
513 514
#endif
#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
515 516
static int sys_inotify_rm_watch(int fd, int32_t wd)
{
A
aurel32 已提交
517
  return (inotify_rm_watch(fd, wd));
518
}
519
#endif
520 521 522 523 524 525 526 527
#ifdef CONFIG_INOTIFY1
#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
static int sys_inotify_init1(int flags)
{
  return (inotify_init1(flags));
}
#endif
#endif
528 529 530
#else
/* Userspace can usually survive runtime without inotify */
#undef TARGET_NR_inotify_init
531
#undef TARGET_NR_inotify_init1
532 533 534 535
#undef TARGET_NR_inotify_add_watch
#undef TARGET_NR_inotify_rm_watch
#endif /* CONFIG_INOTIFY  */

536 537 538 539 540 541 542 543 544
#if defined(TARGET_NR_ppoll)
#ifndef __NR_ppoll
# define __NR_ppoll -1
#endif
#define __NR_sys_ppoll __NR_ppoll
_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
          struct timespec *, timeout, const __sigset_t *, sigmask,
          size_t, sigsetsize)
#endif
B
bellard 已提交
545

546 547 548 549 550 551 552 553 554
#if defined(TARGET_NR_pselect6)
#ifndef __NR_pselect6
# define __NR_pselect6 -1
#endif
#define __NR_sys_pselect6 __NR_pselect6
_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
          fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
#endif

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
#if defined(TARGET_NR_prlimit64)
#ifndef __NR_prlimit64
# define __NR_prlimit64 -1
#endif
#define __NR_sys_prlimit64 __NR_prlimit64
/* The glibc rlimit structure may not be that used by the underlying syscall */
struct host_rlimit64 {
    uint64_t rlim_cur;
    uint64_t rlim_max;
};
_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
          const struct host_rlimit64 *, new_limit,
          struct host_rlimit64 *, old_limit)
#endif

B
bellard 已提交
570
extern int personality(int);
B
bellard 已提交
571 572 573
extern int flock(int, int);
extern int setfsuid(int);
extern int setfsgid(int);
B
bellard 已提交
574
extern int setgroups(int, gid_t *);
575

576 577 578 579 580 581 582 583 584 585 586
/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
#ifdef TARGET_ARM 
static inline int regpairs_aligned(void *cpu_env) {
    return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
}
#elif defined(TARGET_MIPS)
static inline int regpairs_aligned(void *cpu_env) { return 1; }
#else
static inline int regpairs_aligned(void *cpu_env) { return 0; }
#endif

587 588 589 590 591 592 593
#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] = {
};

594
/*
T
ths 已提交
595
 * This list is the union of errno values overridden in asm-<arch>/errno.h
596 597
 * minus the errnos that are not actually generic to all archs.
 */
598
static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
    [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 已提交
686
#ifdef ENOKEY
687
    [ENOKEY]		= TARGET_ENOKEY,
T
ths 已提交
688 689
#endif
#ifdef EKEYEXPIRED
690
    [EKEYEXPIRED]	= TARGET_EKEYEXPIRED,
T
ths 已提交
691 692
#endif
#ifdef EKEYREVOKED
693
    [EKEYREVOKED]	= TARGET_EKEYREVOKED,
T
ths 已提交
694 695
#endif
#ifdef EKEYREJECTED
696
    [EKEYREJECTED]	= TARGET_EKEYREJECTED,
T
ths 已提交
697 698
#endif
#ifdef EOWNERDEAD
699
    [EOWNERDEAD]	= TARGET_EOWNERDEAD,
T
ths 已提交
700 701
#endif
#ifdef ENOTRECOVERABLE
702
    [ENOTRECOVERABLE]	= TARGET_ENOTRECOVERABLE,
T
ths 已提交
703
#endif
704
};
705 706 707 708 709 710 711 712

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

713 714 715 716 717 718 719
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;
}

720
static inline abi_long get_errno(abi_long ret)
721 722
{
    if (ret == -1)
723
        return -host_to_target_errno(errno);
724 725 726 727
    else
        return ret;
}

728
static inline int is_error(abi_long ret)
729
{
730
    return (abi_ulong)ret >= (abi_ulong)(-4096);
731 732
}

733 734
char *target_strerror(int err)
{
735 736 737
    if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
        return NULL;
    }
738 739 740
    return strerror(target_to_host_errno(err));
}

741 742
static abi_ulong target_brk;
static abi_ulong target_original_brk;
743
static abi_ulong brk_page;
744

745
void target_set_brk(abi_ulong new_brk)
746
{
747
    target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
748
    brk_page = HOST_PAGE_ALIGN(target_brk);
749 750
}

751 752 753
//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
#define DEBUGF_BRK(message, args...)

754
/* do_brk() must return target values and target errnos. */
755
abi_long do_brk(abi_ulong new_brk)
756
{
757
    abi_long mapped_addr;
758 759
    int	new_alloc_size;

P
Paul Brook 已提交
760
    DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
761 762

    if (!new_brk) {
P
Paul Brook 已提交
763
        DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
764
        return target_brk;
765 766
    }
    if (new_brk < target_original_brk) {
P
Paul Brook 已提交
767 768
        DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
                   target_brk);
769
        return target_brk;
770
    }
771

772 773 774 775 776 777 778 779
    /* If the new brk is less than the highest page reserved to the
     * target heap allocation, set it and we're almost done...  */
    if (new_brk <= brk_page) {
        /* Heap contents are initialized to zero, as for anonymous
         * mapped pages.  */
        if (new_brk > target_brk) {
            memset(g2h(target_brk), 0, new_brk - target_brk);
        }
780
	target_brk = new_brk;
P
Paul Brook 已提交
781
        DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
782
    	return target_brk;
783 784
    }

785 786 787 788 789 790
    /* We need to allocate more memory after the brk... Note that
     * we don't use MAP_FIXED because that will map over the top of
     * any existing mapping (like the one with the host libc or qemu
     * itself); instead we treat "mapped but at wrong address" as
     * a failure and unmap again.
     */
791
    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
792
    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
B
bellard 已提交
793
                                        PROT_READ|PROT_WRITE,
794 795 796
                                        MAP_ANON|MAP_PRIVATE, 0, 0));

    if (mapped_addr == brk_page) {
797 798 799 800 801 802 803 804 805
        /* Heap contents are initialized to zero, as for anonymous
         * mapped pages.  Technically the new pages are already
         * initialized to zero since they *are* anonymous mapped
         * pages, however we have to take care with the contents that
         * come from the remaining part of the previous page: it may
         * contains garbage data due to a previous heap usage (grown
         * then shrunken).  */
        memset(g2h(target_brk), 0, brk_page - target_brk);

806
        target_brk = new_brk;
807
        brk_page = HOST_PAGE_ALIGN(target_brk);
P
Paul Brook 已提交
808 809
        DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
            target_brk);
810 811 812 813 814 815 816
        return target_brk;
    } else if (mapped_addr != -1) {
        /* Mapped but at wrong address, meaning there wasn't actually
         * enough space for this brk.
         */
        target_munmap(mapped_addr, new_alloc_size);
        mapped_addr = -1;
P
Paul Brook 已提交
817
        DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
818 819
    }
    else {
P
Paul Brook 已提交
820
        DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
821
    }
822

823 824 825
#if defined(TARGET_ALPHA)
    /* We (partially) emulate OSF/1 on Alpha, which requires we
       return a proper errno, not an unchanged brk value.  */
826
    return -TARGET_ENOMEM;
827
#endif
828
    /* For everything else, return the previous break. */
829
    return target_brk;
830 831
}

832 833 834
static inline abi_long copy_from_user_fdset(fd_set *fds,
                                            abi_ulong target_fds_addr,
                                            int n)
835
{
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
    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++;
856 857
        }
    }
858 859 860 861

    unlock_user(target_fds, target_fds_addr, 0);

    return 0;
862 863
}

864 865 866 867 868 869 870 871 872 873 874 875 876 877
static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
                                                 abi_ulong target_fds_addr,
                                                 int n)
{
    if (target_fds_addr) {
        if (copy_from_user_fdset(fds, target_fds_addr, n))
            return -TARGET_EFAULT;
        *fds_ptr = fds;
    } else {
        *fds_ptr = NULL;
    }
    return 0;
}

878 879 880
static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
                                          const fd_set *fds,
                                          int n)
881 882
{
    int i, nw, j, k;
883
    abi_long v;
884
    abi_ulong *target_fds;
885

886 887 888 889 890 891 892 893 894 895 896 897 898
    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++;
899
        }
900
        __put_user(v, &target_fds[i]);
901
    }
902 903 904 905

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

    return 0;
906 907
}

B
bellard 已提交
908 909 910 911 912 913
#if defined(__alpha__)
#define HOST_HZ 1024
#else
#define HOST_HZ 100
#endif

914
static inline abi_long host_to_target_clock_t(long ticks)
B
bellard 已提交
915 916 917 918 919 920 921 922
{
#if HOST_HZ == TARGET_HZ
    return ticks;
#else
    return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
#endif
}

923 924
static inline abi_long host_to_target_rusage(abi_ulong target_addr,
                                             const struct rusage *rusage)
B
bellard 已提交
925
{
926 927
    struct target_rusage *target_rusage;

928 929
    if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
        return -TARGET_EFAULT;
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947
    target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
    target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
    target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
    target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
    target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
    target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
    target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
    target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
    target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
    target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
    target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
    target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
    target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
    target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
    target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
    target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
    target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
    target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
948
    unlock_user_struct(target_rusage, target_addr, 1);
949 950

    return 0;
B
bellard 已提交
951 952
}

953
static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
954
{
955
    abi_ulong target_rlim_swap;
956 957
    rlim_t result;
    
958 959 960 961 962 963 964
    target_rlim_swap = tswapal(target_rlim);
    if (target_rlim_swap == TARGET_RLIM_INFINITY)
        return RLIM_INFINITY;

    result = target_rlim_swap;
    if (target_rlim_swap != (rlim_t)result)
        return RLIM_INFINITY;
965 966
    
    return result;
967 968
}

969
static inline abi_ulong host_to_target_rlim(rlim_t rlim)
970
{
971 972
    abi_ulong target_rlim_swap;
    abi_ulong result;
973
    
974
    if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
975
        target_rlim_swap = TARGET_RLIM_INFINITY;
976
    else
977
        target_rlim_swap = rlim;
978
    result = tswapal(target_rlim_swap);
979 980
    
    return result;
981 982
}

983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
static inline int target_to_host_resource(int code)
{
    switch (code) {
    case TARGET_RLIMIT_AS:
        return RLIMIT_AS;
    case TARGET_RLIMIT_CORE:
        return RLIMIT_CORE;
    case TARGET_RLIMIT_CPU:
        return RLIMIT_CPU;
    case TARGET_RLIMIT_DATA:
        return RLIMIT_DATA;
    case TARGET_RLIMIT_FSIZE:
        return RLIMIT_FSIZE;
    case TARGET_RLIMIT_LOCKS:
        return RLIMIT_LOCKS;
    case TARGET_RLIMIT_MEMLOCK:
        return RLIMIT_MEMLOCK;
    case TARGET_RLIMIT_MSGQUEUE:
        return RLIMIT_MSGQUEUE;
    case TARGET_RLIMIT_NICE:
        return RLIMIT_NICE;
    case TARGET_RLIMIT_NOFILE:
        return RLIMIT_NOFILE;
    case TARGET_RLIMIT_NPROC:
        return RLIMIT_NPROC;
    case TARGET_RLIMIT_RSS:
        return RLIMIT_RSS;
    case TARGET_RLIMIT_RTPRIO:
        return RLIMIT_RTPRIO;
    case TARGET_RLIMIT_SIGPENDING:
        return RLIMIT_SIGPENDING;
    case TARGET_RLIMIT_STACK:
        return RLIMIT_STACK;
    default:
        return code;
    }
}

1021 1022
static inline abi_long copy_from_user_timeval(struct timeval *tv,
                                              abi_ulong target_tv_addr)
1023
{
1024 1025
    struct target_timeval *target_tv;

1026
    if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
1027
        return -TARGET_EFAULT;
1028 1029 1030 1031 1032

    __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);
1033 1034

    return 0;
1035 1036
}

1037 1038
static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
                                            const struct timeval *tv)
1039
{
1040 1041
    struct target_timeval *target_tv;

1042
    if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
1043
        return -TARGET_EFAULT;
1044 1045 1046 1047 1048

    __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);
1049 1050

    return 0;
1051 1052
}

1053 1054 1055
#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
#include <mqueue.h>

1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
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;
}
1093
#endif
1094

1095
#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
1096
/* do_select() must return target values and target errnos. */
1097
static abi_long do_select(int n,
1098 1099
                          abi_ulong rfd_addr, abi_ulong wfd_addr,
                          abi_ulong efd_addr, abi_ulong target_tv_addr)
1100 1101 1102 1103
{
    fd_set rfds, wfds, efds;
    fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
    struct timeval tv, *tv_ptr;
1104
    abi_long ret;
1105

1106 1107 1108
    ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
    if (ret) {
        return ret;
1109
    }
1110 1111 1112
    ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
    if (ret) {
        return ret;
1113
    }
1114 1115 1116
    ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
    if (ret) {
        return ret;
1117
    }
1118

1119
    if (target_tv_addr) {
1120 1121
        if (copy_from_user_timeval(&tv, target_tv_addr))
            return -TARGET_EFAULT;
1122 1123 1124 1125
        tv_ptr = &tv;
    } else {
        tv_ptr = NULL;
    }
1126

1127
    ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
1128

1129 1130 1131 1132 1133 1134 1135
    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;
1136

1137 1138
        if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
            return -TARGET_EFAULT;
1139
    }
1140

1141 1142
    return ret;
}
1143
#endif
1144

R
Riku Voipio 已提交
1145 1146 1147 1148 1149 1150 1151 1152 1153
static abi_long do_pipe2(int host_pipe[], int flags)
{
#ifdef CONFIG_PIPE2
    return pipe2(host_pipe, flags);
#else
    return -ENOSYS;
#endif
}

1154 1155
static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
                        int flags, int is_pipe2)
R
Riku Voipio 已提交
1156 1157 1158 1159 1160 1161 1162
{
    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);
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173

    /* Several targets have special calling conventions for the original
       pipe syscall, but didn't replicate this into the pipe2 syscall.  */
    if (!is_pipe2) {
#if defined(TARGET_ALPHA)
        ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
        return host_pipe[0];
#elif defined(TARGET_MIPS)
        ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
        return host_pipe[0];
#elif defined(TARGET_SH4)
1174
        ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
1175
        return host_pipe[0];
1176
#endif
1177 1178
    }

R
Riku Voipio 已提交
1179 1180 1181 1182 1183 1184
    if (put_user_s32(host_pipe[0], pipedes)
        || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
        return -TARGET_EFAULT;
    return get_errno(ret);
}

1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
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))
1197
        mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
1198 1199 1200 1201 1202
    unlock_user(target_smreqn, target_addr, 0);

    return 0;
}

1203 1204 1205
static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
                                               abi_ulong target_addr,
                                               socklen_t len)
B
bellard 已提交
1206
{
1207 1208
    const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
    sa_family_t sa_family;
1209 1210
    struct target_sockaddr *target_saddr;

1211 1212 1213
    target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
    if (!target_saddr)
        return -TARGET_EFAULT;
1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235

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

1236
    memcpy(addr, target_saddr, len);
1237
    addr->sa_family = sa_family;
1238
    unlock_user(target_saddr, target_addr, 0);
1239 1240

    return 0;
B
bellard 已提交
1241 1242
}

1243 1244 1245
static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
                                               struct sockaddr *addr,
                                               socklen_t len)
B
bellard 已提交
1246
{
1247 1248
    struct target_sockaddr *target_saddr;

1249 1250 1251
    target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
    if (!target_saddr)
        return -TARGET_EFAULT;
1252 1253 1254
    memcpy(target_saddr, addr, len);
    target_saddr->sa_family = tswap16(addr->sa_family);
    unlock_user(target_saddr, target_addr, len);
1255 1256

    return 0;
B
bellard 已提交
1257 1258
}

1259
/* ??? Should this also swap msgh->name?  */
1260 1261
static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
                                           struct target_msghdr *target_msgh)
B
bellard 已提交
1262 1263
{
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
1264 1265 1266
    abi_long msg_controllen;
    abi_ulong target_cmsg_addr;
    struct target_cmsghdr *target_cmsg;
B
bellard 已提交
1267
    socklen_t space = 0;
1268
    
1269
    msg_controllen = tswapal(target_msgh->msg_controllen);
1270 1271
    if (msg_controllen < sizeof (struct target_cmsghdr)) 
        goto the_end;
1272
    target_cmsg_addr = tswapal(target_msgh->msg_control);
1273 1274 1275
    target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
    if (!target_cmsg)
        return -TARGET_EFAULT;
B
bellard 已提交
1276 1277 1278 1279 1280

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

1281
        int len = tswapal(target_cmsg->cmsg_len)
B
bellard 已提交
1282 1283 1284 1285 1286
                  - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));

        space += CMSG_SPACE(len);
        if (space > msgh->msg_controllen) {
            space -= CMSG_SPACE(len);
B
bellard 已提交
1287
            gemu_log("Host cmsg overflow\n");
B
bellard 已提交
1288 1289 1290 1291 1292 1293 1294
            break;
        }

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

1295
        if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
B
bellard 已提交
1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
            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);
    }
1310 1311
    unlock_user(target_cmsg, target_cmsg_addr, 0);
 the_end:
B
bellard 已提交
1312
    msgh->msg_controllen = space;
1313
    return 0;
B
bellard 已提交
1314 1315
}

1316
/* ??? Should this also swap msgh->name?  */
1317 1318
static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
                                           struct msghdr *msgh)
B
bellard 已提交
1319 1320
{
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
1321 1322 1323
    abi_long msg_controllen;
    abi_ulong target_cmsg_addr;
    struct target_cmsghdr *target_cmsg;
B
bellard 已提交
1324 1325
    socklen_t space = 0;

1326
    msg_controllen = tswapal(target_msgh->msg_controllen);
1327 1328
    if (msg_controllen < sizeof (struct target_cmsghdr)) 
        goto the_end;
1329
    target_cmsg_addr = tswapal(target_msgh->msg_control);
1330 1331 1332 1333
    target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
    if (!target_cmsg)
        return -TARGET_EFAULT;

B
bellard 已提交
1334 1335 1336 1337 1338 1339 1340
    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);
1341
        if (space > msg_controllen) {
B
bellard 已提交
1342
            space -= TARGET_CMSG_SPACE(len);
B
bellard 已提交
1343
            gemu_log("Target cmsg overflow\n");
B
bellard 已提交
1344 1345 1346 1347 1348
            break;
        }

        target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
        target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
1349
        target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
B
bellard 已提交
1350

1351
        if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
B
bellard 已提交
1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
            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);
    }
1366 1367
    unlock_user(target_cmsg, target_cmsg_addr, space);
 the_end:
1368
    target_msgh->msg_controllen = tswapal(space);
1369
    return 0;
B
bellard 已提交
1370 1371
}

1372
/* do_setsockopt() Must return target values and target errnos. */
1373
static abi_long do_setsockopt(int sockfd, int level, int optname,
1374
                              abi_ulong optval_addr, socklen_t optlen)
B
bellard 已提交
1375
{
1376
    abi_long ret;
1377
    int val;
1378
    struct ip_mreqn *ip_mreq;
1379
    struct ip_mreq_source *ip_mreq_source;
1380

1381 1382
    switch(level) {
    case SOL_TCP:
B
bellard 已提交
1383 1384
        /* TCP options all take an 'int' value.  */
        if (optlen < sizeof(uint32_t))
1385
            return -TARGET_EINVAL;
1386

1387 1388
        if (get_user_u32(val, optval_addr))
            return -TARGET_EFAULT;
1389 1390 1391 1392
        ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
        break;
    case SOL_IP:
        switch(optname) {
B
bellard 已提交
1393 1394
        case IP_TOS:
        case IP_TTL:
1395
        case IP_HDRINCL:
B
bellard 已提交
1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
        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:
1408 1409
            val = 0;
            if (optlen >= sizeof(uint32_t)) {
1410 1411
                if (get_user_u32(val, optval_addr))
                    return -TARGET_EFAULT;
1412
            } else if (optlen >= 1) {
1413 1414
                if (get_user_u8(val, optval_addr))
                    return -TARGET_EFAULT;
1415 1416 1417
            }
            ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
            break;
1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
        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;

1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440
        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;

1441 1442 1443 1444
        default:
            goto unimplemented;
        }
        break;
1445
    case TARGET_SOL_SOCKET:
1446 1447
        switch (optname) {
            /* Options with 'int' argument.  */
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483
        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 已提交
1484
#ifdef SO_BSDCOMPAT
1485 1486 1487
        case TARGET_SO_BSDCOMPAT:
		optname = SO_BSDCOMPAT;
		break;
B
bellard 已提交
1488
#endif
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503
        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;
1504 1505 1506 1507
            break;
        default:
            goto unimplemented;
        }
1508
	if (optlen < sizeof(uint32_t))
1509
            return -TARGET_EINVAL;
1510

1511 1512
	if (get_user_u32(val, optval_addr))
            return -TARGET_EFAULT;
1513
	ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
1514
        break;
B
bellard 已提交
1515
    default:
1516
    unimplemented:
1517
        gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
1518
        ret = -TARGET_ENOPROTOOPT;
B
bellard 已提交
1519
    }
1520
    return ret;
B
bellard 已提交
1521 1522
}

1523
/* do_getsockopt() Must return target values and target errnos. */
1524
static abi_long do_getsockopt(int sockfd, int level, int optname,
1525
                              abi_ulong optval_addr, abi_ulong optlen)
B
bellard 已提交
1526
{
1527
    abi_long ret;
1528 1529
    int len, val;
    socklen_t lv;
1530 1531

    switch(level) {
1532
    case TARGET_SOL_SOCKET:
1533 1534 1535 1536 1537 1538 1539 1540
        level = SOL_SOCKET;
        switch (optname) {
        /* These don't just return a single integer */
        case TARGET_SO_LINGER:
        case TARGET_SO_RCVTIMEO:
        case TARGET_SO_SNDTIMEO:
        case TARGET_SO_PEERNAME:
            goto unimplemented;
1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573
        case TARGET_SO_PEERCRED: {
            struct ucred cr;
            socklen_t crlen;
            struct target_ucred *tcr;

            if (get_user_u32(len, optlen)) {
                return -TARGET_EFAULT;
            }
            if (len < 0) {
                return -TARGET_EINVAL;
            }

            crlen = sizeof(cr);
            ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
                                       &cr, &crlen));
            if (ret < 0) {
                return ret;
            }
            if (len > crlen) {
                len = crlen;
            }
            if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
                return -TARGET_EFAULT;
            }
            __put_user(cr.pid, &tcr->pid);
            __put_user(cr.uid, &tcr->uid);
            __put_user(cr.gid, &tcr->gid);
            unlock_user_struct(tcr, optval_addr, 1);
            if (put_user_u32(len, optlen)) {
                return -TARGET_EFAULT;
            }
            break;
        }
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624
        /* Options with 'int' argument.  */
        case TARGET_SO_DEBUG:
            optname = SO_DEBUG;
            goto int_case;
        case TARGET_SO_REUSEADDR:
            optname = SO_REUSEADDR;
            goto int_case;
        case TARGET_SO_TYPE:
            optname = SO_TYPE;
            goto int_case;
        case TARGET_SO_ERROR:
            optname = SO_ERROR;
            goto int_case;
        case TARGET_SO_DONTROUTE:
            optname = SO_DONTROUTE;
            goto int_case;
        case TARGET_SO_BROADCAST:
            optname = SO_BROADCAST;
            goto int_case;
        case TARGET_SO_SNDBUF:
            optname = SO_SNDBUF;
            goto int_case;
        case TARGET_SO_RCVBUF:
            optname = SO_RCVBUF;
            goto int_case;
        case TARGET_SO_KEEPALIVE:
            optname = SO_KEEPALIVE;
            goto int_case;
        case TARGET_SO_OOBINLINE:
            optname = SO_OOBINLINE;
            goto int_case;
        case TARGET_SO_NO_CHECK:
            optname = SO_NO_CHECK;
            goto int_case;
        case TARGET_SO_PRIORITY:
            optname = SO_PRIORITY;
            goto int_case;
#ifdef SO_BSDCOMPAT
        case TARGET_SO_BSDCOMPAT:
            optname = SO_BSDCOMPAT;
            goto int_case;
#endif
        case TARGET_SO_PASSCRED:
            optname = SO_PASSCRED;
            goto int_case;
        case TARGET_SO_TIMESTAMP:
            optname = SO_TIMESTAMP;
            goto int_case;
        case TARGET_SO_RCVLOWAT:
            optname = SO_RCVLOWAT;
            goto int_case;
1625
        default:
B
bellard 已提交
1626 1627 1628 1629 1630 1631
            goto int_case;
        }
        break;
    case SOL_TCP:
        /* TCP options all take an 'int' value.  */
    int_case:
1632 1633
        if (get_user_u32(len, optlen))
            return -TARGET_EFAULT;
B
bellard 已提交
1634
        if (len < 0)
1635
            return -TARGET_EINVAL;
1636
        lv = sizeof(lv);
B
bellard 已提交
1637 1638 1639 1640 1641
        ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
        if (ret < 0)
            return ret;
        if (len > lv)
            len = lv;
1642 1643 1644 1645 1646 1647
        if (len == 4) {
            if (put_user_u32(val, optval_addr))
                return -TARGET_EFAULT;
        } else {
            if (put_user_u8(val, optval_addr))
                return -TARGET_EFAULT;
1648
        }
1649 1650
        if (put_user_u32(len, optlen))
            return -TARGET_EFAULT;
B
bellard 已提交
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668
        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:
1669 1670
            if (get_user_u32(len, optlen))
                return -TARGET_EFAULT;
1671
            if (len < 0)
1672
                return -TARGET_EINVAL;
1673
            lv = sizeof(lv);
1674 1675 1676
            ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
            if (ret < 0)
                return ret;
B
bellard 已提交
1677 1678
            if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
                len = 1;
1679 1680 1681
                if (put_user_u32(len, optlen)
                    || put_user_u8(val, optval_addr))
                    return -TARGET_EFAULT;
B
bellard 已提交
1682 1683 1684
            } else {
                if (len > sizeof(int))
                    len = sizeof(int);
1685 1686 1687
                if (put_user_u32(len, optlen)
                    || put_user_u32(val, optval_addr))
                    return -TARGET_EFAULT;
B
bellard 已提交
1688
            }
1689
            break;
B
bellard 已提交
1690
        default:
1691 1692
            ret = -TARGET_ENOPROTOOPT;
            break;
1693 1694 1695 1696 1697 1698
        }
        break;
    default:
    unimplemented:
        gemu_log("getsockopt level=%d optname=%d not yet supported\n",
                 level, optname);
1699
        ret = -TARGET_EOPNOTSUPP;
1700 1701 1702
        break;
    }
    return ret;
B
bellard 已提交
1703 1704
}

1705 1706 1707 1708 1709 1710
/* 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)
1711 1712
{
    struct target_iovec *target_vec;
1713
    abi_ulong base;
1714
    int i;
1715

1716 1717 1718
    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
    if (!target_vec)
        return -TARGET_EFAULT;
1719
    for(i = 0;i < count; i++) {
1720 1721
        base = tswapal(target_vec[i].iov_base);
        vec[i].iov_len = tswapal(target_vec[i].iov_len);
B
bellard 已提交
1722 1723
        if (vec[i].iov_len != 0) {
            vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
1724 1725
            /* Don't check lock_user return value. We must call writev even
               if a element has invalid base address. */
B
bellard 已提交
1726 1727 1728 1729
        } else {
            /* zero length pointer is ignored */
            vec[i].iov_base = NULL;
        }
1730 1731 1732
    }
    unlock_user (target_vec, target_addr, 0);
    return 0;
1733 1734
}

1735 1736
static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
                             int count, int copy)
1737 1738
{
    struct target_iovec *target_vec;
1739
    abi_ulong base;
1740 1741
    int i;

1742 1743 1744
    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
    if (!target_vec)
        return -TARGET_EFAULT;
1745
    for(i = 0;i < count; i++) {
1746
        if (target_vec[i].iov_base) {
1747
            base = tswapal(target_vec[i].iov_base);
1748 1749
            unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
        }
1750 1751
    }
    unlock_user (target_vec, target_addr, 0);
1752 1753

    return 0;
1754 1755
}

1756
/* do_socket() Must return target values and target errnos. */
1757
static abi_long do_socket(int domain, int type, int protocol)
1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780
{
#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
1781 1782
    if (domain == PF_NETLINK)
        return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
1783 1784 1785
    return get_errno(socket(domain, type, protocol));
}

1786
/* do_bind() Must return target values and target errnos. */
1787 1788
static abi_long do_bind(int sockfd, abi_ulong target_addr,
                        socklen_t addrlen)
1789
{
1790
    void *addr;
1791
    abi_long ret;
1792

1793
    if ((int)addrlen < 0) {
1794
        return -TARGET_EINVAL;
1795
    }
1796

1797
    addr = alloca(addrlen+1);
1798

1799 1800 1801 1802
    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
    if (ret)
        return ret;

1803 1804 1805
    return get_errno(bind(sockfd, addr, addrlen));
}

1806
/* do_connect() Must return target values and target errnos. */
1807 1808
static abi_long do_connect(int sockfd, abi_ulong target_addr,
                           socklen_t addrlen)
1809
{
1810
    void *addr;
1811
    abi_long ret;
1812

1813
    if ((int)addrlen < 0) {
1814
        return -TARGET_EINVAL;
1815
    }
1816 1817

    addr = alloca(addrlen);
1818

1819 1820 1821 1822
    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
    if (ret)
        return ret;

1823 1824 1825
    return get_errno(connect(sockfd, addr, addrlen));
}

1826
/* do_sendrecvmsg() Must return target values and target errnos. */
1827 1828
static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
                               int flags, int send)
1829
{
1830
    abi_long ret, len;
1831 1832 1833 1834
    struct target_msghdr *msgp;
    struct msghdr msg;
    int count;
    struct iovec *vec;
1835
    abi_ulong target_vec;
1836

1837 1838 1839 1840 1841 1842
    /* FIXME */
    if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
                          msgp,
                          target_msg,
                          send ? 1 : 0))
        return -TARGET_EFAULT;
1843 1844 1845
    if (msgp->msg_name) {
        msg.msg_namelen = tswap32(msgp->msg_namelen);
        msg.msg_name = alloca(msg.msg_namelen);
1846
        ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
1847
                                msg.msg_namelen);
1848 1849 1850 1851
        if (ret) {
            unlock_user_struct(msgp, target_msg, send ? 0 : 1);
            return ret;
        }
1852 1853 1854 1855
    } else {
        msg.msg_name = NULL;
        msg.msg_namelen = 0;
    }
1856
    msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
1857 1858
    msg.msg_control = alloca(msg.msg_controllen);
    msg.msg_flags = tswap32(msgp->msg_flags);
1859

1860
    count = tswapal(msgp->msg_iovlen);
1861
    vec = alloca(count * sizeof(struct iovec));
1862
    target_vec = tswapal(msgp->msg_iov);
1863
    lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
1864 1865
    msg.msg_iovlen = count;
    msg.msg_iov = vec;
1866

1867
    if (send) {
1868 1869 1870
        ret = target_to_host_cmsg(&msg, msgp);
        if (ret == 0)
            ret = get_errno(sendmsg(fd, &msg, flags));
1871 1872
    } else {
        ret = get_errno(recvmsg(fd, &msg, flags));
1873 1874
        if (!is_error(ret)) {
            len = ret;
1875
            ret = host_to_target_cmsg(msgp, &msg);
1876 1877 1878
            if (!is_error(ret))
                ret = len;
        }
1879 1880
    }
    unlock_iovec(vec, target_vec, count, !send);
1881
    unlock_user_struct(msgp, target_msg, send ? 0 : 1);
1882 1883 1884
    return ret;
}

1885
/* do_accept() Must return target values and target errnos. */
1886
static abi_long do_accept(int fd, abi_ulong target_addr,
1887
                          abi_ulong target_addrlen_addr)
P
pbrook 已提交
1888
{
1889 1890
    socklen_t addrlen;
    void *addr;
1891
    abi_long ret;
P
pbrook 已提交
1892

1893 1894 1895 1896
    if (target_addr == 0)
       return get_errno(accept(fd, NULL, NULL));

    /* linux returns EINVAL if addrlen pointer is invalid */
1897
    if (get_user_u32(addrlen, target_addrlen_addr))
1898
        return -TARGET_EINVAL;
1899

1900
    if ((int)addrlen < 0) {
1901
        return -TARGET_EINVAL;
1902
    }
1903

1904 1905 1906
    if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
        return -TARGET_EINVAL;

1907 1908
    addr = alloca(addrlen);

P
pbrook 已提交
1909 1910 1911
    ret = get_errno(accept(fd, addr, &addrlen));
    if (!is_error(ret)) {
        host_to_target_sockaddr(target_addr, addr, addrlen);
1912 1913
        if (put_user_u32(addrlen, target_addrlen_addr))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1914 1915 1916 1917
    }
    return ret;
}

1918
/* do_getpeername() Must return target values and target errnos. */
1919
static abi_long do_getpeername(int fd, abi_ulong target_addr,
1920
                               abi_ulong target_addrlen_addr)
P
pbrook 已提交
1921
{
1922 1923
    socklen_t addrlen;
    void *addr;
1924
    abi_long ret;
P
pbrook 已提交
1925

1926 1927 1928
    if (get_user_u32(addrlen, target_addrlen_addr))
        return -TARGET_EFAULT;

1929
    if ((int)addrlen < 0) {
1930
        return -TARGET_EINVAL;
1931
    }
1932

1933 1934 1935
    if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
        return -TARGET_EFAULT;

1936 1937
    addr = alloca(addrlen);

P
pbrook 已提交
1938 1939 1940
    ret = get_errno(getpeername(fd, addr, &addrlen));
    if (!is_error(ret)) {
        host_to_target_sockaddr(target_addr, addr, addrlen);
1941 1942
        if (put_user_u32(addrlen, target_addrlen_addr))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1943 1944 1945 1946
    }
    return ret;
}

1947
/* do_getsockname() Must return target values and target errnos. */
1948
static abi_long do_getsockname(int fd, abi_ulong target_addr,
1949
                               abi_ulong target_addrlen_addr)
P
pbrook 已提交
1950
{
1951 1952
    socklen_t addrlen;
    void *addr;
1953
    abi_long ret;
P
pbrook 已提交
1954

1955 1956 1957
    if (get_user_u32(addrlen, target_addrlen_addr))
        return -TARGET_EFAULT;

1958
    if ((int)addrlen < 0) {
1959
        return -TARGET_EINVAL;
1960
    }
1961

1962 1963 1964
    if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
        return -TARGET_EFAULT;

1965 1966
    addr = alloca(addrlen);

P
pbrook 已提交
1967 1968 1969
    ret = get_errno(getsockname(fd, addr, &addrlen));
    if (!is_error(ret)) {
        host_to_target_sockaddr(target_addr, addr, addrlen);
1970 1971
        if (put_user_u32(addrlen, target_addrlen_addr))
            ret = -TARGET_EFAULT;
P
pbrook 已提交
1972 1973 1974 1975
    }
    return ret;
}

1976
/* do_socketpair() Must return target values and target errnos. */
1977
static abi_long do_socketpair(int domain, int type, int protocol,
1978
                              abi_ulong target_tab_addr)
P
pbrook 已提交
1979 1980
{
    int tab[2];
1981
    abi_long ret;
P
pbrook 已提交
1982 1983 1984

    ret = get_errno(socketpair(domain, type, protocol, tab));
    if (!is_error(ret)) {
1985 1986 1987
        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 已提交
1988 1989 1990 1991
    }
    return ret;
}

1992
/* do_sendto() Must return target values and target errnos. */
1993 1994
static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
                          abi_ulong target_addr, socklen_t addrlen)
P
pbrook 已提交
1995 1996 1997
{
    void *addr;
    void *host_msg;
1998
    abi_long ret;
P
pbrook 已提交
1999

2000
    if ((int)addrlen < 0) {
2001
        return -TARGET_EINVAL;
2002
    }
2003

2004 2005 2006
    host_msg = lock_user(VERIFY_READ, msg, len, 1);
    if (!host_msg)
        return -TARGET_EFAULT;
P
pbrook 已提交
2007 2008
    if (target_addr) {
        addr = alloca(addrlen);
2009 2010 2011 2012 2013
        ret = target_to_host_sockaddr(addr, target_addr, addrlen);
        if (ret) {
            unlock_user(host_msg, msg, 0);
            return ret;
        }
P
pbrook 已提交
2014 2015 2016 2017 2018 2019 2020 2021
        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;
}

2022
/* do_recvfrom() Must return target values and target errnos. */
2023 2024 2025
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 已提交
2026 2027 2028 2029
{
    socklen_t addrlen;
    void *addr;
    void *host_msg;
2030
    abi_long ret;
P
pbrook 已提交
2031

2032 2033 2034
    host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
    if (!host_msg)
        return -TARGET_EFAULT;
P
pbrook 已提交
2035
    if (target_addr) {
2036 2037 2038 2039
        if (get_user_u32(addrlen, target_addrlen)) {
            ret = -TARGET_EFAULT;
            goto fail;
        }
2040
        if ((int)addrlen < 0) {
2041 2042 2043
            ret = -TARGET_EINVAL;
            goto fail;
        }
P
pbrook 已提交
2044 2045 2046 2047
        addr = alloca(addrlen);
        ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
    } else {
        addr = NULL; /* To keep compiler quiet.  */
B
Blue Swirl 已提交
2048
        ret = get_errno(qemu_recv(fd, host_msg, len, flags));
P
pbrook 已提交
2049 2050 2051 2052
    }
    if (!is_error(ret)) {
        if (target_addr) {
            host_to_target_sockaddr(target_addr, addr, addrlen);
2053 2054 2055 2056
            if (put_user_u32(addrlen, target_addrlen)) {
                ret = -TARGET_EFAULT;
                goto fail;
            }
P
pbrook 已提交
2057 2058 2059
        }
        unlock_user(host_msg, msg, len);
    } else {
2060
fail:
P
pbrook 已提交
2061 2062 2063 2064 2065
        unlock_user(host_msg, msg, 0);
    }
    return ret;
}

2066
#ifdef TARGET_NR_socketcall
2067
/* do_socketcall() Must return target values and target errnos. */
2068
static abi_long do_socketcall(int num, abi_ulong vptr)
2069
{
2070 2071
    abi_long ret;
    const int n = sizeof(abi_ulong);
2072 2073 2074

    switch(num) {
    case SOCKOP_socket:
B
bellard 已提交
2075
	{
U
Ulrich Hecht 已提交
2076
            abi_ulong domain, type, protocol;
2077

U
Ulrich Hecht 已提交
2078 2079 2080
            if (get_user_ual(domain, vptr)
                || get_user_ual(type, vptr + n)
                || get_user_ual(protocol, vptr + 2 * n))
2081 2082
                return -TARGET_EFAULT;

2083
            ret = do_socket(domain, type, protocol);
B
bellard 已提交
2084
	}
2085 2086
        break;
    case SOCKOP_bind:
B
bellard 已提交
2087
	{
U
Ulrich Hecht 已提交
2088
            abi_ulong sockfd;
2089 2090 2091
            abi_ulong target_addr;
            socklen_t addrlen;

U
Ulrich Hecht 已提交
2092
            if (get_user_ual(sockfd, vptr)
2093
                || get_user_ual(target_addr, vptr + n)
U
Ulrich Hecht 已提交
2094
                || get_user_ual(addrlen, vptr + 2 * n))
2095 2096
                return -TARGET_EFAULT;

2097
            ret = do_bind(sockfd, target_addr, addrlen);
B
bellard 已提交
2098
        }
2099 2100
        break;
    case SOCKOP_connect:
B
bellard 已提交
2101
        {
U
Ulrich Hecht 已提交
2102
            abi_ulong sockfd;
2103 2104 2105
            abi_ulong target_addr;
            socklen_t addrlen;

U
Ulrich Hecht 已提交
2106
            if (get_user_ual(sockfd, vptr)
2107
                || get_user_ual(target_addr, vptr + n)
U
Ulrich Hecht 已提交
2108
                || get_user_ual(addrlen, vptr + 2 * n))
2109 2110
                return -TARGET_EFAULT;

2111
            ret = do_connect(sockfd, target_addr, addrlen);
B
bellard 已提交
2112
        }
2113 2114
        break;
    case SOCKOP_listen:
B
bellard 已提交
2115
        {
U
Ulrich Hecht 已提交
2116
            abi_ulong sockfd, backlog;
2117

U
Ulrich Hecht 已提交
2118 2119
            if (get_user_ual(sockfd, vptr)
                || get_user_ual(backlog, vptr + n))
2120 2121
                return -TARGET_EFAULT;

B
bellard 已提交
2122 2123
            ret = get_errno(listen(sockfd, backlog));
        }
2124 2125 2126
        break;
    case SOCKOP_accept:
        {
U
Ulrich Hecht 已提交
2127
            abi_ulong sockfd;
2128 2129
            abi_ulong target_addr, target_addrlen;

U
Ulrich Hecht 已提交
2130
            if (get_user_ual(sockfd, vptr)
2131
                || get_user_ual(target_addr, vptr + n)
U
Ulrich Hecht 已提交
2132
                || get_user_ual(target_addrlen, vptr + 2 * n))
2133 2134
                return -TARGET_EFAULT;

P
pbrook 已提交
2135
            ret = do_accept(sockfd, target_addr, target_addrlen);
2136 2137 2138 2139
        }
        break;
    case SOCKOP_getsockname:
        {
U
Ulrich Hecht 已提交
2140
            abi_ulong sockfd;
2141 2142
            abi_ulong target_addr, target_addrlen;

U
Ulrich Hecht 已提交
2143
            if (get_user_ual(sockfd, vptr)
2144
                || get_user_ual(target_addr, vptr + n)
U
Ulrich Hecht 已提交
2145
                || get_user_ual(target_addrlen, vptr + 2 * n))
2146 2147
                return -TARGET_EFAULT;

P
pbrook 已提交
2148
            ret = do_getsockname(sockfd, target_addr, target_addrlen);
2149 2150 2151 2152
        }
        break;
    case SOCKOP_getpeername:
        {
U
Ulrich Hecht 已提交
2153
            abi_ulong sockfd;
2154 2155
            abi_ulong target_addr, target_addrlen;

U
Ulrich Hecht 已提交
2156
            if (get_user_ual(sockfd, vptr)
2157
                || get_user_ual(target_addr, vptr + n)
U
Ulrich Hecht 已提交
2158
                || get_user_ual(target_addrlen, vptr + 2 * n))
2159 2160
                return -TARGET_EFAULT;

P
pbrook 已提交
2161
            ret = do_getpeername(sockfd, target_addr, target_addrlen);
2162 2163 2164 2165
        }
        break;
    case SOCKOP_socketpair:
        {
U
Ulrich Hecht 已提交
2166
            abi_ulong domain, type, protocol;
2167 2168
            abi_ulong tab;

U
Ulrich Hecht 已提交
2169 2170 2171
            if (get_user_ual(domain, vptr)
                || get_user_ual(type, vptr + n)
                || get_user_ual(protocol, vptr + 2 * n)
2172 2173 2174
                || get_user_ual(tab, vptr + 3 * n))
                return -TARGET_EFAULT;

P
pbrook 已提交
2175
            ret = do_socketpair(domain, type, protocol, tab);
2176 2177 2178
        }
        break;
    case SOCKOP_send:
B
bellard 已提交
2179
        {
U
Ulrich Hecht 已提交
2180
            abi_ulong sockfd;
2181 2182
            abi_ulong msg;
            size_t len;
U
Ulrich Hecht 已提交
2183
            abi_ulong flags;
2184

U
Ulrich Hecht 已提交
2185
            if (get_user_ual(sockfd, vptr)
2186 2187
                || get_user_ual(msg, vptr + n)
                || get_user_ual(len, vptr + 2 * n)
U
Ulrich Hecht 已提交
2188
                || get_user_ual(flags, vptr + 3 * n))
2189 2190
                return -TARGET_EFAULT;

P
pbrook 已提交
2191
            ret = do_sendto(sockfd, msg, len, flags, 0, 0);
B
bellard 已提交
2192
        }
2193 2194
        break;
    case SOCKOP_recv:
B
bellard 已提交
2195
        {
U
Ulrich Hecht 已提交
2196
            abi_ulong sockfd;
2197 2198
            abi_ulong msg;
            size_t len;
U
Ulrich Hecht 已提交
2199
            abi_ulong flags;
2200

U
Ulrich Hecht 已提交
2201
            if (get_user_ual(sockfd, vptr)
2202 2203
                || get_user_ual(msg, vptr + n)
                || get_user_ual(len, vptr + 2 * n)
U
Ulrich Hecht 已提交
2204
                || get_user_ual(flags, vptr + 3 * n))
2205 2206
                return -TARGET_EFAULT;

P
pbrook 已提交
2207
            ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
B
bellard 已提交
2208
        }
2209 2210
        break;
    case SOCKOP_sendto:
B
bellard 已提交
2211
        {
U
Ulrich Hecht 已提交
2212
            abi_ulong sockfd;
2213 2214
            abi_ulong msg;
            size_t len;
U
Ulrich Hecht 已提交
2215
            abi_ulong flags;
2216 2217 2218
            abi_ulong addr;
            socklen_t addrlen;

U
Ulrich Hecht 已提交
2219
            if (get_user_ual(sockfd, vptr)
2220 2221
                || get_user_ual(msg, vptr + n)
                || get_user_ual(len, vptr + 2 * n)
U
Ulrich Hecht 已提交
2222
                || get_user_ual(flags, vptr + 3 * n)
2223
                || get_user_ual(addr, vptr + 4 * n)
U
Ulrich Hecht 已提交
2224
                || get_user_ual(addrlen, vptr + 5 * n))
2225 2226
                return -TARGET_EFAULT;

P
pbrook 已提交
2227
            ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
B
bellard 已提交
2228
        }
2229 2230 2231
        break;
    case SOCKOP_recvfrom:
        {
U
Ulrich Hecht 已提交
2232
            abi_ulong sockfd;
2233 2234
            abi_ulong msg;
            size_t len;
U
Ulrich Hecht 已提交
2235
            abi_ulong flags;
2236 2237 2238
            abi_ulong addr;
            socklen_t addrlen;

U
Ulrich Hecht 已提交
2239
            if (get_user_ual(sockfd, vptr)
2240 2241
                || get_user_ual(msg, vptr + n)
                || get_user_ual(len, vptr + 2 * n)
U
Ulrich Hecht 已提交
2242
                || get_user_ual(flags, vptr + 3 * n)
2243
                || get_user_ual(addr, vptr + 4 * n)
U
Ulrich Hecht 已提交
2244
                || get_user_ual(addrlen, vptr + 5 * n))
2245 2246
                return -TARGET_EFAULT;

P
pbrook 已提交
2247
            ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
2248 2249 2250
        }
        break;
    case SOCKOP_shutdown:
B
bellard 已提交
2251
        {
U
Ulrich Hecht 已提交
2252
            abi_ulong sockfd, how;
2253

U
Ulrich Hecht 已提交
2254 2255
            if (get_user_ual(sockfd, vptr)
                || get_user_ual(how, vptr + n))
2256
                return -TARGET_EFAULT;
B
bellard 已提交
2257 2258 2259

            ret = get_errno(shutdown(sockfd, how));
        }
2260 2261 2262
        break;
    case SOCKOP_sendmsg:
    case SOCKOP_recvmsg:
B
bellard 已提交
2263
        {
U
Ulrich Hecht 已提交
2264
            abi_ulong fd;
2265
            abi_ulong target_msg;
U
Ulrich Hecht 已提交
2266
            abi_ulong flags;
B
bellard 已提交
2267

U
Ulrich Hecht 已提交
2268
            if (get_user_ual(fd, vptr)
2269
                || get_user_ual(target_msg, vptr + n)
U
Ulrich Hecht 已提交
2270
                || get_user_ual(flags, vptr + 2 * n))
2271
                return -TARGET_EFAULT;
2272

2273
            ret = do_sendrecvmsg(fd, target_msg, flags,
2274
                                 (num == SOCKOP_sendmsg));
B
bellard 已提交
2275 2276
        }
        break;
2277
    case SOCKOP_setsockopt:
B
bellard 已提交
2278
        {
U
Ulrich Hecht 已提交
2279 2280 2281
            abi_ulong sockfd;
            abi_ulong level;
            abi_ulong optname;
2282 2283 2284
            abi_ulong optval;
            socklen_t optlen;

U
Ulrich Hecht 已提交
2285 2286 2287
            if (get_user_ual(sockfd, vptr)
                || get_user_ual(level, vptr + n)
                || get_user_ual(optname, vptr + 2 * n)
2288
                || get_user_ual(optval, vptr + 3 * n)
U
Ulrich Hecht 已提交
2289
                || get_user_ual(optlen, vptr + 4 * n))
2290
                return -TARGET_EFAULT;
B
bellard 已提交
2291 2292 2293 2294

            ret = do_setsockopt(sockfd, level, optname, optval, optlen);
        }
        break;
2295
    case SOCKOP_getsockopt:
B
bellard 已提交
2296
        {
U
Ulrich Hecht 已提交
2297 2298 2299
            abi_ulong sockfd;
            abi_ulong level;
            abi_ulong optname;
2300 2301 2302
            abi_ulong optval;
            socklen_t optlen;

U
Ulrich Hecht 已提交
2303 2304 2305
            if (get_user_ual(sockfd, vptr)
                || get_user_ual(level, vptr + n)
                || get_user_ual(optname, vptr + 2 * n)
2306
                || get_user_ual(optval, vptr + 3 * n)
U
Ulrich Hecht 已提交
2307
                || get_user_ual(optlen, vptr + 4 * n))
2308
                return -TARGET_EFAULT;
B
bellard 已提交
2309

2310
            ret = do_getsockopt(sockfd, level, optname, optval, optlen);
B
bellard 已提交
2311 2312
        }
        break;
2313 2314
    default:
        gemu_log("Unsupported socketcall: %d\n", num);
2315
        ret = -TARGET_ENOSYS;
2316 2317 2318 2319
        break;
    }
    return ret;
}
2320
#endif
2321

2322 2323 2324
#define N_SHM_REGIONS	32

static struct shm_region {
2325 2326
    abi_ulong	start;
    abi_ulong	size;
2327 2328
} shm_regions[N_SHM_REGIONS];

2329 2330
struct target_ipc_perm
{
2331 2332 2333 2334 2335
    abi_long __key;
    abi_ulong uid;
    abi_ulong gid;
    abi_ulong cuid;
    abi_ulong cgid;
2336 2337 2338 2339
    unsigned short int mode;
    unsigned short int __pad1;
    unsigned short int __seq;
    unsigned short int __pad2;
2340 2341
    abi_ulong __unused1;
    abi_ulong __unused2;
2342 2343 2344 2345 2346
};

struct target_semid_ds
{
  struct target_ipc_perm sem_perm;
2347 2348 2349 2350 2351 2352 2353
  abi_ulong sem_otime;
  abi_ulong __unused1;
  abi_ulong sem_ctime;
  abi_ulong __unused2;
  abi_ulong sem_nsems;
  abi_ulong __unused3;
  abi_ulong __unused4;
2354 2355
};

2356 2357
static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
                                               abi_ulong target_addr)
2358 2359 2360 2361
{
    struct target_ipc_perm *target_ip;
    struct target_semid_ds *target_sd;

2362 2363
    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
        return -TARGET_EFAULT;
2364
    target_ip = &(target_sd->sem_perm);
2365 2366 2367 2368 2369 2370
    host_ip->__key = tswapal(target_ip->__key);
    host_ip->uid = tswapal(target_ip->uid);
    host_ip->gid = tswapal(target_ip->gid);
    host_ip->cuid = tswapal(target_ip->cuid);
    host_ip->cgid = tswapal(target_ip->cgid);
    host_ip->mode = tswap16(target_ip->mode);
2371
    unlock_user_struct(target_sd, target_addr, 0);
2372
    return 0;
2373 2374
}

2375 2376
static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
                                               struct ipc_perm *host_ip)
2377 2378 2379 2380
{
    struct target_ipc_perm *target_ip;
    struct target_semid_ds *target_sd;

2381 2382
    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
        return -TARGET_EFAULT;
2383
    target_ip = &(target_sd->sem_perm);
2384 2385 2386 2387 2388 2389
    target_ip->__key = tswapal(host_ip->__key);
    target_ip->uid = tswapal(host_ip->uid);
    target_ip->gid = tswapal(host_ip->gid);
    target_ip->cuid = tswapal(host_ip->cuid);
    target_ip->cgid = tswapal(host_ip->cgid);
    target_ip->mode = tswap16(host_ip->mode);
2390
    unlock_user_struct(target_sd, target_addr, 1);
2391
    return 0;
2392 2393
}

2394 2395
static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
                                               abi_ulong target_addr)
2396 2397 2398
{
    struct target_semid_ds *target_sd;

2399 2400
    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
        return -TARGET_EFAULT;
2401 2402
    if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
        return -TARGET_EFAULT;
2403 2404 2405
    host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
    host_sd->sem_otime = tswapal(target_sd->sem_otime);
    host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
2406
    unlock_user_struct(target_sd, target_addr, 0);
2407
    return 0;
2408 2409
}

2410 2411
static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
                                               struct semid_ds *host_sd)
2412 2413 2414
{
    struct target_semid_ds *target_sd;

2415 2416
    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
        return -TARGET_EFAULT;
2417
    if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
2418
        return -TARGET_EFAULT;
2419 2420 2421
    target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
    target_sd->sem_otime = tswapal(host_sd->sem_otime);
    target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
2422
    unlock_user_struct(target_sd, target_addr, 1);
2423
    return 0;
2424 2425
}

2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458
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;
}

2459 2460
union semun {
	int val;
2461
	struct semid_ds *buf;
2462
	unsigned short *array;
2463
	struct seminfo *__buf;
2464 2465
};

2466 2467
union target_semun {
	int val;
2468 2469 2470
	abi_ulong buf;
	abi_ulong array;
	abi_ulong __buf;
2471 2472
};

2473 2474
static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
                                               abi_ulong target_addr)
2475
{
2476 2477 2478 2479 2480
    int nsems;
    unsigned short *array;
    union semun semun;
    struct semid_ds semid_ds;
    int i, ret;
2481

2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497
    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]);
2498
    }
2499 2500
    unlock_user(array, target_addr, 0);

2501
    return 0;
2502 2503
}

2504 2505
static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
                                               unsigned short **host_array)
2506
{
2507 2508 2509 2510 2511
    int nsems;
    unsigned short *array;
    union semun semun;
    struct semid_ds semid_ds;
    int i, ret;
2512

2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527
    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]);
2528
    }
2529 2530 2531
    free(*host_array);
    unlock_user(array, target_addr, 1);

2532
    return 0;
2533 2534
}

2535 2536
static inline abi_long do_semctl(int semid, int semnum, int cmd,
                                 union target_semun target_su)
2537 2538 2539
{
    union semun arg;
    struct semid_ds dsarg;
2540
    unsigned short *array = NULL;
2541 2542 2543 2544
    struct seminfo seminfo;
    abi_long ret = -TARGET_EINVAL;
    abi_long err;
    cmd &= 0xff;
2545 2546 2547 2548

    switch( cmd ) {
	case GETVAL:
	case SETVAL:
2549
            arg.val = tswap32(target_su.val);
2550
            ret = get_errno(semctl(semid, semnum, cmd, arg));
2551
            target_su.val = tswap32(arg.val);
2552 2553 2554
            break;
	case GETALL:
	case SETALL:
2555 2556 2557 2558 2559 2560 2561 2562
            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;
2563 2564 2565
            break;
	case IPC_STAT:
	case IPC_SET:
2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588
	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));
2589 2590 2591 2592 2593 2594
            break;
    }

    return ret;
}

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
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 已提交
2634 2635
struct target_msqid_ds
{
2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655
    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 已提交
2656 2657
};

2658 2659
static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
                                               abi_ulong target_addr)
T
ths 已提交
2660 2661 2662
{
    struct target_msqid_ds *target_md;

2663 2664
    if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
        return -TARGET_EFAULT;
2665 2666
    if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
        return -TARGET_EFAULT;
2667 2668 2669 2670 2671 2672 2673 2674
    host_md->msg_stime = tswapal(target_md->msg_stime);
    host_md->msg_rtime = tswapal(target_md->msg_rtime);
    host_md->msg_ctime = tswapal(target_md->msg_ctime);
    host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
    host_md->msg_qnum = tswapal(target_md->msg_qnum);
    host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
    host_md->msg_lspid = tswapal(target_md->msg_lspid);
    host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
T
ths 已提交
2675
    unlock_user_struct(target_md, target_addr, 0);
2676
    return 0;
T
ths 已提交
2677 2678
}

2679 2680
static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
                                               struct msqid_ds *host_md)
T
ths 已提交
2681 2682 2683
{
    struct target_msqid_ds *target_md;

2684 2685
    if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
        return -TARGET_EFAULT;
2686 2687
    if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
        return -TARGET_EFAULT;
2688 2689 2690 2691 2692 2693 2694 2695
    target_md->msg_stime = tswapal(host_md->msg_stime);
    target_md->msg_rtime = tswapal(host_md->msg_rtime);
    target_md->msg_ctime = tswapal(host_md->msg_ctime);
    target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
    target_md->msg_qnum = tswapal(host_md->msg_qnum);
    target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
    target_md->msg_lspid = tswapal(host_md->msg_lspid);
    target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
T
ths 已提交
2696
    unlock_user_struct(target_md, target_addr, 1);
2697
    return 0;
T
ths 已提交
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
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);
2726
    return 0;
2727 2728 2729
}

static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
T
ths 已提交
2730 2731
{
    struct msqid_ds dsarg;
2732 2733 2734 2735 2736 2737
    struct msginfo msginfo;
    abi_long ret = -TARGET_EINVAL;

    cmd &= 0xff;

    switch (cmd) {
T
ths 已提交
2738 2739
    case IPC_STAT:
    case IPC_SET:
2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755
    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 已提交
2756
    }
2757

T
ths 已提交
2758 2759 2760 2761
    return ret;
}

struct target_msgbuf {
2762 2763
    abi_long mtype;
    char	mtext[1];
T
ths 已提交
2764 2765
};

2766 2767
static inline abi_long do_msgsnd(int msqid, abi_long msgp,
                                 unsigned int msgsz, int msgflg)
T
ths 已提交
2768 2769 2770
{
    struct target_msgbuf *target_mb;
    struct msgbuf *host_mb;
2771
    abi_long ret = 0;
T
ths 已提交
2772

2773 2774
    if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
        return -TARGET_EFAULT;
T
ths 已提交
2775
    host_mb = malloc(msgsz+sizeof(long));
2776
    host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
2777
    memcpy(host_mb->mtext, target_mb->mtext, msgsz);
T
ths 已提交
2778 2779 2780 2781 2782 2783 2784
    ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
    free(host_mb);
    unlock_user_struct(target_mb, msgp, 0);

    return ret;
}

2785
static inline abi_long do_msgrcv(int msqid, abi_long msgp,
2786
                                 unsigned int msgsz, abi_long msgtyp,
2787
                                 int msgflg)
T
ths 已提交
2788 2789
{
    struct target_msgbuf *target_mb;
2790
    char *target_mtext;
T
ths 已提交
2791
    struct msgbuf *host_mb;
2792
    abi_long ret = 0;
T
ths 已提交
2793

2794 2795
    if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
        return -TARGET_EFAULT;
2796

T
ths 已提交
2797
    host_mb = malloc(msgsz+sizeof(long));
2798
    ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
2799

2800 2801 2802 2803 2804 2805 2806
    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;
        }
2807
        memcpy(target_mb->mtext, host_mb->mtext, ret);
2808 2809
        unlock_user(target_mtext, target_mtext_addr, ret);
    }
2810

2811
    target_mb->mtype = tswapal(host_mb->mtype);
T
ths 已提交
2812 2813
    free(host_mb);

2814 2815 2816
end:
    if (target_mb)
        unlock_user_struct(target_mb, msgp, 1);
T
ths 已提交
2817 2818 2819
    return ret;
}

2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 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 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029
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;
3030
            page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
3031 3032 3033 3034 3035 3036 3037
            break;
        }
    }

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

3038
#ifdef TARGET_NR_ipc
3039
/* ??? This only works with linear mappings.  */
3040
/* do_ipc() must return target values and target errnos. */
3041 3042 3043
static abi_long do_ipc(unsigned int call, int first,
                       int second, int third,
                       abi_long ptr, abi_long fifth)
3044 3045
{
    int version;
3046
    abi_long ret = 0;
3047 3048 3049 3050 3051

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

    switch (call) {
3052
    case IPCOP_semop:
3053
        ret = do_semop(first, ptr, second);
3054 3055 3056 3057 3058 3059 3060
        break;

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

    case IPCOP_semctl:
3061
        ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
3062
        break;
3063

3064 3065 3066
    case IPCOP_msgget:
        ret = get_errno(msgget(first, second));
        break;
3067

3068 3069 3070
    case IPCOP_msgsnd:
        ret = do_msgsnd(first, ptr, second, third);
        break;
3071

3072 3073 3074
    case IPCOP_msgctl:
        ret = do_msgctl(first, second, ptr);
        break;
3075

3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088
    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;
                }
3089

3090
                ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
3091

3092 3093 3094 3095 3096 3097 3098
                unlock_user_struct(tmp, ptr, 0);
                break;
            }
        default:
            ret = do_msgrcv(first, ptr, second, fifth, third);
        }
        break;
3099

3100
    case IPCOP_shmat:
3101 3102
        switch (version) {
        default:
3103 3104
        {
            abi_ulong raddr;
3105 3106 3107
            raddr = do_shmat(first, ptr, second);
            if (is_error(raddr))
                return get_errno(raddr);
3108
            if (put_user_ual(raddr, third))
3109
                return -TARGET_EFAULT;
3110 3111 3112 3113 3114
            break;
        }
        case 1:
            ret = -TARGET_EINVAL;
            break;
3115
        }
3116 3117
	break;
    case IPCOP_shmdt:
3118
        ret = do_shmdt(ptr);
3119 3120 3121 3122 3123 3124 3125 3126 3127
	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:
3128
        ret = do_shmctl(first, second, third);
3129 3130
        break;
    default:
3131
	gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
3132
	ret = -TARGET_ENOSYS;
3133 3134 3135 3136
	break;
    }
    return ret;
}
3137
#endif
3138

3139 3140
/* kernel structure types definitions */

3141
#define STRUCT(name, ...) STRUCT_ ## name,
3142 3143 3144 3145 3146 3147 3148
#define STRUCT_SPECIAL(name) STRUCT_ ## name,
enum {
#include "syscall_types.h"
};
#undef STRUCT
#undef STRUCT_SPECIAL

3149
#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = {  __VA_ARGS__, TYPE_NULL };
3150 3151 3152 3153 3154
#define STRUCT_SPECIAL(name)
#include "syscall_types.h"
#undef STRUCT
#undef STRUCT_SPECIAL

3155 3156 3157 3158 3159 3160
typedef struct IOCTLEntry IOCTLEntry;

typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
                             int fd, abi_long cmd, abi_long arg);

struct IOCTLEntry {
3161 3162
    unsigned int target_cmd;
    unsigned int host_cmd;
3163 3164
    const char *name;
    int access;
3165
    do_ioctl_fn *do_ioctl;
B
bellard 已提交
3166
    const argtype arg_type[5];
3167
};
3168 3169 3170 3171 3172 3173 3174

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

#define MAX_STRUCT_SIZE 4096

3175
#ifdef CONFIG_FIEMAP
3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261
/* So fiemap access checks don't overflow on 32 bit systems.
 * This is very slightly smaller than the limit imposed by
 * the underlying kernel.
 */
#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap))  \
                            / sizeof(struct fiemap_extent))

static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
                                       int fd, abi_long cmd, abi_long arg)
{
    /* The parameter for this ioctl is a struct fiemap followed
     * by an array of struct fiemap_extent whose size is set
     * in fiemap->fm_extent_count. The array is filled in by the
     * ioctl.
     */
    int target_size_in, target_size_out;
    struct fiemap *fm;
    const argtype *arg_type = ie->arg_type;
    const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
    void *argptr, *p;
    abi_long ret;
    int i, extent_size = thunk_type_size(extent_arg_type, 0);
    uint32_t outbufsz;
    int free_fm = 0;

    assert(arg_type[0] == TYPE_PTR);
    assert(ie->access == IOC_RW);
    arg_type++;
    target_size_in = thunk_type_size(arg_type, 0);
    argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
    if (!argptr) {
        return -TARGET_EFAULT;
    }
    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
    unlock_user(argptr, arg, 0);
    fm = (struct fiemap *)buf_temp;
    if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
        return -TARGET_EINVAL;
    }

    outbufsz = sizeof (*fm) +
        (sizeof(struct fiemap_extent) * fm->fm_extent_count);

    if (outbufsz > MAX_STRUCT_SIZE) {
        /* We can't fit all the extents into the fixed size buffer.
         * Allocate one that is large enough and use it instead.
         */
        fm = malloc(outbufsz);
        if (!fm) {
            return -TARGET_ENOMEM;
        }
        memcpy(fm, buf_temp, sizeof(struct fiemap));
        free_fm = 1;
    }
    ret = get_errno(ioctl(fd, ie->host_cmd, fm));
    if (!is_error(ret)) {
        target_size_out = target_size_in;
        /* An extent_count of 0 means we were only counting the extents
         * so there are no structs to copy
         */
        if (fm->fm_extent_count != 0) {
            target_size_out += fm->fm_mapped_extents * extent_size;
        }
        argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
        if (!argptr) {
            ret = -TARGET_EFAULT;
        } else {
            /* Convert the struct fiemap */
            thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
            if (fm->fm_extent_count != 0) {
                p = argptr + target_size_in;
                /* ...and then all the struct fiemap_extents */
                for (i = 0; i < fm->fm_mapped_extents; i++) {
                    thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
                                  THUNK_TARGET);
                    p += extent_size;
                }
            }
            unlock_user(argptr, arg, target_size_out);
        }
    }
    if (free_fm) {
        free(fm);
    }
    return ret;
}
3262
#endif
3263

3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 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
static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
                                int fd, abi_long cmd, abi_long arg)
{
    const argtype *arg_type = ie->arg_type;
    int target_size;
    void *argptr;
    int ret;
    struct ifconf *host_ifconf;
    uint32_t outbufsz;
    const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
    int target_ifreq_size;
    int nb_ifreq;
    int free_buf = 0;
    int i;
    int target_ifc_len;
    abi_long target_ifc_buf;
    int host_ifc_len;
    char *host_ifc_buf;

    assert(arg_type[0] == TYPE_PTR);
    assert(ie->access == IOC_RW);

    arg_type++;
    target_size = thunk_type_size(arg_type, 0);

    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
    if (!argptr)
        return -TARGET_EFAULT;
    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
    unlock_user(argptr, arg, 0);

    host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
    target_ifc_len = host_ifconf->ifc_len;
    target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;

    target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
    nb_ifreq = target_ifc_len / target_ifreq_size;
    host_ifc_len = nb_ifreq * sizeof(struct ifreq);

    outbufsz = sizeof(*host_ifconf) + host_ifc_len;
    if (outbufsz > MAX_STRUCT_SIZE) {
        /* We can't fit all the extents into the fixed size buffer.
         * Allocate one that is large enough and use it instead.
         */
        host_ifconf = malloc(outbufsz);
        if (!host_ifconf) {
            return -TARGET_ENOMEM;
        }
        memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
        free_buf = 1;
    }
    host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);

    host_ifconf->ifc_len = host_ifc_len;
    host_ifconf->ifc_buf = host_ifc_buf;

    ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
    if (!is_error(ret)) {
	/* convert host ifc_len to target ifc_len */

        nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
        target_ifc_len = nb_ifreq * target_ifreq_size;
        host_ifconf->ifc_len = target_ifc_len;

	/* restore target ifc_buf */

        host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;

	/* copy struct ifconf to target user */

        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
        if (!argptr)
            return -TARGET_EFAULT;
        thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
        unlock_user(argptr, arg, target_size);

	/* copy ifreq[] to target user */

        argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
        for (i = 0; i < nb_ifreq ; i++) {
            thunk_convert(argptr + i * target_ifreq_size,
                          host_ifc_buf + i * sizeof(struct ifreq),
                          ifreq_arg_type, THUNK_TARGET);
        }
        unlock_user(argptr, target_ifc_buf, target_ifc_len);
    }

    if (free_buf) {
        free(host_ifconf);
    }

    return ret;
}

3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 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 3425 3426 3427 3428 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 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582
static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
                            abi_long cmd, abi_long arg)
{
    void *argptr;
    struct dm_ioctl *host_dm;
    abi_long guest_data;
    uint32_t guest_data_size;
    int target_size;
    const argtype *arg_type = ie->arg_type;
    abi_long ret;
    void *big_buf = NULL;
    char *host_data;

    arg_type++;
    target_size = thunk_type_size(arg_type, 0);
    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
    if (!argptr) {
        ret = -TARGET_EFAULT;
        goto out;
    }
    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
    unlock_user(argptr, arg, 0);

    /* buf_temp is too small, so fetch things into a bigger buffer */
    big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
    memcpy(big_buf, buf_temp, target_size);
    buf_temp = big_buf;
    host_dm = big_buf;

    guest_data = arg + host_dm->data_start;
    if ((guest_data - arg) < 0) {
        ret = -EINVAL;
        goto out;
    }
    guest_data_size = host_dm->data_size - host_dm->data_start;
    host_data = (char*)host_dm + host_dm->data_start;

    argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
    switch (ie->host_cmd) {
    case DM_REMOVE_ALL:
    case DM_LIST_DEVICES:
    case DM_DEV_CREATE:
    case DM_DEV_REMOVE:
    case DM_DEV_SUSPEND:
    case DM_DEV_STATUS:
    case DM_DEV_WAIT:
    case DM_TABLE_STATUS:
    case DM_TABLE_CLEAR:
    case DM_TABLE_DEPS:
    case DM_LIST_VERSIONS:
        /* no input data */
        break;
    case DM_DEV_RENAME:
    case DM_DEV_SET_GEOMETRY:
        /* data contains only strings */
        memcpy(host_data, argptr, guest_data_size);
        break;
    case DM_TARGET_MSG:
        memcpy(host_data, argptr, guest_data_size);
        *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
        break;
    case DM_TABLE_LOAD:
    {
        void *gspec = argptr;
        void *cur_data = host_data;
        const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
        int spec_size = thunk_type_size(arg_type, 0);
        int i;

        for (i = 0; i < host_dm->target_count; i++) {
            struct dm_target_spec *spec = cur_data;
            uint32_t next;
            int slen;

            thunk_convert(spec, gspec, arg_type, THUNK_HOST);
            slen = strlen((char*)gspec + spec_size) + 1;
            next = spec->next;
            spec->next = sizeof(*spec) + slen;
            strcpy((char*)&spec[1], gspec + spec_size);
            gspec += next;
            cur_data += spec->next;
        }
        break;
    }
    default:
        ret = -TARGET_EINVAL;
        goto out;
    }
    unlock_user(argptr, guest_data, 0);

    ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
    if (!is_error(ret)) {
        guest_data = arg + host_dm->data_start;
        guest_data_size = host_dm->data_size - host_dm->data_start;
        argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
        switch (ie->host_cmd) {
        case DM_REMOVE_ALL:
        case DM_DEV_CREATE:
        case DM_DEV_REMOVE:
        case DM_DEV_RENAME:
        case DM_DEV_SUSPEND:
        case DM_DEV_STATUS:
        case DM_TABLE_LOAD:
        case DM_TABLE_CLEAR:
        case DM_TARGET_MSG:
        case DM_DEV_SET_GEOMETRY:
            /* no return data */
            break;
        case DM_LIST_DEVICES:
        {
            struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
            uint32_t remaining_data = guest_data_size;
            void *cur_data = argptr;
            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
            int nl_size = 12; /* can't use thunk_size due to alignment */

            while (1) {
                uint32_t next = nl->next;
                if (next) {
                    nl->next = nl_size + (strlen(nl->name) + 1);
                }
                if (remaining_data < nl->next) {
                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
                    break;
                }
                thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
                strcpy(cur_data + nl_size, nl->name);
                cur_data += nl->next;
                remaining_data -= nl->next;
                if (!next) {
                    break;
                }
                nl = (void*)nl + next;
            }
            break;
        }
        case DM_DEV_WAIT:
        case DM_TABLE_STATUS:
        {
            struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
            void *cur_data = argptr;
            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
            int spec_size = thunk_type_size(arg_type, 0);
            int i;

            for (i = 0; i < host_dm->target_count; i++) {
                uint32_t next = spec->next;
                int slen = strlen((char*)&spec[1]) + 1;
                spec->next = (cur_data - argptr) + spec_size + slen;
                if (guest_data_size < spec->next) {
                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
                    break;
                }
                thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
                strcpy(cur_data + spec_size, (char*)&spec[1]);
                cur_data = argptr + spec->next;
                spec = (void*)host_dm + host_dm->data_start + next;
            }
            break;
        }
        case DM_TABLE_DEPS:
        {
            void *hdata = (void*)host_dm + host_dm->data_start;
            int count = *(uint32_t*)hdata;
            uint64_t *hdev = hdata + 8;
            uint64_t *gdev = argptr + 8;
            int i;

            *(uint32_t*)argptr = tswap32(count);
            for (i = 0; i < count; i++) {
                *gdev = tswap64(*hdev);
                gdev++;
                hdev++;
            }
            break;
        }
        case DM_LIST_VERSIONS:
        {
            struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
            uint32_t remaining_data = guest_data_size;
            void *cur_data = argptr;
            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
            int vers_size = thunk_type_size(arg_type, 0);

            while (1) {
                uint32_t next = vers->next;
                if (next) {
                    vers->next = vers_size + (strlen(vers->name) + 1);
                }
                if (remaining_data < vers->next) {
                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
                    break;
                }
                thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
                strcpy(cur_data + vers_size, vers->name);
                cur_data += vers->next;
                remaining_data -= vers->next;
                if (!next) {
                    break;
                }
                vers = (void*)vers + next;
            }
            break;
        }
        default:
            ret = -TARGET_EINVAL;
            goto out;
        }
        unlock_user(argptr, guest_data, guest_data_size);

        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
        if (!argptr) {
            ret = -TARGET_EFAULT;
            goto out;
        }
        thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
        unlock_user(argptr, arg, target_size);
    }
out:
    if (big_buf) {
        free(big_buf);
    }
    return ret;
}

B
blueswir1 已提交
3583
static IOCTLEntry ioctl_entries[] = {
3584
#define IOCTL(cmd, access, ...) \
3585 3586 3587
    { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
#define IOCTL_SPECIAL(cmd, access, dofn, ...)                      \
    { TARGET_ ## cmd, cmd, #cmd, access, dofn, {  __VA_ARGS__ } },
3588 3589 3590 3591
#include "ioctls.h"
    { 0, 0, },
};

3592
/* ??? Implement proper locking for ioctls.  */
3593
/* do_ioctl() Must return target values and target errnos. */
3594
static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
3595 3596 3597
{
    const IOCTLEntry *ie;
    const argtype *arg_type;
3598
    abi_long ret;
3599
    uint8_t buf_temp[MAX_STRUCT_SIZE];
3600 3601
    int target_size;
    void *argptr;
3602 3603 3604 3605

    ie = ioctl_entries;
    for(;;) {
        if (ie->target_cmd == 0) {
3606
            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
3607
            return -TARGET_ENOSYS;
3608 3609 3610 3611 3612 3613
        }
        if (ie->target_cmd == cmd)
            break;
        ie++;
    }
    arg_type = ie->arg_type;
B
bellard 已提交
3614
#if defined(DEBUG)
3615
    gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
B
bellard 已提交
3616
#endif
3617 3618 3619 3620
    if (ie->do_ioctl) {
        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
    }

3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632
    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++;
3633
        target_size = thunk_type_size(arg_type, 0);
3634 3635 3636 3637
        switch(ie->access) {
        case IOC_R:
            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
            if (!is_error(ret)) {
3638 3639 3640
                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
                if (!argptr)
                    return -TARGET_EFAULT;
3641 3642
                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
                unlock_user(argptr, arg, target_size);
3643 3644 3645
            }
            break;
        case IOC_W:
3646 3647 3648
            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
            if (!argptr)
                return -TARGET_EFAULT;
3649 3650
            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
            unlock_user(argptr, arg, 0);
3651 3652 3653 3654
            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
            break;
        default:
        case IOC_RW:
3655 3656 3657
            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
            if (!argptr)
                return -TARGET_EFAULT;
3658 3659
            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
            unlock_user(argptr, arg, 0);
3660 3661
            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
            if (!is_error(ret)) {
3662 3663 3664
                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
                if (!argptr)
                    return -TARGET_EFAULT;
3665 3666
                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
                unlock_user(argptr, arg, target_size);
3667 3668 3669 3670 3671
            }
            break;
        }
        break;
    default:
3672 3673
        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
                 (long)cmd, arg_type[0]);
3674
        ret = -TARGET_ENOSYS;
3675 3676 3677 3678 3679
        break;
    }
    return ret;
}

B
blueswir1 已提交
3680
static const bitmask_transtbl iflag_tbl[] = {
3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697
        { 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 已提交
3698
static const bitmask_transtbl oflag_tbl[] = {
3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725
	{ 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 已提交
3726
static const bitmask_transtbl cflag_tbl[] = {
3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760
	{ 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 已提交
3761
static const bitmask_transtbl lflag_tbl[] = {
3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783
	{ 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;
3784

3785
    host->c_iflag =
3786
        target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
3787
    host->c_oflag =
3788
        target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
3789
    host->c_cflag =
3790
        target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
3791
    host->c_lflag =
3792 3793
        target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
    host->c_line = target->c_line;
3794

3795
    memset(host->c_cc, 0, sizeof(host->c_cc));
3796 3797
    host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
    host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
3798
    host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
3799
    host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
3800
    host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
3801
    host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
3802
    host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
3803
    host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
3804
    host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
3805 3806
    host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
    host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
3807 3808 3809 3810 3811
    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];
3812
    host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
3813
}
3814

3815 3816 3817 3818 3819
static void host_to_target_termios (void *dst, const void *src)
{
    struct target_termios *target = dst;
    const struct host_termios *host = src;

3820
    target->c_iflag =
3821
        tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
3822
    target->c_oflag =
3823
        tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
3824
    target->c_cflag =
3825
        tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
3826
    target->c_lflag =
3827 3828
        tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
    target->c_line = host->c_line;
3829

3830
    memset(target->c_cc, 0, sizeof(target->c_cc));
3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849
    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 已提交
3850
static const StructEntry struct_termios_def = {
3851 3852 3853 3854 3855
    .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 已提交
3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867
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 }
};

3868
#if defined(TARGET_I386)
B
bellard 已提交
3869 3870

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

3873
static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
B
bellard 已提交
3874 3875
{
    int size;
3876
    void *p;
B
bellard 已提交
3877 3878 3879 3880 3881 3882

    if (!ldt_table)
        return 0;
    size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
    if (size > bytecount)
        size = bytecount;
3883 3884
    p = lock_user(VERIFY_WRITE, ptr, size, 0);
    if (!p)
3885
        return -TARGET_EFAULT;
3886
    /* ??? Should this by byteswapped?  */
3887 3888
    memcpy(p, ldt_table, size);
    unlock_user(p, ptr, size);
B
bellard 已提交
3889 3890 3891 3892
    return size;
}

/* XXX: add locking support */
3893 3894
static abi_long write_ldt(CPUX86State *env,
                          abi_ulong ptr, unsigned long bytecount, int oldmode)
B
bellard 已提交
3895 3896
{
    struct target_modify_ldt_ldt_s ldt_info;
3897
    struct target_modify_ldt_ldt_s *target_ldt_info;
B
bellard 已提交
3898
    int seg_32bit, contents, read_exec_only, limit_in_pages;
B
bellard 已提交
3899
    int seg_not_present, useable, lm;
B
bellard 已提交
3900 3901 3902
    uint32_t *lp, entry_1, entry_2;

    if (bytecount != sizeof(ldt_info))
3903
        return -TARGET_EINVAL;
3904
    if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
3905
        return -TARGET_EFAULT;
3906
    ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
3907
    ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
3908 3909 3910
    ldt_info.limit = tswap32(target_ldt_info->limit);
    ldt_info.flags = tswap32(target_ldt_info->flags);
    unlock_user_struct(target_ldt_info, ptr, 0);
3911

B
bellard 已提交
3912
    if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
3913
        return -TARGET_EINVAL;
B
bellard 已提交
3914 3915 3916 3917 3918 3919
    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 已提交
3920 3921 3922 3923 3924
#ifdef TARGET_ABI32
    lm = 0;
#else
    lm = (ldt_info.flags >> 7) & 1;
#endif
B
bellard 已提交
3925 3926
    if (contents == 3) {
        if (oldmode)
3927
            return -TARGET_EINVAL;
B
bellard 已提交
3928
        if (seg_not_present == 0)
3929
            return -TARGET_EINVAL;
B
bellard 已提交
3930 3931 3932
    }
    /* allocate the LDT */
    if (!ldt_table) {
3933 3934 3935 3936 3937
        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)
3938
            return -TARGET_ENOMEM;
3939 3940
        memset(g2h(env->ldt.base), 0,
               TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
B
bellard 已提交
3941
        env->ldt.limit = 0xffff;
3942
        ldt_table = g2h(env->ldt.base);
B
bellard 已提交
3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959
    }

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

B
bellard 已提交
3961 3962 3963 3964 3965 3966 3967 3968 3969 3970
    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 已提交
3971
        (lm << 21) |
B
bellard 已提交
3972 3973 3974
        0x7000;
    if (!oldmode)
        entry_2 |= (useable << 20);
B
bellard 已提交
3975

B
bellard 已提交
3976 3977 3978 3979 3980 3981 3982 3983 3984
    /* 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 */
3985 3986
static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
                              unsigned long bytecount)
B
bellard 已提交
3987
{
3988
    abi_long ret;
3989

B
bellard 已提交
3990 3991 3992 3993 3994 3995 3996 3997 3998 3999
    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;
4000 4001 4002
    default:
        ret = -TARGET_ENOSYS;
        break;
B
bellard 已提交
4003 4004 4005
    }
    return ret;
}
B
bellard 已提交
4006

4007
#if defined(TARGET_I386) && defined(TARGET_ABI32)
4008
static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
B
bellard 已提交
4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021
{
    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);
4022
    ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
B
bellard 已提交
4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092
    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;
}

4093
static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
B
bellard 已提交
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 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132
{
    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);
4133
    target_ldt_info->base_addr = tswapal(base_addr);
B
bellard 已提交
4134 4135 4136 4137 4138
    target_ldt_info->limit = tswap32(limit);
    target_ldt_info->flags = tswap32(flags);
    unlock_user_struct(target_ldt_info, ptr, 1);
    return 0;
}
4139
#endif /* TARGET_I386 && TARGET_ABI32 */
B
bellard 已提交
4140

B
bellard 已提交
4141
#ifndef TARGET_ABI32
4142
static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
B
bellard 已提交
4143
{
J
Juan Quintela 已提交
4144
    abi_long ret = 0;
B
bellard 已提交
4145 4146
    abi_ulong val;
    int idx;
J
Juan Quintela 已提交
4147

B
bellard 已提交
4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165
    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))
J
Juan Quintela 已提交
4166
            ret = -TARGET_EFAULT;
B
bellard 已提交
4167 4168 4169 4170 4171
        break;
    default:
        ret = -TARGET_EINVAL;
        break;
    }
J
Juan Quintela 已提交
4172
    return ret;
B
bellard 已提交
4173 4174 4175
}
#endif

4176 4177
#endif /* defined(TARGET_I386) */

4178
#define NEW_STACK_SIZE 0x40000
P
pbrook 已提交
4179

4180
#if defined(CONFIG_USE_NPTL)
P
pbrook 已提交
4181 4182 4183

static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
typedef struct {
4184
    CPUArchState *env;
P
pbrook 已提交
4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196
    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;
4197
    CPUArchState *env;
4198
    TaskState *ts;
P
pbrook 已提交
4199 4200 4201

    env = info->env;
    thread_env = env;
4202
    ts = (TaskState *)thread_env->opaque;
P
pbrook 已提交
4203
    info->tid = gettid();
4204
    env->host_tid = info->tid;
4205
    task_settid(ts);
P
pbrook 已提交
4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223
    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 已提交
4224 4225 4226

static int clone_func(void *arg)
{
4227
    CPUArchState *env = arg;
B
bellard 已提交
4228 4229 4230 4231
    cpu_loop(env);
    /* never exits */
    return 0;
}
P
pbrook 已提交
4232
#endif
B
bellard 已提交
4233

4234 4235
/* do_fork() Must return host values and target errnos (unlike most
   do_*() functions). */
4236
static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
P
pbrook 已提交
4237 4238
                   abi_ulong parent_tidptr, target_ulong newtls,
                   abi_ulong child_tidptr)
B
bellard 已提交
4239 4240
{
    int ret;
B
bellard 已提交
4241
    TaskState *ts;
4242
    CPUArchState *new_env;
4243
#if defined(CONFIG_USE_NPTL)
P
pbrook 已提交
4244 4245
    unsigned int nptl_flags;
    sigset_t sigmask;
4246 4247
#else
    uint8_t *new_stack;
P
pbrook 已提交
4248
#endif
4249

4250 4251 4252 4253
    /* Emulate vfork() with fork() */
    if (flags & CLONE_VFORK)
        flags &= ~(CLONE_VFORK | CLONE_VM);

B
bellard 已提交
4254
    if (flags & CLONE_VM) {
4255
        TaskState *parent_ts = (TaskState *)env->opaque;
4256
#if defined(CONFIG_USE_NPTL)
P
pbrook 已提交
4257 4258
        new_thread_info info;
        pthread_attr_t attr;
4259
#endif
4260
        ts = g_malloc0(sizeof(TaskState));
P
pbrook 已提交
4261
        init_task_state(ts);
B
bellard 已提交
4262
        /* we create a new CPU instance. */
4263
        new_env = cpu_copy(env);
B
Blue Swirl 已提交
4264
#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
4265
        cpu_state_reset(new_env);
B
Blue Swirl 已提交
4266
#endif
4267 4268
        /* Init regs that differ from the parent.  */
        cpu_clone_regs(new_env, newsp);
B
bellard 已提交
4269
        new_env->opaque = ts;
4270 4271
        ts->bprm = parent_ts->bprm;
        ts->info = parent_ts->info;
4272
#if defined(CONFIG_USE_NPTL)
P
pbrook 已提交
4273 4274 4275
        nptl_flags = flags;
        flags &= ~CLONE_NPTL_FLAGS2;

4276 4277 4278 4279
        if (nptl_flags & CLONE_CHILD_CLEARTID) {
            ts->child_tidptr = child_tidptr;
        }

P
pbrook 已提交
4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296
        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);
4297 4298
        ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
        ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
P
pbrook 已提交
4299 4300 4301 4302 4303 4304
        /* 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);
4305
        /* TODO: Free new CPU state if thread creation failed.  */
P
pbrook 已提交
4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325

        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.  */
4326
        new_stack = g_malloc0 (NEW_STACK_SIZE);
4327
#ifdef __ia64__
4328
        ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
4329 4330
#else
	ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
P
pbrook 已提交
4331
#endif
4332
#endif
B
bellard 已提交
4333 4334
    } else {
        /* if no CLONE_VM, we consider it is a fork */
P
pbrook 已提交
4335
        if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
B
bellard 已提交
4336
            return -EINVAL;
P
pbrook 已提交
4337
        fork_start();
B
bellard 已提交
4338
        ret = fork();
P
pbrook 已提交
4339
        if (ret == 0) {
4340
            /* Child Process.  */
P
pbrook 已提交
4341 4342
            cpu_clone_regs(env, newsp);
            fork_end(1);
4343
#if defined(CONFIG_USE_NPTL)
4344 4345 4346 4347 4348 4349
            /* 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 已提交
4350 4351 4352 4353 4354 4355 4356
            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);
4357 4358
            if (flags & CLONE_CHILD_CLEARTID)
                ts->child_tidptr = child_tidptr;
4359
#endif
P
pbrook 已提交
4360 4361 4362
        } else {
            fork_end(0);
        }
B
bellard 已提交
4363 4364 4365 4366
    }
    return ret;
}

4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398
/* 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
U
Ulrich Hecht 已提交
4399 4400 4401 4402
        case TARGET_F_SETLEASE:
            return F_SETLEASE;
        case TARGET_F_GETLEASE:
            return F_GETLEASE;
4403
#ifdef F_DUPFD_CLOEXEC
U
Ulrich Hecht 已提交
4404 4405
        case TARGET_F_DUPFD_CLOEXEC:
            return F_DUPFD_CLOEXEC;
4406
#endif
U
Ulrich Hecht 已提交
4407 4408
        case TARGET_F_NOTIFY:
            return F_NOTIFY;
4409 4410 4411 4412 4413 4414
	default:
            return -TARGET_EINVAL;
    }
    return -TARGET_EINVAL;
}

4415
static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
B
bellard 已提交
4416 4417
{
    struct flock fl;
4418
    struct target_flock *target_fl;
4419 4420
    struct flock64 fl64;
    struct target_flock64 *target_fl64;
4421
    abi_long ret;
4422 4423 4424 4425
    int host_cmd = target_to_host_fcntl_cmd(cmd);

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

B
bellard 已提交
4427 4428
    switch(cmd) {
    case TARGET_F_GETLK:
4429 4430
        if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
            return -TARGET_EFAULT;
T
ths 已提交
4431 4432
        fl.l_type = tswap16(target_fl->l_type);
        fl.l_whence = tswap16(target_fl->l_whence);
4433 4434
        fl.l_start = tswapal(target_fl->l_start);
        fl.l_len = tswapal(target_fl->l_len);
U
Ulrich Hecht 已提交
4435
        fl.l_pid = tswap32(target_fl->l_pid);
T
ths 已提交
4436
        unlock_user_struct(target_fl, arg, 0);
4437
        ret = get_errno(fcntl(fd, host_cmd, &fl));
B
bellard 已提交
4438
        if (ret == 0) {
4439 4440
            if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
                return -TARGET_EFAULT;
B
bellard 已提交
4441 4442
            target_fl->l_type = tswap16(fl.l_type);
            target_fl->l_whence = tswap16(fl.l_whence);
4443 4444
            target_fl->l_start = tswapal(fl.l_start);
            target_fl->l_len = tswapal(fl.l_len);
U
Ulrich Hecht 已提交
4445
            target_fl->l_pid = tswap32(fl.l_pid);
4446
            unlock_user_struct(target_fl, arg, 1);
B
bellard 已提交
4447 4448
        }
        break;
4449

B
bellard 已提交
4450 4451
    case TARGET_F_SETLK:
    case TARGET_F_SETLKW:
4452 4453
        if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
            return -TARGET_EFAULT;
B
bellard 已提交
4454 4455
        fl.l_type = tswap16(target_fl->l_type);
        fl.l_whence = tswap16(target_fl->l_whence);
4456 4457
        fl.l_start = tswapal(target_fl->l_start);
        fl.l_len = tswapal(target_fl->l_len);
U
Ulrich Hecht 已提交
4458
        fl.l_pid = tswap32(target_fl->l_pid);
4459
        unlock_user_struct(target_fl, arg, 0);
4460
        ret = get_errno(fcntl(fd, host_cmd, &fl));
B
bellard 已提交
4461
        break;
4462

B
bellard 已提交
4463
    case TARGET_F_GETLK64:
4464 4465
        if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
            return -TARGET_EFAULT;
T
ths 已提交
4466 4467
        fl64.l_type = tswap16(target_fl64->l_type) >> 1;
        fl64.l_whence = tswap16(target_fl64->l_whence);
4468 4469
        fl64.l_start = tswap64(target_fl64->l_start);
        fl64.l_len = tswap64(target_fl64->l_len);
U
Ulrich Hecht 已提交
4470
        fl64.l_pid = tswap32(target_fl64->l_pid);
T
ths 已提交
4471
        unlock_user_struct(target_fl64, arg, 0);
4472
        ret = get_errno(fcntl(fd, host_cmd, &fl64));
4473
        if (ret == 0) {
4474 4475
            if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
                return -TARGET_EFAULT;
4476 4477
            target_fl64->l_type = tswap16(fl64.l_type) >> 1;
            target_fl64->l_whence = tswap16(fl64.l_whence);
4478 4479
            target_fl64->l_start = tswap64(fl64.l_start);
            target_fl64->l_len = tswap64(fl64.l_len);
U
Ulrich Hecht 已提交
4480
            target_fl64->l_pid = tswap32(fl64.l_pid);
4481 4482
            unlock_user_struct(target_fl64, arg, 1);
        }
B
bellard 已提交
4483
        break;
B
bellard 已提交
4484 4485
    case TARGET_F_SETLK64:
    case TARGET_F_SETLKW64:
4486 4487
        if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
            return -TARGET_EFAULT;
4488 4489
        fl64.l_type = tswap16(target_fl64->l_type) >> 1;
        fl64.l_whence = tswap16(target_fl64->l_whence);
4490 4491
        fl64.l_start = tswap64(target_fl64->l_start);
        fl64.l_len = tswap64(target_fl64->l_len);
U
Ulrich Hecht 已提交
4492
        fl64.l_pid = tswap32(target_fl64->l_pid);
4493
        unlock_user_struct(target_fl64, arg, 0);
4494
        ret = get_errno(fcntl(fd, host_cmd, &fl64));
B
bellard 已提交
4495 4496
        break;

4497 4498
    case TARGET_F_GETFL:
        ret = get_errno(fcntl(fd, host_cmd, arg));
B
bellard 已提交
4499 4500 4501
        if (ret >= 0) {
            ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
        }
B
bellard 已提交
4502 4503
        break;

4504 4505 4506 4507 4508 4509 4510 4511
    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:
U
Ulrich Hecht 已提交
4512 4513
    case TARGET_F_SETLEASE:
    case TARGET_F_GETLEASE:
4514
        ret = get_errno(fcntl(fd, host_cmd, arg));
B
bellard 已提交
4515 4516
        break;

B
bellard 已提交
4517
    default:
B
bellard 已提交
4518
        ret = get_errno(fcntl(fd, cmd, arg));
B
bellard 已提交
4519 4520 4521 4522 4523
        break;
    }
    return ret;
}

4524
#ifdef USE_UID16
B
bellard 已提交
4525

4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556
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;
}
4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581
static inline int tswapid(int id)
{
    return tswap16(id);
}
#else /* !USE_UID16 */
static inline int high2lowuid(int uid)
{
    return uid;
}
static inline int high2lowgid(int gid)
{
    return gid;
}
static inline int low2highuid(int uid)
{
    return uid;
}
static inline int low2highgid(int gid)
{
    return gid;
}
static inline int tswapid(int id)
{
    return tswap32(id);
}
4582
#endif /* USE_UID16 */
B
bellard 已提交
4583

4584 4585
void syscall_init(void)
{
4586 4587 4588
    IOCTLEntry *ie;
    const argtype *arg_type;
    int size;
4589
    int i;
4590

4591
#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
4592
#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
4593 4594 4595
#include "syscall_types.h"
#undef STRUCT
#undef STRUCT_SPECIAL
4596 4597 4598 4599 4600 4601 4602 4603 4604

    /* 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) {
4605
                fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
4606 4607 4608 4609 4610
                        ie->target_cmd);
                exit(1);
            }
            arg_type++;
            size = thunk_type_size(arg_type, 0);
4611
            ie->target_cmd = (ie->target_cmd &
4612 4613 4614
                              ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
                (size << TARGET_IOC_SIZESHIFT);
        }
4615 4616 4617 4618 4619 4620

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

4621
        /* automatic consistency check if same arch */
4622 4623 4624 4625 4626
#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);
4627 4628 4629 4630
        }
#endif
        ie++;
    }
4631
}
B
bellard 已提交
4632

4633
#if TARGET_ABI_BITS == 32
P
pbrook 已提交
4634 4635
static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
{
T
ths 已提交
4636
#ifdef TARGET_WORDS_BIGENDIAN
P
pbrook 已提交
4637 4638 4639 4640 4641
    return ((uint64_t)word0 << 32) | word1;
#else
    return ((uint64_t)word1 << 32) | word0;
#endif
}
4642
#else /* TARGET_ABI_BITS == 32 */
4643 4644 4645 4646
static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
{
    return word0;
}
4647
#endif /* TARGET_ABI_BITS != 32 */
P
pbrook 已提交
4648 4649

#ifdef TARGET_NR_truncate64
4650 4651 4652 4653
static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
                                         abi_long arg2,
                                         abi_long arg3,
                                         abi_long arg4)
P
pbrook 已提交
4654
{
4655
    if (regpairs_aligned(cpu_env)) {
P
pbrook 已提交
4656 4657
        arg2 = arg3;
        arg3 = arg4;
4658
    }
P
pbrook 已提交
4659 4660 4661 4662 4663
    return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
}
#endif

#ifdef TARGET_NR_ftruncate64
4664 4665 4666 4667
static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
                                          abi_long arg2,
                                          abi_long arg3,
                                          abi_long arg4)
P
pbrook 已提交
4668
{
4669
    if (regpairs_aligned(cpu_env)) {
P
pbrook 已提交
4670 4671
        arg2 = arg3;
        arg3 = arg4;
4672
    }
P
pbrook 已提交
4673 4674 4675 4676
    return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
}
#endif

4677 4678
static inline abi_long target_to_host_timespec(struct timespec *host_ts,
                                               abi_ulong target_addr)
4679 4680 4681
{
    struct target_timespec *target_ts;

4682 4683
    if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
        return -TARGET_EFAULT;
4684 4685
    host_ts->tv_sec = tswapal(target_ts->tv_sec);
    host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
4686
    unlock_user_struct(target_ts, target_addr, 0);
B
bellard 已提交
4687
    return 0;
4688 4689
}

4690 4691
static inline abi_long host_to_target_timespec(abi_ulong target_addr,
                                               struct timespec *host_ts)
4692 4693 4694
{
    struct target_timespec *target_ts;

4695 4696
    if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
        return -TARGET_EFAULT;
4697 4698
    target_ts->tv_sec = tswapal(host_ts->tv_sec);
    target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
4699
    unlock_user_struct(target_ts, target_addr, 1);
B
bellard 已提交
4700
    return 0;
4701 4702
}

4703
#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734
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
    {
4735
#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
4736 4737
        struct target_stat *target_st;
#else
4738
        struct target_stat64 *target_st;
4739
#endif
4740 4741 4742

        if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
            return -TARGET_EFAULT;
4743
        memset(target_st, 0, sizeof(*target_st));
4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767
        __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

4768
#if defined(CONFIG_USE_NPTL)
4769 4770 4771 4772 4773
/* ??? 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.  */
4774 4775
static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
                    target_ulong uaddr2, int val3)
4776 4777
{
    struct timespec ts, *pts;
4778
    int base_op;
4779 4780 4781

    /* ??? We assume FUTEX_* constants are the same on both host
       and target.  */
4782
#ifdef FUTEX_CMD_MASK
4783
    base_op = op & FUTEX_CMD_MASK;
4784
#else
4785
    base_op = op;
4786
#endif
4787
    switch (base_op) {
4788 4789 4790 4791 4792 4793 4794
    case FUTEX_WAIT:
        if (timeout) {
            pts = &ts;
            target_to_host_timespec(pts, timeout);
        } else {
            pts = NULL;
        }
4795
        return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
4796 4797
                         pts, NULL, 0));
    case FUTEX_WAKE:
4798
        return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
4799
    case FUTEX_FD:
4800
        return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
4801 4802
    case FUTEX_REQUEUE:
    case FUTEX_CMP_REQUEUE:
4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814
    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)));
4815 4816 4817 4818 4819 4820
    default:
        return -TARGET_ENOSYS;
    }
}
#endif

P
pbrook 已提交
4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834
/* 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 已提交
4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865
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;
}

4866 4867 4868

static int open_self_maps(void *cpu_env, int fd)
{
4869
    TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
4870 4871 4872 4873 4874 4875 4876 4877 4878 4879

    dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0          [stack]\n",
                (unsigned long long)ts->info->stack_limit,
                (unsigned long long)(ts->stack_base + (TARGET_PAGE_SIZE - 1))
                                     & TARGET_PAGE_MASK,
                (unsigned long long)ts->stack_base);

    return 0;
}

4880 4881
static int open_self_stat(void *cpu_env, int fd)
{
4882
    TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
4883 4884 4885 4886 4887 4888 4889 4890
    abi_ulong start_stack = ts->info->start_stack;
    int i;

    for (i = 0; i < 44; i++) {
      char buf[128];
      int len;
      uint64_t val = 0;

4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904
      if (i == 0) {
        /* pid */
        val = getpid();
        snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
      } else if (i == 1) {
        /* app name */
        snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
      } else if (i == 27) {
        /* stack bottom */
        val = start_stack;
        snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
      } else {
        /* for the rest, there is MasterCard */
        snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
4905
      }
4906

4907 4908 4909 4910 4911 4912 4913 4914 4915
      len = strlen(buf);
      if (write(fd, buf, len) != len) {
          return -1;
      }
    }

    return 0;
}

4916 4917
static int open_self_auxv(void *cpu_env, int fd)
{
4918
    TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944
    abi_ulong auxv = ts->info->saved_auxv;
    abi_ulong len = ts->info->auxv_len;
    char *ptr;

    /*
     * Auxiliary vector is stored in target process stack.
     * read in whole auxv vector and copy it to file
     */
    ptr = lock_user(VERIFY_READ, auxv, len, 0);
    if (ptr != NULL) {
        while (len > 0) {
            ssize_t r;
            r = write(fd, ptr, len);
            if (r <= 0) {
                break;
            }
            len -= r;
            ptr += r;
        }
        lseek(fd, 0, SEEK_SET);
        unlock_user(ptr, auxv, len);
    }

    return 0;
}

4945 4946 4947 4948 4949 4950 4951 4952
static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
{
    struct fake_open {
        const char *filename;
        int (*fill)(void *cpu_env, int fd);
    };
    const struct fake_open *fake_open;
    static const struct fake_open fakes[] = {
4953
        { "/proc/self/maps", open_self_maps },
4954
        { "/proc/self/stat", open_self_stat },
4955
        { "/proc/self/auxv", open_self_auxv },
4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993
        { NULL, NULL }
    };

    for (fake_open = fakes; fake_open->filename; fake_open++) {
        if (!strncmp(pathname, fake_open->filename,
                     strlen(fake_open->filename))) {
            break;
        }
    }

    if (fake_open->filename) {
        const char *tmpdir;
        char filename[PATH_MAX];
        int fd, r;

        /* create temporary file to map stat to */
        tmpdir = getenv("TMPDIR");
        if (!tmpdir)
            tmpdir = "/tmp";
        snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
        fd = mkstemp(filename);
        if (fd < 0) {
            return fd;
        }
        unlink(filename);

        if ((r = fake_open->fill(cpu_env, fd))) {
            close(fd);
            return r;
        }
        lseek(fd, 0, SEEK_SET);

        return fd;
    }

    return get_errno(open(path(pathname), flags, mode));
}

4994 4995 4996
/* 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>. */
4997 4998
abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                    abi_long arg2, abi_long arg3, abi_long arg4,
4999 5000
                    abi_long arg5, abi_long arg6, abi_long arg7,
                    abi_long arg8)
5001
{
5002
    abi_long ret;
5003
    struct stat st;
B
bellard 已提交
5004
    struct statfs stfs;
5005
    void *p;
5006

B
bellard 已提交
5007
#ifdef DEBUG
B
bellard 已提交
5008
    gemu_log("syscall %d", num);
B
bellard 已提交
5009
#endif
5010 5011 5012
    if(do_strace)
        print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);

5013 5014
    switch(num) {
    case TARGET_NR_exit:
5015
#ifdef CONFIG_USE_NPTL
5016 5017 5018 5019 5020 5021 5022
      /* 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) {
5023
          TaskState *ts;
5024 5025
          CPUArchState **lastp;
          CPUArchState *p;
5026 5027 5028 5029

          cpu_list_lock();
          lastp = &first_cpu;
          p = first_cpu;
5030
          while (p && p != (CPUArchState *)cpu_env) {
5031 5032 5033 5034 5035 5036 5037 5038 5039 5040
              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();
5041
          ts = ((CPUArchState *)cpu_env)->opaque;
5042 5043 5044 5045 5046
          if (ts->child_tidptr) {
              put_user_u32(0, ts->child_tidptr);
              sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
                        NULL, NULL, 0);
          }
5047
          thread_env = NULL;
5048
          object_delete(OBJECT(ENV_GET_CPU(cpu_env)));
5049
          g_free(ts);
5050 5051 5052
          pthread_exit(NULL);
      }
#endif
5053
#ifdef TARGET_GPROF
B
bellard 已提交
5054 5055
        _mcleanup();
#endif
5056
        gdb_exit(cpu_env, arg1);
5057
        _exit(arg1);
5058 5059 5060
        ret = 0; /* avoid warning */
        break;
    case TARGET_NR_read:
5061 5062 5063 5064 5065 5066 5067 5068
        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);
        }
5069 5070
        break;
    case TARGET_NR_write:
5071 5072
        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
            goto efault;
5073 5074
        ret = get_errno(write(arg1, p, arg3));
        unlock_user(p, arg2, 0);
5075 5076
        break;
    case TARGET_NR_open:
5077 5078
        if (!(p = lock_user_string(arg1)))
            goto efault;
5079 5080 5081
        ret = get_errno(do_open(cpu_env, p,
                                target_to_host_bitmask(arg2, fcntl_flags_tbl),
                                arg3));
5082
        unlock_user(p, arg1, 0);
5083
        break;
5084 5085
#if defined(TARGET_NR_openat) && defined(__NR_openat)
    case TARGET_NR_openat:
5086 5087 5088 5089 5090 5091 5092
        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);
5093 5094
        break;
#endif
5095 5096 5097 5098
    case TARGET_NR_close:
        ret = get_errno(close(arg1));
        break;
    case TARGET_NR_brk:
5099
        ret = do_brk(arg1);
5100 5101
        break;
    case TARGET_NR_fork:
P
pbrook 已提交
5102
        ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
5103
        break;
5104
#ifdef TARGET_NR_waitpid
5105 5106
    case TARGET_NR_waitpid:
        {
5107 5108
            int status;
            ret = get_errno(waitpid(arg1, &status, arg3));
5109
            if (!is_error(ret) && arg2 && ret
P
pbrook 已提交
5110
                && put_user_s32(host_to_target_waitstatus(status), arg2))
5111
                goto efault;
5112 5113
        }
        break;
5114
#endif
P
pbrook 已提交
5115 5116 5117 5118 5119 5120 5121
#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) {
A
Anthony Liguori 已提交
5122
                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
P
pbrook 已提交
5123 5124
                    goto efault;
                host_to_target_siginfo(p, &info);
A
Anthony Liguori 已提交
5125
                unlock_user(p, arg3, sizeof(target_siginfo_t));
P
pbrook 已提交
5126 5127 5128 5129
            }
        }
        break;
#endif
5130
#ifdef TARGET_NR_creat /* not on alpha */
5131
    case TARGET_NR_creat:
5132 5133
        if (!(p = lock_user_string(arg1)))
            goto efault;
5134 5135
        ret = get_errno(creat(p, arg2));
        unlock_user(p, arg1, 0);
5136
        break;
5137
#endif
5138
    case TARGET_NR_link:
5139 5140 5141 5142
        {
            void * p2;
            p = lock_user_string(arg1);
            p2 = lock_user_string(arg2);
5143 5144 5145 5146
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(link(p, p2));
5147 5148 5149
            unlock_user(p2, arg2, 0);
            unlock_user(p, arg1, 0);
        }
5150
        break;
5151 5152 5153 5154
#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
    case TARGET_NR_linkat:
        {
            void * p2 = NULL;
5155 5156
            if (!arg2 || !arg4)
                goto efault;
5157 5158
            p  = lock_user_string(arg2);
            p2 = lock_user_string(arg4);
5159
            if (!p || !p2)
5160
                ret = -TARGET_EFAULT;
5161 5162
            else
                ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
5163 5164
            unlock_user(p, arg2, 0);
            unlock_user(p2, arg4, 0);
5165 5166 5167
        }
        break;
#endif
5168
    case TARGET_NR_unlink:
5169 5170
        if (!(p = lock_user_string(arg1)))
            goto efault;
5171 5172
        ret = get_errno(unlink(p));
        unlock_user(p, arg1, 0);
5173
        break;
5174 5175
#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
    case TARGET_NR_unlinkat:
5176 5177 5178 5179
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_unlinkat(arg1, p, arg3));
        unlock_user(p, arg2, 0);
5180
        break;
5181
#endif
5182
    case TARGET_NR_execve:
B
bellard 已提交
5183 5184
        {
            char **argp, **envp;
B
bellard 已提交
5185
            int argc, envc;
5186 5187 5188 5189
            abi_ulong gp;
            abi_ulong guest_argp;
            abi_ulong guest_envp;
            abi_ulong addr;
B
bellard 已提交
5190
            char **q;
5191
            int total_size = 0;
B
bellard 已提交
5192

B
bellard 已提交
5193
            argc = 0;
5194
            guest_argp = arg2;
5195
            for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
5196
                if (get_user_ual(addr, gp))
5197
                    goto efault;
5198
                if (!addr)
5199
                    break;
B
bellard 已提交
5200
                argc++;
5201
            }
B
bellard 已提交
5202
            envc = 0;
5203
            guest_envp = arg3;
5204
            for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
5205
                if (get_user_ual(addr, gp))
5206
                    goto efault;
5207
                if (!addr)
5208
                    break;
B
bellard 已提交
5209
                envc++;
5210
            }
B
bellard 已提交
5211

B
bellard 已提交
5212 5213
            argp = alloca((argc + 1) * sizeof(void *));
            envp = alloca((envc + 1) * sizeof(void *));
B
bellard 已提交
5214

5215
            for (gp = guest_argp, q = argp; gp;
5216
                  gp += sizeof(abi_ulong), q++) {
5217 5218
                if (get_user_ual(addr, gp))
                    goto execve_efault;
5219 5220
                if (!addr)
                    break;
5221 5222
                if (!(*q = lock_user_string(addr)))
                    goto execve_efault;
5223
                total_size += strlen(*q) + 1;
5224
            }
B
bellard 已提交
5225 5226
            *q = NULL;

5227
            for (gp = guest_envp, q = envp; gp;
5228
                  gp += sizeof(abi_ulong), q++) {
5229 5230
                if (get_user_ual(addr, gp))
                    goto execve_efault;
5231 5232
                if (!addr)
                    break;
5233 5234
                if (!(*q = lock_user_string(addr)))
                    goto execve_efault;
5235
                total_size += strlen(*q) + 1;
5236
            }
B
bellard 已提交
5237
            *q = NULL;
B
bellard 已提交
5238

5239 5240 5241 5242 5243 5244
            /* This case will not be caught by the host's execve() if its
               page size is bigger than the target's. */
            if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
                ret = -TARGET_E2BIG;
                goto execve_end;
            }
5245 5246
            if (!(p = lock_user_string(arg1)))
                goto execve_efault;
5247 5248 5249
            ret = get_errno(execve(p, argp, envp));
            unlock_user(p, arg1, 0);

5250 5251 5252 5253 5254 5255
            goto execve_end;

        execve_efault:
            ret = -TARGET_EFAULT;

        execve_end:
5256
            for (gp = guest_argp, q = argp; *q;
5257
                  gp += sizeof(abi_ulong), q++) {
5258 5259 5260
                if (get_user_ual(addr, gp)
                    || !addr)
                    break;
5261 5262 5263
                unlock_user(*q, addr, 0);
            }
            for (gp = guest_envp, q = envp; *q;
5264
                  gp += sizeof(abi_ulong), q++) {
5265 5266 5267
                if (get_user_ual(addr, gp)
                    || !addr)
                    break;
5268 5269
                unlock_user(*q, addr, 0);
            }
B
bellard 已提交
5270
        }
5271 5272
        break;
    case TARGET_NR_chdir:
5273 5274
        if (!(p = lock_user_string(arg1)))
            goto efault;
5275 5276
        ret = get_errno(chdir(p));
        unlock_user(p, arg1, 0);
5277
        break;
B
bellard 已提交
5278
#ifdef TARGET_NR_time
5279 5280
    case TARGET_NR_time:
        {
5281 5282
            time_t host_time;
            ret = get_errno(time(&host_time));
5283 5284 5285 5286
            if (!is_error(ret)
                && arg1
                && put_user_sal(host_time, arg1))
                goto efault;
5287 5288
        }
        break;
B
bellard 已提交
5289
#endif
5290
    case TARGET_NR_mknod:
5291 5292
        if (!(p = lock_user_string(arg1)))
            goto efault;
5293 5294
        ret = get_errno(mknod(p, arg2, arg3));
        unlock_user(p, arg1, 0);
5295
        break;
5296 5297
#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
    case TARGET_NR_mknodat:
5298 5299 5300 5301
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
        unlock_user(p, arg2, 0);
5302 5303
        break;
#endif
5304
    case TARGET_NR_chmod:
5305 5306
        if (!(p = lock_user_string(arg1)))
            goto efault;
5307 5308
        ret = get_errno(chmod(p, arg2));
        unlock_user(p, arg1, 0);
5309
        break;
5310
#ifdef TARGET_NR_break
5311 5312
    case TARGET_NR_break:
        goto unimplemented;
5313 5314
#endif
#ifdef TARGET_NR_oldstat
5315 5316
    case TARGET_NR_oldstat:
        goto unimplemented;
5317
#endif
5318 5319 5320
    case TARGET_NR_lseek:
        ret = get_errno(lseek(arg1, arg2, arg3));
        break;
5321 5322
#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
    /* Alpha specific */
5323
    case TARGET_NR_getxpid:
5324 5325 5326
        ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
        ret = get_errno(getpid());
        break;
5327
#endif
5328 5329
#ifdef TARGET_NR_getpid
    case TARGET_NR_getpid:
5330 5331
        ret = get_errno(getpid());
        break;
5332
#endif
5333
    case TARGET_NR_mount:
5334 5335 5336 5337 5338 5339
		{
			/* 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);
5340 5341
                        if (!p || !p2 || !p3)
                            ret = -TARGET_EFAULT;
5342
                        else {
5343 5344 5345 5346
                            /* 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.
                             */
5347 5348 5349 5350 5351
                            if ( ! arg5 )
                                ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
                            else
                                ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
                        }
5352 5353 5354
                        unlock_user(p, arg1, 0);
                        unlock_user(p2, arg2, 0);
                        unlock_user(p3, arg3, 0);
5355 5356
			break;
		}
5357
#ifdef TARGET_NR_umount
5358
    case TARGET_NR_umount:
5359 5360
        if (!(p = lock_user_string(arg1)))
            goto efault;
5361 5362
        ret = get_errno(umount(p));
        unlock_user(p, arg1, 0);
5363
        break;
5364
#endif
5365
#ifdef TARGET_NR_stime /* not on alpha */
5366 5367
    case TARGET_NR_stime:
        {
5368
            time_t host_time;
5369 5370
            if (get_user_sal(host_time, arg1))
                goto efault;
5371
            ret = get_errno(stime(&host_time));
5372 5373
        }
        break;
5374
#endif
5375 5376
    case TARGET_NR_ptrace:
        goto unimplemented;
5377
#ifdef TARGET_NR_alarm /* not on alpha */
5378 5379 5380
    case TARGET_NR_alarm:
        ret = alarm(arg1);
        break;
5381
#endif
5382
#ifdef TARGET_NR_oldfstat
5383 5384
    case TARGET_NR_oldfstat:
        goto unimplemented;
5385
#endif
5386
#ifdef TARGET_NR_pause /* not on alpha */
5387 5388 5389
    case TARGET_NR_pause:
        ret = get_errno(pause());
        break;
5390
#endif
5391
#ifdef TARGET_NR_utime
5392
    case TARGET_NR_utime:
5393
        {
5394 5395 5396
            struct utimbuf tbuf, *host_tbuf;
            struct target_utimbuf *target_tbuf;
            if (arg2) {
5397 5398
                if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
                    goto efault;
5399 5400
                tbuf.actime = tswapal(target_tbuf->actime);
                tbuf.modtime = tswapal(target_tbuf->modtime);
5401 5402
                unlock_user_struct(target_tbuf, arg2, 0);
                host_tbuf = &tbuf;
B
bellard 已提交
5403
            } else {
5404
                host_tbuf = NULL;
B
bellard 已提交
5405
            }
5406 5407
            if (!(p = lock_user_string(arg1)))
                goto efault;
5408 5409
            ret = get_errno(utime(p, host_tbuf));
            unlock_user(p, arg1, 0);
5410 5411
        }
        break;
5412
#endif
B
bellard 已提交
5413 5414 5415
    case TARGET_NR_utimes:
        {
            struct timeval *tvp, tv[2];
5416
            if (arg2) {
5417 5418 5419 5420
                if (copy_from_user_timeval(&tv[0], arg2)
                    || copy_from_user_timeval(&tv[1],
                                              arg2 + sizeof(struct target_timeval)))
                    goto efault;
B
bellard 已提交
5421 5422 5423 5424
                tvp = tv;
            } else {
                tvp = NULL;
            }
5425 5426
            if (!(p = lock_user_string(arg1)))
                goto efault;
5427 5428
            ret = get_errno(utimes(p, tvp));
            unlock_user(p, arg1, 0);
B
bellard 已提交
5429 5430
        }
        break;
5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450
#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
5451
#ifdef TARGET_NR_stty
5452 5453
    case TARGET_NR_stty:
        goto unimplemented;
5454 5455
#endif
#ifdef TARGET_NR_gtty
5456 5457
    case TARGET_NR_gtty:
        goto unimplemented;
5458
#endif
5459
    case TARGET_NR_access:
5460 5461
        if (!(p = lock_user_string(arg1)))
            goto efault;
U
Ulrich Hecht 已提交
5462
        ret = get_errno(access(path(p), arg2));
5463
        unlock_user(p, arg1, 0);
5464
        break;
5465 5466
#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
    case TARGET_NR_faccessat:
5467 5468
        if (!(p = lock_user_string(arg2)))
            goto efault;
5469
        ret = get_errno(sys_faccessat(arg1, p, arg3));
5470
        unlock_user(p, arg2, 0);
5471 5472
        break;
#endif
5473
#ifdef TARGET_NR_nice /* not on alpha */
5474 5475 5476
    case TARGET_NR_nice:
        ret = get_errno(nice(arg1));
        break;
5477
#endif
5478
#ifdef TARGET_NR_ftime
5479 5480
    case TARGET_NR_ftime:
        goto unimplemented;
5481
#endif
5482
    case TARGET_NR_sync:
B
bellard 已提交
5483 5484
        sync();
        ret = 0;
5485 5486
        break;
    case TARGET_NR_kill:
5487
        ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
5488 5489
        break;
    case TARGET_NR_rename:
5490 5491 5492 5493
        {
            void *p2;
            p = lock_user_string(arg1);
            p2 = lock_user_string(arg2);
5494 5495 5496 5497
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(rename(p, p2));
5498 5499 5500
            unlock_user(p2, arg2, 0);
            unlock_user(p, arg1, 0);
        }
5501
        break;
5502 5503 5504
#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
    case TARGET_NR_renameat:
        {
5505
            void *p2;
5506 5507
            p  = lock_user_string(arg2);
            p2 = lock_user_string(arg4);
5508
            if (!p || !p2)
5509
                ret = -TARGET_EFAULT;
5510 5511
            else
                ret = get_errno(sys_renameat(arg1, p, arg3, p2));
5512 5513
            unlock_user(p2, arg4, 0);
            unlock_user(p, arg2, 0);
5514 5515 5516
        }
        break;
#endif
5517
    case TARGET_NR_mkdir:
5518 5519
        if (!(p = lock_user_string(arg1)))
            goto efault;
5520 5521
        ret = get_errno(mkdir(p, arg2));
        unlock_user(p, arg1, 0);
5522
        break;
5523 5524
#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
    case TARGET_NR_mkdirat:
5525 5526 5527 5528
        if (!(p = lock_user_string(arg2)))
            goto efault;
        ret = get_errno(sys_mkdirat(arg1, p, arg3));
        unlock_user(p, arg2, 0);
5529 5530
        break;
#endif
5531
    case TARGET_NR_rmdir:
5532 5533
        if (!(p = lock_user_string(arg1)))
            goto efault;
5534 5535
        ret = get_errno(rmdir(p));
        unlock_user(p, arg1, 0);
5536 5537 5538 5539 5540
        break;
    case TARGET_NR_dup:
        ret = get_errno(dup(arg1));
        break;
    case TARGET_NR_pipe:
5541
        ret = do_pipe(cpu_env, arg1, 0, 0);
R
Riku Voipio 已提交
5542 5543 5544
        break;
#ifdef TARGET_NR_pipe2
    case TARGET_NR_pipe2:
5545
        ret = do_pipe(cpu_env, arg1, arg2, 1);
5546
        break;
R
Riku Voipio 已提交
5547
#endif
5548
    case TARGET_NR_times:
B
bellard 已提交
5549
        {
5550
            struct target_tms *tmsp;
B
bellard 已提交
5551 5552
            struct tms tms;
            ret = get_errno(times(&tms));
5553
            if (arg1) {
5554 5555 5556
                tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
                if (!tmsp)
                    goto efault;
5557 5558 5559 5560
                tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
                tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
                tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
                tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
B
bellard 已提交
5561
            }
B
bellard 已提交
5562 5563
            if (!is_error(ret))
                ret = host_to_target_clock_t(ret);
B
bellard 已提交
5564 5565
        }
        break;
5566
#ifdef TARGET_NR_prof
5567 5568
    case TARGET_NR_prof:
        goto unimplemented;
5569
#endif
5570
#ifdef TARGET_NR_signal
5571 5572
    case TARGET_NR_signal:
        goto unimplemented;
5573
#endif
5574
    case TARGET_NR_acct:
5575 5576 5577 5578 5579 5580 5581 5582
        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);
        }
5583
        break;
5584
#ifdef TARGET_NR_umount2 /* not on alpha */
5585
    case TARGET_NR_umount2:
5586 5587
        if (!(p = lock_user_string(arg1)))
            goto efault;
5588 5589
        ret = get_errno(umount2(p, arg2));
        unlock_user(p, arg1, 0);
5590
        break;
5591
#endif
5592
#ifdef TARGET_NR_lock
5593 5594
    case TARGET_NR_lock:
        goto unimplemented;
5595
#endif
5596 5597 5598 5599
    case TARGET_NR_ioctl:
        ret = do_ioctl(arg1, arg2, arg3);
        break;
    case TARGET_NR_fcntl:
B
bellard 已提交
5600
        ret = do_fcntl(arg1, arg2, arg3);
5601
        break;
5602
#ifdef TARGET_NR_mpx
5603 5604
    case TARGET_NR_mpx:
        goto unimplemented;
5605
#endif
5606 5607 5608
    case TARGET_NR_setpgid:
        ret = get_errno(setpgid(arg1, arg2));
        break;
5609
#ifdef TARGET_NR_ulimit
5610 5611
    case TARGET_NR_ulimit:
        goto unimplemented;
5612 5613
#endif
#ifdef TARGET_NR_oldolduname
5614 5615
    case TARGET_NR_oldolduname:
        goto unimplemented;
5616
#endif
5617 5618 5619 5620
    case TARGET_NR_umask:
        ret = get_errno(umask(arg1));
        break;
    case TARGET_NR_chroot:
5621 5622
        if (!(p = lock_user_string(arg1)))
            goto efault;
5623 5624
        ret = get_errno(chroot(p));
        unlock_user(p, arg1, 0);
5625 5626 5627 5628 5629 5630
        break;
    case TARGET_NR_ustat:
        goto unimplemented;
    case TARGET_NR_dup2:
        ret = get_errno(dup2(arg1, arg2));
        break;
5631 5632 5633 5634 5635
#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
    case TARGET_NR_dup3:
        ret = get_errno(dup3(arg1, arg2, arg3));
        break;
#endif
5636
#ifdef TARGET_NR_getppid /* not on alpha */
5637 5638 5639
    case TARGET_NR_getppid:
        ret = get_errno(getppid());
        break;
5640
#endif
5641 5642 5643 5644 5645 5646
    case TARGET_NR_getpgrp:
        ret = get_errno(getpgrp());
        break;
    case TARGET_NR_setsid:
        ret = get_errno(setsid());
        break;
5647
#ifdef TARGET_NR_sigaction
5648 5649
    case TARGET_NR_sigaction:
        {
5650 5651
#if defined(TARGET_ALPHA)
            struct target_sigaction act, oact, *pact = 0;
5652 5653
            struct target_old_sigaction *old_act;
            if (arg2) {
5654 5655
                if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
                    goto efault;
B
bellard 已提交
5656 5657 5658
                act._sa_handler = old_act->_sa_handler;
                target_siginitset(&act.sa_mask, old_act->sa_mask);
                act.sa_flags = old_act->sa_flags;
5659
                act.sa_restorer = 0;
5660
                unlock_user_struct(old_act, arg2, 0);
B
bellard 已提交
5661 5662 5663
                pact = &act;
            }
            ret = get_errno(do_sigaction(arg1, pact, &oact));
5664
            if (!is_error(ret) && arg3) {
5665 5666
                if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
                    goto efault;
5667 5668 5669 5670
                old_act->_sa_handler = oact._sa_handler;
                old_act->sa_mask = oact.sa_mask.sig[0];
                old_act->sa_flags = oact.sa_flags;
                unlock_user_struct(old_act, arg3, 1);
B
bellard 已提交
5671
            }
5672
#elif defined(TARGET_MIPS)
5673 5674 5675
	    struct target_sigaction act, oact, *pact, *old_act;

	    if (arg2) {
5676 5677
                if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
                    goto efault;
5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689
		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) {
5690 5691
                if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
                    goto efault;
5692 5693 5694 5695 5696 5697 5698 5699
		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);
	    }
5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724
#else
            struct target_old_sigaction *old_act;
            struct target_sigaction act, oact, *pact;
            if (arg2) {
                if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
                    goto efault;
                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;
                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) {
                if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
                    goto efault;
                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);
            }
T
ths 已提交
5725
#endif
5726 5727
        }
        break;
5728
#endif
B
bellard 已提交
5729
    case TARGET_NR_rt_sigaction:
5730
        {
5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754
#if defined(TARGET_ALPHA)
            struct target_sigaction act, oact, *pact = 0;
            struct target_rt_sigaction *rt_act;
            /* ??? arg4 == sizeof(sigset_t).  */
            if (arg2) {
                if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
                    goto efault;
                act._sa_handler = rt_act->_sa_handler;
                act.sa_mask = rt_act->sa_mask;
                act.sa_flags = rt_act->sa_flags;
                act.sa_restorer = arg5;
                unlock_user_struct(rt_act, arg2, 0);
                pact = &act;
            }
            ret = get_errno(do_sigaction(arg1, pact, &oact));
            if (!is_error(ret) && arg3) {
                if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
                    goto efault;
                rt_act->_sa_handler = oact._sa_handler;
                rt_act->sa_mask = oact.sa_mask;
                rt_act->sa_flags = oact.sa_flags;
                unlock_user_struct(rt_act, arg3, 1);
            }
#else
5755 5756 5757
            struct target_sigaction *act;
            struct target_sigaction *oact;

5758 5759 5760 5761
            if (arg2) {
                if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
                    goto efault;
            } else
5762
                act = NULL;
5763 5764 5765 5766 5767 5768
            if (arg3) {
                if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
                    ret = -TARGET_EFAULT;
                    goto rt_sigaction_fail;
                }
            } else
5769 5770
                oact = NULL;
            ret = get_errno(do_sigaction(arg1, act, oact));
5771 5772
	rt_sigaction_fail:
            if (act)
5773
                unlock_user_struct(act, arg2, 0);
5774
            if (oact)
5775
                unlock_user_struct(oact, arg3, 1);
5776
#endif
5777
        }
B
bellard 已提交
5778
        break;
5779
#ifdef TARGET_NR_sgetmask /* not on alpha */
5780
    case TARGET_NR_sgetmask:
B
bellard 已提交
5781 5782
        {
            sigset_t cur_set;
5783
            abi_ulong target_set;
B
bellard 已提交
5784 5785 5786 5787 5788
            sigprocmask(0, NULL, &cur_set);
            host_to_target_old_sigset(&target_set, &cur_set);
            ret = target_set;
        }
        break;
5789 5790
#endif
#ifdef TARGET_NR_ssetmask /* not on alpha */
5791
    case TARGET_NR_ssetmask:
B
bellard 已提交
5792 5793
        {
            sigset_t set, oset, cur_set;
5794
            abi_ulong target_set = arg1;
B
bellard 已提交
5795 5796 5797 5798 5799 5800 5801 5802
            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;
5803
#endif
5804
#ifdef TARGET_NR_sigprocmask
B
bellard 已提交
5805 5806
    case TARGET_NR_sigprocmask:
        {
5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836
#if defined(TARGET_ALPHA)
            sigset_t set, oldset;
            abi_ulong mask;
            int how;

            switch (arg1) {
            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:
                ret = -TARGET_EINVAL;
                goto fail;
            }
            mask = arg2;
            target_to_host_old_sigset(&set, &mask);

            ret = get_errno(sigprocmask(how, &set, &oldset));

            if (!is_error(ret)) {
                host_to_target_old_sigset(&mask, &oldset);
                ret = mask;
                ((CPUAlphaState *)cpu_env)->[IR_V0] = 0; /* force no error */
            }
#else
B
bellard 已提交
5837
            sigset_t set, oldset, *set_ptr;
5838
            int how;
5839

5840
            if (arg2) {
5841
                switch (arg1) {
B
bellard 已提交
5842 5843 5844 5845 5846 5847 5848 5849 5850 5851
                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:
5852
                    ret = -TARGET_EINVAL;
B
bellard 已提交
5853 5854
                    goto fail;
                }
A
Anthony Liguori 已提交
5855
                if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
5856
                    goto efault;
5857 5858
                target_to_host_old_sigset(&set, p);
                unlock_user(p, arg2, 0);
B
bellard 已提交
5859 5860 5861 5862 5863
                set_ptr = &set;
            } else {
                how = 0;
                set_ptr = NULL;
            }
5864
            ret = get_errno(sigprocmask(how, set_ptr, &oldset));
5865
            if (!is_error(ret) && arg3) {
A
Anthony Liguori 已提交
5866
                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
5867
                    goto efault;
5868
                host_to_target_old_sigset(p, &oldset);
A
Anthony Liguori 已提交
5869
                unlock_user(p, arg3, sizeof(target_sigset_t));
B
bellard 已提交
5870
            }
5871
#endif
B
bellard 已提交
5872 5873
        }
        break;
5874
#endif
B
bellard 已提交
5875 5876 5877 5878
    case TARGET_NR_rt_sigprocmask:
        {
            int how = arg1;
            sigset_t set, oldset, *set_ptr;
5879

5880
            if (arg2) {
B
bellard 已提交
5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891
                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:
5892
                    ret = -TARGET_EINVAL;
B
bellard 已提交
5893 5894
                    goto fail;
                }
A
Anthony Liguori 已提交
5895
                if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
5896
                    goto efault;
5897 5898
                target_to_host_sigset(&set, p);
                unlock_user(p, arg2, 0);
B
bellard 已提交
5899 5900 5901 5902 5903 5904
                set_ptr = &set;
            } else {
                how = 0;
                set_ptr = NULL;
            }
            ret = get_errno(sigprocmask(how, set_ptr, &oldset));
5905
            if (!is_error(ret) && arg3) {
A
Anthony Liguori 已提交
5906
                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
5907
                    goto efault;
5908
                host_to_target_sigset(p, &oldset);
A
Anthony Liguori 已提交
5909
                unlock_user(p, arg3, sizeof(target_sigset_t));
B
bellard 已提交
5910 5911 5912
            }
        }
        break;
5913
#ifdef TARGET_NR_sigpending
B
bellard 已提交
5914 5915 5916 5917 5918
    case TARGET_NR_sigpending:
        {
            sigset_t set;
            ret = get_errno(sigpending(&set));
            if (!is_error(ret)) {
A
Anthony Liguori 已提交
5919
                if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
5920
                    goto efault;
5921
                host_to_target_old_sigset(p, &set);
A
Anthony Liguori 已提交
5922
                unlock_user(p, arg1, sizeof(target_sigset_t));
B
bellard 已提交
5923 5924 5925
            }
        }
        break;
5926
#endif
B
bellard 已提交
5927 5928 5929 5930 5931
    case TARGET_NR_rt_sigpending:
        {
            sigset_t set;
            ret = get_errno(sigpending(&set));
            if (!is_error(ret)) {
A
Anthony Liguori 已提交
5932
                if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
5933
                    goto efault;
5934
                host_to_target_sigset(p, &set);
A
Anthony Liguori 已提交
5935
                unlock_user(p, arg1, sizeof(target_sigset_t));
B
bellard 已提交
5936 5937 5938
            }
        }
        break;
5939
#ifdef TARGET_NR_sigsuspend
B
bellard 已提交
5940 5941 5942
    case TARGET_NR_sigsuspend:
        {
            sigset_t set;
5943 5944 5945 5946
#if defined(TARGET_ALPHA)
            abi_ulong mask = arg1;
            target_to_host_old_sigset(&set, &mask);
#else
A
Anthony Liguori 已提交
5947
            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
5948
                goto efault;
5949 5950
            target_to_host_old_sigset(&set, p);
            unlock_user(p, arg1, 0);
5951
#endif
B
bellard 已提交
5952 5953 5954
            ret = get_errno(sigsuspend(&set));
        }
        break;
5955
#endif
B
bellard 已提交
5956 5957 5958
    case TARGET_NR_rt_sigsuspend:
        {
            sigset_t set;
A
Anthony Liguori 已提交
5959
            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
5960
                goto efault;
5961 5962
            target_to_host_sigset(&set, p);
            unlock_user(p, arg1, 0);
B
bellard 已提交
5963 5964 5965 5966 5967 5968 5969 5970
            ret = get_errno(sigsuspend(&set));
        }
        break;
    case TARGET_NR_rt_sigtimedwait:
        {
            sigset_t set;
            struct timespec uts, *puts;
            siginfo_t uinfo;
5971

A
Anthony Liguori 已提交
5972
            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
5973
                goto efault;
5974 5975 5976
            target_to_host_sigset(&set, p);
            unlock_user(p, arg1, 0);
            if (arg3) {
B
bellard 已提交
5977
                puts = &uts;
5978
                target_to_host_timespec(puts, arg3);
B
bellard 已提交
5979 5980 5981 5982
            } else {
                puts = NULL;
            }
            ret = get_errno(sigtimedwait(&set, &uinfo, puts));
5983
            if (!is_error(ret) && arg2) {
A
Anthony Liguori 已提交
5984
                if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
5985
                    goto efault;
5986
                host_to_target_siginfo(p, &uinfo);
A
Anthony Liguori 已提交
5987
                unlock_user(p, arg2, sizeof(target_siginfo_t));
B
bellard 已提交
5988 5989 5990 5991 5992 5993
            }
        }
        break;
    case TARGET_NR_rt_sigqueueinfo:
        {
            siginfo_t uinfo;
A
Anthony Liguori 已提交
5994
            if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
5995
                goto efault;
5996 5997
            target_to_host_siginfo(&uinfo, p);
            unlock_user(p, arg1, 0);
B
bellard 已提交
5998 5999 6000
            ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
        }
        break;
6001
#ifdef TARGET_NR_sigreturn
B
bellard 已提交
6002 6003 6004 6005
    case TARGET_NR_sigreturn:
        /* NOTE: ret is eax, so not transcoding must be done */
        ret = do_sigreturn(cpu_env);
        break;
6006
#endif
B
bellard 已提交
6007 6008 6009 6010
    case TARGET_NR_rt_sigreturn:
        /* NOTE: ret is eax, so not transcoding must be done */
        ret = do_rt_sigreturn(cpu_env);
        break;
6011
    case TARGET_NR_sethostname:
6012 6013
        if (!(p = lock_user_string(arg1)))
            goto efault;
6014 6015
        ret = get_errno(sethostname(p, arg2));
        unlock_user(p, arg1, 0);
6016 6017
        break;
    case TARGET_NR_setrlimit:
B
bellard 已提交
6018
        {
6019
            int resource = target_to_host_resource(arg1);
6020
            struct target_rlimit *target_rlim;
B
bellard 已提交
6021
            struct rlimit rlim;
6022 6023
            if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
                goto efault;
6024 6025
            rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
            rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
6026
            unlock_user_struct(target_rlim, arg2, 0);
B
bellard 已提交
6027 6028 6029
            ret = get_errno(setrlimit(resource, &rlim));
        }
        break;
6030
    case TARGET_NR_getrlimit:
B
bellard 已提交
6031
        {
6032
            int resource = target_to_host_resource(arg1);
6033
            struct target_rlimit *target_rlim;
B
bellard 已提交
6034
            struct rlimit rlim;
6035

B
bellard 已提交
6036 6037
            ret = get_errno(getrlimit(resource, &rlim));
            if (!is_error(ret)) {
6038 6039
                if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
                    goto efault;
6040 6041
                target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
                target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
6042
                unlock_user_struct(target_rlim, arg2, 1);
B
bellard 已提交
6043 6044 6045
            }
        }
        break;
6046
    case TARGET_NR_getrusage:
B
bellard 已提交
6047 6048 6049 6050
        {
            struct rusage rusage;
            ret = get_errno(getrusage(arg1, &rusage));
            if (!is_error(ret)) {
6051
                host_to_target_rusage(arg2, &rusage);
B
bellard 已提交
6052 6053 6054
            }
        }
        break;
6055 6056 6057 6058 6059
    case TARGET_NR_gettimeofday:
        {
            struct timeval tv;
            ret = get_errno(gettimeofday(&tv, NULL));
            if (!is_error(ret)) {
6060 6061
                if (copy_to_user_timeval(arg1, &tv))
                    goto efault;
6062 6063 6064 6065 6066 6067
            }
        }
        break;
    case TARGET_NR_settimeofday:
        {
            struct timeval tv;
6068 6069
            if (copy_from_user_timeval(&tv, arg1))
                goto efault;
6070 6071 6072
            ret = get_errno(settimeofday(&tv, NULL));
        }
        break;
U
Ulrich Hecht 已提交
6073
#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390)
6074
    case TARGET_NR_select:
B
bellard 已提交
6075
        {
6076
            struct target_sel_arg_struct *sel;
6077
            abi_ulong inp, outp, exp, tvp;
6078 6079
            long nsel;

6080 6081
            if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
                goto efault;
6082 6083 6084 6085 6086
            nsel = tswapal(sel->n);
            inp = tswapal(sel->inp);
            outp = tswapal(sel->outp);
            exp = tswapal(sel->exp);
            tvp = tswapal(sel->tvp);
6087 6088
            unlock_user_struct(sel, arg1, 0);
            ret = do_select(nsel, inp, outp, exp, tvp);
B
bellard 已提交
6089 6090
        }
        break;
6091 6092 6093
#endif
#ifdef TARGET_NR_pselect6
    case TARGET_NR_pselect6:
6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153
        {
            abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
            fd_set rfds, wfds, efds;
            fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
            struct timespec ts, *ts_ptr;

            /*
             * The 6th arg is actually two args smashed together,
             * so we cannot use the C library.
             */
            sigset_t set;
            struct {
                sigset_t *set;
                size_t size;
            } sig, *sig_ptr;

            abi_ulong arg_sigset, arg_sigsize, *arg7;
            target_sigset_t *target_sigset;

            n = arg1;
            rfd_addr = arg2;
            wfd_addr = arg3;
            efd_addr = arg4;
            ts_addr = arg5;

            ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
            if (ret) {
                goto fail;
            }
            ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
            if (ret) {
                goto fail;
            }
            ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
            if (ret) {
                goto fail;
            }

            /*
             * This takes a timespec, and not a timeval, so we cannot
             * use the do_select() helper ...
             */
            if (ts_addr) {
                if (target_to_host_timespec(&ts, ts_addr)) {
                    goto efault;
                }
                ts_ptr = &ts;
            } else {
                ts_ptr = NULL;
            }

            /* Extract the two packed args for the sigset */
            if (arg6) {
                sig_ptr = &sig;
                sig.size = _NSIG / 8;

                arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
                if (!arg7) {
                    goto efault;
                }
6154 6155
                arg_sigset = tswapal(arg7[0]);
                arg_sigsize = tswapal(arg7[1]);
6156 6157 6158 6159
                unlock_user(arg7, arg6, 0);

                if (arg_sigset) {
                    sig.set = &set;
6160 6161 6162 6163 6164
                    if (arg_sigsize != sizeof(*target_sigset)) {
                        /* Like the kernel, we enforce correct size sigsets */
                        ret = -TARGET_EINVAL;
                        goto fail;
                    }
6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194
                    target_sigset = lock_user(VERIFY_READ, arg_sigset,
                                              sizeof(*target_sigset), 1);
                    if (!target_sigset) {
                        goto efault;
                    }
                    target_to_host_sigset(&set, target_sigset);
                    unlock_user(target_sigset, arg_sigset, 0);
                } else {
                    sig.set = NULL;
                }
            } else {
                sig_ptr = NULL;
            }

            ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
                                         ts_ptr, sig_ptr));

            if (!is_error(ret)) {
                if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
                    goto efault;
                if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
                    goto efault;
                if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
                    goto efault;

                if (ts_addr && host_to_target_timespec(ts_addr, &ts))
                    goto efault;
            }
        }
        break;
B
bellard 已提交
6195
#endif
6196
    case TARGET_NR_symlink:
6197 6198 6199 6200
        {
            void *p2;
            p = lock_user_string(arg1);
            p2 = lock_user_string(arg2);
6201 6202 6203 6204
            if (!p || !p2)
                ret = -TARGET_EFAULT;
            else
                ret = get_errno(symlink(p, p2));
6205 6206 6207
            unlock_user(p2, arg2, 0);
            unlock_user(p, arg1, 0);
        }
6208
        break;
6209 6210 6211
#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
    case TARGET_NR_symlinkat:
        {
6212
            void *p2;
6213 6214
            p  = lock_user_string(arg1);
            p2 = lock_user_string(arg3);
6215
            if (!p || !p2)
6216
                ret = -TARGET_EFAULT;
6217 6218
            else
                ret = get_errno(sys_symlinkat(p, arg2, p2));
6219 6220
            unlock_user(p2, arg3, 0);
            unlock_user(p, arg1, 0);
6221 6222 6223
        }
        break;
#endif
6224
#ifdef TARGET_NR_oldlstat
6225 6226
    case TARGET_NR_oldlstat:
        goto unimplemented;
6227
#endif
6228
    case TARGET_NR_readlink:
6229
        {
6230
            void *p2, *temp;
6231
            p = lock_user_string(arg1);
6232 6233 6234
            p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
            if (!p || !p2)
                ret = -TARGET_EFAULT;
6235 6236 6237 6238 6239 6240 6241 6242 6243 6244
            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));
            }
6245 6246 6247
            unlock_user(p2, arg2, ret);
            unlock_user(p, arg1, 0);
        }
6248
        break;
6249 6250 6251
#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
    case TARGET_NR_readlinkat:
        {
6252
            void *p2;
6253
            p  = lock_user_string(arg2);
6254 6255
            p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
            if (!p || !p2)
6256
        	ret = -TARGET_EFAULT;
6257 6258
            else
                ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
6259 6260
            unlock_user(p2, arg3, ret);
            unlock_user(p, arg2, 0);
6261 6262 6263
        }
        break;
#endif
6264
#ifdef TARGET_NR_uselib
6265 6266
    case TARGET_NR_uselib:
        goto unimplemented;
6267 6268
#endif
#ifdef TARGET_NR_swapon
6269
    case TARGET_NR_swapon:
6270 6271
        if (!(p = lock_user_string(arg1)))
            goto efault;
6272 6273
        ret = get_errno(swapon(p, arg2));
        unlock_user(p, arg1, 0);
6274
        break;
6275
#endif
6276
    case TARGET_NR_reboot:
6277 6278 6279 6280 6281
        if (!(p = lock_user_string(arg4)))
            goto efault;
        ret = reboot(arg1, arg2, arg3, p);
        unlock_user(p, arg4, 0);
        break;
6282
#ifdef TARGET_NR_readdir
6283 6284
    case TARGET_NR_readdir:
        goto unimplemented;
6285 6286
#endif
#ifdef TARGET_NR_mmap
6287
    case TARGET_NR_mmap:
U
Ulrich Hecht 已提交
6288 6289 6290
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
    defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
    || defined(TARGET_S390X)
6291
        {
6292 6293
            abi_ulong *v;
            abi_ulong v1, v2, v3, v4, v5, v6;
6294 6295
            if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
                goto efault;
6296 6297 6298 6299 6300 6301
            v1 = tswapal(v[0]);
            v2 = tswapal(v[1]);
            v3 = tswapal(v[2]);
            v4 = tswapal(v[3]);
            v5 = tswapal(v[4]);
            v6 = tswapal(v[5]);
6302
            unlock_user(v, arg1, 0);
6303
            ret = get_errno(target_mmap(v1, v2, v3,
B
bellard 已提交
6304 6305
                                        target_to_host_bitmask(v4, mmap_flags_tbl),
                                        v5, v6));
6306 6307
        }
#else
6308 6309
        ret = get_errno(target_mmap(arg1, arg2, arg3,
                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
B
bellard 已提交
6310 6311
                                    arg5,
                                    arg6));
6312
#endif
B
bellard 已提交
6313
        break;
6314
#endif
B
bellard 已提交
6315
#ifdef TARGET_NR_mmap2
B
bellard 已提交
6316
    case TARGET_NR_mmap2:
P
pbrook 已提交
6317
#ifndef MMAP_SHIFT
B
bellard 已提交
6318 6319
#define MMAP_SHIFT 12
#endif
6320 6321
        ret = get_errno(target_mmap(arg1, arg2, arg3,
                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
B
bellard 已提交
6322
                                    arg5,
B
bellard 已提交
6323
                                    arg6 << MMAP_SHIFT));
6324
        break;
B
bellard 已提交
6325
#endif
6326
    case TARGET_NR_munmap:
B
bellard 已提交
6327
        ret = get_errno(target_munmap(arg1, arg2));
6328
        break;
B
bellard 已提交
6329
    case TARGET_NR_mprotect:
P
Paul Brook 已提交
6330
        {
6331
            TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
P
Paul Brook 已提交
6332 6333 6334 6335 6336 6337 6338 6339 6340
            /* Special hack to detect libc making the stack executable.  */
            if ((arg3 & PROT_GROWSDOWN)
                && arg1 >= ts->info->stack_limit
                && arg1 <= ts->info->start_stack) {
                arg3 &= ~PROT_GROWSDOWN;
                arg2 = arg2 + arg1 - ts->info->stack_limit;
                arg1 = ts->info->stack_limit;
            }
        }
B
bellard 已提交
6341
        ret = get_errno(target_mprotect(arg1, arg2, arg3));
B
bellard 已提交
6342
        break;
6343
#ifdef TARGET_NR_mremap
B
bellard 已提交
6344
    case TARGET_NR_mremap:
B
bellard 已提交
6345
        ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
B
bellard 已提交
6346
        break;
6347
#endif
6348
        /* ??? msync/mlock/munlock are broken for softmmu.  */
6349
#ifdef TARGET_NR_msync
B
bellard 已提交
6350
    case TARGET_NR_msync:
6351
        ret = get_errno(msync(g2h(arg1), arg2, arg3));
B
bellard 已提交
6352
        break;
6353 6354
#endif
#ifdef TARGET_NR_mlock
B
bellard 已提交
6355
    case TARGET_NR_mlock:
6356
        ret = get_errno(mlock(g2h(arg1), arg2));
B
bellard 已提交
6357
        break;
6358 6359
#endif
#ifdef TARGET_NR_munlock
B
bellard 已提交
6360
    case TARGET_NR_munlock:
6361
        ret = get_errno(munlock(g2h(arg1), arg2));
B
bellard 已提交
6362
        break;
6363 6364
#endif
#ifdef TARGET_NR_mlockall
B
bellard 已提交
6365 6366 6367
    case TARGET_NR_mlockall:
        ret = get_errno(mlockall(arg1));
        break;
6368 6369
#endif
#ifdef TARGET_NR_munlockall
B
bellard 已提交
6370 6371 6372
    case TARGET_NR_munlockall:
        ret = get_errno(munlockall());
        break;
6373
#endif
6374
    case TARGET_NR_truncate:
6375 6376
        if (!(p = lock_user_string(arg1)))
            goto efault;
6377 6378
        ret = get_errno(truncate(p, arg2));
        unlock_user(p, arg1, 0);
6379 6380 6381 6382 6383 6384 6385
        break;
    case TARGET_NR_ftruncate:
        ret = get_errno(ftruncate(arg1, arg2));
        break;
    case TARGET_NR_fchmod:
        ret = get_errno(fchmod(arg1, arg2));
        break;
6386 6387
#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
    case TARGET_NR_fchmodat:
6388 6389
        if (!(p = lock_user_string(arg2)))
            goto efault;
6390
        ret = get_errno(sys_fchmodat(arg1, p, arg3));
6391
        unlock_user(p, arg2, 0);
6392 6393
        break;
#endif
6394
    case TARGET_NR_getpriority:
6395 6396 6397
        /* 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. */
U
Ulrich Hecht 已提交
6398
        ret = get_errno(sys_getpriority(arg1, arg2));
6399 6400 6401 6402
        break;
    case TARGET_NR_setpriority:
        ret = get_errno(setpriority(arg1, arg2, arg3));
        break;
6403
#ifdef TARGET_NR_profil
6404 6405
    case TARGET_NR_profil:
        goto unimplemented;
6406
#endif
6407
    case TARGET_NR_statfs:
6408 6409
        if (!(p = lock_user_string(arg1)))
            goto efault;
6410 6411
        ret = get_errno(statfs(path(p), &stfs));
        unlock_user(p, arg1, 0);
6412 6413
    convert_statfs:
        if (!is_error(ret)) {
6414
            struct target_statfs *target_stfs;
6415

6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427
            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);
6428
            unlock_user_struct(target_stfs, arg2, 1);
6429 6430 6431
        }
        break;
    case TARGET_NR_fstatfs:
B
bellard 已提交
6432
        ret = get_errno(fstatfs(arg1, &stfs));
6433
        goto convert_statfs;
B
bellard 已提交
6434 6435
#ifdef TARGET_NR_statfs64
    case TARGET_NR_statfs64:
6436 6437
        if (!(p = lock_user_string(arg1)))
            goto efault;
6438 6439
        ret = get_errno(statfs(path(p), &stfs));
        unlock_user(p, arg1, 0);
B
bellard 已提交
6440 6441
    convert_statfs64:
        if (!is_error(ret)) {
6442
            struct target_statfs64 *target_stfs;
6443

6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456
            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 已提交
6457 6458 6459 6460 6461 6462
        }
        break;
    case TARGET_NR_fstatfs64:
        ret = get_errno(fstatfs(arg1, &stfs));
        goto convert_statfs64;
#endif
6463
#ifdef TARGET_NR_ioperm
6464 6465
    case TARGET_NR_ioperm:
        goto unimplemented;
6466
#endif
6467
#ifdef TARGET_NR_socketcall
6468
    case TARGET_NR_socketcall:
6469
        ret = do_socketcall(arg1, arg2);
6470
        break;
6471
#endif
6472 6473
#ifdef TARGET_NR_accept
    case TARGET_NR_accept:
P
pbrook 已提交
6474
        ret = do_accept(arg1, arg2, arg3);
6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488
        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 已提交
6489
        ret = do_getpeername(arg1, arg2, arg3);
6490 6491 6492 6493
        break;
#endif
#ifdef TARGET_NR_getsockname
    case TARGET_NR_getsockname:
P
pbrook 已提交
6494
        ret = do_getsockname(arg1, arg2, arg3);
6495 6496 6497 6498 6499 6500 6501 6502 6503
        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 已提交
6504
        ret = get_errno(listen(arg1, arg2));
6505 6506 6507 6508
        break;
#endif
#ifdef TARGET_NR_recv
    case TARGET_NR_recv:
P
pbrook 已提交
6509
        ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
6510 6511 6512 6513
        break;
#endif
#ifdef TARGET_NR_recvfrom
    case TARGET_NR_recvfrom:
P
pbrook 已提交
6514
        ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
6515 6516 6517 6518 6519 6520 6521 6522 6523
        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 已提交
6524
        ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
6525 6526 6527 6528 6529 6530 6531 6532 6533
        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 已提交
6534
        ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
6535 6536 6537 6538
        break;
#endif
#ifdef TARGET_NR_shutdown
    case TARGET_NR_shutdown:
P
pbrook 已提交
6539
        ret = get_errno(shutdown(arg1, arg2));
6540 6541 6542 6543 6544 6545 6546 6547 6548
        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 已提交
6549
        ret = do_socketpair(arg1, arg2, arg3, arg4);
6550 6551 6552 6553 6554 6555 6556
        break;
#endif
#ifdef TARGET_NR_setsockopt
    case TARGET_NR_setsockopt:
        ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
        break;
#endif
6557

6558
    case TARGET_NR_syslog:
6559 6560
        if (!(p = lock_user_string(arg2)))
            goto efault;
6561 6562
        ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
        unlock_user(p, arg2, 0);
6563 6564
        break;

6565
    case TARGET_NR_setitimer:
B
bellard 已提交
6566 6567 6568
        {
            struct itimerval value, ovalue, *pvalue;

6569
            if (arg2) {
B
bellard 已提交
6570
                pvalue = &value;
6571 6572 6573 6574
                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 已提交
6575 6576 6577 6578
            } else {
                pvalue = NULL;
            }
            ret = get_errno(setitimer(arg1, pvalue, &ovalue));
6579
            if (!is_error(ret) && arg3) {
6580 6581 6582 6583 6584
                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 已提交
6585 6586 6587
            }
        }
        break;
6588
    case TARGET_NR_getitimer:
B
bellard 已提交
6589 6590
        {
            struct itimerval value;
6591

B
bellard 已提交
6592
            ret = get_errno(getitimer(arg1, &value));
6593
            if (!is_error(ret) && arg2) {
6594 6595 6596 6597 6598
                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 已提交
6599 6600 6601
            }
        }
        break;
6602
    case TARGET_NR_stat:
6603 6604
        if (!(p = lock_user_string(arg1)))
            goto efault;
6605 6606
        ret = get_errno(stat(path(p), &st));
        unlock_user(p, arg1, 0);
6607 6608
        goto do_stat;
    case TARGET_NR_lstat:
6609 6610
        if (!(p = lock_user_string(arg1)))
            goto efault;
6611 6612
        ret = get_errno(lstat(path(p), &st));
        unlock_user(p, arg1, 0);
6613 6614 6615 6616 6617 6618
        goto do_stat;
    case TARGET_NR_fstat:
        {
            ret = get_errno(fstat(arg1, &st));
        do_stat:
            if (!is_error(ret)) {
6619
                struct target_stat *target_st;
6620

6621 6622
                if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
                    goto efault;
6623
                memset(target_st, 0, sizeof(*target_st));
B
bellard 已提交
6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636
                __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);
6637
                unlock_user_struct(target_st, arg2, 1);
6638 6639 6640
            }
        }
        break;
6641
#ifdef TARGET_NR_olduname
6642 6643
    case TARGET_NR_olduname:
        goto unimplemented;
6644 6645
#endif
#ifdef TARGET_NR_iopl
6646 6647
    case TARGET_NR_iopl:
        goto unimplemented;
6648
#endif
6649 6650 6651
    case TARGET_NR_vhangup:
        ret = get_errno(vhangup());
        break;
6652
#ifdef TARGET_NR_idle
6653 6654
    case TARGET_NR_idle:
        goto unimplemented;
B
bellard 已提交
6655 6656 6657
#endif
#ifdef TARGET_NR_syscall
    case TARGET_NR_syscall:
6658 6659 6660
        ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
                         arg6, arg7, arg8, 0);
        break;
6661
#endif
6662 6663 6664
    case TARGET_NR_wait4:
        {
            int status;
6665
            abi_long status_ptr = arg2;
6666
            struct rusage rusage, *rusage_ptr;
6667
            abi_ulong target_rusage = arg4;
6668 6669 6670 6671 6672 6673
            if (target_rusage)
                rusage_ptr = &rusage;
            else
                rusage_ptr = NULL;
            ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
            if (!is_error(ret)) {
6674
                if (status_ptr && ret) {
P
pbrook 已提交
6675
                    status = host_to_target_waitstatus(status);
6676 6677
                    if (put_user_s32(status, status_ptr))
                        goto efault;
6678
                }
6679 6680
                if (target_rusage)
                    host_to_target_rusage(target_rusage, &rusage);
6681 6682 6683
            }
        }
        break;
6684
#ifdef TARGET_NR_swapoff
6685
    case TARGET_NR_swapoff:
6686 6687
        if (!(p = lock_user_string(arg1)))
            goto efault;
6688 6689
        ret = get_errno(swapoff(p));
        unlock_user(p, arg1, 0);
6690
        break;
6691
#endif
6692
    case TARGET_NR_sysinfo:
B
bellard 已提交
6693
        {
6694
            struct target_sysinfo *target_value;
B
bellard 已提交
6695 6696
            struct sysinfo value;
            ret = get_errno(sysinfo(&value));
6697
            if (!is_error(ret) && arg1)
B
bellard 已提交
6698
            {
6699 6700
                if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
                    goto efault;
B
bellard 已提交
6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714
                __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);
6715
                unlock_user_struct(target_value, arg1, 1);
B
bellard 已提交
6716 6717 6718
            }
        }
        break;
6719
#ifdef TARGET_NR_ipc
6720
    case TARGET_NR_ipc:
6721 6722
	ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
	break;
6723
#endif
6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738
#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 已提交
6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757
#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;
6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777
#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 已提交
6778
#endif
6779 6780 6781 6782
    case TARGET_NR_fsync:
        ret = get_errno(fsync(arg1));
        break;
    case TARGET_NR_clone:
R
Richard Henderson 已提交
6783
#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
A
aurel32 已提交
6784
        ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
6785 6786
#elif defined(TARGET_CRIS)
        ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
U
Ulrich Hecht 已提交
6787 6788
#elif defined(TARGET_S390X)
        ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
A
aurel32 已提交
6789
#else
P
pbrook 已提交
6790
        ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
A
aurel32 已提交
6791
#endif
B
bellard 已提交
6792
        break;
6793 6794 6795
#ifdef __NR_exit_group
        /* new thread calls */
    case TARGET_NR_exit_group:
6796
#ifdef TARGET_GPROF
A
aurel32 已提交
6797 6798
        _mcleanup();
#endif
6799
        gdb_exit(cpu_env, arg1);
6800 6801 6802
        ret = get_errno(exit_group(arg1));
        break;
#endif
6803
    case TARGET_NR_setdomainname:
6804 6805
        if (!(p = lock_user_string(arg1)))
            goto efault;
6806 6807
        ret = get_errno(setdomainname(p, arg2));
        unlock_user(p, arg1, 0);
6808 6809 6810
        break;
    case TARGET_NR_uname:
        /* no need to transcode because we use the linux syscall */
B
bellard 已提交
6811 6812
        {
            struct new_utsname * buf;
6813

6814 6815
            if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
                goto efault;
B
bellard 已提交
6816 6817 6818 6819
            ret = get_errno(sys_uname(buf));
            if (!is_error(ret)) {
                /* Overrite the native machine name with whatever is being
                   emulated. */
6820
                strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
6821 6822 6823
                /* Allow the user to override the reported release.  */
                if (qemu_uname_release && *qemu_uname_release)
                  strcpy (buf->release, qemu_uname_release);
B
bellard 已提交
6824
            }
6825
            unlock_user_struct(buf, arg1, 1);
B
bellard 已提交
6826
        }
6827
        break;
B
bellard 已提交
6828
#ifdef TARGET_I386
6829
    case TARGET_NR_modify_ldt:
6830
        ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
B
bellard 已提交
6831
        break;
6832
#if !defined(TARGET_X86_64)
B
bellard 已提交
6833 6834 6835
    case TARGET_NR_vm86old:
        goto unimplemented;
    case TARGET_NR_vm86:
6836
        ret = do_vm86(cpu_env, arg1, arg2);
B
bellard 已提交
6837
        break;
6838
#endif
B
bellard 已提交
6839
#endif
6840 6841
    case TARGET_NR_adjtimex:
        goto unimplemented;
6842
#ifdef TARGET_NR_create_module
6843
    case TARGET_NR_create_module:
6844
#endif
6845 6846
    case TARGET_NR_init_module:
    case TARGET_NR_delete_module:
6847
#ifdef TARGET_NR_get_kernel_syms
6848
    case TARGET_NR_get_kernel_syms:
6849
#endif
6850 6851 6852 6853 6854 6855 6856 6857 6858
        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;
6859
#ifdef TARGET_NR_bdflush /* not on x86_64 */
6860 6861
    case TARGET_NR_bdflush:
        goto unimplemented;
6862
#endif
6863
#ifdef TARGET_NR_sysfs
6864 6865
    case TARGET_NR_sysfs:
        goto unimplemented;
6866
#endif
6867
    case TARGET_NR_personality:
B
bellard 已提交
6868
        ret = get_errno(personality(arg1));
6869
        break;
6870
#ifdef TARGET_NR_afs_syscall
6871 6872
    case TARGET_NR_afs_syscall:
        goto unimplemented;
6873
#endif
6874
#ifdef TARGET_NR__llseek /* Not on alpha */
6875 6876
    case TARGET_NR__llseek:
        {
6877
            int64_t res;
R
Richard Henderson 已提交
6878
#if !defined(__NR_llseek)
6879 6880 6881 6882 6883 6884
            res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
            if (res == -1) {
                ret = get_errno(res);
            } else {
                ret = 0;
            }
B
bellard 已提交
6885
#else
6886
            ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
B
bellard 已提交
6887
#endif
6888 6889 6890
            if ((ret == 0) && put_user_s64(res, arg4)) {
                goto efault;
            }
6891 6892
        }
        break;
6893
#endif
6894
    case TARGET_NR_getdents:
6895
#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
B
bellard 已提交
6896
        {
6897
            struct target_dirent *target_dirp;
A
aurel32 已提交
6898
            struct linux_dirent *dirp;
6899
            abi_long count = arg3;
B
bellard 已提交
6900 6901

	    dirp = malloc(count);
6902
	    if (!dirp) {
6903
                ret = -TARGET_ENOMEM;
6904 6905
                goto fail;
            }
6906

B
bellard 已提交
6907 6908
            ret = get_errno(sys_getdents(arg1, dirp, count));
            if (!is_error(ret)) {
A
aurel32 已提交
6909
                struct linux_dirent *de;
B
bellard 已提交
6910 6911 6912 6913 6914 6915 6916
		struct target_dirent *tde;
                int len = ret;
                int reclen, treclen;
		int count1, tnamelen;

		count1 = 0;
                de = dirp;
6917 6918
                if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
                    goto efault;
B
bellard 已提交
6919 6920 6921
		tde = target_dirp;
                while (len > 0) {
                    reclen = de->d_reclen;
6922
		    treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
B
bellard 已提交
6923
                    tde->d_reclen = tswap16(treclen);
6924 6925
                    tde->d_ino = tswapal(de->d_ino);
                    tde->d_off = tswapal(de->d_off);
6926
		    tnamelen = treclen - (2 * sizeof(abi_long) + 2);
B
bellard 已提交
6927 6928
		    if (tnamelen > 256)
                        tnamelen = 256;
B
bellard 已提交
6929
                    /* XXX: may not be correct */
6930
                    pstrcpy(tde->d_name, tnamelen, de->d_name);
A
aurel32 已提交
6931
                    de = (struct linux_dirent *)((char *)de + reclen);
B
bellard 已提交
6932
                    len -= reclen;
J
j_mayer 已提交
6933
                    tde = (struct target_dirent *)((char *)tde + treclen);
B
bellard 已提交
6934 6935 6936
		    count1 += treclen;
                }
		ret = count1;
6937
                unlock_user(target_dirp, arg2, ret);
B
bellard 已提交
6938 6939 6940 6941
            }
	    free(dirp);
        }
#else
6942
        {
A
aurel32 已提交
6943
            struct linux_dirent *dirp;
6944
            abi_long count = arg3;
B
bellard 已提交
6945

6946 6947
            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
                goto efault;
B
bellard 已提交
6948
            ret = get_errno(sys_getdents(arg1, dirp, count));
6949
            if (!is_error(ret)) {
A
aurel32 已提交
6950
                struct linux_dirent *de;
6951 6952 6953 6954
                int len = ret;
                int reclen;
                de = dirp;
                while (len > 0) {
B
bellard 已提交
6955
                    reclen = de->d_reclen;
6956 6957
                    if (reclen > len)
                        break;
B
bellard 已提交
6958
                    de->d_reclen = tswap16(reclen);
6959 6960
                    tswapls(&de->d_ino);
                    tswapls(&de->d_off);
A
aurel32 已提交
6961
                    de = (struct linux_dirent *)((char *)de + reclen);
6962 6963 6964
                    len -= reclen;
                }
            }
6965
            unlock_user(dirp, arg2, ret);
6966
        }
B
bellard 已提交
6967
#endif
6968
        break;
T
ths 已提交
6969
#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
B
bellard 已提交
6970 6971
    case TARGET_NR_getdents64:
        {
A
aurel32 已提交
6972
            struct linux_dirent64 *dirp;
6973
            abi_long count = arg3;
6974 6975
            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
                goto efault;
B
bellard 已提交
6976 6977
            ret = get_errno(sys_getdents64(arg1, dirp, count));
            if (!is_error(ret)) {
A
aurel32 已提交
6978
                struct linux_dirent64 *de;
B
bellard 已提交
6979 6980 6981 6982
                int len = ret;
                int reclen;
                de = dirp;
                while (len > 0) {
B
bellard 已提交
6983
                    reclen = de->d_reclen;
B
bellard 已提交
6984 6985
                    if (reclen > len)
                        break;
B
bellard 已提交
6986
                    de->d_reclen = tswap16(reclen);
B
bellard 已提交
6987 6988
                    tswap64s((uint64_t *)&de->d_ino);
                    tswap64s((uint64_t *)&de->d_off);
A
aurel32 已提交
6989
                    de = (struct linux_dirent64 *)((char *)de + reclen);
B
bellard 已提交
6990 6991 6992
                    len -= reclen;
                }
            }
6993
            unlock_user(dirp, arg2, ret);
B
bellard 已提交
6994 6995
        }
        break;
6996
#endif /* TARGET_NR_getdents64 */
U
Ulrich Hecht 已提交
6997 6998 6999 7000
#if defined(TARGET_NR__newselect) || defined(TARGET_S390X)
#ifdef TARGET_S390X
    case TARGET_NR_select:
#else
7001
    case TARGET_NR__newselect:
U
Ulrich Hecht 已提交
7002
#endif
7003
        ret = do_select(arg1, arg2, arg3, arg4, arg5);
7004
        break;
7005
#endif
7006 7007
#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
# ifdef TARGET_NR_poll
B
bellard 已提交
7008
    case TARGET_NR_poll:
7009 7010 7011 7012
# endif
# ifdef TARGET_NR_ppoll
    case TARGET_NR_ppoll:
# endif
B
bellard 已提交
7013
        {
7014
            struct target_pollfd *target_pfd;
B
bellard 已提交
7015 7016 7017
            unsigned int nfds = arg2;
            int timeout = arg3;
            struct pollfd *pfd;
B
bellard 已提交
7018
            unsigned int i;
B
bellard 已提交
7019

7020 7021 7022
            target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
            if (!target_pfd)
                goto efault;
7023

B
bellard 已提交
7024 7025
            pfd = alloca(sizeof(struct pollfd) * nfds);
            for(i = 0; i < nfds; i++) {
B
bellard 已提交
7026 7027
                pfd[i].fd = tswap32(target_pfd[i].fd);
                pfd[i].events = tswap16(target_pfd[i].events);
B
bellard 已提交
7028
            }
7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067

# ifdef TARGET_NR_ppoll
            if (num == TARGET_NR_ppoll) {
                struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
                target_sigset_t *target_set;
                sigset_t _set, *set = &_set;

                if (arg3) {
                    if (target_to_host_timespec(timeout_ts, arg3)) {
                        unlock_user(target_pfd, arg1, 0);
                        goto efault;
                    }
                } else {
                    timeout_ts = NULL;
                }

                if (arg4) {
                    target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
                    if (!target_set) {
                        unlock_user(target_pfd, arg1, 0);
                        goto efault;
                    }
                    target_to_host_sigset(set, target_set);
                } else {
                    set = NULL;
                }

                ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));

                if (!is_error(ret) && arg3) {
                    host_to_target_timespec(arg3, timeout_ts);
                }
                if (arg4) {
                    unlock_user(target_set, arg4, 0);
                }
            } else
# endif
                ret = get_errno(poll(pfd, nfds, timeout));

B
bellard 已提交
7068 7069
            if (!is_error(ret)) {
                for(i = 0; i < nfds; i++) {
B
bellard 已提交
7070
                    target_pfd[i].revents = tswap16(pfd[i].revents);
B
bellard 已提交
7071 7072
                }
            }
7073
            unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
B
bellard 已提交
7074 7075
        }
        break;
7076
#endif
7077
    case TARGET_NR_flock:
B
bellard 已提交
7078 7079 7080
        /* NOTE: the flock constant seems to be the same for every
           Linux platform */
        ret = get_errno(flock(arg1, arg2));
7081 7082 7083 7084 7085 7086 7087
        break;
    case TARGET_NR_readv:
        {
            int count = arg3;
            struct iovec *vec;

            vec = alloca(count * sizeof(struct iovec));
B
bellard 已提交
7088 7089
            if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
                goto efault;
7090
            ret = get_errno(readv(arg1, vec, count));
7091
            unlock_iovec(vec, arg2, count, 1);
7092 7093 7094 7095 7096 7097 7098 7099
        }
        break;
    case TARGET_NR_writev:
        {
            int count = arg3;
            struct iovec *vec;

            vec = alloca(count * sizeof(struct iovec));
B
bellard 已提交
7100 7101
            if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
                goto efault;
7102
            ret = get_errno(writev(arg1, vec, count));
7103
            unlock_iovec(vec, arg2, count, 0);
7104 7105 7106 7107 7108
        }
        break;
    case TARGET_NR_getsid:
        ret = get_errno(getsid(arg1));
        break;
7109
#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
7110
    case TARGET_NR_fdatasync:
B
bellard 已提交
7111 7112
        ret = get_errno(fdatasync(arg1));
        break;
7113
#endif
7114
    case TARGET_NR__sysctl:
7115
        /* We don't implement this, but ENOTDIR is always a safe
B
bellard 已提交
7116
           return value. */
7117 7118
        ret = -TARGET_ENOTDIR;
        break;
7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137
    case TARGET_NR_sched_getaffinity:
        {
            unsigned int mask_size;
            unsigned long *mask;

            /*
             * sched_getaffinity needs multiples of ulong, so need to take
             * care of mismatches between target ulong and host ulong sizes.
             */
            if (arg2 & (sizeof(abi_ulong) - 1)) {
                ret = -TARGET_EINVAL;
                break;
            }
            mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);

            mask = alloca(mask_size);
            ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));

            if (!is_error(ret)) {
7138
                if (copy_to_user(arg3, mask, ret)) {
7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168
                    goto efault;
                }
            }
        }
        break;
    case TARGET_NR_sched_setaffinity:
        {
            unsigned int mask_size;
            unsigned long *mask;

            /*
             * sched_setaffinity needs multiples of ulong, so need to take
             * care of mismatches between target ulong and host ulong sizes.
             */
            if (arg2 & (sizeof(abi_ulong) - 1)) {
                ret = -TARGET_EINVAL;
                break;
            }
            mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);

            mask = alloca(mask_size);
            if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
                goto efault;
            }
            memcpy(mask, p, arg2);
            unlock_user_struct(p, arg2, 0);

            ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
        }
        break;
7169
    case TARGET_NR_sched_setparam:
B
bellard 已提交
7170
        {
7171
            struct sched_param *target_schp;
B
bellard 已提交
7172
            struct sched_param schp;
7173

7174 7175
            if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
                goto efault;
B
bellard 已提交
7176
            schp.sched_priority = tswap32(target_schp->sched_priority);
7177
            unlock_user_struct(target_schp, arg2, 0);
B
bellard 已提交
7178 7179 7180
            ret = get_errno(sched_setparam(arg1, &schp));
        }
        break;
7181
    case TARGET_NR_sched_getparam:
B
bellard 已提交
7182
        {
7183
            struct sched_param *target_schp;
B
bellard 已提交
7184 7185 7186
            struct sched_param schp;
            ret = get_errno(sched_getparam(arg1, &schp));
            if (!is_error(ret)) {
7187 7188
                if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
                    goto efault;
B
bellard 已提交
7189
                target_schp->sched_priority = tswap32(schp.sched_priority);
7190
                unlock_user_struct(target_schp, arg2, 1);
B
bellard 已提交
7191 7192 7193
            }
        }
        break;
7194
    case TARGET_NR_sched_setscheduler:
B
bellard 已提交
7195
        {
7196
            struct sched_param *target_schp;
B
bellard 已提交
7197
            struct sched_param schp;
7198 7199
            if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
                goto efault;
B
bellard 已提交
7200
            schp.sched_priority = tswap32(target_schp->sched_priority);
7201
            unlock_user_struct(target_schp, arg3, 0);
B
bellard 已提交
7202 7203 7204
            ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
        }
        break;
7205
    case TARGET_NR_sched_getscheduler:
B
bellard 已提交
7206 7207
        ret = get_errno(sched_getscheduler(arg1));
        break;
7208 7209 7210 7211
    case TARGET_NR_sched_yield:
        ret = get_errno(sched_yield());
        break;
    case TARGET_NR_sched_get_priority_max:
B
bellard 已提交
7212 7213
        ret = get_errno(sched_get_priority_max(arg1));
        break;
7214
    case TARGET_NR_sched_get_priority_min:
B
bellard 已提交
7215 7216
        ret = get_errno(sched_get_priority_min(arg1));
        break;
7217
    case TARGET_NR_sched_rr_get_interval:
B
bellard 已提交
7218 7219 7220 7221
        {
            struct timespec ts;
            ret = get_errno(sched_rr_get_interval(arg1, &ts));
            if (!is_error(ret)) {
7222
                host_to_target_timespec(arg2, &ts);
B
bellard 已提交
7223 7224 7225
            }
        }
        break;
7226
    case TARGET_NR_nanosleep:
B
bellard 已提交
7227 7228
        {
            struct timespec req, rem;
7229
            target_to_host_timespec(&req, arg1);
B
bellard 已提交
7230
            ret = get_errno(nanosleep(&req, &rem));
7231 7232
            if (is_error(ret) && arg2) {
                host_to_target_timespec(arg2, &rem);
B
bellard 已提交
7233 7234 7235
            }
        }
        break;
7236
#ifdef TARGET_NR_query_module
7237
    case TARGET_NR_query_module:
B
bellard 已提交
7238
        goto unimplemented;
7239 7240
#endif
#ifdef TARGET_NR_nfsservctl
7241
    case TARGET_NR_nfsservctl:
B
bellard 已提交
7242
        goto unimplemented;
7243
#endif
7244
    case TARGET_NR_prctl:
7245 7246 7247 7248 7249 7250 7251 7252
        switch (arg1) {
        case PR_GET_PDEATHSIG:
        {
            int deathsig;
            ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
            if (!is_error(ret) && arg2
                && put_user_ual(deathsig, arg2)) {
                goto efault;
7253
            }
7254 7255
            break;
        }
7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279
#ifdef PR_GET_NAME
        case PR_GET_NAME:
        {
            void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
            if (!name) {
                goto efault;
            }
            ret = get_errno(prctl(arg1, (unsigned long)name,
                                  arg3, arg4, arg5));
            unlock_user(name, arg2, 16);
            break;
        }
        case PR_SET_NAME:
        {
            void *name = lock_user(VERIFY_READ, arg2, 16, 1);
            if (!name) {
                goto efault;
            }
            ret = get_errno(prctl(arg1, (unsigned long)name,
                                  arg3, arg4, arg5));
            unlock_user(name, arg2, 0);
            break;
        }
#endif
7280 7281 7282 7283 7284
        default:
            /* Most prctl options have no pointer arguments */
            ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
            break;
        }
7285
        break;
B
bellard 已提交
7286 7287 7288 7289 7290 7291 7292 7293 7294
#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
7295
#ifdef TARGET_NR_pread
7296
    case TARGET_NR_pread:
7297
        if (regpairs_aligned(cpu_env))
7298
            arg4 = arg5;
7299 7300
        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
            goto efault;
7301 7302
        ret = get_errno(pread(arg1, p, arg3, arg4));
        unlock_user(p, arg2, ret);
7303
        break;
7304
    case TARGET_NR_pwrite:
7305
        if (regpairs_aligned(cpu_env))
7306
            arg4 = arg5;
7307 7308
        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
            goto efault;
7309 7310
        ret = get_errno(pwrite(arg1, p, arg3, arg4));
        unlock_user(p, arg2, 0);
7311
        break;
A
aurel32 已提交
7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325
#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;
7326
#endif
7327
    case TARGET_NR_getcwd:
7328 7329
        if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
            goto efault;
7330 7331
        ret = get_errno(sys_getcwd1(p, arg2));
        unlock_user(p, arg1, ret);
7332 7333
        break;
    case TARGET_NR_capget:
B
bellard 已提交
7334
        goto unimplemented;
7335
    case TARGET_NR_capset:
B
bellard 已提交
7336
        goto unimplemented;
7337
    case TARGET_NR_sigaltstack:
7338
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
7339
    defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
U
Ulrich Hecht 已提交
7340
    defined(TARGET_M68K) || defined(TARGET_S390X)
7341
        ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
7342 7343
        break;
#else
B
bellard 已提交
7344
        goto unimplemented;
7345
#endif
7346
    case TARGET_NR_sendfile:
B
bellard 已提交
7347
        goto unimplemented;
7348
#ifdef TARGET_NR_getpmsg
7349
    case TARGET_NR_getpmsg:
B
bellard 已提交
7350
        goto unimplemented;
7351 7352
#endif
#ifdef TARGET_NR_putpmsg
7353
    case TARGET_NR_putpmsg:
B
bellard 已提交
7354
        goto unimplemented;
7355
#endif
B
bellard 已提交
7356
#ifdef TARGET_NR_vfork
7357
    case TARGET_NR_vfork:
P
pbrook 已提交
7358 7359
        ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
                        0, 0, 0, 0));
7360
        break;
B
bellard 已提交
7361
#endif
7362
#ifdef TARGET_NR_ugetrlimit
7363
    case TARGET_NR_ugetrlimit:
B
bellard 已提交
7364 7365
    {
	struct rlimit rlim;
7366 7367
	int resource = target_to_host_resource(arg1);
	ret = get_errno(getrlimit(resource, &rlim));
B
bellard 已提交
7368
	if (!is_error(ret)) {
7369
	    struct target_rlimit *target_rlim;
7370 7371
            if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
                goto efault;
7372 7373
	    target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
	    target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
7374
            unlock_user_struct(target_rlim, arg2, 1);
B
bellard 已提交
7375 7376 7377
	}
	break;
    }
7378
#endif
B
bellard 已提交
7379
#ifdef TARGET_NR_truncate64
7380
    case TARGET_NR_truncate64:
7381 7382
        if (!(p = lock_user_string(arg1)))
            goto efault;
7383 7384
	ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
        unlock_user(p, arg1, 0);
B
bellard 已提交
7385
	break;
B
bellard 已提交
7386 7387
#endif
#ifdef TARGET_NR_ftruncate64
7388
    case TARGET_NR_ftruncate64:
P
pbrook 已提交
7389
	ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
B
bellard 已提交
7390
	break;
B
bellard 已提交
7391 7392
#endif
#ifdef TARGET_NR_stat64
7393
    case TARGET_NR_stat64:
7394 7395
        if (!(p = lock_user_string(arg1)))
            goto efault;
7396 7397
        ret = get_errno(stat(path(p), &st));
        unlock_user(p, arg1, 0);
7398 7399 7400
        if (!is_error(ret))
            ret = host_to_target_stat64(cpu_env, arg2, &st);
        break;
B
bellard 已提交
7401 7402
#endif
#ifdef TARGET_NR_lstat64
7403
    case TARGET_NR_lstat64:
7404 7405
        if (!(p = lock_user_string(arg1)))
            goto efault;
7406 7407
        ret = get_errno(lstat(path(p), &st));
        unlock_user(p, arg1, 0);
7408 7409 7410
        if (!is_error(ret))
            ret = host_to_target_stat64(cpu_env, arg2, &st);
        break;
B
bellard 已提交
7411 7412
#endif
#ifdef TARGET_NR_fstat64
7413
    case TARGET_NR_fstat64:
7414 7415 7416 7417
        ret = get_errno(fstat(arg1, &st));
        if (!is_error(ret))
            ret = host_to_target_stat64(cpu_env, arg2, &st);
        break;
P
pbrook 已提交
7418
#endif
7419 7420 7421
#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
        (defined(__NR_fstatat64) || defined(__NR_newfstatat))
#ifdef TARGET_NR_fstatat64
7422
    case TARGET_NR_fstatat64:
7423 7424 7425 7426
#endif
#ifdef TARGET_NR_newfstatat
    case TARGET_NR_newfstatat:
#endif
7427 7428
        if (!(p = lock_user_string(arg2)))
            goto efault;
7429
#ifdef __NR_fstatat64
7430
        ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
7431 7432 7433
#else
        ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
#endif
7434 7435
        if (!is_error(ret))
            ret = host_to_target_stat64(cpu_env, arg3, &st);
B
bellard 已提交
7436
        break;
B
bellard 已提交
7437
#endif
7438
    case TARGET_NR_lchown:
7439 7440
        if (!(p = lock_user_string(arg1)))
            goto efault;
7441 7442
        ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
        unlock_user(p, arg1, 0);
7443
        break;
7444
#ifdef TARGET_NR_getuid
7445 7446 7447
    case TARGET_NR_getuid:
        ret = get_errno(high2lowuid(getuid()));
        break;
7448 7449
#endif
#ifdef TARGET_NR_getgid
7450 7451 7452
    case TARGET_NR_getgid:
        ret = get_errno(high2lowgid(getgid()));
        break;
7453 7454
#endif
#ifdef TARGET_NR_geteuid
7455 7456 7457
    case TARGET_NR_geteuid:
        ret = get_errno(high2lowuid(geteuid()));
        break;
7458 7459
#endif
#ifdef TARGET_NR_getegid
7460 7461 7462
    case TARGET_NR_getegid:
        ret = get_errno(high2lowgid(getegid()));
        break;
7463
#endif
7464 7465 7466 7467 7468 7469 7470 7471 7472
    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;
7473
            target_id *target_grouplist;
7474 7475 7476 7477 7478
            gid_t *grouplist;
            int i;

            grouplist = alloca(gidsetsize * sizeof(gid_t));
            ret = get_errno(getgroups(gidsetsize, grouplist));
7479 7480
            if (gidsetsize == 0)
                break;
7481
            if (!is_error(ret)) {
7482 7483 7484
                target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
                if (!target_grouplist)
                    goto efault;
7485
                for(i = 0;i < ret; i++)
7486
                    target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
7487
                unlock_user(target_grouplist, arg2, gidsetsize * 2);
7488 7489 7490 7491 7492 7493
            }
        }
        break;
    case TARGET_NR_setgroups:
        {
            int gidsetsize = arg1;
7494
            target_id *target_grouplist;
7495 7496 7497 7498
            gid_t *grouplist;
            int i;

            grouplist = alloca(gidsetsize * sizeof(gid_t));
7499 7500 7501 7502 7503
            target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
            if (!target_grouplist) {
                ret = -TARGET_EFAULT;
                goto fail;
            }
7504
            for(i = 0;i < gidsetsize; i++)
7505
                grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
7506
            unlock_user(target_grouplist, arg2, 0);
7507 7508 7509 7510 7511 7512
            ret = get_errno(setgroups(gidsetsize, grouplist));
        }
        break;
    case TARGET_NR_fchown:
        ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
        break;
7513 7514
#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
    case TARGET_NR_fchownat:
7515 7516 7517 7518
        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);
7519 7520
        break;
#endif
7521 7522
#ifdef TARGET_NR_setresuid
    case TARGET_NR_setresuid:
7523 7524
        ret = get_errno(setresuid(low2highuid(arg1),
                                  low2highuid(arg2),
7525 7526 7527 7528 7529 7530
                                  low2highuid(arg3)));
        break;
#endif
#ifdef TARGET_NR_getresuid
    case TARGET_NR_getresuid:
        {
7531
            uid_t ruid, euid, suid;
7532 7533
            ret = get_errno(getresuid(&ruid, &euid, &suid));
            if (!is_error(ret)) {
7534 7535 7536 7537
                if (put_user_u16(high2lowuid(ruid), arg1)
                    || put_user_u16(high2lowuid(euid), arg2)
                    || put_user_u16(high2lowuid(suid), arg3))
                    goto efault;
7538 7539 7540 7541 7542 7543
            }
        }
        break;
#endif
#ifdef TARGET_NR_getresgid
    case TARGET_NR_setresgid:
7544 7545
        ret = get_errno(setresgid(low2highgid(arg1),
                                  low2highgid(arg2),
7546 7547 7548 7549 7550 7551
                                  low2highgid(arg3)));
        break;
#endif
#ifdef TARGET_NR_getresgid
    case TARGET_NR_getresgid:
        {
7552
            gid_t rgid, egid, sgid;
7553 7554
            ret = get_errno(getresgid(&rgid, &egid, &sgid));
            if (!is_error(ret)) {
7555 7556 7557 7558
                if (put_user_u16(high2lowgid(rgid), arg1)
                    || put_user_u16(high2lowgid(egid), arg2)
                    || put_user_u16(high2lowgid(sgid), arg3))
                    goto efault;
7559 7560 7561 7562 7563
            }
        }
        break;
#endif
    case TARGET_NR_chown:
7564 7565
        if (!(p = lock_user_string(arg1)))
            goto efault;
7566 7567
        ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
        unlock_user(p, arg1, 0);
7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581
        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;

B
bellard 已提交
7582
#ifdef TARGET_NR_lchown32
7583
    case TARGET_NR_lchown32:
7584 7585
        if (!(p = lock_user_string(arg1)))
            goto efault;
7586 7587
        ret = get_errno(lchown(p, arg2, arg3));
        unlock_user(p, arg1, 0);
B
bellard 已提交
7588
        break;
B
bellard 已提交
7589 7590
#endif
#ifdef TARGET_NR_getuid32
7591
    case TARGET_NR_getuid32:
B
bellard 已提交
7592 7593
        ret = get_errno(getuid());
        break;
B
bellard 已提交
7594
#endif
7595 7596 7597 7598

#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
   /* Alpha specific */
    case TARGET_NR_getxuid:
7599 7600 7601 7602 7603
         {
            uid_t euid;
            euid=geteuid();
            ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
         }
7604 7605 7606 7607 7608 7609
        ret = get_errno(getuid());
        break;
#endif
#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
   /* Alpha specific */
    case TARGET_NR_getxgid:
7610 7611 7612 7613 7614
         {
            uid_t egid;
            egid=getegid();
            ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
         }
7615 7616 7617
        ret = get_errno(getgid());
        break;
#endif
7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709
#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
    /* Alpha specific */
    case TARGET_NR_osf_getsysinfo:
        ret = -TARGET_EOPNOTSUPP;
        switch (arg1) {
          case TARGET_GSI_IEEE_FP_CONTROL:
            {
                uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);

                /* Copied from linux ieee_fpcr_to_swcr.  */
                swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
                swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
                swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
                                        | SWCR_TRAP_ENABLE_DZE
                                        | SWCR_TRAP_ENABLE_OVF);
                swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
                                        | SWCR_TRAP_ENABLE_INE);
                swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
                swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;

                if (put_user_u64 (swcr, arg2))
                        goto efault;
                ret = 0;
            }
            break;

          /* case GSI_IEEE_STATE_AT_SIGNAL:
             -- Not implemented in linux kernel.
             case GSI_UACPROC:
             -- Retrieves current unaligned access state; not much used.
             case GSI_PROC_TYPE:
             -- Retrieves implver information; surely not used.
             case GSI_GET_HWRPB:
             -- Grabs a copy of the HWRPB; surely not used.
          */
        }
        break;
#endif
#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
    /* Alpha specific */
    case TARGET_NR_osf_setsysinfo:
        ret = -TARGET_EOPNOTSUPP;
        switch (arg1) {
          case TARGET_SSI_IEEE_FP_CONTROL:
          case TARGET_SSI_IEEE_RAISE_EXCEPTION:
            {
                uint64_t swcr, fpcr, orig_fpcr;

                if (get_user_u64 (swcr, arg2))
                    goto efault;
                orig_fpcr = cpu_alpha_load_fpcr (cpu_env);
                fpcr = orig_fpcr & FPCR_DYN_MASK;

                /* Copied from linux ieee_swcr_to_fpcr.  */
                fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
                fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
                fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
                                  | SWCR_TRAP_ENABLE_DZE
                                  | SWCR_TRAP_ENABLE_OVF)) << 48;
                fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
                                  | SWCR_TRAP_ENABLE_INE)) << 57;
                fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
                fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;

                cpu_alpha_store_fpcr (cpu_env, fpcr);
                ret = 0;

                if (arg1 == TARGET_SSI_IEEE_RAISE_EXCEPTION) {
                    /* Old exceptions are not signaled.  */
                    fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);

                    /* If any exceptions set by this call, and are unmasked,
                       send a signal.  */
                    /* ??? FIXME */
                }
            }
            break;

          /* case SSI_NVPAIRS:
             -- Used with SSIN_UACPROC to enable unaligned accesses.
             case SSI_IEEE_STATE_AT_SIGNAL:
             case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
             -- Not implemented in linux kernel
          */
        }
        break;
#endif
#ifdef TARGET_NR_osf_sigprocmask
    /* Alpha specific.  */
    case TARGET_NR_osf_sigprocmask:
        {
            abi_ulong mask;
7710
            int how;
7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728
            sigset_t set, oldset;

            switch(arg1) {
            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:
                ret = -TARGET_EINVAL;
                goto fail;
            }
            mask = arg2;
            target_to_host_old_sigset(&set, &mask);
7729
            sigprocmask(how, &set, &oldset);
7730 7731 7732 7733 7734
            host_to_target_old_sigset(&mask, &oldset);
            ret = mask;
        }
        break;
#endif
7735

B
bellard 已提交
7736
#ifdef TARGET_NR_getgid32
7737
    case TARGET_NR_getgid32:
B
bellard 已提交
7738 7739
        ret = get_errno(getgid());
        break;
B
bellard 已提交
7740 7741
#endif
#ifdef TARGET_NR_geteuid32
7742
    case TARGET_NR_geteuid32:
B
bellard 已提交
7743 7744
        ret = get_errno(geteuid());
        break;
B
bellard 已提交
7745 7746
#endif
#ifdef TARGET_NR_getegid32
7747
    case TARGET_NR_getegid32:
B
bellard 已提交
7748 7749
        ret = get_errno(getegid());
        break;
B
bellard 已提交
7750 7751
#endif
#ifdef TARGET_NR_setreuid32
7752
    case TARGET_NR_setreuid32:
B
bellard 已提交
7753 7754
        ret = get_errno(setreuid(arg1, arg2));
        break;
B
bellard 已提交
7755 7756
#endif
#ifdef TARGET_NR_setregid32
7757
    case TARGET_NR_setregid32:
B
bellard 已提交
7758 7759
        ret = get_errno(setregid(arg1, arg2));
        break;
B
bellard 已提交
7760 7761
#endif
#ifdef TARGET_NR_getgroups32
7762
    case TARGET_NR_getgroups32:
B
bellard 已提交
7763 7764
        {
            int gidsetsize = arg1;
7765
            uint32_t *target_grouplist;
B
bellard 已提交
7766 7767 7768 7769 7770
            gid_t *grouplist;
            int i;

            grouplist = alloca(gidsetsize * sizeof(gid_t));
            ret = get_errno(getgroups(gidsetsize, grouplist));
7771 7772
            if (gidsetsize == 0)
                break;
B
bellard 已提交
7773
            if (!is_error(ret)) {
7774 7775 7776 7777 7778
                target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
                if (!target_grouplist) {
                    ret = -TARGET_EFAULT;
                    goto fail;
                }
7779
                for(i = 0;i < ret; i++)
7780 7781
                    target_grouplist[i] = tswap32(grouplist[i]);
                unlock_user(target_grouplist, arg2, gidsetsize * 4);
B
bellard 已提交
7782 7783 7784
            }
        }
        break;
B
bellard 已提交
7785 7786
#endif
#ifdef TARGET_NR_setgroups32
7787
    case TARGET_NR_setgroups32:
B
bellard 已提交
7788 7789
        {
            int gidsetsize = arg1;
7790
            uint32_t *target_grouplist;
B
bellard 已提交
7791 7792
            gid_t *grouplist;
            int i;
7793

B
bellard 已提交
7794
            grouplist = alloca(gidsetsize * sizeof(gid_t));
7795 7796 7797 7798 7799
            target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
            if (!target_grouplist) {
                ret = -TARGET_EFAULT;
                goto fail;
            }
B
bellard 已提交
7800
            for(i = 0;i < gidsetsize; i++)
7801 7802
                grouplist[i] = tswap32(target_grouplist[i]);
            unlock_user(target_grouplist, arg2, 0);
B
bellard 已提交
7803 7804 7805
            ret = get_errno(setgroups(gidsetsize, grouplist));
        }
        break;
B
bellard 已提交
7806 7807
#endif
#ifdef TARGET_NR_fchown32
7808
    case TARGET_NR_fchown32:
B
bellard 已提交
7809 7810
        ret = get_errno(fchown(arg1, arg2, arg3));
        break;
B
bellard 已提交
7811 7812
#endif
#ifdef TARGET_NR_setresuid32
7813
    case TARGET_NR_setresuid32:
B
bellard 已提交
7814 7815
        ret = get_errno(setresuid(arg1, arg2, arg3));
        break;
B
bellard 已提交
7816 7817
#endif
#ifdef TARGET_NR_getresuid32
7818
    case TARGET_NR_getresuid32:
B
bellard 已提交
7819
        {
7820
            uid_t ruid, euid, suid;
B
bellard 已提交
7821 7822
            ret = get_errno(getresuid(&ruid, &euid, &suid));
            if (!is_error(ret)) {
7823 7824 7825 7826
                if (put_user_u32(ruid, arg1)
                    || put_user_u32(euid, arg2)
                    || put_user_u32(suid, arg3))
                    goto efault;
B
bellard 已提交
7827 7828 7829
            }
        }
        break;
B
bellard 已提交
7830 7831
#endif
#ifdef TARGET_NR_setresgid32
7832
    case TARGET_NR_setresgid32:
B
bellard 已提交
7833 7834
        ret = get_errno(setresgid(arg1, arg2, arg3));
        break;
B
bellard 已提交
7835 7836
#endif
#ifdef TARGET_NR_getresgid32
7837
    case TARGET_NR_getresgid32:
B
bellard 已提交
7838
        {
7839
            gid_t rgid, egid, sgid;
B
bellard 已提交
7840 7841
            ret = get_errno(getresgid(&rgid, &egid, &sgid));
            if (!is_error(ret)) {
7842 7843 7844 7845
                if (put_user_u32(rgid, arg1)
                    || put_user_u32(egid, arg2)
                    || put_user_u32(sgid, arg3))
                    goto efault;
B
bellard 已提交
7846 7847 7848
            }
        }
        break;
B
bellard 已提交
7849 7850
#endif
#ifdef TARGET_NR_chown32
7851
    case TARGET_NR_chown32:
7852 7853
        if (!(p = lock_user_string(arg1)))
            goto efault;
7854 7855
        ret = get_errno(chown(p, arg2, arg3));
        unlock_user(p, arg1, 0);
B
bellard 已提交
7856
        break;
B
bellard 已提交
7857 7858
#endif
#ifdef TARGET_NR_setuid32
7859
    case TARGET_NR_setuid32:
B
bellard 已提交
7860 7861
        ret = get_errno(setuid(arg1));
        break;
B
bellard 已提交
7862 7863
#endif
#ifdef TARGET_NR_setgid32
7864
    case TARGET_NR_setgid32:
B
bellard 已提交
7865 7866
        ret = get_errno(setgid(arg1));
        break;
B
bellard 已提交
7867 7868
#endif
#ifdef TARGET_NR_setfsuid32
7869
    case TARGET_NR_setfsuid32:
B
bellard 已提交
7870 7871
        ret = get_errno(setfsuid(arg1));
        break;
B
bellard 已提交
7872 7873
#endif
#ifdef TARGET_NR_setfsgid32
7874
    case TARGET_NR_setfsgid32:
B
bellard 已提交
7875 7876
        ret = get_errno(setfsgid(arg1));
        break;
B
bellard 已提交
7877
#endif
7878

7879
    case TARGET_NR_pivot_root:
B
bellard 已提交
7880
        goto unimplemented;
B
bellard 已提交
7881
#ifdef TARGET_NR_mincore
7882
    case TARGET_NR_mincore:
A
aurel32 已提交
7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895
        {
            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 已提交
7896
#endif
A
aurel32 已提交
7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909
#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
7910
#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
A
aurel32 已提交
7911 7912 7913
#ifdef TARGET_NR_fadvise64_64
    case TARGET_NR_fadvise64_64:
#endif
7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926
#ifdef TARGET_NR_fadvise64
    case TARGET_NR_fadvise64:
#endif
#ifdef TARGET_S390X
        switch (arg4) {
        case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
        case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
        case 6: arg4 = POSIX_FADV_DONTNEED; break;
        case 7: arg4 = POSIX_FADV_NOREUSE; break;
        default: break;
        }
#endif
        ret = -posix_fadvise(arg1, arg2, arg3, arg4);
A
aurel32 已提交
7927 7928
	break;
#endif
B
bellard 已提交
7929
#ifdef TARGET_NR_madvise
7930
    case TARGET_NR_madvise:
7931 7932 7933 7934 7935 7936
        /* 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 已提交
7937
#endif
7938
#if TARGET_ABI_BITS == 32
7939
    case TARGET_NR_fcntl64:
B
bellard 已提交
7940
    {
T
ths 已提交
7941
	int cmd;
B
bellard 已提交
7942
	struct flock64 fl;
7943
	struct target_flock64 *target_fl;
P
pbrook 已提交
7944
#ifdef TARGET_ARM
7945
	struct target_eabi_flock64 *target_efl;
P
pbrook 已提交
7946
#endif
B
bellard 已提交
7947

7948
	cmd = target_to_host_fcntl_cmd(arg2);
7949 7950 7951 7952
        if (cmd == -TARGET_EINVAL) {
            ret = cmd;
            break;
        }
T
ths 已提交
7953

B
bellard 已提交
7954
        switch(arg2) {
T
ths 已提交
7955
        case TARGET_F_GETLK64:
T
ths 已提交
7956 7957
#ifdef TARGET_ARM
            if (((CPUARMState *)cpu_env)->eabi) {
B
bellard 已提交
7958 7959
                if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) 
                    goto efault;
T
ths 已提交
7960 7961 7962 7963
                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);
U
Ulrich Hecht 已提交
7964
                fl.l_pid = tswap32(target_efl->l_pid);
T
ths 已提交
7965 7966 7967 7968
                unlock_user_struct(target_efl, arg3, 0);
            } else
#endif
            {
B
bellard 已提交
7969 7970
                if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) 
                    goto efault;
T
ths 已提交
7971 7972 7973 7974
                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);
U
Ulrich Hecht 已提交
7975
                fl.l_pid = tswap32(target_fl->l_pid);
T
ths 已提交
7976 7977
                unlock_user_struct(target_fl, arg3, 0);
            }
T
ths 已提交
7978
            ret = get_errno(fcntl(arg1, cmd, &fl));
B
bellard 已提交
7979
	    if (ret == 0) {
P
pbrook 已提交
7980 7981
#ifdef TARGET_ARM
                if (((CPUARMState *)cpu_env)->eabi) {
B
bellard 已提交
7982 7983
                    if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) 
                        goto efault;
P
pbrook 已提交
7984 7985 7986 7987
                    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);
U
Ulrich Hecht 已提交
7988
                    target_efl->l_pid = tswap32(fl.l_pid);
7989
                    unlock_user_struct(target_efl, arg3, 1);
P
pbrook 已提交
7990 7991 7992
                } else
#endif
                {
B
bellard 已提交
7993 7994
                    if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) 
                        goto efault;
P
pbrook 已提交
7995 7996 7997 7998
                    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);
U
Ulrich Hecht 已提交
7999
                    target_fl->l_pid = tswap32(fl.l_pid);
8000
                    unlock_user_struct(target_fl, arg3, 1);
P
pbrook 已提交
8001
                }
B
bellard 已提交
8002 8003 8004
	    }
	    break;

T
ths 已提交
8005 8006
        case TARGET_F_SETLK64:
        case TARGET_F_SETLKW64:
P
pbrook 已提交
8007 8008
#ifdef TARGET_ARM
            if (((CPUARMState *)cpu_env)->eabi) {
B
bellard 已提交
8009 8010
                if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) 
                    goto efault;
P
pbrook 已提交
8011 8012 8013 8014
                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);
U
Ulrich Hecht 已提交
8015
                fl.l_pid = tswap32(target_efl->l_pid);
8016
                unlock_user_struct(target_efl, arg3, 0);
P
pbrook 已提交
8017 8018 8019
            } else
#endif
            {
B
bellard 已提交
8020 8021
                if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) 
                    goto efault;
P
pbrook 已提交
8022 8023 8024 8025
                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);
U
Ulrich Hecht 已提交
8026
                fl.l_pid = tswap32(target_fl->l_pid);
8027
                unlock_user_struct(target_fl, arg3, 0);
P
pbrook 已提交
8028
            }
T
ths 已提交
8029
            ret = get_errno(fcntl(arg1, cmd, &fl));
B
bellard 已提交
8030
	    break;
B
bellard 已提交
8031
        default:
8032
            ret = do_fcntl(arg1, arg2, arg3);
B
bellard 已提交
8033 8034
            break;
        }
B
bellard 已提交
8035 8036
	break;
    }
B
bellard 已提交
8037
#endif
8038 8039 8040 8041 8042 8043
#ifdef TARGET_NR_cacheflush
    case TARGET_NR_cacheflush:
        /* self-modifying code is handled automatically, so nothing needed */
        ret = 0;
        break;
#endif
8044
#ifdef TARGET_NR_security
8045 8046
    case TARGET_NR_security:
        goto unimplemented;
B
bellard 已提交
8047 8048 8049 8050 8051
#endif
#ifdef TARGET_NR_getpagesize
    case TARGET_NR_getpagesize:
        ret = TARGET_PAGE_SIZE;
        break;
8052
#endif
8053 8054 8055
    case TARGET_NR_gettid:
        ret = get_errno(gettid());
        break;
8056
#ifdef TARGET_NR_readahead
8057
    case TARGET_NR_readahead:
A
aurel32 已提交
8058
#if TARGET_ABI_BITS == 32
8059
        if (regpairs_aligned(cpu_env)) {
A
aurel32 已提交
8060 8061 8062 8063 8064 8065 8066 8067 8068
            arg2 = arg3;
            arg3 = arg4;
            arg4 = arg5;
        }
        ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
#else
        ret = get_errno(readahead(arg1, arg2, arg3));
#endif
        break;
8069
#endif
8070
#ifdef CONFIG_ATTR
8071
#ifdef TARGET_NR_setxattr
8072 8073
    case TARGET_NR_listxattr:
    case TARGET_NR_llistxattr:
8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096
    {
        void *p, *b = 0;
        if (arg2) {
            b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
            if (!b) {
                ret = -TARGET_EFAULT;
                break;
            }
        }
        p = lock_user_string(arg1);
        if (p) {
            if (num == TARGET_NR_listxattr) {
                ret = get_errno(listxattr(p, b, arg3));
            } else {
                ret = get_errno(llistxattr(p, b, arg3));
            }
        } else {
            ret = -TARGET_EFAULT;
        }
        unlock_user(p, arg1, 0);
        unlock_user(b, arg2, arg3);
        break;
    }
8097
    case TARGET_NR_flistxattr:
8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108
    {
        void *b = 0;
        if (arg2) {
            b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
            if (!b) {
                ret = -TARGET_EFAULT;
                break;
            }
        }
        ret = get_errno(flistxattr(arg1, b, arg3));
        unlock_user(b, arg2, arg3);
8109
        break;
8110
    }
8111
    case TARGET_NR_setxattr:
8112
    case TARGET_NR_lsetxattr:
8113
        {
8114 8115 8116 8117 8118 8119 8120 8121
            void *p, *n, *v = 0;
            if (arg3) {
                v = lock_user(VERIFY_READ, arg3, arg4, 1);
                if (!v) {
                    ret = -TARGET_EFAULT;
                    break;
                }
            }
8122 8123
            p = lock_user_string(arg1);
            n = lock_user_string(arg2);
8124
            if (p && n) {
8125 8126 8127 8128 8129
                if (num == TARGET_NR_setxattr) {
                    ret = get_errno(setxattr(p, n, v, arg4, arg5));
                } else {
                    ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
                }
8130 8131 8132 8133 8134 8135 8136 8137
            } else {
                ret = -TARGET_EFAULT;
            }
            unlock_user(p, arg1, 0);
            unlock_user(n, arg2, 0);
            unlock_user(v, arg3, 0);
        }
        break;
8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157
    case TARGET_NR_fsetxattr:
        {
            void *n, *v = 0;
            if (arg3) {
                v = lock_user(VERIFY_READ, arg3, arg4, 1);
                if (!v) {
                    ret = -TARGET_EFAULT;
                    break;
                }
            }
            n = lock_user_string(arg2);
            if (n) {
                ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
            } else {
                ret = -TARGET_EFAULT;
            }
            unlock_user(n, arg2, 0);
            unlock_user(v, arg3, 0);
        }
        break;
8158
    case TARGET_NR_getxattr:
8159
    case TARGET_NR_lgetxattr:
8160
        {
8161 8162 8163 8164 8165 8166 8167 8168
            void *p, *n, *v = 0;
            if (arg3) {
                v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
                if (!v) {
                    ret = -TARGET_EFAULT;
                    break;
                }
            }
8169 8170
            p = lock_user_string(arg1);
            n = lock_user_string(arg2);
8171
            if (p && n) {
8172 8173 8174 8175 8176
                if (num == TARGET_NR_getxattr) {
                    ret = get_errno(getxattr(p, n, v, arg4));
                } else {
                    ret = get_errno(lgetxattr(p, n, v, arg4));
                }
8177 8178 8179 8180 8181 8182 8183 8184
            } else {
                ret = -TARGET_EFAULT;
            }
            unlock_user(p, arg1, 0);
            unlock_user(n, arg2, 0);
            unlock_user(v, arg3, arg4);
        }
        break;
8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203 8204
    case TARGET_NR_fgetxattr:
        {
            void *n, *v = 0;
            if (arg3) {
                v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
                if (!v) {
                    ret = -TARGET_EFAULT;
                    break;
                }
            }
            n = lock_user_string(arg2);
            if (n) {
                ret = get_errno(fgetxattr(arg1, n, v, arg4));
            } else {
                ret = -TARGET_EFAULT;
            }
            unlock_user(n, arg2, 0);
            unlock_user(v, arg3, arg4);
        }
        break;
8205
    case TARGET_NR_removexattr:
8206
    case TARGET_NR_lremovexattr:
8207 8208 8209 8210 8211
        {
            void *p, *n;
            p = lock_user_string(arg1);
            n = lock_user_string(arg2);
            if (p && n) {
8212 8213 8214 8215 8216
                if (num == TARGET_NR_removexattr) {
                    ret = get_errno(removexattr(p, n));
                } else {
                    ret = get_errno(lremovexattr(p, n));
                }
8217 8218 8219 8220 8221 8222 8223
            } else {
                ret = -TARGET_EFAULT;
            }
            unlock_user(p, arg1, 0);
            unlock_user(n, arg2, 0);
        }
        break;
8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235
    case TARGET_NR_fremovexattr:
        {
            void *n;
            n = lock_user_string(arg2);
            if (n) {
                ret = get_errno(fremovexattr(arg1, n));
            } else {
                ret = -TARGET_EFAULT;
            }
            unlock_user(n, arg2, 0);
        }
        break;
8236
#endif
8237
#endif /* CONFIG_ATTR */
8238
#ifdef TARGET_NR_set_thread_area
B
bellard 已提交
8239
    case TARGET_NR_set_thread_area:
B
bellard 已提交
8240
#if defined(TARGET_MIPS)
8241 8242 8243
      ((CPUMIPSState *) cpu_env)->tls_value = arg1;
      ret = 0;
      break;
8244 8245 8246 8247 8248 8249 8250 8251
#elif defined(TARGET_CRIS)
      if (arg1 & 0xff)
          ret = -TARGET_EINVAL;
      else {
          ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
          ret = 0;
      }
      break;
B
bellard 已提交
8252 8253 8254
#elif defined(TARGET_I386) && defined(TARGET_ABI32)
      ret = do_set_thread_area(cpu_env, arg1);
      break;
8255 8256 8257 8258 8259
#else
      goto unimplemented_nowarn;
#endif
#endif
#ifdef TARGET_NR_get_thread_area
B
bellard 已提交
8260
    case TARGET_NR_get_thread_area:
B
bellard 已提交
8261 8262 8263
#if defined(TARGET_I386) && defined(TARGET_ABI32)
        ret = do_get_thread_area(cpu_env, arg1);
#else
B
bellard 已提交
8264
        goto unimplemented_nowarn;
B
bellard 已提交
8265
#endif
B
bellard 已提交
8266
#endif
B
bellard 已提交
8267 8268 8269
#ifdef TARGET_NR_getdomainname
    case TARGET_NR_getdomainname:
        goto unimplemented_nowarn;
8270
#endif
8271

8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293
#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 已提交
8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304
#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
8305

8306 8307
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
    case TARGET_NR_set_tid_address:
8308 8309
        ret = get_errno(set_tid_address((int *)g2h(arg1)));
        break;
8310 8311
#endif

T
ths 已提交
8312
#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
T
ths 已提交
8313
    case TARGET_NR_tkill:
8314
        ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
T
ths 已提交
8315 8316 8317
        break;
#endif

T
ths 已提交
8318
#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
T
ths 已提交
8319
    case TARGET_NR_tgkill:
8320 8321
	ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
                        target_to_host_signal(arg3)));
T
ths 已提交
8322 8323 8324
	break;
#endif

8325 8326 8327 8328 8329
#ifdef TARGET_NR_set_robust_list
    case TARGET_NR_set_robust_list:
	goto unimplemented_nowarn;
#endif

8330 8331 8332
#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
    case TARGET_NR_utimensat:
        {
R
Riku Voipio 已提交
8333 8334 8335 8336 8337 8338 8339 8340
            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;
            }
8341
            if (!arg2)
R
Riku Voipio 已提交
8342
                ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
8343
            else {
8344
                if (!(p = lock_user_string(arg2))) {
8345
                    ret = -TARGET_EFAULT;
8346 8347
                    goto fail;
                }
R
Riku Voipio 已提交
8348
                ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
8349
                unlock_user(p, arg2, 0);
8350 8351 8352 8353
            }
        }
	break;
#endif
8354
#if defined(CONFIG_USE_NPTL)
8355 8356 8357 8358
    case TARGET_NR_futex:
        ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
        break;
#endif
8359
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
A
aurel32 已提交
8360 8361 8362 8363
    case TARGET_NR_inotify_init:
        ret = get_errno(sys_inotify_init());
        break;
#endif
8364
#ifdef CONFIG_INOTIFY1
8365 8366 8367 8368 8369
#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
    case TARGET_NR_inotify_init1:
        ret = get_errno(sys_inotify_init1(arg1));
        break;
#endif
8370
#endif
8371
#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
A
aurel32 已提交
8372 8373 8374 8375 8376 8377
    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
8378
#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
A
aurel32 已提交
8379 8380 8381 8382
    case TARGET_NR_inotify_rm_watch:
        ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
        break;
#endif
8383

8384
#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458
    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

8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 8498
#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 已提交
8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510
#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  */
8511 8512
#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
    case TARGET_NR_fallocate:
A
Alexander Graf 已提交
8513 8514 8515 8516
#if TARGET_ABI_BITS == 32
        ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
                                  target_offset64(arg5, arg6)));
#else
8517
        ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
A
Alexander Graf 已提交
8518
#endif
8519
        break;
8520 8521 8522 8523 8524
#endif
#if defined(CONFIG_SYNC_FILE_RANGE)
#if defined(TARGET_NR_sync_file_range)
    case TARGET_NR_sync_file_range:
#if TARGET_ABI_BITS == 32
8525 8526 8527 8528
#if defined(TARGET_MIPS)
        ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
                                        target_offset64(arg5, arg6), arg7));
#else
8529 8530
        ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
                                        target_offset64(arg4, arg5), arg6));
8531
#endif /* !TARGET_MIPS */
8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547
#else
        ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
#endif
        break;
#endif
#if defined(TARGET_NR_sync_file_range2)
    case TARGET_NR_sync_file_range2:
        /* This is like sync_file_range but the arguments are reordered */
#if TARGET_ABI_BITS == 32
        ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
                                        target_offset64(arg5, arg6), arg2));
#else
        ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
#endif
        break;
#endif
8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 8648 8649 8650 8651
#endif
#if defined(CONFIG_EPOLL)
#if defined(TARGET_NR_epoll_create)
    case TARGET_NR_epoll_create:
        ret = get_errno(epoll_create(arg1));
        break;
#endif
#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
    case TARGET_NR_epoll_create1:
        ret = get_errno(epoll_create1(arg1));
        break;
#endif
#if defined(TARGET_NR_epoll_ctl)
    case TARGET_NR_epoll_ctl:
    {
        struct epoll_event ep;
        struct epoll_event *epp = 0;
        if (arg4) {
            struct target_epoll_event *target_ep;
            if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
                goto efault;
            }
            ep.events = tswap32(target_ep->events);
            /* The epoll_data_t union is just opaque data to the kernel,
             * so we transfer all 64 bits across and need not worry what
             * actual data type it is.
             */
            ep.data.u64 = tswap64(target_ep->data.u64);
            unlock_user_struct(target_ep, arg4, 0);
            epp = &ep;
        }
        ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
        break;
    }
#endif

#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
#define IMPLEMENT_EPOLL_PWAIT
#endif
#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
#if defined(TARGET_NR_epoll_wait)
    case TARGET_NR_epoll_wait:
#endif
#if defined(IMPLEMENT_EPOLL_PWAIT)
    case TARGET_NR_epoll_pwait:
#endif
    {
        struct target_epoll_event *target_ep;
        struct epoll_event *ep;
        int epfd = arg1;
        int maxevents = arg3;
        int timeout = arg4;

        target_ep = lock_user(VERIFY_WRITE, arg2,
                              maxevents * sizeof(struct target_epoll_event), 1);
        if (!target_ep) {
            goto efault;
        }

        ep = alloca(maxevents * sizeof(struct epoll_event));

        switch (num) {
#if defined(IMPLEMENT_EPOLL_PWAIT)
        case TARGET_NR_epoll_pwait:
        {
            target_sigset_t *target_set;
            sigset_t _set, *set = &_set;

            if (arg5) {
                target_set = lock_user(VERIFY_READ, arg5,
                                       sizeof(target_sigset_t), 1);
                if (!target_set) {
                    unlock_user(target_ep, arg2, 0);
                    goto efault;
                }
                target_to_host_sigset(set, target_set);
                unlock_user(target_set, arg5, 0);
            } else {
                set = NULL;
            }

            ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
            break;
        }
#endif
#if defined(TARGET_NR_epoll_wait)
        case TARGET_NR_epoll_wait:
            ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
            break;
#endif
        default:
            ret = -TARGET_ENOSYS;
        }
        if (!is_error(ret)) {
            int i;
            for (i = 0; i < ret; i++) {
                target_ep[i].events = tswap32(ep[i].events);
                target_ep[i].data.u64 = tswap64(ep[i].data.u64);
            }
        }
        unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
        break;
    }
#endif
8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679
#endif
#ifdef TARGET_NR_prlimit64
    case TARGET_NR_prlimit64:
    {
        /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
        struct target_rlimit64 *target_rnew, *target_rold;
        struct host_rlimit64 rnew, rold, *rnewp = 0;
        if (arg3) {
            if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
                goto efault;
            }
            rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
            rnew.rlim_max = tswap64(target_rnew->rlim_max);
            unlock_user_struct(target_rnew, arg3, 0);
            rnewp = &rnew;
        }

        ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
        if (!is_error(ret) && arg4) {
            if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
                goto efault;
            }
            target_rold->rlim_cur = tswap64(rold.rlim_cur);
            target_rold->rlim_max = tswap64(rold.rlim_max);
            unlock_user_struct(target_rold, arg4, 1);
        }
        break;
    }
8680
#endif
8681 8682
    default:
    unimplemented:
B
bellard 已提交
8683
        gemu_log("qemu: Unsupported syscall: %d\n", num);
8684
#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list)
B
bellard 已提交
8685
    unimplemented_nowarn:
B
bellard 已提交
8686
#endif
8687
        ret = -TARGET_ENOSYS;
8688 8689
        break;
    }
8690
fail:
B
bellard 已提交
8691
#ifdef DEBUG
8692
    gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
B
bellard 已提交
8693
#endif
8694 8695
    if(do_strace)
        print_syscall_ret(num, ret);
8696
    return ret;
8697 8698 8699
efault:
    ret = -TARGET_EFAULT;
    goto fail;
8700
}