All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support.
@ 2013-10-16 14:36 Stacey Son
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 01/18] bsd-user: refresh freebsd system call numbers Stacey Son
                   ` (39 more replies)
  0 siblings, 40 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This patch series adds a significant number of system calls and mips/arm
support for bsd-user.  In its current state it can emulate most
FreeBSD mips/mips64 and arm target binaries on a x86 host in a simple
chroot environment. (see https://wiki.freebsd.org/QemuUserModeHowTo for
the details.)

Besides adding a lot of shims and other support code this change
restructures the code significantly to reduce the amount of C
preprocessor conditionals for the various target and host arch/OS's.
In general, the target cpu depedent code has been moved into into
the various arch directories and the host OS dependent code (ie.
FreeBSD, NetBSD, OpenBSD) has been moved into the OS directories as
much as possible.

I would like to recognize Olivier Houchard for a lot of the arm
dependent code and Juergen Lock, the maintainer of the FreeBSD
Qemu port, for their contributions.

Best Regards,

Stacey D. Son
---

Stacey Son (18):
  bsd-user: refresh freebsd system call numbers
  bsd-user: add HOST_ABI_DIR for the various *BSD dependent code.
  bsd-user: move OS/arch dependent code for strace into separate
    directories
  bsd-user: move target arch and host OS dependent code out of main.c
  bsd-user: move target arch and host OS dependent code out of
    syscall.c
  bsd-user: add support for freebsd time related system calls
  bsd-user: add support for freebsd signal related system calls
  bsd-user: move target arch and host OS dependent code out of
    elfload.c
  bsd-user: add support for freebsd process related system calls
  bsd-user: add support for file system related system calls
  bsd-user: add support for stat, directory, and file control related
    system calls
  bsd-user: add support for memory management related system calls
  bsd-user: add support for socket related system calls
  bsd-user: add support for thread related system calls
  bsd-user: add support for the ioctl system call
  bsd-user: add support for extended attribute and ACL related syscalls
  bsd-user: add support for miscellaneous system calls
  bsd-user: add arm, mips and mips64 options to configure target-list

 Makefile.target                         |    5 +-
 bsd-user/Makefile.objs                  |    6 +-
 bsd-user/arm/syscall.h                  |   36 +
 bsd-user/arm/target_arch.h              |   10 +
 bsd-user/arm/target_arch_cpu.c          |   27 +
 bsd-user/arm/target_arch_cpu.h          |  435 +++++++
 bsd-user/arm/target_arch_elf.h          |   54 +
 bsd-user/arm/target_arch_signal.h       |  257 +++++
 bsd-user/arm/target_arch_sigtramp.h     |   33 +
 bsd-user/arm/target_arch_sysarch.h      |   81 ++
 bsd-user/arm/target_arch_thread.h       |   62 +
 bsd-user/arm/target_arch_vmparam.h      |   49 +
 bsd-user/bsd-file.h                     | 1111 ++++++++++++++++++
 bsd-user/bsd-ioctl.c                    |  448 ++++++++
 bsd-user/bsd-ioctl.h                    |   27 +
 bsd-user/bsd-mem.c                      |  122 ++
 bsd-user/bsd-mem.h                      |  393 +++++++
 bsd-user/bsd-misc.c                     |  209 ++++
 bsd-user/bsd-misc.h                     |  339 ++++++
 bsd-user/bsd-proc.c                     |  160 +++
 bsd-user/bsd-proc.h                     |  434 +++++++
 bsd-user/bsd-signal.h                   |  232 ++++
 bsd-user/bsd-socket.c                   |  108 ++
 bsd-user/bsd-socket.h                   |  266 +++++
 bsd-user/bsdload.c                      |  147 ++-
 bsd-user/elfload.c                      |  947 +++-------------
 bsd-user/errno_defs.h                   |   13 +-
 bsd-user/freebsd/host_os.h              |   46 +
 bsd-user/freebsd/os-extattr.c           |  119 ++
 bsd-user/freebsd/os-extattr.h           |  644 +++++++++++
 bsd-user/freebsd/os-ioctl-cmds.h        |   47 +
 bsd-user/freebsd/os-ioctl-filio.h       |   45 +
 bsd-user/freebsd/os-ioctl-ioccom.h      |   54 +
 bsd-user/freebsd/os-ioctl-ttycom.h      |  257 +++++
 bsd-user/freebsd/os-ioctl-types.h       |    7 +
 bsd-user/freebsd/os-misc.h              |  442 ++++++++
 bsd-user/freebsd/os-proc.c              |  234 ++++
 bsd-user/freebsd/os-proc.h              |  428 +++++++
 bsd-user/freebsd/os-signal.h            |   43 +
 bsd-user/freebsd/os-socket.c            |  149 +++
 bsd-user/freebsd/os-socket.h            |  548 +++++++++
 bsd-user/freebsd/os-stat.c              |  234 ++++
 bsd-user/freebsd/os-stat.h              |  437 +++++++
 bsd-user/freebsd/os-strace.h            |   29 +
 bsd-user/freebsd/os-sys.c               |  268 +++++
 bsd-user/freebsd/os-thread.c            |  936 +++++++++++++++
 bsd-user/freebsd/os-thread.h            |  510 +++++++++
 bsd-user/freebsd/os-time.c              |  205 ++++
 bsd-user/freebsd/os-time.h              |  643 +++++++++++
 bsd-user/freebsd/qemu-os.h              |   79 ++
 bsd-user/freebsd/strace.list            |   76 ++-
 bsd-user/freebsd/syscall_nr.h           |  813 ++++++++------
 bsd-user/freebsd/target_os_elf.h        |  145 +++
 bsd-user/freebsd/target_os_siginfo.h    |  100 ++
 bsd-user/freebsd/target_os_signal.h     |   79 ++
 bsd-user/freebsd/target_os_stack.h      |  157 +++
 bsd-user/freebsd/target_os_thread.h     |    6 +
 bsd-user/freebsd/target_os_vmparam.h    |   23 +
 bsd-user/i386/syscall.h                 |   23 +
 bsd-user/i386/target_arch.h             |   13 +
 bsd-user/i386/target_arch_cpu.c         |   79 ++
 bsd-user/i386/target_arch_cpu.h         |  302 +++++
 bsd-user/i386/target_arch_elf.h         |   62 +
 bsd-user/i386/target_arch_signal.h      |   94 ++
 bsd-user/i386/target_arch_sigtramp.h    |   11 +
 bsd-user/i386/target_arch_sysarch.h     |   78 ++
 bsd-user/i386/target_arch_thread.h      |   45 +
 bsd-user/i386/target_arch_vmparam.h     |   26 +
 bsd-user/i386/target_signal.h           |    6 -
 bsd-user/main.c                         |  881 +++------------
 bsd-user/mips/syscall.h                 |   52 +
 bsd-user/mips/target_arch.h             |   10 +
 bsd-user/mips/target_arch_cpu.c         |   27 +
 bsd-user/mips/target_arch_cpu.h         |  243 ++++
 bsd-user/mips/target_arch_elf.h         |   36 +
 bsd-user/mips/target_arch_signal.h      |  237 ++++
 bsd-user/mips/target_arch_sigtramp.h    |   23 +
 bsd-user/mips/target_arch_sysarch.h     |   69 ++
 bsd-user/mips/target_arch_thread.h      |   54 +
 bsd-user/mips/target_arch_vmparam.h     |   47 +
 bsd-user/mips64/syscall.h               |   53 +
 bsd-user/mips64/target_arch.h           |   10 +
 bsd-user/mips64/target_arch_cpu.c       |   27 +
 bsd-user/mips64/target_arch_cpu.h       |  243 ++++
 bsd-user/mips64/target_arch_elf.h       |   36 +
 bsd-user/mips64/target_arch_signal.h    |  236 ++++
 bsd-user/mips64/target_arch_sigtramp.h  |   23 +
 bsd-user/mips64/target_arch_sysarch.h   |   69 ++
 bsd-user/mips64/target_arch_thread.h    |   54 +
 bsd-user/mips64/target_arch_vmparam.h   |   47 +
 bsd-user/mmap.c                         |  140 +--
 bsd-user/netbsd/host_os.h               |   31 +
 bsd-user/netbsd/os-extattr.h            |  247 ++++
 bsd-user/netbsd/os-ioctl-cmds.h         |   48 +
 bsd-user/netbsd/os-ioctl-filio.h        |   29 +
 bsd-user/netbsd/os-ioctl-ioccom.h       |   38 +
 bsd-user/netbsd/os-ioctl-ttycom.h       |  240 ++++
 bsd-user/netbsd/os-ioctl-types.h        |    7 +
 bsd-user/netbsd/os-misc.h               |  375 ++++++
 bsd-user/netbsd/os-proc.c               |   11 +
 bsd-user/netbsd/os-proc.h               |  243 ++++
 bsd-user/netbsd/os-socket.c             |    1 +
 bsd-user/netbsd/os-socket.h             |   98 ++
 bsd-user/netbsd/os-stat.c               |    1 +
 bsd-user/netbsd/os-stat.h               |    1 +
 bsd-user/netbsd/os-strace.h             |    1 +
 bsd-user/netbsd/os-sys.c                |   46 +
 bsd-user/netbsd/os-thread.c             |    1 +
 bsd-user/netbsd/os-thread.h             |  133 +++
 bsd-user/netbsd/os-time.c               |    1 +
 bsd-user/netbsd/os-time.h               |  179 +++
 bsd-user/netbsd/qemu-os.h               |    1 +
 bsd-user/netbsd/target_os_elf.h         |  226 ++++
 bsd-user/netbsd/target_os_siginfo.h     |   82 ++
 bsd-user/netbsd/target_os_signal.h      |   70 ++
 bsd-user/netbsd/target_os_stack.h       |   33 +
 bsd-user/netbsd/target_os_thread.h      |    6 +
 bsd-user/openbsd/host_os.h              |   31 +
 bsd-user/openbsd/os-extattr.h           |  247 ++++
 bsd-user/openbsd/os-ioctl-cmds.h        |   48 +
 bsd-user/openbsd/os-ioctl-filio.h       |   29 +
 bsd-user/openbsd/os-ioctl-ioccom.h      |   38 +
 bsd-user/openbsd/os-ioctl-ttycom.h      |  240 ++++
 bsd-user/openbsd/os-ioctl-types.h       |    7 +
 bsd-user/openbsd/os-misc.h              |  375 ++++++
 bsd-user/openbsd/os-proc.c              |   11 +
 bsd-user/openbsd/os-proc.h              |  243 ++++
 bsd-user/openbsd/os-socket.c            |    1 +
 bsd-user/openbsd/os-socket.h            |   98 ++
 bsd-user/openbsd/os-stat.c              |    1 +
 bsd-user/openbsd/os-stat.h              |  176 +++
 bsd-user/openbsd/os-strace.h            |    1 +
 bsd-user/openbsd/os-sys.c               |   46 +
 bsd-user/openbsd/os-thread.c            |    1 +
 bsd-user/openbsd/os-thread.h            |  133 +++
 bsd-user/openbsd/os-time.c              |    1 +
 bsd-user/openbsd/os-time.h              |  179 +++
 bsd-user/openbsd/qemu-os.h              |    1 +
 bsd-user/openbsd/target_os_elf.h        |  226 ++++
 bsd-user/openbsd/target_os_siginfo.h    |   82 ++
 bsd-user/openbsd/target_os_signal.h     |   70 ++
 bsd-user/openbsd/target_os_stack.h      |   33 +
 bsd-user/openbsd/target_os_thread.h     |    6 +
 bsd-user/qemu-bsd.h                     |   79 ++
 bsd-user/qemu.h                         |  202 +++-
 bsd-user/signal.c                       |  907 +++++++++++++++-
 bsd-user/sparc/syscall.h                |   29 +-
 bsd-user/sparc/target_arch.h            |   11 +
 bsd-user/sparc/target_arch_cpu.c        |  113 ++
 bsd-user/sparc/target_arch_cpu.h        |  158 +++
 bsd-user/sparc/target_arch_elf.h        |   30 +
 bsd-user/sparc/target_arch_signal.h     |   77 ++
 bsd-user/sparc/target_arch_sigtramp.h   |   11 +
 bsd-user/sparc/target_arch_sysarch.h    |   52 +
 bsd-user/sparc/target_arch_thread.h     |   39 +
 bsd-user/sparc/target_arch_vmparam.h    |   35 +
 bsd-user/sparc/target_signal.h          |    5 -
 bsd-user/sparc64/syscall.h              |   28 +-
 bsd-user/sparc64/target_arch.h          |   11 +
 bsd-user/sparc64/target_arch_cpu.c      |  118 ++
 bsd-user/sparc64/target_arch_cpu.h      |  191 ++++
 bsd-user/sparc64/target_arch_elf.h      |   34 +
 bsd-user/sparc64/target_arch_signal.h   |   94 ++
 bsd-user/sparc64/target_arch_sigtramp.h |   11 +
 bsd-user/sparc64/target_arch_sysarch.h  |   52 +
 bsd-user/sparc64/target_arch_thread.h   |   55 +
 bsd-user/sparc64/target_arch_vmparam.h  |   37 +
 bsd-user/sparc64/target_signal.h        |    5 -
 bsd-user/strace.c                       |  175 ++-
 bsd-user/syscall.c                      | 1884 ++++++++++++++++++++++++-------
 bsd-user/syscall_defs.h                 |  860 +++++++++++++--
 bsd-user/x86_64/syscall.h               |   26 +-
 bsd-user/x86_64/target_arch.h           |   13 +
 bsd-user/x86_64/target_arch_cpu.c       |   79 ++
 bsd-user/x86_64/target_arch_cpu.h       |  324 ++++++
 bsd-user/x86_64/target_arch_elf.h       |   55 +
 bsd-user/x86_64/target_arch_signal.h    |   94 ++
 bsd-user/x86_64/target_arch_sigtramp.h  |   11 +
 bsd-user/x86_64/target_arch_sysarch.h   |   76 ++
 bsd-user/x86_64/target_arch_thread.h    |   40 +
 bsd-user/x86_64/target_arch_vmparam.h   |   28 +
 bsd-user/x86_64/target_signal.h         |    5 -
 configure                               |   11 +
 default-configs/arm-bsd-user.mak        |    3 +
 default-configs/mips-bsd-user.mak       |    1 +
 default-configs/mips64-bsd-user.mak     |    1 +
 default-configs/mips64el-bsd-user.mak   |    1 +
 default-configs/mipsel-bsd-user.mak     |    1 +
 188 files changed, 25101 insertions(+), 2614 deletions(-)
 create mode 100644 bsd-user/arm/syscall.h
 create mode 100644 bsd-user/arm/target_arch.h
 create mode 100644 bsd-user/arm/target_arch_cpu.c
 create mode 100644 bsd-user/arm/target_arch_cpu.h
 create mode 100644 bsd-user/arm/target_arch_elf.h
 create mode 100644 bsd-user/arm/target_arch_signal.h
 create mode 100644 bsd-user/arm/target_arch_sigtramp.h
 create mode 100644 bsd-user/arm/target_arch_sysarch.h
 create mode 100644 bsd-user/arm/target_arch_thread.h
 create mode 100644 bsd-user/arm/target_arch_vmparam.h
 create mode 100644 bsd-user/bsd-file.h
 create mode 100644 bsd-user/bsd-ioctl.c
 create mode 100644 bsd-user/bsd-ioctl.h
 create mode 100644 bsd-user/bsd-mem.c
 create mode 100644 bsd-user/bsd-mem.h
 create mode 100644 bsd-user/bsd-misc.c
 create mode 100644 bsd-user/bsd-misc.h
 create mode 100644 bsd-user/bsd-proc.c
 create mode 100644 bsd-user/bsd-proc.h
 create mode 100644 bsd-user/bsd-signal.h
 create mode 100644 bsd-user/bsd-socket.c
 create mode 100644 bsd-user/bsd-socket.h
 create mode 100644 bsd-user/freebsd/host_os.h
 create mode 100644 bsd-user/freebsd/os-extattr.c
 create mode 100644 bsd-user/freebsd/os-extattr.h
 create mode 100644 bsd-user/freebsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/freebsd/os-ioctl-filio.h
 create mode 100644 bsd-user/freebsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/freebsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/freebsd/os-ioctl-types.h
 create mode 100644 bsd-user/freebsd/os-misc.h
 create mode 100644 bsd-user/freebsd/os-proc.c
 create mode 100644 bsd-user/freebsd/os-proc.h
 create mode 100644 bsd-user/freebsd/os-signal.h
 create mode 100644 bsd-user/freebsd/os-socket.c
 create mode 100644 bsd-user/freebsd/os-socket.h
 create mode 100644 bsd-user/freebsd/os-stat.c
 create mode 100644 bsd-user/freebsd/os-stat.h
 create mode 100644 bsd-user/freebsd/os-strace.h
 create mode 100644 bsd-user/freebsd/os-sys.c
 create mode 100644 bsd-user/freebsd/os-thread.c
 create mode 100644 bsd-user/freebsd/os-thread.h
 create mode 100644 bsd-user/freebsd/os-time.c
 create mode 100644 bsd-user/freebsd/os-time.h
 create mode 100644 bsd-user/freebsd/qemu-os.h
 create mode 100644 bsd-user/freebsd/target_os_elf.h
 create mode 100644 bsd-user/freebsd/target_os_siginfo.h
 create mode 100644 bsd-user/freebsd/target_os_signal.h
 create mode 100644 bsd-user/freebsd/target_os_stack.h
 create mode 100644 bsd-user/freebsd/target_os_thread.h
 create mode 100644 bsd-user/freebsd/target_os_vmparam.h
 create mode 100644 bsd-user/i386/target_arch.h
 create mode 100644 bsd-user/i386/target_arch_cpu.c
 create mode 100644 bsd-user/i386/target_arch_cpu.h
 create mode 100644 bsd-user/i386/target_arch_elf.h
 create mode 100644 bsd-user/i386/target_arch_signal.h
 create mode 100644 bsd-user/i386/target_arch_sigtramp.h
 create mode 100644 bsd-user/i386/target_arch_sysarch.h
 create mode 100644 bsd-user/i386/target_arch_thread.h
 create mode 100644 bsd-user/i386/target_arch_vmparam.h
 create mode 100644 bsd-user/mips/syscall.h
 create mode 100644 bsd-user/mips/target_arch.h
 create mode 100644 bsd-user/mips/target_arch_cpu.c
 create mode 100644 bsd-user/mips/target_arch_cpu.h
 create mode 100644 bsd-user/mips/target_arch_elf.h
 create mode 100644 bsd-user/mips/target_arch_signal.h
 create mode 100644 bsd-user/mips/target_arch_sigtramp.h
 create mode 100644 bsd-user/mips/target_arch_sysarch.h
 create mode 100644 bsd-user/mips/target_arch_thread.h
 create mode 100644 bsd-user/mips/target_arch_vmparam.h
 create mode 100644 bsd-user/mips64/syscall.h
 create mode 100644 bsd-user/mips64/target_arch.h
 create mode 100644 bsd-user/mips64/target_arch_cpu.c
 create mode 100644 bsd-user/mips64/target_arch_cpu.h
 create mode 100644 bsd-user/mips64/target_arch_elf.h
 create mode 100644 bsd-user/mips64/target_arch_signal.h
 create mode 100644 bsd-user/mips64/target_arch_sigtramp.h
 create mode 100644 bsd-user/mips64/target_arch_sysarch.h
 create mode 100644 bsd-user/mips64/target_arch_thread.h
 create mode 100644 bsd-user/mips64/target_arch_vmparam.h
 create mode 100644 bsd-user/netbsd/host_os.h
 create mode 100644 bsd-user/netbsd/os-extattr.h
 create mode 100644 bsd-user/netbsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/netbsd/os-ioctl-filio.h
 create mode 100644 bsd-user/netbsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/netbsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/netbsd/os-ioctl-types.h
 create mode 100644 bsd-user/netbsd/os-misc.h
 create mode 100644 bsd-user/netbsd/os-proc.c
 create mode 100644 bsd-user/netbsd/os-proc.h
 create mode 100644 bsd-user/netbsd/os-socket.c
 create mode 100644 bsd-user/netbsd/os-socket.h
 create mode 100644 bsd-user/netbsd/os-stat.c
 create mode 100644 bsd-user/netbsd/os-stat.h
 create mode 100644 bsd-user/netbsd/os-strace.h
 create mode 100644 bsd-user/netbsd/os-sys.c
 create mode 100644 bsd-user/netbsd/os-thread.c
 create mode 100644 bsd-user/netbsd/os-thread.h
 create mode 100644 bsd-user/netbsd/os-time.c
 create mode 100644 bsd-user/netbsd/os-time.h
 create mode 100644 bsd-user/netbsd/qemu-os.h
 create mode 100644 bsd-user/netbsd/target_os_elf.h
 create mode 100644 bsd-user/netbsd/target_os_siginfo.h
 create mode 100644 bsd-user/netbsd/target_os_signal.h
 create mode 100644 bsd-user/netbsd/target_os_stack.h
 create mode 100644 bsd-user/netbsd/target_os_thread.h
 create mode 100644 bsd-user/openbsd/host_os.h
 create mode 100644 bsd-user/openbsd/os-extattr.h
 create mode 100644 bsd-user/openbsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/openbsd/os-ioctl-filio.h
 create mode 100644 bsd-user/openbsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/openbsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/openbsd/os-ioctl-types.h
 create mode 100644 bsd-user/openbsd/os-misc.h
 create mode 100644 bsd-user/openbsd/os-proc.c
 create mode 100644 bsd-user/openbsd/os-proc.h
 create mode 100644 bsd-user/openbsd/os-socket.c
 create mode 100644 bsd-user/openbsd/os-socket.h
 create mode 100644 bsd-user/openbsd/os-stat.c
 create mode 100644 bsd-user/openbsd/os-stat.h
 create mode 100644 bsd-user/openbsd/os-strace.h
 create mode 100644 bsd-user/openbsd/os-sys.c
 create mode 100644 bsd-user/openbsd/os-thread.c
 create mode 100644 bsd-user/openbsd/os-thread.h
 create mode 100644 bsd-user/openbsd/os-time.c
 create mode 100644 bsd-user/openbsd/os-time.h
 create mode 100644 bsd-user/openbsd/qemu-os.h
 create mode 100644 bsd-user/openbsd/target_os_elf.h
 create mode 100644 bsd-user/openbsd/target_os_siginfo.h
 create mode 100644 bsd-user/openbsd/target_os_signal.h
 create mode 100644 bsd-user/openbsd/target_os_stack.h
 create mode 100644 bsd-user/openbsd/target_os_thread.h
 create mode 100644 bsd-user/qemu-bsd.h
 create mode 100644 bsd-user/sparc/target_arch.h
 create mode 100644 bsd-user/sparc/target_arch_cpu.c
 create mode 100644 bsd-user/sparc/target_arch_cpu.h
 create mode 100644 bsd-user/sparc/target_arch_elf.h
 create mode 100644 bsd-user/sparc/target_arch_signal.h
 create mode 100644 bsd-user/sparc/target_arch_sigtramp.h
 create mode 100644 bsd-user/sparc/target_arch_sysarch.h
 create mode 100644 bsd-user/sparc/target_arch_thread.h
 create mode 100644 bsd-user/sparc/target_arch_vmparam.h
 create mode 100644 bsd-user/sparc64/target_arch.h
 create mode 100644 bsd-user/sparc64/target_arch_cpu.c
 create mode 100644 bsd-user/sparc64/target_arch_cpu.h
 create mode 100644 bsd-user/sparc64/target_arch_elf.h
 create mode 100644 bsd-user/sparc64/target_arch_signal.h
 create mode 100644 bsd-user/sparc64/target_arch_sigtramp.h
 create mode 100644 bsd-user/sparc64/target_arch_sysarch.h
 create mode 100644 bsd-user/sparc64/target_arch_thread.h
 create mode 100644 bsd-user/sparc64/target_arch_vmparam.h
 create mode 100644 bsd-user/x86_64/target_arch.h
 create mode 100644 bsd-user/x86_64/target_arch_cpu.c
 create mode 100644 bsd-user/x86_64/target_arch_cpu.h
 create mode 100644 bsd-user/x86_64/target_arch_elf.h
 create mode 100644 bsd-user/x86_64/target_arch_signal.h
 create mode 100644 bsd-user/x86_64/target_arch_sigtramp.h
 create mode 100644 bsd-user/x86_64/target_arch_sysarch.h
 create mode 100644 bsd-user/x86_64/target_arch_thread.h
 create mode 100644 bsd-user/x86_64/target_arch_vmparam.h
 create mode 100644 default-configs/arm-bsd-user.mak
 create mode 100644 default-configs/mips-bsd-user.mak
 create mode 100644 default-configs/mips64-bsd-user.mak
 create mode 100644 default-configs/mips64el-bsd-user.mak
 create mode 100644 default-configs/mipsel-bsd-user.mak

-- 
1.7.8

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 01/18] bsd-user: refresh freebsd system call numbers
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
@ 2013-10-16 14:36 ` Stacey Son
  2013-10-24  1:22   ` Ed Maste
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 02/18] bsd-user: add HOST_ABI_DIR for the various *BSD dependent code Stacey Son
                   ` (38 subsequent siblings)
  39 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

Update FreeBSD system call numbers in freebsd/syscall_nr.h.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/freebsd/syscall_nr.h |  813 ++++++++++++++++++++++-------------------
 1 files changed, 445 insertions(+), 368 deletions(-)

diff --git a/bsd-user/freebsd/syscall_nr.h b/bsd-user/freebsd/syscall_nr.h
index 36336ab..d849024 100644
--- a/bsd-user/freebsd/syscall_nr.h
+++ b/bsd-user/freebsd/syscall_nr.h
@@ -1,373 +1,450 @@
 /*
  * System call numbers.
  *
- * $FreeBSD: src/sys/sys/syscall.h,v 1.224 2008/08/24 21:23:08 rwatson Exp $
- * created from FreeBSD: head/sys/kern/syscalls.master 182123 2008-08-24 21:20:35Z rwatson
+ * created from FreeBSD: releng/9.1/sys/kern/syscalls.master 229723
+ * 2012-01-06 19:29:16Z jhb
  */
 
-#define TARGET_FREEBSD_NR_syscall     0
-#define TARGET_FREEBSD_NR_exit        1
-#define TARGET_FREEBSD_NR_fork        2
-#define TARGET_FREEBSD_NR_read        3
-#define TARGET_FREEBSD_NR_write       4
-#define TARGET_FREEBSD_NR_open        5
-#define TARGET_FREEBSD_NR_close       6
-#define TARGET_FREEBSD_NR_wait4       7
-#define TARGET_FREEBSD_NR_link        9
-#define TARGET_FREEBSD_NR_unlink      10
-#define TARGET_FREEBSD_NR_chdir       12
-#define TARGET_FREEBSD_NR_fchdir      13
-#define TARGET_FREEBSD_NR_mknod       14
-#define TARGET_FREEBSD_NR_chmod       15
-#define TARGET_FREEBSD_NR_chown       16
-#define TARGET_FREEBSD_NR_break       17
-#define TARGET_FREEBSD_NR_freebsd4_getfsstat  18
-#define TARGET_FREEBSD_NR_getpid      20
-#define TARGET_FREEBSD_NR_mount       21
-#define TARGET_FREEBSD_NR_unmount     22
-#define TARGET_FREEBSD_NR_setuid      23
-#define TARGET_FREEBSD_NR_getuid      24
-#define TARGET_FREEBSD_NR_geteuid     25
-#define TARGET_FREEBSD_NR_ptrace      26
-#define TARGET_FREEBSD_NR_recvmsg     27
-#define TARGET_FREEBSD_NR_sendmsg     28
-#define TARGET_FREEBSD_NR_recvfrom    29
-#define TARGET_FREEBSD_NR_accept      30
-#define TARGET_FREEBSD_NR_getpeername 31
-#define TARGET_FREEBSD_NR_getsockname 32
-#define TARGET_FREEBSD_NR_access      33
-#define TARGET_FREEBSD_NR_chflags     34
-#define TARGET_FREEBSD_NR_fchflags    35
-#define TARGET_FREEBSD_NR_sync        36
-#define TARGET_FREEBSD_NR_kill        37
-#define TARGET_FREEBSD_NR_getppid     39
-#define TARGET_FREEBSD_NR_dup 41
-#define TARGET_FREEBSD_NR_pipe        42
-#define TARGET_FREEBSD_NR_getegid     43
-#define TARGET_FREEBSD_NR_profil      44
-#define TARGET_FREEBSD_NR_ktrace      45
-#define TARGET_FREEBSD_NR_getgid      47
-#define TARGET_FREEBSD_NR_getlogin    49
-#define TARGET_FREEBSD_NR_setlogin    50
-#define TARGET_FREEBSD_NR_acct        51
-#define TARGET_FREEBSD_NR_sigaltstack 53
-#define TARGET_FREEBSD_NR_ioctl       54
-#define TARGET_FREEBSD_NR_reboot      55
-#define TARGET_FREEBSD_NR_revoke      56
-#define TARGET_FREEBSD_NR_symlink     57
-#define TARGET_FREEBSD_NR_readlink    58
-#define TARGET_FREEBSD_NR_execve      59
-#define TARGET_FREEBSD_NR_umask       60
-#define TARGET_FREEBSD_NR_chroot      61
-#define TARGET_FREEBSD_NR_msync       65
-#define TARGET_FREEBSD_NR_vfork       66
-#define TARGET_FREEBSD_NR_sbrk        69
-#define TARGET_FREEBSD_NR_sstk        70
-#define TARGET_FREEBSD_NR_vadvise     72
-#define TARGET_FREEBSD_NR_munmap      73
-#define TARGET_FREEBSD_NR_mprotect    74
-#define TARGET_FREEBSD_NR_madvise     75
-#define TARGET_FREEBSD_NR_mincore     78
-#define TARGET_FREEBSD_NR_getgroups   79
-#define TARGET_FREEBSD_NR_setgroups   80
-#define TARGET_FREEBSD_NR_getpgrp     81
-#define TARGET_FREEBSD_NR_setpgid     82
-#define TARGET_FREEBSD_NR_setitimer   83
-#define TARGET_FREEBSD_NR_swapon      85
-#define TARGET_FREEBSD_NR_getitimer   86
-#define TARGET_FREEBSD_NR_getdtablesize       89
-#define TARGET_FREEBSD_NR_dup2        90
-#define TARGET_FREEBSD_NR_fcntl       92
-#define TARGET_FREEBSD_NR_select      93
-#define TARGET_FREEBSD_NR_fsync       95
-#define TARGET_FREEBSD_NR_setpriority 96
-#define TARGET_FREEBSD_NR_socket      97
-#define TARGET_FREEBSD_NR_connect     98
-#define TARGET_FREEBSD_NR_getpriority 100
-#define TARGET_FREEBSD_NR_bind        104
-#define TARGET_FREEBSD_NR_setsockopt  105
-#define TARGET_FREEBSD_NR_listen      106
-#define TARGET_FREEBSD_NR_gettimeofday        116
-#define TARGET_FREEBSD_NR_getrusage   117
-#define TARGET_FREEBSD_NR_getsockopt  118
-#define TARGET_FREEBSD_NR_readv       120
-#define TARGET_FREEBSD_NR_writev      121
-#define TARGET_FREEBSD_NR_settimeofday        122
-#define TARGET_FREEBSD_NR_fchown      123
-#define TARGET_FREEBSD_NR_fchmod      124
-#define TARGET_FREEBSD_NR_setreuid    126
-#define TARGET_FREEBSD_NR_setregid    127
-#define TARGET_FREEBSD_NR_rename      128
-#define TARGET_FREEBSD_NR_flock       131
-#define TARGET_FREEBSD_NR_mkfifo      132
-#define TARGET_FREEBSD_NR_sendto      133
-#define TARGET_FREEBSD_NR_shutdown    134
-#define TARGET_FREEBSD_NR_socketpair  135
-#define TARGET_FREEBSD_NR_mkdir       136
-#define TARGET_FREEBSD_NR_rmdir       137
-#define TARGET_FREEBSD_NR_utimes      138
-#define TARGET_FREEBSD_NR_adjtime     140
-#define TARGET_FREEBSD_NR_setsid      147
-#define TARGET_FREEBSD_NR_quotactl    148
-#define TARGET_FREEBSD_NR_nlm_syscall 154
-#define TARGET_FREEBSD_NR_nfssvc      155
-#define TARGET_FREEBSD_NR_freebsd4_statfs     157
-#define TARGET_FREEBSD_NR_freebsd4_fstatfs    158
-#define TARGET_FREEBSD_NR_lgetfh      160
-#define TARGET_FREEBSD_NR_getfh       161
-#define TARGET_FREEBSD_NR_getdomainname       162
-#define TARGET_FREEBSD_NR_setdomainname       163
-#define TARGET_FREEBSD_NR_uname       164
-#define TARGET_FREEBSD_NR_sysarch     165
-#define TARGET_FREEBSD_NR_rtprio      166
-#define TARGET_FREEBSD_NR_semsys      169
-#define TARGET_FREEBSD_NR_msgsys      170
-#define TARGET_FREEBSD_NR_shmsys      171
-#define TARGET_FREEBSD_NR_freebsd6_pread      173
-#define TARGET_FREEBSD_NR_freebsd6_pwrite     174
-#define TARGET_FREEBSD_NR_setfib      175
-#define TARGET_FREEBSD_NR_ntp_adjtime 176
-#define TARGET_FREEBSD_NR_setgid      181
-#define TARGET_FREEBSD_NR_setegid     182
-#define TARGET_FREEBSD_NR_seteuid     183
-#define TARGET_FREEBSD_NR_stat        188
-#define TARGET_FREEBSD_NR_fstat       189
-#define TARGET_FREEBSD_NR_lstat       190
-#define TARGET_FREEBSD_NR_pathconf    191
-#define TARGET_FREEBSD_NR_fpathconf   192
-#define TARGET_FREEBSD_NR_getrlimit   194
-#define TARGET_FREEBSD_NR_setrlimit   195
-#define TARGET_FREEBSD_NR_getdirentries       196
-#define TARGET_FREEBSD_NR_freebsd6_mmap       197
-#define TARGET_FREEBSD_NR___syscall   198
-#define TARGET_FREEBSD_NR_freebsd6_lseek      199
-#define TARGET_FREEBSD_NR_freebsd6_truncate   200
-#define TARGET_FREEBSD_NR_freebsd6_ftruncate  201
-#define TARGET_FREEBSD_NR___sysctl    202
-#define TARGET_FREEBSD_NR_mlock       203
-#define TARGET_FREEBSD_NR_munlock     204
-#define TARGET_FREEBSD_NR_undelete    205
-#define TARGET_FREEBSD_NR_futimes     206
-#define TARGET_FREEBSD_NR_getpgid     207
-#define TARGET_FREEBSD_NR_poll        209
-#define TARGET_FREEBSD_NR___semctl    220
-#define TARGET_FREEBSD_NR_semget      221
-#define TARGET_FREEBSD_NR_semop       222
-#define TARGET_FREEBSD_NR_msgctl      224
-#define TARGET_FREEBSD_NR_msgget      225
-#define TARGET_FREEBSD_NR_msgsnd      226
-#define TARGET_FREEBSD_NR_msgrcv      227
-#define TARGET_FREEBSD_NR_shmat       228
-#define TARGET_FREEBSD_NR_shmctl      229
-#define TARGET_FREEBSD_NR_shmdt       230
-#define TARGET_FREEBSD_NR_shmget      231
-#define TARGET_FREEBSD_NR_clock_gettime       232
-#define TARGET_FREEBSD_NR_clock_settime       233
-#define TARGET_FREEBSD_NR_clock_getres        234
-#define TARGET_FREEBSD_NR_ktimer_create       235
-#define TARGET_FREEBSD_NR_ktimer_delete       236
-#define TARGET_FREEBSD_NR_ktimer_settime      237
-#define TARGET_FREEBSD_NR_ktimer_gettime      238
-#define TARGET_FREEBSD_NR_ktimer_getoverrun   239
-#define TARGET_FREEBSD_NR_nanosleep   240
-#define TARGET_FREEBSD_NR_ntp_gettime 248
-#define TARGET_FREEBSD_NR_minherit    250
-#define TARGET_FREEBSD_NR_rfork       251
-#define TARGET_FREEBSD_NR_openbsd_poll        252
-#define TARGET_FREEBSD_NR_issetugid   253
-#define TARGET_FREEBSD_NR_lchown      254
-#define TARGET_FREEBSD_NR_aio_read    255
-#define TARGET_FREEBSD_NR_aio_write   256
-#define TARGET_FREEBSD_NR_lio_listio  257
-#define TARGET_FREEBSD_NR_getdents    272
-#define TARGET_FREEBSD_NR_lchmod      274
-#define TARGET_FREEBSD_NR_netbsd_lchown       275
-#define TARGET_FREEBSD_NR_lutimes     276
-#define TARGET_FREEBSD_NR_netbsd_msync        277
-#define TARGET_FREEBSD_NR_nstat       278
-#define TARGET_FREEBSD_NR_nfstat      279
-#define TARGET_FREEBSD_NR_nlstat      280
-#define TARGET_FREEBSD_NR_preadv      289
-#define TARGET_FREEBSD_NR_pwritev     290
-#define TARGET_FREEBSD_NR_freebsd4_fhstatfs   297
-#define TARGET_FREEBSD_NR_fhopen      298
-#define TARGET_FREEBSD_NR_fhstat      299
-#define TARGET_FREEBSD_NR_modnext     300
-#define TARGET_FREEBSD_NR_modstat     301
-#define TARGET_FREEBSD_NR_modfnext    302
-#define TARGET_FREEBSD_NR_modfind     303
-#define TARGET_FREEBSD_NR_kldload     304
-#define TARGET_FREEBSD_NR_kldunload   305
-#define TARGET_FREEBSD_NR_kldfind     306
-#define TARGET_FREEBSD_NR_kldnext     307
-#define TARGET_FREEBSD_NR_kldstat     308
-#define TARGET_FREEBSD_NR_kldfirstmod 309
-#define TARGET_FREEBSD_NR_getsid      310
-#define TARGET_FREEBSD_NR_setresuid   311
-#define TARGET_FREEBSD_NR_setresgid   312
-#define TARGET_FREEBSD_NR_aio_return  314
-#define TARGET_FREEBSD_NR_aio_suspend 315
-#define TARGET_FREEBSD_NR_aio_cancel  316
-#define TARGET_FREEBSD_NR_aio_error   317
-#define TARGET_FREEBSD_NR_oaio_read   318
-#define TARGET_FREEBSD_NR_oaio_write  319
-#define TARGET_FREEBSD_NR_olio_listio 320
-#define TARGET_FREEBSD_NR_yield       321
-#define TARGET_FREEBSD_NR_mlockall    324
-#define TARGET_FREEBSD_NR_munlockall  325
-#define TARGET_FREEBSD_NR___getcwd    326
-#define TARGET_FREEBSD_NR_sched_setparam      327
-#define TARGET_FREEBSD_NR_sched_getparam      328
-#define TARGET_FREEBSD_NR_sched_setscheduler  329
-#define TARGET_FREEBSD_NR_sched_getscheduler  330
-#define TARGET_FREEBSD_NR_sched_yield 331
-#define TARGET_FREEBSD_NR_sched_get_priority_max      332
-#define TARGET_FREEBSD_NR_sched_get_priority_min      333
-#define TARGET_FREEBSD_NR_sched_rr_get_interval       334
-#define TARGET_FREEBSD_NR_utrace      335
-#define TARGET_FREEBSD_NR_freebsd4_sendfile   336
-#define TARGET_FREEBSD_NR_kldsym      337
-#define TARGET_FREEBSD_NR_jail        338
-#define TARGET_FREEBSD_NR_sigprocmask 340
-#define TARGET_FREEBSD_NR_sigsuspend  341
-#define TARGET_FREEBSD_NR_freebsd4_sigaction  342
-#define TARGET_FREEBSD_NR_sigpending  343
-#define TARGET_FREEBSD_NR_freebsd4_sigreturn  344
-#define TARGET_FREEBSD_NR_sigtimedwait        345
-#define TARGET_FREEBSD_NR_sigwaitinfo 346
-#define TARGET_FREEBSD_NR___acl_get_file      347
-#define TARGET_FREEBSD_NR___acl_set_file      348
-#define TARGET_FREEBSD_NR___acl_get_fd        349
-#define TARGET_FREEBSD_NR___acl_set_fd        350
-#define TARGET_FREEBSD_NR___acl_delete_file   351
-#define TARGET_FREEBSD_NR___acl_delete_fd     352
-#define TARGET_FREEBSD_NR___acl_aclcheck_file 353
-#define TARGET_FREEBSD_NR___acl_aclcheck_fd   354
-#define TARGET_FREEBSD_NR_extattrctl  355
-#define TARGET_FREEBSD_NR_extattr_set_file    356
-#define TARGET_FREEBSD_NR_extattr_get_file    357
-#define TARGET_FREEBSD_NR_extattr_delete_file 358
-#define TARGET_FREEBSD_NR_aio_waitcomplete    359
-#define TARGET_FREEBSD_NR_getresuid   360
-#define TARGET_FREEBSD_NR_getresgid   361
-#define TARGET_FREEBSD_NR_kqueue      362
-#define TARGET_FREEBSD_NR_kevent      363
-#define TARGET_FREEBSD_NR_extattr_set_fd      371
-#define TARGET_FREEBSD_NR_extattr_get_fd      372
-#define TARGET_FREEBSD_NR_extattr_delete_fd   373
-#define TARGET_FREEBSD_NR___setugid   374
-#define TARGET_FREEBSD_NR_nfsclnt     375
-#define TARGET_FREEBSD_NR_eaccess     376
-#define TARGET_FREEBSD_NR_nmount      378
-#define TARGET_FREEBSD_NR___mac_get_proc      384
-#define TARGET_FREEBSD_NR___mac_set_proc      385
-#define TARGET_FREEBSD_NR___mac_get_fd        386
-#define TARGET_FREEBSD_NR___mac_get_file      387
-#define TARGET_FREEBSD_NR___mac_set_fd        388
-#define TARGET_FREEBSD_NR___mac_set_file      389
-#define TARGET_FREEBSD_NR_kenv        390
-#define TARGET_FREEBSD_NR_lchflags    391
-#define TARGET_FREEBSD_NR_uuidgen     392
-#define TARGET_FREEBSD_NR_sendfile    393
-#define TARGET_FREEBSD_NR_mac_syscall 394
-#define TARGET_FREEBSD_NR_getfsstat   395
-#define TARGET_FREEBSD_NR_statfs      396
-#define TARGET_FREEBSD_NR_fstatfs     397
-#define TARGET_FREEBSD_NR_fhstatfs    398
-#define TARGET_FREEBSD_NR_ksem_close  400
-#define TARGET_FREEBSD_NR_ksem_post   401
-#define TARGET_FREEBSD_NR_ksem_wait   402
-#define TARGET_FREEBSD_NR_ksem_trywait        403
-#define TARGET_FREEBSD_NR_ksem_init   404
-#define TARGET_FREEBSD_NR_ksem_open   405
-#define TARGET_FREEBSD_NR_ksem_unlink 406
-#define TARGET_FREEBSD_NR_ksem_getvalue       407
-#define TARGET_FREEBSD_NR_ksem_destroy        408
-#define TARGET_FREEBSD_NR___mac_get_pid       409
-#define TARGET_FREEBSD_NR___mac_get_link      410
-#define TARGET_FREEBSD_NR___mac_set_link      411
-#define TARGET_FREEBSD_NR_extattr_set_link    412
-#define TARGET_FREEBSD_NR_extattr_get_link    413
-#define TARGET_FREEBSD_NR_extattr_delete_link 414
-#define TARGET_FREEBSD_NR___mac_execve        415
-#define TARGET_FREEBSD_NR_sigaction   416
-#define TARGET_FREEBSD_NR_sigreturn   417
-#define TARGET_FREEBSD_NR_getcontext  421
-#define TARGET_FREEBSD_NR_setcontext  422
-#define TARGET_FREEBSD_NR_swapcontext 423
-#define TARGET_FREEBSD_NR_swapoff     424
-#define TARGET_FREEBSD_NR___acl_get_link      425
-#define TARGET_FREEBSD_NR___acl_set_link      426
-#define TARGET_FREEBSD_NR___acl_delete_link   427
-#define TARGET_FREEBSD_NR___acl_aclcheck_link 428
-#define TARGET_FREEBSD_NR_sigwait     429
-#define TARGET_FREEBSD_NR_thr_create  430
-#define TARGET_FREEBSD_NR_thr_exit    431
-#define TARGET_FREEBSD_NR_thr_self    432
-#define TARGET_FREEBSD_NR_thr_kill    433
-#define TARGET_FREEBSD_NR__umtx_lock  434
-#define TARGET_FREEBSD_NR__umtx_unlock        435
-#define TARGET_FREEBSD_NR_jail_attach 436
-#define TARGET_FREEBSD_NR_extattr_list_fd     437
-#define TARGET_FREEBSD_NR_extattr_list_file   438
-#define TARGET_FREEBSD_NR_extattr_list_link   439
-#define TARGET_FREEBSD_NR_ksem_timedwait      441
-#define TARGET_FREEBSD_NR_thr_suspend 442
-#define TARGET_FREEBSD_NR_thr_wake    443
-#define TARGET_FREEBSD_NR_kldunloadf  444
-#define TARGET_FREEBSD_NR_audit       445
-#define TARGET_FREEBSD_NR_auditon     446
-#define TARGET_FREEBSD_NR_getauid     447
-#define TARGET_FREEBSD_NR_setauid     448
-#define TARGET_FREEBSD_NR_getaudit    449
-#define TARGET_FREEBSD_NR_setaudit    450
-#define TARGET_FREEBSD_NR_getaudit_addr       451
-#define TARGET_FREEBSD_NR_setaudit_addr       452
-#define TARGET_FREEBSD_NR_auditctl    453
-#define TARGET_FREEBSD_NR__umtx_op    454
-#define TARGET_FREEBSD_NR_thr_new     455
-#define TARGET_FREEBSD_NR_sigqueue    456
-#define TARGET_FREEBSD_NR_kmq_open    457
-#define TARGET_FREEBSD_NR_kmq_setattr 458
-#define TARGET_FREEBSD_NR_kmq_timedreceive    459
-#define TARGET_FREEBSD_NR_kmq_timedsend       460
-#define TARGET_FREEBSD_NR_kmq_notify  461
-#define TARGET_FREEBSD_NR_kmq_unlink  462
-#define TARGET_FREEBSD_NR_abort2      463
-#define TARGET_FREEBSD_NR_thr_set_name        464
-#define TARGET_FREEBSD_NR_aio_fsync   465
-#define TARGET_FREEBSD_NR_rtprio_thread       466
-#define TARGET_FREEBSD_NR_sctp_peeloff        471
-#define TARGET_FREEBSD_NR_sctp_generic_sendmsg        472
-#define TARGET_FREEBSD_NR_sctp_generic_sendmsg_iov    473
-#define TARGET_FREEBSD_NR_sctp_generic_recvmsg        474
-#define TARGET_FREEBSD_NR_pread       475
-#define TARGET_FREEBSD_NR_pwrite      476
-#define TARGET_FREEBSD_NR_mmap        477
-#define TARGET_FREEBSD_NR_lseek       478
-#define TARGET_FREEBSD_NR_truncate    479
-#define TARGET_FREEBSD_NR_ftruncate   480
-#define TARGET_FREEBSD_NR_thr_kill2   481
-#define TARGET_FREEBSD_NR_shm_open    482
-#define TARGET_FREEBSD_NR_shm_unlink  483
-#define TARGET_FREEBSD_NR_cpuset      484
-#define TARGET_FREEBSD_NR_cpuset_setid        485
-#define TARGET_FREEBSD_NR_cpuset_getid        486
-#define TARGET_FREEBSD_NR_cpuset_getaffinity  487
-#define TARGET_FREEBSD_NR_cpuset_setaffinity  488
-#define TARGET_FREEBSD_NR_faccessat   489
-#define TARGET_FREEBSD_NR_fchmodat    490
-#define TARGET_FREEBSD_NR_fchownat    491
-#define TARGET_FREEBSD_NR_fexecve     492
-#define TARGET_FREEBSD_NR_fstatat     493
-#define TARGET_FREEBSD_NR_futimesat   494
-#define TARGET_FREEBSD_NR_linkat      495
-#define TARGET_FREEBSD_NR_mkdirat     496
-#define TARGET_FREEBSD_NR_mkfifoat    497
-#define TARGET_FREEBSD_NR_mknodat     498
-#define TARGET_FREEBSD_NR_openat      499
-#define TARGET_FREEBSD_NR_readlinkat  500
-#define TARGET_FREEBSD_NR_renameat    501
-#define TARGET_FREEBSD_NR_symlinkat   502
-#define TARGET_FREEBSD_NR_unlinkat    503
-#define TARGET_FREEBSD_NR_posix_openpt        504
+#define TARGET_FREEBSD_NR_syscall   0
+#define TARGET_FREEBSD_NR_exit  1
+#define TARGET_FREEBSD_NR_fork  2
+#define TARGET_FREEBSD_NR_read  3
+#define TARGET_FREEBSD_NR_write 4
+#define TARGET_FREEBSD_NR_open  5
+#define TARGET_FREEBSD_NR_close 6
+#define TARGET_FREEBSD_NR_wait4 7
+                /* 8 is old creat */
+#define TARGET_FREEBSD_NR_link  9
+#define TARGET_FREEBSD_NR_unlink    10
+                /* 11 is obsolete execv */
+#define TARGET_FREEBSD_NR_chdir 12
+#define TARGET_FREEBSD_NR_fchdir    13
+#define TARGET_FREEBSD_NR_mknod 14
+#define TARGET_FREEBSD_NR_chmod 15
+#define TARGET_FREEBSD_NR_chown 16
+#define TARGET_FREEBSD_NR_break 17
+#define TARGET_FREEBSD_NR_freebsd4_getfsstat    18
+                /* 19 is old lseek */
+#define TARGET_FREEBSD_NR_getpid    20
+#define TARGET_FREEBSD_NR_mount 21
+#define TARGET_FREEBSD_NR_unmount   22
+#define TARGET_FREEBSD_NR_setuid    23
+#define TARGET_FREEBSD_NR_getuid    24
+#define TARGET_FREEBSD_NR_geteuid   25
+#define TARGET_FREEBSD_NR_ptrace    26
+#define TARGET_FREEBSD_NR_recvmsg   27
+#define TARGET_FREEBSD_NR_sendmsg   28
+#define TARGET_FREEBSD_NR_recvfrom  29
+#define TARGET_FREEBSD_NR_accept    30
+#define TARGET_FREEBSD_NR_getpeername   31
+#define TARGET_FREEBSD_NR_getsockname   32
+#define TARGET_FREEBSD_NR_access    33
+#define TARGET_FREEBSD_NR_chflags   34
+#define TARGET_FREEBSD_NR_fchflags  35
+#define TARGET_FREEBSD_NR_sync  36
+#define TARGET_FREEBSD_NR_kill  37
+                /* 38 is old stat */
+#define TARGET_FREEBSD_NR_getppid   39
+                /* 40 is old lstat */
+#define TARGET_FREEBSD_NR_dup   41
+#define TARGET_FREEBSD_NR_pipe  42
+#define TARGET_FREEBSD_NR_getegid   43
+#define TARGET_FREEBSD_NR_profil    44
+#define TARGET_FREEBSD_NR_ktrace    45
+                /* 46 is old sigaction */
+#define TARGET_FREEBSD_NR_getgid    47
+                /* 48 is old sigprocmask */
+#define TARGET_FREEBSD_NR_getlogin  49
+#define TARGET_FREEBSD_NR_setlogin  50
+#define TARGET_FREEBSD_NR_acct  51
+                /* 52 is old sigpending */
+#define TARGET_FREEBSD_NR_sigaltstack   53
+#define TARGET_FREEBSD_NR_ioctl 54
+#define TARGET_FREEBSD_NR_reboot    55
+#define TARGET_FREEBSD_NR_revoke    56
+#define TARGET_FREEBSD_NR_symlink   57
+#define TARGET_FREEBSD_NR_readlink  58
+#define TARGET_FREEBSD_NR_execve    59
+#define TARGET_FREEBSD_NR_umask 60
+#define TARGET_FREEBSD_NR_chroot    61
+                /* 62 is old fstat */
+                /* 63 is old getkerninfo */
+                /* 64 is old getpagesize */
+#define TARGET_FREEBSD_NR_msync 65
+#define TARGET_FREEBSD_NR_vfork 66
+                /* 67 is obsolete vread */
+                /* 68 is obsolete vwrite */
+#define TARGET_FREEBSD_NR_sbrk  69
+#define TARGET_FREEBSD_NR_sstk  70
+                /* 71 is old mmap */
+#define TARGET_FREEBSD_NR_vadvise   72
+#define TARGET_FREEBSD_NR_munmap    73
+#define TARGET_FREEBSD_NR_mprotect  74
+#define TARGET_FREEBSD_NR_madvise   75
+                /* 76 is obsolete vhangup */
+                /* 77 is obsolete vlimit */
+#define TARGET_FREEBSD_NR_mincore   78
+#define TARGET_FREEBSD_NR_getgroups 79
+#define TARGET_FREEBSD_NR_setgroups 80
+#define TARGET_FREEBSD_NR_getpgrp   81
+#define TARGET_FREEBSD_NR_setpgid   82
+#define TARGET_FREEBSD_NR_setitimer 83
+                /* 84 is old wait */
+#define TARGET_FREEBSD_NR_swapon    85
+#define TARGET_FREEBSD_NR_getitimer 86
+                /* 87 is old gethostname */
+                /* 88 is old sethostname */
+#define TARGET_FREEBSD_NR_getdtablesize 89
+#define TARGET_FREEBSD_NR_dup2  90
+#define TARGET_FREEBSD_NR_fcntl 92
+#define TARGET_FREEBSD_NR_select    93
+#define TARGET_FREEBSD_NR_fsync 95
+#define TARGET_FREEBSD_NR_setpriority   96
+#define TARGET_FREEBSD_NR_socket    97
+#define TARGET_FREEBSD_NR_connect   98
+                /* 99 is old accept */
+#define TARGET_FREEBSD_NR_getpriority   100
+                /* 101 is old send */
+                /* 102 is old recv */
+                /* 103 is old sigreturn */
+#define TARGET_FREEBSD_NR_bind  104
+#define TARGET_FREEBSD_NR_setsockopt    105
+#define TARGET_FREEBSD_NR_listen    106
+                /* 107 is obsolete vtimes */
+                /* 108 is old sigvec */
+                /* 109 is old sigblock */
+                /* 110 is old sigsetmask */
+                /* 111 is old sigsuspend */
+                /* 112 is old sigstack */
+                /* 113 is old recvmsg */
+                /* 114 is old sendmsg */
+                /* 115 is obsolete vtrace */
+#define TARGET_FREEBSD_NR_gettimeofday  116
+#define TARGET_FREEBSD_NR_getrusage 117
+#define TARGET_FREEBSD_NR_getsockopt    118
+#define TARGET_FREEBSD_NR_readv 120
+#define TARGET_FREEBSD_NR_writev    121
+#define TARGET_FREEBSD_NR_settimeofday  122
+#define TARGET_FREEBSD_NR_fchown    123
+#define TARGET_FREEBSD_NR_fchmod    124
+                /* 125 is old recvfrom */
+#define TARGET_FREEBSD_NR_setreuid  126
+#define TARGET_FREEBSD_NR_setregid  127
+#define TARGET_FREEBSD_NR_rename    128
+                /* 129 is old truncate */
+                /* 130 is old ftruncate */
+#define TARGET_FREEBSD_NR_flock 131
+#define TARGET_FREEBSD_NR_mkfifo    132
+#define TARGET_FREEBSD_NR_sendto    133
+#define TARGET_FREEBSD_NR_shutdown  134
+#define TARGET_FREEBSD_NR_socketpair    135
+#define TARGET_FREEBSD_NR_mkdir 136
+#define TARGET_FREEBSD_NR_rmdir 137
+#define TARGET_FREEBSD_NR_utimes    138
+                /* 139 is obsolete 4.2 sigreturn */
+#define TARGET_FREEBSD_NR_adjtime   140
+                /* 141 is old getpeername */
+                /* 142 is old gethostid */
+                /* 143 is old sethostid */
+                /* 144 is old getrlimit */
+                /* 145 is old setrlimit */
+                /* 146 is old killpg */
+#define TARGET_FREEBSD_NR_killpg    146 /* COMPAT */
+#define TARGET_FREEBSD_NR_setsid    147
+#define TARGET_FREEBSD_NR_quotactl  148
+                /* 149 is old quota */
+                /* 150 is old getsockname */
+#define TARGET_FREEBSD_NR_nlm_syscall   154
+#define TARGET_FREEBSD_NR_nfssvc    155
+                /* 156 is old getdirentries */
+#define TARGET_FREEBSD_NR_freebsd4_statfs   157
+#define TARGET_FREEBSD_NR_freebsd4_fstatfs  158
+#define TARGET_FREEBSD_NR_lgetfh    160
+#define TARGET_FREEBSD_NR_getfh 161
+#define TARGET_FREEBSD_NR_freebsd4_getdomainname    162
+#define TARGET_FREEBSD_NR_freebsd4_setdomainname    163
+#define TARGET_FREEBSD_NR_freebsd4_uname    164
+#define TARGET_FREEBSD_NR_sysarch   165
+#define TARGET_FREEBSD_NR_rtprio    166
+#define TARGET_FREEBSD_NR_semsys    169
+#define TARGET_FREEBSD_NR_msgsys    170
+#define TARGET_FREEBSD_NR_shmsys    171
+#define TARGET_FREEBSD_NR_freebsd6_pread    173
+#define TARGET_FREEBSD_NR_freebsd6_pwrite   174
+#define TARGET_FREEBSD_NR_setfib    175
+#define TARGET_FREEBSD_NR_ntp_adjtime   176
+#define TARGET_FREEBSD_NR_setgid    181
+#define TARGET_FREEBSD_NR_setegid   182
+#define TARGET_FREEBSD_NR_seteuid   183
+#define TARGET_FREEBSD_NR_stat  188
+#define TARGET_FREEBSD_NR_fstat 189
+#define TARGET_FREEBSD_NR_lstat 190
+#define TARGET_FREEBSD_NR_pathconf  191
+#define TARGET_FREEBSD_NR_fpathconf 192
+#define TARGET_FREEBSD_NR_getrlimit 194
+#define TARGET_FREEBSD_NR_setrlimit 195
+#define TARGET_FREEBSD_NR_getdirentries 196
+#define TARGET_FREEBSD_NR_freebsd6_mmap 197
+#define TARGET_FREEBSD_NR___syscall 198
+#define TARGET_FREEBSD_NR_freebsd6_lseek    199
+#define TARGET_FREEBSD_NR_freebsd6_truncate 200
+#define TARGET_FREEBSD_NR_freebsd6_ftruncate    201
+#define TARGET_FREEBSD_NR___sysctl  202
+#define TARGET_FREEBSD_NR_mlock 203
+#define TARGET_FREEBSD_NR_munlock   204
+#define TARGET_FREEBSD_NR_undelete  205
+#define TARGET_FREEBSD_NR_futimes   206
+#define TARGET_FREEBSD_NR_getpgid   207
+#define TARGET_FREEBSD_NR_poll  209
+#define TARGET_FREEBSD_NR_freebsd7___semctl 220
+#define TARGET_FREEBSD_NR_semget    221
+#define TARGET_FREEBSD_NR_semop 222
+#define TARGET_FREEBSD_NR_freebsd7_msgctl   224
+#define TARGET_FREEBSD_NR_msgget    225
+#define TARGET_FREEBSD_NR_msgsnd    226
+#define TARGET_FREEBSD_NR_msgrcv    227
+#define TARGET_FREEBSD_NR_shmat 228
+#define TARGET_FREEBSD_NR_freebsd7_shmctl   229
+#define TARGET_FREEBSD_NR_shmdt 230
+#define TARGET_FREEBSD_NR_shmget    231
+#define TARGET_FREEBSD_NR_clock_gettime 232
+#define TARGET_FREEBSD_NR_clock_settime 233
+#define TARGET_FREEBSD_NR_clock_getres  234
+#define TARGET_FREEBSD_NR_ktimer_create 235
+#define TARGET_FREEBSD_NR_ktimer_delete 236
+#define TARGET_FREEBSD_NR_ktimer_settime    237
+#define TARGET_FREEBSD_NR_ktimer_gettime    238
+#define TARGET_FREEBSD_NR_ktimer_getoverrun 239
+#define TARGET_FREEBSD_NR_nanosleep 240
+#define TARGET_FREEBSD_NR_ntp_gettime   248
+#define TARGET_FREEBSD_NR_minherit  250
+#define TARGET_FREEBSD_NR_rfork 251
+#define TARGET_FREEBSD_NR_openbsd_poll  252
+#define TARGET_FREEBSD_NR_issetugid 253
+#define TARGET_FREEBSD_NR_lchown    254
+#define TARGET_FREEBSD_NR_aio_read  255
+#define TARGET_FREEBSD_NR_aio_write 256
+#define TARGET_FREEBSD_NR_lio_listio    257
+#define TARGET_FREEBSD_NR_getdents  272
+#define TARGET_FREEBSD_NR_lchmod    274
+#define TARGET_FREEBSD_NR_netbsd_lchown 275
+#define TARGET_FREEBSD_NR_lutimes   276
+#define TARGET_FREEBSD_NR_netbsd_msync  277
+#define TARGET_FREEBSD_NR_nstat 278
+#define TARGET_FREEBSD_NR_nfstat    279
+#define TARGET_FREEBSD_NR_nlstat    280
+#define TARGET_FREEBSD_NR_preadv    289
+#define TARGET_FREEBSD_NR_pwritev   290
+#define TARGET_FREEBSD_NR_freebsd4_fhstatfs 297
+#define TARGET_FREEBSD_NR_fhopen    298
+#define TARGET_FREEBSD_NR_fhstat    299
+#define TARGET_FREEBSD_NR_modnext   300
+#define TARGET_FREEBSD_NR_modstat   301
+#define TARGET_FREEBSD_NR_modfnext  302
+#define TARGET_FREEBSD_NR_modfind   303
+#define TARGET_FREEBSD_NR_kldload   304
+#define TARGET_FREEBSD_NR_kldunload 305
+#define TARGET_FREEBSD_NR_kldfind   306
+#define TARGET_FREEBSD_NR_kldnext   307
+#define TARGET_FREEBSD_NR_kldstat   308
+#define TARGET_FREEBSD_NR_kldfirstmod   309
+#define TARGET_FREEBSD_NR_getsid    310
+#define TARGET_FREEBSD_NR_setresuid 311
+#define TARGET_FREEBSD_NR_setresgid 312
+                /* 313 is obsolete signanosleep */
+#define TARGET_FREEBSD_NR_aio_return    314
+#define TARGET_FREEBSD_NR_aio_suspend   315
+#define TARGET_FREEBSD_NR_aio_cancel    316
+#define TARGET_FREEBSD_NR_aio_error 317
+#define TARGET_FREEBSD_NR_oaio_read 318
+#define TARGET_FREEBSD_NR_oaio_write    319
+#define TARGET_FREEBSD_NR_olio_listio   320
+#define TARGET_FREEBSD_NR_yield 321
+                /* 322 is obsolete thr_sleep */
+                /* 323 is obsolete thr_wakeup */
+#define TARGET_FREEBSD_NR_mlockall  324
+#define TARGET_FREEBSD_NR_munlockall    325
+#define TARGET_FREEBSD_NR___getcwd  326
+#define TARGET_FREEBSD_NR_sched_setparam    327
+#define TARGET_FREEBSD_NR_sched_getparam    328
+#define TARGET_FREEBSD_NR_sched_setscheduler    329
+#define TARGET_FREEBSD_NR_sched_getscheduler    330
+#define TARGET_FREEBSD_NR_sched_yield   331
+#define TARGET_FREEBSD_NR_sched_get_priority_max    332
+#define TARGET_FREEBSD_NR_sched_get_priority_min    333
+#define TARGET_FREEBSD_NR_sched_rr_get_interval 334
+#define TARGET_FREEBSD_NR_utrace    335
+#define TARGET_FREEBSD_NR_freebsd4_sendfile 336
+#define TARGET_FREEBSD_NR_kldsym    337
+#define TARGET_FREEBSD_NR_jail  338
+#define TARGET_FREEBSD_NR_nnpfs_syscall 339
+#define TARGET_FREEBSD_NR_sigprocmask   340
+#define TARGET_FREEBSD_NR_sigsuspend    341
+#define TARGET_FREEBSD_NR_freebsd4_sigaction    342
+#define TARGET_FREEBSD_NR_sigpending    343
+#define TARGET_FREEBSD_NR_freebsd4_sigreturn    344
+#define TARGET_FREEBSD_NR_sigtimedwait  345
+#define TARGET_FREEBSD_NR_sigwaitinfo   346
+#define TARGET_FREEBSD_NR___acl_get_file    347
+#define TARGET_FREEBSD_NR___acl_set_file    348
+#define TARGET_FREEBSD_NR___acl_get_fd  349
+#define TARGET_FREEBSD_NR___acl_set_fd  350
+#define TARGET_FREEBSD_NR___acl_delete_file 351
+#define TARGET_FREEBSD_NR___acl_delete_fd   352
+#define TARGET_FREEBSD_NR___acl_aclcheck_file   353
+#define TARGET_FREEBSD_NR___acl_aclcheck_fd 354
+#define TARGET_FREEBSD_NR_extattrctl    355
+#define TARGET_FREEBSD_NR_extattr_set_file  356
+#define TARGET_FREEBSD_NR_extattr_get_file  357
+#define TARGET_FREEBSD_NR_extattr_delete_file   358
+#define TARGET_FREEBSD_NR_aio_waitcomplete  359
+#define TARGET_FREEBSD_NR_getresuid 360
+#define TARGET_FREEBSD_NR_getresgid 361
+#define TARGET_FREEBSD_NR_kqueue    362
+#define TARGET_FREEBSD_NR_kevent    363
+#define TARGET_FREEBSD_NR_extattr_set_fd    371
+#define TARGET_FREEBSD_NR_extattr_get_fd    372
+#define TARGET_FREEBSD_NR_extattr_delete_fd 373
+#define TARGET_FREEBSD_NR___setugid 374
+#define TARGET_FREEBSD_NR_eaccess   376
+#define TARGET_FREEBSD_NR_afs3_syscall  377
+#define TARGET_FREEBSD_NR_nmount    378
+#define TARGET_FREEBSD_NR___mac_get_proc    384
+#define TARGET_FREEBSD_NR___mac_set_proc    385
+#define TARGET_FREEBSD_NR___mac_get_fd  386
+#define TARGET_FREEBSD_NR___mac_get_file    387
+#define TARGET_FREEBSD_NR___mac_set_fd  388
+#define TARGET_FREEBSD_NR___mac_set_file    389
+#define TARGET_FREEBSD_NR_kenv  390
+#define TARGET_FREEBSD_NR_lchflags  391
+#define TARGET_FREEBSD_NR_uuidgen   392
+#define TARGET_FREEBSD_NR_sendfile  393
+#define TARGET_FREEBSD_NR_mac_syscall   394
+#define TARGET_FREEBSD_NR_getfsstat 395
+#define TARGET_FREEBSD_NR_statfs    396
+#define TARGET_FREEBSD_NR_fstatfs   397
+#define TARGET_FREEBSD_NR_fhstatfs  398
+#define TARGET_FREEBSD_NR_ksem_close    400
+#define TARGET_FREEBSD_NR_ksem_post 401
+#define TARGET_FREEBSD_NR_ksem_wait 402
+#define TARGET_FREEBSD_NR_ksem_trywait  403
+#define TARGET_FREEBSD_NR_ksem_init 404
+#define TARGET_FREEBSD_NR_ksem_open 405
+#define TARGET_FREEBSD_NR_ksem_unlink   406
+#define TARGET_FREEBSD_NR_ksem_getvalue 407
+#define TARGET_FREEBSD_NR_ksem_destroy  408
+#define TARGET_FREEBSD_NR___mac_get_pid 409
+#define TARGET_FREEBSD_NR___mac_get_link    410
+#define TARGET_FREEBSD_NR___mac_set_link    411
+#define TARGET_FREEBSD_NR_extattr_set_link  412
+#define TARGET_FREEBSD_NR_extattr_get_link  413
+#define TARGET_FREEBSD_NR_extattr_delete_link   414
+#define TARGET_FREEBSD_NR___mac_execve  415
+#define TARGET_FREEBSD_NR_sigaction 416
+#define TARGET_FREEBSD_NR_sigreturn 417
+#define TARGET_FREEBSD_NR_getcontext    421
+#define TARGET_FREEBSD_NR_setcontext    422
+#define TARGET_FREEBSD_NR_swapcontext   423
+#define TARGET_FREEBSD_NR_swapoff   424
+#define TARGET_FREEBSD_NR___acl_get_link    425
+#define TARGET_FREEBSD_NR___acl_set_link    426
+#define TARGET_FREEBSD_NR___acl_delete_link 427
+#define TARGET_FREEBSD_NR___acl_aclcheck_link   428
+#define TARGET_FREEBSD_NR_sigwait   429
+#define TARGET_FREEBSD_NR_thr_create    430
+#define TARGET_FREEBSD_NR_thr_exit  431
+#define TARGET_FREEBSD_NR_thr_self  432
+#define TARGET_FREEBSD_NR_thr_kill  433
+#define TARGET_FREEBSD_NR__umtx_lock    434
+#define TARGET_FREEBSD_NR__umtx_unlock  435
+#define TARGET_FREEBSD_NR_jail_attach   436
+#define TARGET_FREEBSD_NR_extattr_list_fd   437
+#define TARGET_FREEBSD_NR_extattr_list_file 438
+#define TARGET_FREEBSD_NR_extattr_list_link 439
+#define TARGET_FREEBSD_NR_ksem_timedwait    441
+#define TARGET_FREEBSD_NR_thr_suspend   442
+#define TARGET_FREEBSD_NR_thr_wake  443
+#define TARGET_FREEBSD_NR_kldunloadf    444
+#define TARGET_FREEBSD_NR_audit 445
+#define TARGET_FREEBSD_NR_auditon   446
+#define TARGET_FREEBSD_NR_getauid   447
+#define TARGET_FREEBSD_NR_setauid   448
+#define TARGET_FREEBSD_NR_getaudit  449
+#define TARGET_FREEBSD_NR_setaudit  450
+#define TARGET_FREEBSD_NR_getaudit_addr 451
+#define TARGET_FREEBSD_NR_setaudit_addr 452
+#define TARGET_FREEBSD_NR_auditctl  453
+#define TARGET_FREEBSD_NR__umtx_op  454
+#define TARGET_FREEBSD_NR_thr_new   455
+#define TARGET_FREEBSD_NR_sigqueue  456
+#define TARGET_FREEBSD_NR_kmq_open  457
+#define TARGET_FREEBSD_NR_kmq_setattr   458
+#define TARGET_FREEBSD_NR_kmq_timedreceive  459
+#define TARGET_FREEBSD_NR_kmq_timedsend 460
+#define TARGET_FREEBSD_NR_kmq_notify    461
+#define TARGET_FREEBSD_NR_kmq_unlink    462
+#define TARGET_FREEBSD_NR_abort2    463
+#define TARGET_FREEBSD_NR_thr_set_name  464
+#define TARGET_FREEBSD_NR_aio_fsync 465
+#define TARGET_FREEBSD_NR_rtprio_thread 466
+#define TARGET_FREEBSD_NR_sctp_peeloff  471
+#define TARGET_FREEBSD_NR_sctp_generic_sendmsg  472
+#define TARGET_FREEBSD_NR_sctp_generic_sendmsg_iov  473
+#define TARGET_FREEBSD_NR_sctp_generic_recvmsg  474
+#define TARGET_FREEBSD_NR_pread 475
+#define TARGET_FREEBSD_NR_pwrite    476
+#define TARGET_FREEBSD_NR_mmap  477
+#define TARGET_FREEBSD_NR_lseek 478
+#define TARGET_FREEBSD_NR_truncate  479
+#define TARGET_FREEBSD_NR_ftruncate 480
+#define TARGET_FREEBSD_NR_thr_kill2 481
+#define TARGET_FREEBSD_NR_shm_open  482
+#define TARGET_FREEBSD_NR_shm_unlink    483
+#define TARGET_FREEBSD_NR_cpuset    484
+#define TARGET_FREEBSD_NR_cpuset_setid  485
+#define TARGET_FREEBSD_NR_cpuset_getid  486
+#define TARGET_FREEBSD_NR_cpuset_getaffinity    487
+#define TARGET_FREEBSD_NR_cpuset_setaffinity    488
+#define TARGET_FREEBSD_NR_faccessat 489
+#define TARGET_FREEBSD_NR_fchmodat  490
+#define TARGET_FREEBSD_NR_fchownat  491
+#define TARGET_FREEBSD_NR_fexecve   492
+#define TARGET_FREEBSD_NR_fstatat   493
+#define TARGET_FREEBSD_NR_futimesat 494
+#define TARGET_FREEBSD_NR_linkat    495
+#define TARGET_FREEBSD_NR_mkdirat   496
+#define TARGET_FREEBSD_NR_mkfifoat  497
+#define TARGET_FREEBSD_NR_mknodat   498
+#define TARGET_FREEBSD_NR_openat    499
+#define TARGET_FREEBSD_NR_readlinkat    500
+#define TARGET_FREEBSD_NR_renameat  501
+#define TARGET_FREEBSD_NR_symlinkat 502
+#define TARGET_FREEBSD_NR_unlinkat  503
+#define TARGET_FREEBSD_NR_posix_openpt  504
+#define TARGET_FREEBSD_NR_gssd_syscall  505
+#define TARGET_FREEBSD_NR_jail_get  506
+#define TARGET_FREEBSD_NR_jail_set  507
+#define TARGET_FREEBSD_NR_jail_remove   508
+#define TARGET_FREEBSD_NR_closefrom 509
+#define TARGET_FREEBSD_NR___semctl  510
+#define TARGET_FREEBSD_NR_msgctl    511
+#define TARGET_FREEBSD_NR_shmctl    512
+#define TARGET_FREEBSD_NR_lpathconf 513
+#define TARGET_FREEBSD_NR_cap_new   514
+#define TARGET_FREEBSD_NR_cap_getrights 515
+#define TARGET_FREEBSD_NR_cap_enter 516
+#define TARGET_FREEBSD_NR_cap_getmode   517
+#define TARGET_FREEBSD_NR_pdfork    518
+#define TARGET_FREEBSD_NR_pdkill    519
+#define TARGET_FREEBSD_NR_pdgetpid  520
+#define TARGET_FREEBSD_NR_pselect   522
+#define TARGET_FREEBSD_NR_getloginclass 523
+#define TARGET_FREEBSD_NR_setloginclass 524
+#define TARGET_FREEBSD_NR_rctl_get_racct    525
+#define TARGET_FREEBSD_NR_rctl_get_rules    526
+#define TARGET_FREEBSD_NR_rctl_get_limits   527
+#define TARGET_FREEBSD_NR_rctl_add_rule 528
+#define TARGET_FREEBSD_NR_rctl_remove_rule  529
+#define TARGET_FREEBSD_NR_posix_fallocate   530
+#define TARGET_FREEBSD_NR_posix_fadvise 531
+#define TARGET_FREEBSD_NR_MAXSYSCALL    532
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 02/18] bsd-user: add HOST_ABI_DIR for the various *BSD dependent code.
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 01/18] bsd-user: refresh freebsd system call numbers Stacey Son
@ 2013-10-16 14:36 ` Stacey Son
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 03/18] bsd-user: move OS/arch dependent code for strace into separate directories Stacey Son
                   ` (37 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds HOST_ABI_DIR (similar to TARGET_ABI_DIR) so the various
BSD OS dependent code can be seperated into its own directories rather
than using #ifdef's.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 Makefile.target |    3 ++-
 configure       |   11 +++++++++++
 2 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/Makefile.target b/Makefile.target
index 9a49852..7da81dc 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -103,7 +103,8 @@ endif #CONFIG_LINUX_USER
 
 ifdef CONFIG_BSD_USER
 
-QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR)
+QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR) \
+			 -I$(SRC_PATH)/bsd-user/$(HOST_ABI_DIR)
 
 obj-y += bsd-user/
 obj-y += gdbstub.o user-exec.o
diff --git a/configure b/configure
index 23dbaaf..fb81859 100755
--- a/configure
+++ b/configure
@@ -449,6 +449,9 @@ fi
 
 # OS specific
 
+# host *BSD for user mode
+HOST_ABI_DIR=""
+
 case $targetos in
 CYGWIN*)
   mingw32="yes"
@@ -473,12 +476,14 @@ FreeBSD)
   audio_possible_drivers="oss sdl esd pa"
   # needed for kinfo_getvmmap(3) in libutil.h
   LIBS="-lutil $LIBS"
+  HOST_ABI_DIR="freebsd"
 ;;
 DragonFly)
   bsd="yes"
   make="${MAKE-gmake}"
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd pa"
+  HOST_ABI_DIR="dragonfly"
 ;;
 NetBSD)
   bsd="yes"
@@ -486,12 +491,14 @@ NetBSD)
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd"
   oss_lib="-lossaudio"
+  HOST_ABI_DIR="netbsd"
 ;;
 OpenBSD)
   bsd="yes"
   make="${MAKE-gmake}"
   audio_drv_list="sdl"
   audio_possible_drivers="sdl esd"
+  HOST_ABI_DIR="openbsd"
 ;;
 Darwin)
   bsd="yes"
@@ -510,6 +517,7 @@ Darwin)
   # Disable attempts to use ObjectiveC features in os/object.h since they
   # won't work when we're compiling with gcc as a C compiler.
   QEMU_CFLAGS="-DOS_OBJECT_USE_OBJC=0 $QEMU_CFLAGS"
+  HOST_ABI_DIR="darwin"
 ;;
 SunOS)
   solaris="yes"
@@ -4475,6 +4483,9 @@ if [ "$TARGET_ABI_DIR" = "" ]; then
   TARGET_ABI_DIR=$TARGET_ARCH
 fi
 echo "TARGET_ABI_DIR=$TARGET_ABI_DIR" >> $config_target_mak
+if [ "$HOST_ABI_DIR" != "" ]; then
+    echo "HOST_ABI_DIR=$HOST_ABI_DIR" >> $config_target_mak
+fi
 case "$target_name" in
   i386|x86_64)
     if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 03/18] bsd-user: move OS/arch dependent code for strace into separate directories
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 01/18] bsd-user: refresh freebsd system call numbers Stacey Son
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 02/18] bsd-user: add HOST_ABI_DIR for the various *BSD dependent code Stacey Son
@ 2013-10-16 14:36 ` Stacey Son
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 04/18] bsd-user: move target arch and host OS dependent code out of main.c Stacey Son
                   ` (36 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change moves host OS and arch dependent code for the sysarch system
call related to the -strace functionality into the appropriate HOST_ABI_DIR
and TARGET_ABI_DIR directories.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/arm/syscall.h                 |   36 +++++++
 bsd-user/arm/target_arch_sysarch.h     |   81 +++++++++++++++
 bsd-user/freebsd/os-strace.h           |   29 +++++
 bsd-user/freebsd/strace.list           |   76 +++++++++++++--
 bsd-user/i386/syscall.h                |   23 ++++
 bsd-user/i386/target_arch_sysarch.h    |   78 ++++++++++++++
 bsd-user/mips/syscall.h                |   52 ++++++++++
 bsd-user/mips/target_arch_sysarch.h    |   69 +++++++++++++
 bsd-user/mips64/syscall.h              |   53 ++++++++++
 bsd-user/mips64/target_arch_sysarch.h  |   69 +++++++++++++
 bsd-user/netbsd/os-strace.h            |    1 +
 bsd-user/openbsd/os-strace.h           |    1 +
 bsd-user/qemu.h                        |   26 +++++
 bsd-user/sparc/syscall.h               |   29 +++++-
 bsd-user/sparc/target_arch_sysarch.h   |   52 ++++++++++
 bsd-user/sparc64/syscall.h             |   28 +++++-
 bsd-user/sparc64/target_arch_sysarch.h |   52 ++++++++++
 bsd-user/strace.c                      |  175 +++++++++++++++++++++----------
 bsd-user/x86_64/syscall.h              |   26 +++++-
 bsd-user/x86_64/target_arch_sysarch.h  |   76 ++++++++++++++
 20 files changed, 965 insertions(+), 67 deletions(-)
 create mode 100644 bsd-user/arm/syscall.h
 create mode 100644 bsd-user/arm/target_arch_sysarch.h
 create mode 100644 bsd-user/freebsd/os-strace.h
 create mode 100644 bsd-user/i386/target_arch_sysarch.h
 create mode 100644 bsd-user/mips/syscall.h
 create mode 100644 bsd-user/mips/target_arch_sysarch.h
 create mode 100644 bsd-user/mips64/syscall.h
 create mode 100644 bsd-user/mips64/target_arch_sysarch.h
 create mode 100644 bsd-user/netbsd/os-strace.h
 create mode 100644 bsd-user/openbsd/os-strace.h
 create mode 100644 bsd-user/sparc/target_arch_sysarch.h
 create mode 100644 bsd-user/sparc64/target_arch_sysarch.h
 create mode 100644 bsd-user/x86_64/target_arch_sysarch.h

diff --git a/bsd-user/arm/syscall.h b/bsd-user/arm/syscall.h
new file mode 100644
index 0000000..bc3d6e6
--- /dev/null
+++ b/bsd-user/arm/syscall.h
@@ -0,0 +1,36 @@
+#ifndef __ARCH_SYSCALL_H_
+#define __ARCH_SYSCALL_H_
+
+struct target_pt_regs {
+    abi_long uregs[17];
+};
+
+#define ARM_cpsr    uregs[16]
+#define ARM_pc      uregs[15]
+#define ARM_lr      uregs[14]
+#define ARM_sp      uregs[13]
+#define ARM_ip      uregs[12]
+#define ARM_fp      uregs[11]
+#define ARM_r10     uregs[10]
+#define ARM_r9      uregs[9]
+#define ARM_r8      uregs[8]
+#define ARM_r7      uregs[7]
+#define ARM_r6      uregs[6]
+#define ARM_r5      uregs[5]
+#define ARM_r4      uregs[4]
+#define ARM_r3      uregs[3]
+#define ARM_r2      uregs[2]
+#define ARM_r1      uregs[1]
+#define ARM_r0      uregs[0]
+
+#define ARM_SYSCALL_BASE    0 /* XXX: FreeBSD only */
+
+#define TARGET_FREEBSD_ARM_SYNC_ICACHE      0
+#define TARGET_FREEBSD_ARM_DRAIN_WRITEBUF   1
+#define TARGET_FREEBSD_ARM_SET_TP       2
+#define TARGET_FREEBSD_ARM_GET_TP       3
+
+#define TARGET_HW_MACHINE       "arm"
+#define TARGET_HW_MACHINE_ARCH  "armv6"
+
+#endif /* !__ARCH_SYSCALL_H_ */
diff --git a/bsd-user/arm/target_arch_sysarch.h b/bsd-user/arm/target_arch_sysarch.h
new file mode 100644
index 0000000..0baa54a
--- /dev/null
+++ b/bsd-user/arm/target_arch_sysarch.h
@@ -0,0 +1,81 @@
+/*
+ *  arm sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+#include "target_arch.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUARMState *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_FREEBSD_ARM_SYNC_ICACHE:
+    case TARGET_FREEBSD_ARM_DRAIN_WRITEBUF:
+        break;
+
+    case TARGET_FREEBSD_ARM_SET_TP:
+        target_cpu_set_tls(env, parms);
+        break;
+
+    case TARGET_FREEBSD_ARM_GET_TP:
+        /* XXX Need a cpu_get_tls() */
+        if (put_user(target_cpu_get_tls(env), parms, abi_ulong)) {
+            ret = -TARGET_EFAULT;
+        }
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    switch (arg1) {
+    case TARGET_FREEBSD_ARM_SYNC_ICACHE:
+        gemu_log("%s(ARM_SYNC_ICACHE, ...)", name->name);
+        break;
+
+    case TARGET_FREEBSD_ARM_DRAIN_WRITEBUF:
+        gemu_log("%s(ARM_DRAIN_WRITEBUF, ...)", name->name);
+        break;
+
+    case TARGET_FREEBSD_ARM_SET_TP:
+        gemu_log("%s(ARM_SET_TP, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    case TARGET_FREEBSD_ARM_GET_TP:
+        gemu_log("%s(ARM_GET_TP, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    default:
+        gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
+    }
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/freebsd/os-strace.h b/bsd-user/freebsd/os-strace.h
new file mode 100644
index 0000000..a222f09
--- /dev/null
+++ b/bsd-user/freebsd/os-strace.h
@@ -0,0 +1,29 @@
+/*
+ *  FreeBSD dependent strace print functions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "target_arch_sysarch.h"    /* architecture dependent functions */
+
+
+static inline void do_os_print_sysarch(const struct syscallname *name,
+        abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4,
+        abi_long arg5, abi_long arg6)
+{
+    /* This is arch dependent */
+    do_freebsd_arch_print_sysarch(name, arg1, arg2, arg3, arg4, arg5, arg6);
+}
diff --git a/bsd-user/freebsd/strace.list b/bsd-user/freebsd/strace.list
index 1edf412..ae2a4a3 100644
--- a/bsd-user/freebsd/strace.list
+++ b/bsd-user/freebsd/strace.list
@@ -1,7 +1,38 @@
+/*
+ *  FreeBSD strace list
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+{ TARGET_FREEBSD_NR___acl_aclcheck_fd, "__acl_get_fd", "%s(%d, %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_aclcheck_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_aclcheck_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_delete_fd, "__acl_delete_fd", "%s(%d, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_delete_file, "__acl_delete_file", "%s(\"%s\", %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_delete_link, "__acl_delete_link", "%s(\"%s\", %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_get_fd, "__acl_get_fd", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_get_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_get_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_set_fd, "__acl_get_fd", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_set_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_set_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL },
 { TARGET_FREEBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR___semctl, "__semctl", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR___syscall, "__syscall", NULL, NULL, NULL },
-{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, print_sysctl, NULL },
+{ TARGET_FREEBSD_NR__umtx_op, "_umtx_op", "%s(%#x, %d, %d, %#x, %#x)", NULL, NULL },
 { TARGET_FREEBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL },
 { TARGET_FREEBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL },
 { TARGET_FREEBSD_NR_acct, "acct", NULL, NULL, NULL },
@@ -20,24 +51,41 @@
 { TARGET_FREEBSD_NR_connect, "connect", "%s(%d,%#x,%d)", NULL, NULL },
 { TARGET_FREEBSD_NR_dup, "dup", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_dup2, "dup2", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_eaccess, "eaccess", "%s(%s,%#x)", NULL, NULL },
 { TARGET_FREEBSD_NR_execve, "execve", NULL, print_execve, NULL },
 { TARGET_FREEBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattrctl, "extattrctl", "%s(\"%s\", %d, \"%s\", %d, \"%s\"", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_delete_fd, "extattr_delete_fd", "%s(%d, %d, \"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_delete_file, "extattr_delete_file", "%s(\"%s\", %d, \"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_delete_link, "extattr_delete_link", "%s(\"%s\", %d, \"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_get_fd, "extattr_get_fd", "%s(%d, %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_get_file, "extattr_get_file", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_get_file, "extattr_get_link", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_list_fd, "extattr_list_fd", "%s(%d, %d, %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_list_file, "extattr_list_file", "%s(\"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_list_link, "extattr_list_link", "%s(\"%s\", %d, %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_set_fd, "extattr_set_fd", "%s(%d, %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_set_file, "extattr_set_file", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_set_link, "extattr_set_link", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL },
 { TARGET_FREEBSD_NR_fchdir, "fchdir", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fchflags, "fchflags", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL },
-{ TARGET_FREEBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fchown, "fchown", "%s(%d,%d,%d)", NULL, NULL },
 { TARGET_FREEBSD_NR_fcntl, "fcntl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_fexecve, "fexecve", NULL, print_execve, NULL },
 { TARGET_FREEBSD_NR_fhopen, "fhopen", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fhstat, "fhstat", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fhstatfs, "fhstatfs", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_flock, "flock", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fork, "fork", "%s()", NULL, NULL },
 { TARGET_FREEBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL },
-{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%p)", NULL, NULL },
-{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%p)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fstatat, "fstatat", "%s(%d,\"%s\", %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%#x)", NULL, NULL },
 { TARGET_FREEBSD_NR_fsync, "fsync", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getcontext, "getcontext", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_freebsd6_mmap, "freebsd6_mmap", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getegid, "getegid", "%s()", NULL, NULL },
@@ -63,7 +111,7 @@
 { TARGET_FREEBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getuid, "getuid", "%s()", NULL, NULL },
-{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, print_ioctl, NULL },
 { TARGET_FREEBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL },
 { TARGET_FREEBSD_NR_kevent, "kevent", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_kill, "kill", NULL, NULL, NULL },
@@ -72,6 +120,7 @@
 { TARGET_FREEBSD_NR_lchown, "lchown", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL },
 { TARGET_FREEBSD_NR_listen, "listen", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_lpathconf, "lpathconf", "%s(\"%s\", %d)", NULL, NULL },
 { TARGET_FREEBSD_NR_lseek, "lseek", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_lstat, "lstat", "%s(\"%s\",%p)", NULL, NULL },
 { TARGET_FREEBSD_NR_madvise, "madvise", NULL, NULL, NULL },
@@ -96,7 +145,9 @@
 { TARGET_FREEBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL },
+{ TARGET_FREEBSD_NR_openat, "openat", "%s(%d, \"%s\",%#x,%#o)", NULL, NULL },
 { TARGET_FREEBSD_NR_pathconf, "pathconf", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_pathconf, "pathconf", "%s(\"%s\", %d)", NULL, NULL },
 { TARGET_FREEBSD_NR_pipe, "pipe", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_poll, "poll", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_pread, "pread", NULL, NULL, NULL },
@@ -116,6 +167,7 @@
 { TARGET_FREEBSD_NR_revoke, "revoke", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_rfork, "rfork", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_rmdir, "rmdir", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_rtprio_thread, "rtprio_thread", "%s(%d, %d, %p)", NULL, NULL },
 { TARGET_FREEBSD_NR_sbrk, "sbrk", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_select, "select", NULL, NULL, NULL },
@@ -123,6 +175,7 @@
 { TARGET_FREEBSD_NR_semop, "semop", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sendto, "sendto", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setcontext, "setcontext", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_setegid, "setegid", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_seteuid, "seteuid", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_setgid, "setgid", NULL, NULL, NULL },
@@ -151,15 +204,24 @@
 { TARGET_FREEBSD_NR_sigprocmask, "sigprocmask", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sigreturn, "sigreturn", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sigsuspend, "sigsuspend", NULL, NULL, NULL },
-{ TARGET_FREEBSD_NR_socket, "socket", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_socket, "socket", "%s(%d,%d,%d)", NULL, NULL },
 { TARGET_FREEBSD_NR_socketpair, "socketpair", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sstk, "sstk", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_stat, "stat", "%s(\"%s\",%p)", NULL, NULL },
 { TARGET_FREEBSD_NR_statfs, "statfs", "%s(\"%s\",%p)", NULL, NULL },
 { TARGET_FREEBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL },
 { TARGET_FREEBSD_NR_sync, "sync", NULL, NULL, NULL },
-{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, print_sysarch, NULL },
 { TARGET_FREEBSD_NR_syscall, "syscall", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_create, "thr_create", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_exit, "thr_exit", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_kill, "thr_kill", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_kill2, "thr_kill2", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_new, "thr_new", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_self, "thr_self", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_set_name, "thr_set_name", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_suspend, "thr_suspend", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_wake, "thr_wake", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_truncate, "truncate", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL },
 { TARGET_FREEBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL },
diff --git a/bsd-user/i386/syscall.h b/bsd-user/i386/syscall.h
index 9b34c61..52de302 100644
--- a/bsd-user/i386/syscall.h
+++ b/bsd-user/i386/syscall.h
@@ -1,3 +1,23 @@
+/*
+ *  i386 system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _I386_SYSCALL_H_
+#define _I386_SYSCALL_H_
+
 /* default linux values for the selectors */
 #define __USER_CS	(0x23)
 #define __USER_DS	(0x2B)
@@ -158,4 +178,7 @@ struct target_vm86plus_struct {
 
 
 #define UNAME_MACHINE "i386"
+#define TARGET_HW_MACHINE UNAME_MACHINE
+#define TARGET_HW_MACHINE_ARCH UNAME_MACHINE
 
+#endif /* ! _I386_SYSCALL_H_ */
diff --git a/bsd-user/i386/target_arch_sysarch.h b/bsd-user/i386/target_arch_sysarch.h
new file mode 100644
index 0000000..4fa6698
--- /dev/null
+++ b/bsd-user/i386/target_arch_sysarch.h
@@ -0,0 +1,78 @@
+/*
+ *  i386 sysarch system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUX86State *env, int op,
+        abi_ulong parms)
+{
+    abi_long ret = 0;
+    abi_ulong val;
+    int idx;
+
+    switch (op) {
+    case TARGET_FREEBSD_I386_SET_GSBASE:
+    case TARGET_FREEBSD_I386_SET_FSBASE:
+        if (op == TARGET_FREEBSD_I386_SET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        if (get_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        cpu_x86_load_seg(env, idx, 0);
+        env->segs[idx].base = val;
+        break;
+
+    case TARGET_FREEBSD_I386_GET_GSBASE:
+    case TARGET_FREEBSD_I386_GET_FSBASE:
+        if (op == TARGET_FREEBSD_I386_GET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        val = env->segs[idx].base;
+        if (put_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    /* XXX handle the others... */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", "
+        TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4);
+}
+
+#endif /* !__ARCH_SYSARCH_H_ */
+
diff --git a/bsd-user/mips/syscall.h b/bsd-user/mips/syscall.h
new file mode 100644
index 0000000..aacc6dd
--- /dev/null
+++ b/bsd-user/mips/syscall.h
@@ -0,0 +1,52 @@
+/*
+ *  mips system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _MIPS_SYSCALL_H_
+#define _MIPS_SYSCALL_H_
+
+/*
+ * struct target_pt_regs defines the way the registers are stored on the stack
+ * during a system call.
+ */
+
+struct target_pt_regs {
+    /* Saved main processor registers. */
+    abi_ulong regs[32];
+
+    /* Saved special registers. */
+    abi_ulong cp0_status;
+    abi_ulong lo;
+    abi_ulong hi;
+    abi_ulong cp0_badvaddr;
+    abi_ulong cp0_cause;
+    abi_ulong cp0_epc;
+};
+
+#if defined(TARGET_WORDS_BIGENDIAN)
+#define UNAME_MACHINE "mips"
+#else
+#define UNAME_MACHINE "mipsel"
+#endif
+
+#define TARGET_HW_MACHINE       "mips"
+#define TARGET_HW_MACHINE_ARCH   UNAME_MACHINE
+
+/* sysarch() commands */
+#define TARGET_MIPS_SET_TLS     1
+#define TARGET_MIPS_GET_TLS     2
+
+#endif /* !_MIPS_SYSCALL_H_ */
diff --git a/bsd-user/mips/target_arch_sysarch.h b/bsd-user/mips/target_arch_sysarch.h
new file mode 100644
index 0000000..d333740
--- /dev/null
+++ b/bsd-user/mips/target_arch_sysarch.h
@@ -0,0 +1,69 @@
+/*
+ *  mips sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+#include "target_arch.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUMIPSState *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_MIPS_SET_TLS:
+        target_cpu_set_tls(env, parms);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        if (put_user(target_cpu_get_tls(env), parms, abi_ulong)) {
+            ret = -TARGET_EFAULT;
+        }
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    switch (arg1) {
+    case TARGET_MIPS_SET_TLS:
+        gemu_log("%s(SET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        gemu_log("%s(GET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    default:
+        gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
+    }
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/mips64/syscall.h b/bsd-user/mips64/syscall.h
new file mode 100644
index 0000000..bf4c598
--- /dev/null
+++ b/bsd-user/mips64/syscall.h
@@ -0,0 +1,53 @@
+/*
+ *  mips64 system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _MIPS64_SYSCALL_H_
+#define _MIPS64_SYSCALL_H_
+
+/*
+ * struct target_pt_regs defines the way the registers are stored on the stack
+ * during a system call.
+ */
+
+struct target_pt_regs {
+    /* Saved main processor registers. */
+    abi_ulong regs[32];
+
+    /* Saved special registers. */
+    abi_ulong cp0_status;
+    abi_ulong lo;
+    abi_ulong hi;
+    abi_ulong cp0_badvaddr;
+    abi_ulong cp0_cause;
+    abi_ulong cp0_epc;
+};
+
+
+#if defined(TARGET_WORDS_BIGENDIAN)
+#define UNAME_MACHINE "mips64"
+#else
+#define UNAME_MACHINE "mips64el"
+#endif
+
+#define TARGET_HW_MACHINE       "mips"
+#define TARGET_HW_MACHINE_ARCH  UNAME_MACHINE
+
+/* sysarch() commands */
+#define TARGET_MIPS_SET_TLS     1
+#define TARGET_MIPS_GET_TLS     2
+
+#endif /* !_MIPS64_SYSCALL_H_ */
diff --git a/bsd-user/mips64/target_arch_sysarch.h b/bsd-user/mips64/target_arch_sysarch.h
new file mode 100644
index 0000000..95b4e78
--- /dev/null
+++ b/bsd-user/mips64/target_arch_sysarch.h
@@ -0,0 +1,69 @@
+/*
+ *  mips64 sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+#include "target_arch.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUMIPSState *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_MIPS_SET_TLS:
+        target_cpu_set_tls(env, parms);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        if (put_user(target_cpu_get_tls(env), parms, abi_ulong)) {
+            ret = -TARGET_EFAULT;
+        }
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    switch (arg1) {
+    case TARGET_MIPS_SET_TLS:
+        gemu_log("%s(SET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        gemu_log("%s(GET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    default:
+        gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
+    }
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/netbsd/os-strace.h b/bsd-user/netbsd/os-strace.h
new file mode 100644
index 0000000..70cf51d
--- /dev/null
+++ b/bsd-user/netbsd/os-strace.h
@@ -0,0 +1 @@
+/* XXX NetBSD dependent strace print functions */
diff --git a/bsd-user/openbsd/os-strace.h b/bsd-user/openbsd/os-strace.h
new file mode 100644
index 0000000..9161390
--- /dev/null
+++ b/bsd-user/openbsd/os-strace.h
@@ -0,0 +1 @@
+/* XXX OpenBSD dependent strace print functions */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index ddc74ed..b8a34c7 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -1,3 +1,19 @@
+/*
+ *  qemu bsd user mode definition
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
 #ifndef QEMU_H
 #define QEMU_H
 
@@ -149,6 +165,16 @@ void fork_end(int child);
 #include "qemu/log.h"
 
 /* strace.c */
+struct syscallname {
+    int nr;
+    const char *name;
+    const char *format;
+    void (*call)(const struct syscallname *,
+                 abi_long, abi_long, abi_long,
+                 abi_long, abi_long, abi_long);
+    void (*result)(const struct syscallname *, abi_long);
+};
+
 void
 print_freebsd_syscall(int num,
                       abi_long arg1, abi_long arg2, abi_long arg3,
diff --git a/bsd-user/sparc/syscall.h b/bsd-user/sparc/syscall.h
index 5a9bb7e..3a5b1e2 100644
--- a/bsd-user/sparc/syscall.h
+++ b/bsd-user/sparc/syscall.h
@@ -1,3 +1,23 @@
+/*
+ *  sparc dependent system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _SPARC_SYSCALL_H_
+#define _SPARC_SYSCALL_H_
+
 struct target_pt_regs {
 	abi_ulong psr;
 	abi_ulong pc;
@@ -6,4 +26,11 @@ struct target_pt_regs {
 	abi_ulong u_regs[16];
 };
 
-#define UNAME_MACHINE "sun4"
+#define UNAME_MACHINE           "sun4"
+#define TARGET_HW_MACHINE       "sparc"
+#define TARGET_HW_MACHINE_ARCH  "sparc"
+
+#define TARGET_SPARC_UTRAP_INSTALL      1
+#define TARGET_SPARC_SIGTRAMP_INSTALL   2
+
+#endif /* ! _SPARC_SYSCALL_H_ */
diff --git a/bsd-user/sparc/target_arch_sysarch.h b/bsd-user/sparc/target_arch_sysarch.h
new file mode 100644
index 0000000..454c084
--- /dev/null
+++ b/bsd-user/sparc/target_arch_sysarch.h
@@ -0,0 +1,52 @@
+/*
+ *  SPARC sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(void *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_SPARC_SIGTRAMP_INSTALL:
+        /* XXX not currently handled */
+    case TARGET_SPARC_UTRAP_INSTALL:
+        /* XXX not currently handled */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", "
+        TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4);
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/sparc64/syscall.h b/bsd-user/sparc64/syscall.h
index 81a816d..58cc38d 100644
--- a/bsd-user/sparc64/syscall.h
+++ b/bsd-user/sparc64/syscall.h
@@ -1,3 +1,22 @@
+/*
+ *  sparc64 dependent system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _SPARC64_SYSCALL_H_
+#define _SPARC64_SYSCALL_H_
 struct target_pt_regs {
 	abi_ulong u_regs[16];
 	abi_ulong tstate;
@@ -7,4 +26,11 @@ struct target_pt_regs {
 	abi_ulong fprs;
 };
 
-#define UNAME_MACHINE "sun4u"
+#define UNAME_MACHINE           "sun4u"
+#define TARGET_HW_MACHINE       "sparc"
+#define TARGET_HW_MACHINE_ARCH  "sparc64"
+
+#define TARGET_SPARC_UTRAP_INSTALL      1
+#define TARGET_SPARC_SIGTRAMP_INSTALL   2
+
+#endif /* !_SPARC64_SYSCALL_H_ */
diff --git a/bsd-user/sparc64/target_arch_sysarch.h b/bsd-user/sparc64/target_arch_sysarch.h
new file mode 100644
index 0000000..84e1339
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_sysarch.h
@@ -0,0 +1,52 @@
+/*
+ *  SPARC64 sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(void *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_SPARC_SIGTRAMP_INSTALL:
+        /* XXX not currently handled */
+    case TARGET_SPARC_UTRAP_INSTALL:
+        /* XXX not currently handled */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", "
+        TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4);
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/strace.c b/bsd-user/strace.c
index d73bbca..60aabc3 100644
--- a/bsd-user/strace.c
+++ b/bsd-user/strace.c
@@ -1,37 +1,73 @@
+/*
+ *  System call tracing and debugging
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
 #include <stdio.h>
 #include <errno.h>
 #include <sys/select.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <sys/syscall.h>
+#include <sys/ioccom.h>
+#include <ctype.h>
+
 #include "qemu.h"
 
-int do_strace=0;
+#include "os-strace.h"  /* OS dependent strace print functions */
 
-struct syscallname {
-    int nr;
-    const char *name;
-    const char *format;
-    void (*call)(const struct syscallname *,
-                 abi_long, abi_long, abi_long,
-                 abi_long, abi_long, abi_long);
-    void (*result)(const struct syscallname *, abi_long);
-};
+int do_strace;
 
 /*
  * Utility functions
  */
 
-static void
-print_execve(const struct syscallname *name,
-             abi_long arg1, abi_long arg2, abi_long arg3,
-             abi_long arg4, abi_long arg5, abi_long arg6)
+static void print_sysctl(const struct syscallname *name, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
+        abi_long arg6)
+{
+    uint32_t i;
+    int32_t *namep;
+
+    gemu_log("%s({ ", name->name);
+    namep = lock_user(VERIFY_READ, arg1, sizeof(int32_t) * arg2, 1);
+    if (namep) {
+        int32_t *p = namep;
+
+        for (i = 0; i < (uint32_t)arg2; i++) {
+            gemu_log("%d ", tswap32(*p++));
+        }
+        unlock_user(namep, arg1, 0);
+    }
+    gemu_log("}, %u, 0x" TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ", 0x"
+        TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ")",
+        (uint32_t)arg2, arg3, arg4, arg5, arg6);
+}
+
+static void print_execve(const struct syscallname *name, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
+        abi_long arg6)
 {
     abi_ulong arg_ptr_addr;
     char *s;
 
-    if (!(s = lock_user_string(arg1)))
+    s = lock_user_string(arg1);
+    if (s == NULL) {
         return;
+    }
     gemu_log("%s(\"%s\",{", name->name, s);
     unlock_user(s, arg1, 0);
 
@@ -39,29 +75,56 @@ print_execve(const struct syscallname *name,
         abi_ulong *arg_ptr, arg_addr;
 
         arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
-        if (!arg_ptr)
+        if (!arg_ptr) {
             return;
+        }
         arg_addr = tswapl(*arg_ptr);
         unlock_user(arg_ptr, arg_ptr_addr, 0);
-        if (!arg_addr)
+        if (!arg_addr) {
             break;
+        }
         if ((s = lock_user_string(arg_addr))) {
             gemu_log("\"%s\",", s);
             unlock_user(s, arg_addr, 0);
         }
     }
-
     gemu_log("NULL})");
 }
 
+static void print_ioctl(const struct syscallname *name,
+        abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4,
+        abi_long arg5, abi_long arg6)
+{
+    /* Decode the ioctl request */
+    gemu_log("%s(%d, 0x%0lx { IO%s%s GRP:0x%x('%c') CMD:%d LEN:%d }, 0x"
+            TARGET_ABI_FMT_lx ", ...)",
+            name->name,
+            (int)arg1,
+            (unsigned long)arg2,
+            arg2 & IOC_OUT ? "R" : "",
+            arg2 & IOC_IN ? "W" : "",
+            (unsigned)IOCGROUP(arg2),
+            isprint(IOCGROUP(arg2)) ? (char)IOCGROUP(arg2) : '?',
+            (int)arg2 & 0xFF,
+            (int)IOCPARM_LEN(arg2),
+            arg3);
+}
+
+static void print_sysarch(const struct syscallname *name, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
+        abi_long arg6)
+{
+    /* This is os dependent. */
+    do_os_print_sysarch(name, arg1, arg2, arg3, arg4, arg5, arg6);
+}
+
 /*
  * Variants for the return value output function
  */
 
-static void
-print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
+static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
 {
-if( ret == -1 ) {
+    if (ret == -1) {
         gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno));
     } else {
         gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
@@ -90,10 +153,9 @@ static const struct syscallname openbsd_scnames[] = {
 #include "openbsd/strace.list"
 };
 
-static void
-print_syscall(int num, const struct syscallname *scnames, unsigned int nscnames,
-              abi_long arg1, abi_long arg2, abi_long arg3,
-              abi_long arg4, abi_long arg5, abi_long arg6)
+static void print_syscall(int num, const struct syscallname *scnames,
+        unsigned int nscnames, abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5, abi_long arg6)
 {
     unsigned int i;
     const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
@@ -102,36 +164,37 @@ print_syscall(int num, const struct syscallname *scnames, unsigned int nscnames,
 
     gemu_log("%d ", getpid() );
 
-    for (i = 0; i < nscnames; i++)
+    for (i = 0; i < nscnames; i++) {
         if (scnames[i].nr == num) {
             if (scnames[i].call != NULL) {
                 scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5,
-                                arg6);
+                        arg6);
             } else {
                 /* XXX: this format system is broken because it uses
                    host types and host pointers for strings */
-                if (scnames[i].format != NULL)
+                if (scnames[i].format != NULL) {
                     format = scnames[i].format;
-                gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4,
-                         arg5, arg6);
+                }
+                gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4, arg5,
+                        arg6);
             }
             return;
         }
+    }
     gemu_log("Unknown syscall %d\n", num);
 }
 
-static void
-print_syscall_ret(int num, abi_long ret, const struct syscallname *scnames,
-                  unsigned int nscnames)
+static void print_syscall_ret(int num, abi_long ret,
+        const struct syscallname *scnames, unsigned int nscnames)
 {
     unsigned int i;
 
-    for (i = 0; i < nscnames; i++)
+    for (i = 0; i < nscnames; i++) {
         if (scnames[i].nr == num) {
             if (scnames[i].result != NULL) {
                 scnames[i].result(&scnames[i], ret);
             } else {
-                if( ret < 0 ) {
+                if (ret < 0) {
                     gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret,
                              strerror(-ret));
                 } else {
@@ -140,52 +203,50 @@ print_syscall_ret(int num, abi_long ret, const struct syscallname *scnames,
             }
             break;
         }
+    }
 }
 
 /*
  * The public interface to this module.
  */
-void
-print_freebsd_syscall(int num,
-                      abi_long arg1, abi_long arg2, abi_long arg3,
-                      abi_long arg4, abi_long arg5, abi_long arg6)
+void print_freebsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5, abi_long arg6)
 {
-    print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames),
-                  arg1, arg2, arg3, arg4, arg5, arg6);
+
+    print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames), arg1, arg2,
+            arg3, arg4, arg5, arg6);
 }
 
-void
-print_freebsd_syscall_ret(int num, abi_long ret)
+void print_freebsd_syscall_ret(int num, abi_long ret)
 {
+
     print_syscall_ret(num, ret, freebsd_scnames, ARRAY_SIZE(freebsd_scnames));
 }
 
-void
-print_netbsd_syscall(int num,
-                      abi_long arg1, abi_long arg2, abi_long arg3,
-                      abi_long arg4, abi_long arg5, abi_long arg6)
+void print_netbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5, abi_long arg6)
 {
+
     print_syscall(num, netbsd_scnames, ARRAY_SIZE(netbsd_scnames),
                   arg1, arg2, arg3, arg4, arg5, arg6);
 }
 
-void
-print_netbsd_syscall_ret(int num, abi_long ret)
+void print_netbsd_syscall_ret(int num, abi_long ret)
 {
+
     print_syscall_ret(num, ret, netbsd_scnames, ARRAY_SIZE(netbsd_scnames));
 }
 
-void
-print_openbsd_syscall(int num,
-                      abi_long arg1, abi_long arg2, abi_long arg3,
-                      abi_long arg4, abi_long arg5, abi_long arg6)
+void print_openbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5, abi_long arg6)
 {
-    print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames),
-                  arg1, arg2, arg3, arg4, arg5, arg6);
+
+    print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames), arg1, arg2,
+            arg3, arg4, arg5, arg6);
 }
 
-void
-print_openbsd_syscall_ret(int num, abi_long ret)
+void print_openbsd_syscall_ret(int num, abi_long ret)
 {
+
     print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
 }
diff --git a/bsd-user/x86_64/syscall.h b/bsd-user/x86_64/syscall.h
index 630514a..4fff6a5 100644
--- a/bsd-user/x86_64/syscall.h
+++ b/bsd-user/x86_64/syscall.h
@@ -1,3 +1,23 @@
+/*
+ *  x86_64 system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _X86_64_SYSCALL_H_
+#define _X86_64_SYSCALL_H_
+
 #define __USER_CS	(0x33)
 #define __USER_DS	(0x2B)
 
@@ -108,9 +128,13 @@ struct target_msqid64_ds {
 #define TARGET_FREEBSD_AMD64_SET_GSBASE	131
 
 
-#define UNAME_MACHINE "x86_64"
+#define UNAME_MACHINE           "x86_64"
+#define TARGET_HW_MACHINE       "amd64"
+#define TARGET_HW_MACHINE_ARCH  "amd64"
 
 #define TARGET_ARCH_SET_GS 0x1001
 #define TARGET_ARCH_SET_FS 0x1002
 #define TARGET_ARCH_GET_FS 0x1003
 #define TARGET_ARCH_GET_GS 0x1004
+
+#endif /* ! _X86_64_SYSCALL_H_ */
diff --git a/bsd-user/x86_64/target_arch_sysarch.h b/bsd-user/x86_64/target_arch_sysarch.h
new file mode 100644
index 0000000..6d09d50
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_sysarch.h
@@ -0,0 +1,76 @@
+/*
+ *  x86_64 sysarch() syscall emulation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUX86State *env, int op,
+        abi_ulong parms)
+{
+    abi_long ret = 0;
+    abi_ulong val;
+    int idx;
+
+    switch (op) {
+    case TARGET_FREEBSD_AMD64_SET_GSBASE:
+    case TARGET_FREEBSD_AMD64_SET_FSBASE:
+        if (op == TARGET_FREEBSD_AMD64_SET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        if (get_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        cpu_x86_load_seg(env, idx, 0);
+        env->segs[idx].base = val;
+        break;
+
+    case TARGET_FREEBSD_AMD64_GET_GSBASE:
+    case TARGET_FREEBSD_AMD64_GET_FSBASE:
+        if (op == TARGET_FREEBSD_AMD64_GET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        val = env->segs[idx].base;
+        if (put_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    /* XXX handle the others... */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", "
+        TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4);
+}
+
+#endif /*! __ARCH_SYSARCH_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 04/18] bsd-user: move target arch and host OS dependent code out of main.c
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (2 preceding siblings ...)
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 03/18] bsd-user: move OS/arch dependent code for strace into separate directories Stacey Son
@ 2013-10-16 14:36 ` Stacey Son
  2013-10-16 15:38   ` [Qemu-devel] [PATCH 04/18] bsd-user: move target arch and host OSdependent code out of main.cc Alex Bennée
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 05/18] bsd-user: move target arch and host OS dependent code out of syscall.c Stacey Son
                   ` (35 subsequent siblings)
  39 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change moves the cpu initialization and main loop code from
main.c to the OS and arch dependent directories. This eliminates
many of the #ifdef's in main.c. The cpu initialization and loop
code is now located in the arch directory along with target arch
support code.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs                 |    2 +-
 bsd-user/arm/target_arch.h             |   10 +
 bsd-user/arm/target_arch_cpu.c         |   27 ++
 bsd-user/arm/target_arch_cpu.h         |  435 +++++++++++++++++
 bsd-user/arm/target_arch_vmparam.h     |   49 ++
 bsd-user/elfload.c                     |    2 +-
 bsd-user/freebsd/host_os.h             |   46 ++
 bsd-user/freebsd/target_os_vmparam.h   |   23 +
 bsd-user/i386/target_arch.h            |   13 +
 bsd-user/i386/target_arch_cpu.c        |   79 ++++
 bsd-user/i386/target_arch_cpu.h        |  302 ++++++++++++
 bsd-user/i386/target_arch_vmparam.h    |   26 +
 bsd-user/i386/target_signal.h          |    6 -
 bsd-user/main.c                        |  803 +++-----------------------------
 bsd-user/mips/target_arch.h            |   10 +
 bsd-user/mips/target_arch_cpu.c        |   27 ++
 bsd-user/mips/target_arch_cpu.h        |  243 ++++++++++
 bsd-user/mips/target_arch_vmparam.h    |   47 ++
 bsd-user/mips64/target_arch.h          |   10 +
 bsd-user/mips64/target_arch_cpu.c      |   27 ++
 bsd-user/mips64/target_arch_cpu.h      |  243 ++++++++++
 bsd-user/mips64/target_arch_vmparam.h  |   47 ++
 bsd-user/netbsd/host_os.h              |   31 ++
 bsd-user/openbsd/host_os.h             |   31 ++
 bsd-user/qemu.h                        |   10 +-
 bsd-user/sparc/target_arch.h           |   11 +
 bsd-user/sparc/target_arch_cpu.c       |  113 +++++
 bsd-user/sparc/target_arch_cpu.h       |  158 +++++++
 bsd-user/sparc/target_arch_vmparam.h   |   35 ++
 bsd-user/sparc/target_signal.h         |    5 -
 bsd-user/sparc64/target_arch.h         |   11 +
 bsd-user/sparc64/target_arch_cpu.c     |  118 +++++
 bsd-user/sparc64/target_arch_cpu.h     |  191 ++++++++
 bsd-user/sparc64/target_arch_vmparam.h |   37 ++
 bsd-user/sparc64/target_signal.h       |    5 -
 bsd-user/x86_64/target_arch.h          |   13 +
 bsd-user/x86_64/target_arch_cpu.c      |   79 ++++
 bsd-user/x86_64/target_arch_cpu.h      |  324 +++++++++++++
 bsd-user/x86_64/target_arch_vmparam.h  |   28 ++
 bsd-user/x86_64/target_signal.h        |    5 -
 40 files changed, 2915 insertions(+), 767 deletions(-)
 create mode 100644 bsd-user/arm/target_arch.h
 create mode 100644 bsd-user/arm/target_arch_cpu.c
 create mode 100644 bsd-user/arm/target_arch_cpu.h
 create mode 100644 bsd-user/arm/target_arch_vmparam.h
 create mode 100644 bsd-user/freebsd/host_os.h
 create mode 100644 bsd-user/freebsd/target_os_vmparam.h
 create mode 100644 bsd-user/i386/target_arch.h
 create mode 100644 bsd-user/i386/target_arch_cpu.c
 create mode 100644 bsd-user/i386/target_arch_cpu.h
 create mode 100644 bsd-user/i386/target_arch_vmparam.h
 create mode 100644 bsd-user/mips/target_arch.h
 create mode 100644 bsd-user/mips/target_arch_cpu.c
 create mode 100644 bsd-user/mips/target_arch_cpu.h
 create mode 100644 bsd-user/mips/target_arch_vmparam.h
 create mode 100644 bsd-user/mips64/target_arch.h
 create mode 100644 bsd-user/mips64/target_arch_cpu.c
 create mode 100644 bsd-user/mips64/target_arch_cpu.h
 create mode 100644 bsd-user/mips64/target_arch_vmparam.h
 create mode 100644 bsd-user/netbsd/host_os.h
 create mode 100644 bsd-user/openbsd/host_os.h
 create mode 100644 bsd-user/sparc/target_arch.h
 create mode 100644 bsd-user/sparc/target_arch_cpu.c
 create mode 100644 bsd-user/sparc/target_arch_cpu.h
 create mode 100644 bsd-user/sparc/target_arch_vmparam.h
 create mode 100644 bsd-user/sparc64/target_arch.h
 create mode 100644 bsd-user/sparc64/target_arch_cpu.c
 create mode 100644 bsd-user/sparc64/target_arch_cpu.h
 create mode 100644 bsd-user/sparc64/target_arch_vmparam.h
 create mode 100644 bsd-user/x86_64/target_arch.h
 create mode 100644 bsd-user/x86_64/target_arch_cpu.c
 create mode 100644 bsd-user/x86_64/target_arch_cpu.h
 create mode 100644 bsd-user/x86_64/target_arch_vmparam.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 5e77f57..41e8dce 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,2 +1,2 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o
+	        uaccess.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/arm/target_arch.h b/bsd-user/arm/target_arch.h
new file mode 100644
index 0000000..b5c5ddb
--- /dev/null
+++ b/bsd-user/arm/target_arch.h
@@ -0,0 +1,10 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+#include "qemu.h"
+
+void target_cpu_set_tls(CPUARMState *env, target_ulong newtls);
+target_ulong target_cpu_get_tls(CPUARMState *env);
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/arm/target_arch_cpu.c b/bsd-user/arm/target_arch_cpu.c
new file mode 100644
index 0000000..d94a32a
--- /dev/null
+++ b/bsd-user/arm/target_arch_cpu.c
@@ -0,0 +1,27 @@
+/*
+ *  arm cpu related code
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "target_arch.h"
+
+void target_cpu_set_tls(CPUARMState *env, target_ulong newtls)
+{
+    env->cp15.c13_tls2 = newtls;
+}
+
+target_ulong target_cpu_get_tls(CPUARMState *env)
+{
+    return (env->cp15.c13_tls2);
+}
diff --git a/bsd-user/arm/target_arch_cpu.h b/bsd-user/arm/target_arch_cpu.h
new file mode 100644
index 0000000..713cec4
--- /dev/null
+++ b/bsd-user/arm/target_arch_cpu.h
@@ -0,0 +1,435 @@
+/*
+ *  arm cpu init and loop
+ *
+ *  Olivier Houchard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+/* #define DEBUG_ARM */
+
+#define TARGET_DEFAULT_CPU_MODEL "any"
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUARMState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    cpsr_write(env, regs->uregs[16], 0xffffffff);
+    for (i = 0; i < 16; i++) {
+        env->regs[i] = regs->uregs[i];
+    }
+}
+
+static inline int do_strex(CPUARMState *env)
+{
+    uint32_t val;
+    int size;
+    int rc = 1;
+    int segv = 0;
+    uint32_t addr;
+    start_exclusive();
+    addr = env->exclusive_addr;
+    if (addr != env->exclusive_test) {
+        goto fail;
+    }
+    size = env->exclusive_info & 0xf;
+    switch (size) {
+    case 0:
+        segv = get_user_u8(val, addr);
+        break;
+    case 1:
+        segv = get_user_u16(val, addr);
+        break;
+    case 2:
+    case 3:
+        segv = get_user_u32(val, addr);
+        break;
+    default:
+        abort();
+    }
+    if (segv) {
+        env->cp15.c6_data = addr;
+        goto done;
+    }
+    if (val != env->exclusive_val) {
+        goto fail;
+    }
+    if (size == 3) {
+        segv = get_user_u32(val, addr + 4);
+        if (segv) {
+            env->cp15.c6_data = addr + 4;
+            goto done;
+        }
+        if (val != env->exclusive_high) {
+            goto fail;
+        }
+    }
+    val = env->regs[(env->exclusive_info >> 8) & 0xf];
+    switch (size) {
+    case 0:
+        segv = put_user_u8(val, addr);
+        break;
+    case 1:
+        segv = put_user_u16(val, addr);
+        break;
+    case 2:
+    case 3:
+        segv = put_user_u32(val, addr);
+        break;
+    }
+    if (segv) {
+        env->cp15.c6_data = addr;
+        goto done;
+    }
+    if (size == 3) {
+        val = env->regs[(env->exclusive_info >> 12) & 0xf];
+        segv = put_user_u32(val, addr + 4);
+        if (segv) {
+            env->cp15.c6_data = addr + 4;
+            goto done;
+        }
+    }
+    rc = 0;
+fail:
+    env->regs[15] += 4;
+    env->regs[(env->exclusive_info >> 4) & 0xf] = rc;
+done:
+    end_exclusive();
+    return segv;
+}
+
+static inline void target_cpu_loop(CPUARMState *env)
+{
+    int trapnr;
+    unsigned int n;
+#ifdef FREEBSD_ARM_OABI
+    unsigned int insn;
+#endif
+    uint32_t addr;
+    CPUState *cs = CPU(arm_env_get_cpu(env));
+
+    for (;;) {
+#ifdef DEBUG_ARM
+        printf("CPU LOOPING\n");
+#endif
+        cpu_exec_start(cs);
+#ifdef DEBUG_ARM
+        printf("EXECUTING...\n");
+#endif
+        trapnr = cpu_arm_exec(env);
+#ifdef DEBUG_ARM
+        printf("trapnr %d\n", trapnr);
+#endif
+        cpu_exec_end(cs);
+        switch (trapnr) {
+        case EXCP_UDEF:
+            {
+#if 0
+                TaskState *ts = env->opaque;
+                uint32_t opcode;
+                int rc;
+
+                /* we handle the FPU emulation here, as Linux */
+                /* we get the opcode */
+                /* FIXME - what to do if get_user() fails? */
+                get_user_u32(opcode, env->regs[15]);
+
+                rc = EmulateAll(opcode, &ts->fpa, env);
+                if (rc == 0) { /* illegal instruction */
+                    info.si_signo = SIGILL;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_ILL_ILLOPN;
+                    info._sifields._sigfault._addr = env->regs[15];
+                    queue_signal(env, info.si_signo, &info);
+
+                } else if (rc < 0) { /* FP exception */
+                    int arm_fpe = 0;
+
+                    /* translate softfloat flags to FPSR flags */
+                    if (-rc & float_flag_invalid) {
+                        arm_fpe |= BIT_IOC;
+                    }
+                    if (-rc & float_flag_divbyzero) {
+                        arm_fpe |= BIT_DZC;
+                    }
+                    if (-rc & float_flag_overflow) {
+                        arm_fpe |= BIT_OFC;
+                    }
+                    if (-rc & float_flag_underflow) {
+                        arm_fpe |= BIT_UFC;
+                    }
+                    if (-rc & float_flag_inexact) {
+                        arm_fpe |= BIT_IXC;
+                    }
+
+                    FPSR fpsr = ts->fpa.fpsr;
+                    /* printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe); */
+
+                    if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
+                        info.si_signo = SIGFPE;
+                        info.si_errno = 0;
+
+                        /* ordered by priority, least first */
+                        if (arm_fpe & BIT_IXC) {
+                            info.si_code = TARGET_FPE_FLTRES;
+                        }
+                        if (arm_fpe & BIT_UFC) {
+                            info.si_code = TARGET_FPE_FLTUND;
+                        }
+                        if (arm_fpe & BIT_OFC) {
+                            info.si_code = TARGET_FPE_FLTOVF;
+                        }
+                        if (arm_fpe & BIT_DZC) {
+                            info.si_code = TARGET_FPE_FLTDIV;
+                        }
+                        if (arm_fpe & BIT_IOC) {
+                            info.si_code = TARGET_FPE_FLTINV;
+                        }
+                        info._sifields._sigfault._addr = env->regs[15];
+                        queue_signal(env, info.si_signo, &info);
+                    } else {
+                        env->regs[15] += 4;
+                    }
+
+                    /* accumulate unenabled exceptions */
+                    if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) {
+                        fpsr |= BIT_IXC;
+                    }
+                    if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) {
+                        fpsr |= BIT_UFC;
+                    }
+                    if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) {
+                        fpsr |= BIT_OFC;
+                    }
+                    if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) {
+                        fpsr |= BIT_DZC;
+                    }
+                    if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) {
+                        fpsr |= BIT_IOC;
+                    }
+                    ts->fpa.fpsr = fpsr;
+                } else { /* everything OK */
+                    /* increment PC */
+                    env->regs[15] += 4;
+                }
+            }
+#endif
+            break;
+        case EXCP_SWI:
+        case EXCP_BKPT:
+            {
+                env->eabi = 1;
+                /* system call */
+                if (trapnr == EXCP_BKPT) {
+                    if (env->thumb) {
+                        /* FIXME - what to do if get_user() fails? */
+#ifdef FREEBSD_ARM_OABI
+                        get_user_u16(insn, env->regs[15]);
+                        n = insn & 0xff;
+#else
+                        n = env->regs[7];
+#endif
+                        env->regs[15] += 2;
+                    } else {
+                        /* FIXME - what to do if get_user() fails? */
+#ifdef FREEBSD_ARM_OABI
+                        get_user_u32(insn, env->regs[15]);
+                        n = (insn & 0xf) | ((insn >> 4) & 0xff0);
+#else
+                        n = env->regs[7];
+#endif
+                        env->regs[15] += 4;
+                    }
+                } else {
+                    if (env->thumb) {
+#ifdef FREEBSD_ARM_OABI
+                        /* FIXME - what to do if get_user() fails? */
+                        get_user_u16(insn, env->regs[15] - 2);
+                        n = insn & 0xff;
+#else
+                        n = env->regs[7];
+#endif
+                    } else {
+#ifdef FREEBSD_ARM_OABI
+                        /* FIXME - what to do if get_user() fails? */
+                        get_user_u32(insn, env->regs[15] - 4);
+                        n = insn & 0xffffff;
+#else
+                        n = env->regs[7];
+#endif
+                    }
+                }
+
+#ifdef DEBUG_ARM
+        printf("AVANT CALL %d\n", n);
+#endif
+                if (bsd_type == target_freebsd) {
+                    int ret;
+                    abi_ulong params = get_sp_from_cpustate(env);
+                    int32_t syscall_nr = n;
+                    int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+#if 0 /* XXX FIXME */
+                    if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                        get_user_s32(syscall_nr, params);
+                        params += sizeof(int32_t);
+                    } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+                        get_user_s32(syscall_nr, params);
+                        params += sizeof(int64_t);
+                    }
+#endif
+                    arg1 = env->regs[0];
+                    arg2 = env->regs[1];
+                    arg3 = env->regs[2];
+                    arg4 = env->regs[3];
+                    get_user_s32(arg5, params);
+                    params += sizeof(int32_t);
+                    get_user_s32(arg6, params);
+                    params += sizeof(int32_t);
+                    get_user_s32(arg7, params);
+                    params += sizeof(int32_t);
+                    get_user_s32(arg8, params);
+                    ret = do_freebsd_syscall(env,
+                                                      syscall_nr,
+                                                      arg1,
+                                                      arg2,
+                                                      arg3,
+                                                      arg4,
+                                                      arg5,
+                                                      arg6,
+                                                      arg7,
+                                                      arg8);
+                    /*
+                     * Compare to arm/arm/vm_machdep.c
+                     * cpu_set_syscall_retval()
+                     */
+                    /* XXX armeb may need some extra magic here */
+                    if (-TARGET_EJUSTRETURN == ret) {
+                        /*
+                         * Returning from a successful sigreturn syscall.
+                         * Avoid clobbering register state.
+                         */
+                        break;
+                    }
+                    /*
+                     * XXX Need to handle ERESTART. Backup the PC by
+                     * 1 instruction.
+                     */
+                    if ((unsigned int)ret >= (unsigned int)(-515)) {
+                        ret = -ret;
+                        cpsr_write(env, CPSR_C, CPSR_C);
+                        env->regs[0] = ret;
+                    } else {
+                        cpsr_write(env, 0, CPSR_C);
+                        env->regs[0] = ret; /* XXX need to handle lseek()? */
+                        /* env->regs[1] = 0; */
+                    }
+                } else {
+                    /* XXX is this correct? */
+                    env->regs[0] = do_openbsd_syscall(env,
+                        n,
+                        env->regs[0],
+                        env->regs[1],
+                        env->regs[2],
+                        env->regs[3],
+                        env->regs[4],
+                        env->regs[5]);
+                }
+#ifdef DEBUG_ARM
+                printf("APRES CALL\n");
+#endif
+            }
+        }
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_PREFETCH_ABORT:
+            addr = env->cp15.c6_insn;
+            goto do_segv;
+        case EXCP_DATA_ABORT:
+            addr = env->cp15.c6_data;
+        do_segv:
+            {
+#if 0
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = addr;
+                queue_signal(env, info.si_signo, &info);
+#endif
+            }
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+                if (sig) {
+#if 0
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+#endif
+                }
+            }
+            break;
+#if 0
+        case EXCP_KERNEL_TRAP:
+            if (do_kernel_trap(env)) {
+                goto error;
+            }
+            break;
+#endif
+        case EXCP_STREX:
+            if (do_strex(env)) {
+                addr = env->cp15.c6_data;
+                goto do_segv;
+            }
+            break;
+#if 0
+        error:
+#endif
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+                    trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[13] = newsp;
+    env->regs[0] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+}
+
+#endif /* !_TARGET_ARCH_CPU_H */
diff --git a/bsd-user/arm/target_arch_vmparam.h b/bsd-user/arm/target_arch_vmparam.h
new file mode 100644
index 0000000..46cd0cf
--- /dev/null
+++ b/bsd-user/arm/target_arch_vmparam.h
@@ -0,0 +1,49 @@
+/*
+ *  arm VM parameters definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to sys/arm/include/vmparam.h */
+#define TARGET_MAXTSIZ      (64UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ      (128UL*1024*1024)   /* initial data size limit */
+#define TARGET_MAXDSIZ      (512UL*1024*1024)    /* max data size */
+#define TARGET_DFLSSIZ      (2UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ      (8UL*1024*1024)    /* max stack size */
+#define TARGET_SGROWSIZ     (128UL*1024)        /* amount to grow stack */
+
+                /* KERNBASE - 512 MB */
+#define TARGET_VM_MAXUSER_ADDRESS   (0xc0000000 - (512 * 1024 * 1024))
+#define TARGET_USRSTACK             TARGET_VM_MAXUSER_ADDRESS
+
+#define TARGET_SPACE_USRSPACE   4096
+#define TARGET_ARG_MAX          262144
+
+static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
+{
+    return state->regs[13]; /* sp */
+}
+
+static inline void set_second_rval(CPUARMState *state, abi_ulong retval2)
+{
+    state->regs[1] = retval2;
+}
+
+#endif  /* ! _TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 93fd9e4..ccf72d1 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -674,7 +674,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
     /* Create enough stack to hold everything.  If we don't use
      * it for args, we'll use it for something else...
      */
-    size = x86_stack_size;
+    size = target_dflssiz;
     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
     error = target_mmap(0,
diff --git a/bsd-user/freebsd/host_os.h b/bsd-user/freebsd/host_os.h
new file mode 100644
index 0000000..efe2351
--- /dev/null
+++ b/bsd-user/freebsd/host_os.h
@@ -0,0 +1,46 @@
+/*
+ *  FreeBSD host dependent code and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST_OS_H_
+#define __HOST_OS_H_
+
+#include <stdio.h>
+#include <sys/sysctl.h>
+
+#include "qemu.h"
+
+#define HOST_DEFAULT_BSD_TYPE target_freebsd
+
+static inline void save_proc_pathname(char *argv0)
+{
+    int mib[4];
+    size_t len;
+
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_PATHNAME;
+    mib[3] = -1;
+
+    len = PATH_MAX;
+    if (sysctl(mib, 4, qemu_proc_pathname, &len, NULL, 0)) {
+        perror("sysctl");
+    }
+}
+
+#endif /*!__HOST_OS_H_ */
diff --git a/bsd-user/freebsd/target_os_vmparam.h b/bsd-user/freebsd/target_os_vmparam.h
new file mode 100644
index 0000000..80ac6c8
--- /dev/null
+++ b/bsd-user/freebsd/target_os_vmparam.h
@@ -0,0 +1,23 @@
+#ifndef _TARGET_OS_VMPARAM_H_
+#define _TARGET_OS_VMPARAM_H_
+
+#include "target_arch_vmparam.h"
+
+#define TARGET_SPACE_USRSPACE   4096
+#define TARGET_ARG_MAX          262144
+
+/* Compare to sys/exec.h */
+struct target_ps_strings {
+    abi_ulong ps_argvstr;
+    uint32_t ps_nargvstr;
+    abi_ulong ps_envstr;
+    uint32_t ps_nenvstr;
+};
+
+extern abi_ulong target_stkbas;
+extern abi_ulong target_stksiz;
+
+#define TARGET_PS_STRINGS  ((target_stkbas + target_stksiz) - \
+		sizeof(struct target_ps_strings))
+
+#endif /* !TARGET_OS_VMPARAM_H_ */
diff --git a/bsd-user/i386/target_arch.h b/bsd-user/i386/target_arch.h
new file mode 100644
index 0000000..4cb398c
--- /dev/null
+++ b/bsd-user/i386/target_arch.h
@@ -0,0 +1,13 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+/* target_arch_cpu.c */
+void bsd_i386_write_dt(void *ptr, unsigned long addr, unsigned long limit,
+                int flags);
+void bsd_i386_set_idt(int n, unsigned int dpl);
+void bsd_i386_set_idt_base(uint64_t base);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* ! _TARGET_ARCH_H_ */
diff --git a/bsd-user/i386/target_arch_cpu.c b/bsd-user/i386/target_arch_cpu.c
new file mode 100644
index 0000000..2e0eec0
--- /dev/null
+++ b/bsd-user/i386/target_arch_cpu.c
@@ -0,0 +1,79 @@
+/*
+ *  i386 cpu related code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+#include "qemu/timer.h"
+
+#include "target_arch.h"
+
+static uint64_t *idt_table;
+
+/* CPUX86 core interface */
+void cpu_smm_update(CPUX86State *env)
+{
+}
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+    return cpu_get_real_ticks();
+}
+
+int cpu_get_pic_interrupt(CPUX86State *env)
+{
+    return -1;
+}
+
+void bsd_i386_write_dt(void *ptr, unsigned long addr, unsigned long limit,
+                     int flags)
+{
+    unsigned int e1, e2;
+    uint32_t *p;
+    e1 = (addr << 16) | (limit & 0xffff);
+    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+    e2 |= flags;
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+                     uint32_t addr, unsigned int sel)
+{
+    uint32_t *p, e1, e2;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+/* only dpl matters as we do only user space emulation */
+void bsd_i386_set_idt(int n, unsigned int dpl)
+{
+    set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+
+void bsd_i386_set_idt_base(uint64_t base)
+{
+    idt_table = g2h(base);
+}
+
diff --git a/bsd-user/i386/target_arch_cpu.h b/bsd-user/i386/target_arch_cpu.h
new file mode 100644
index 0000000..c3df814
--- /dev/null
+++ b/bsd-user/i386/target_arch_cpu.h
@@ -0,0 +1,302 @@
+/*
+ *  i386 cpu init and loop
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "qemu32"
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUX86State *env,
+        struct target_pt_regs *regs)
+{
+    uint64_t *gdt_table;
+
+    cpu_x86_set_cpl(env, 3);
+
+    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+    env->hflags |= HF_PE_MASK;
+    if (env->features[FEAT_1_EDX] & CPUID_SSE) {
+        env->cr[4] |= CR4_OSFXSR_MASK;
+        env->hflags |= HF_OSFXSR_MASK;
+    }
+
+    /* flags setup : we activate the IRQs by default as in user mode */
+    env->eflags |= IF_MASK;
+
+    /* register setup */
+    env->regs[R_EAX] = regs->eax;
+    env->regs[R_EBX] = regs->ebx;
+    env->regs[R_ECX] = regs->ecx;
+    env->regs[R_EDX] = regs->edx;
+    env->regs[R_ESI] = regs->esi;
+    env->regs[R_EDI] = regs->edi;
+    env->regs[R_EBP] = regs->ebp;
+    env->regs[R_ESP] = regs->esp;
+    env->eip = regs->eip;
+
+    /* interrupt setup */
+    env->idt.limit = 255;
+
+    env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+        PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    bsd_i386_set_idt_base(env->idt.base);
+    bsd_i386_set_idt(0, 0);
+    bsd_i386_set_idt(1, 0);
+    bsd_i386_set_idt(2, 0);
+    bsd_i386_set_idt(3, 3);
+    bsd_i386_set_idt(4, 3);
+    bsd_i386_set_idt(5, 0);
+    bsd_i386_set_idt(6, 0);
+    bsd_i386_set_idt(7, 0);
+    bsd_i386_set_idt(8, 0);
+    bsd_i386_set_idt(9, 0);
+    bsd_i386_set_idt(10, 0);
+    bsd_i386_set_idt(11, 0);
+    bsd_i386_set_idt(12, 0);
+    bsd_i386_set_idt(13, 0);
+    bsd_i386_set_idt(14, 0);
+    bsd_i386_set_idt(15, 0);
+    bsd_i386_set_idt(16, 0);
+    bsd_i386_set_idt(17, 0);
+    bsd_i386_set_idt(18, 0);
+    bsd_i386_set_idt(19, 0);
+    bsd_i386_set_idt(0x80, 3);
+
+    /* segment setup */
+    env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+            PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+    gdt_table = g2h(env->gdt.base);
+
+    bsd_i386_write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+            (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+
+    bsd_i386_write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+            (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+
+    cpu_x86_load_seg(env, R_CS, __USER_CS);
+    cpu_x86_load_seg(env, R_SS, __USER_DS);
+    cpu_x86_load_seg(env, R_DS, __USER_DS);
+    cpu_x86_load_seg(env, R_ES, __USER_DS);
+    cpu_x86_load_seg(env, R_FS, __USER_DS);
+    cpu_x86_load_seg(env, R_GS, __USER_DS);
+    /* This hack makes Wine work... */
+    env->segs[R_FS].selector = 0;
+}
+
+static inline void target_cpu_loop(CPUX86State *env)
+{
+    int trapnr;
+    abi_ulong pc;
+    /* target_siginfo_t info; */
+
+    for (;;) {
+        trapnr = cpu_x86_exec(env);
+        switch (trapnr) {
+        case 0x80:
+            /* syscall from int $0x80 */
+            if (bsd_type == target_freebsd) {
+                abi_ulong params = (abi_ulong) env->regs[R_ESP] +
+                    sizeof(int32_t);
+                int32_t syscall_nr = env->regs[R_EAX];
+                int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+                if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int32_t);
+                } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int64_t);
+                }
+                get_user_s32(arg1, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg2, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg3, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg4, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg5, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg6, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg7, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg8, params);
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      syscall_nr,
+                                                      arg1,
+                                                      arg2,
+                                                      arg3,
+                                                      arg4,
+                                                      arg5,
+                                                      arg6,
+                                                      arg7,
+                                                      arg8);
+            } else { /* if (bsd_type == target_openbsd) */
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EBX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_EBP]);
+            }
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
+            break;
+
+#if 0
+        case EXCP0B_NOSEG:
+        case EXCP0C_STACK:
+            info.si_signo = SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP0D_GPF:
+            /* XXX: potential problem if ABI32 */
+            if (env->eflags & VM_MASK) {
+                handle_vm86_fault(env);
+            } else {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+
+        case EXCP0E_PAGE:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            if (!(env->error_code & 1)) {
+                info.si_code = TARGET_SEGV_MAPERR;
+            } else {
+                info.si_code = TARGET_SEGV_ACCERR;
+            }
+            info._sifields._sigfault._addr = env->cr[2];
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP00_DIVZ:
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else {
+                /* division by zero */
+                info.si_signo = SIGFPE;
+                info.si_errno = 0;
+                info.si_code = TARGET_FPE_INTDIV;
+                info._sifields._sigfault._addr = env->eip;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+
+        case EXCP01_DB:
+        case EXCP03_INT3:
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else {
+                info.si_signo = SIGTRAP;
+                info.si_errno = 0;
+                if (trapnr == EXCP01_DB) {
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    info._sifields._sigfault._addr = env->eip;
+                } else {
+                    info.si_code = TARGET_SI_KERNEL;
+                    info._sifields._sigfault._addr = 0;
+                }
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+
+        case EXCP04_INTO:
+        case EXCP05_BOUND:
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+
+        case EXCP06_ILLOP:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(env, info.si_signo, &info);
+            break;
+#endif
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+#if 0
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(env, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                }
+            }
+            break;
+#endif
+        default:
+            pc = env->segs[R_CS].base + env->eip;
+            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - "
+                    "aborting\n", (long)pc, trapnr);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[R_ESP] = newsp;
+    env->regs[R_EAX] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+    cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/i386/target_arch_vmparam.h b/bsd-user/i386/target_arch_vmparam.h
new file mode 100644
index 0000000..654400a
--- /dev/null
+++ b/bsd-user/i386/target_arch_vmparam.h
@@ -0,0 +1,26 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to i386/include/vmparam.h */
+#define TARGET_MAXTSIZ  (128UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ  (128UL*1024*1024)   /* initial data size limit */
+#define TARGET_MAXDSIZ  (512UL*1024*1024)   /* max data size */
+#define TARGET_DFLSSIZ  (8UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ  (64UL*1024*1024)    /* max stack size */
+#define TARGET_SGROWSIZ (128UL*1024)        /* amount to grow stack */
+
+#define TARGET_USRSTACK (0xbfc00000)
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+    return state->regs[R_ESP];
+}
+
+static inline void set_second_rval(CPUX86State *state, abi_ulong retval2)
+{
+    state->regs[R_EDX] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/i386/target_signal.h b/bsd-user/i386/target_signal.h
index 2ef36d1..5491687 100644
--- a/bsd-user/i386/target_signal.h
+++ b/bsd-user/i386/target_signal.h
@@ -11,10 +11,4 @@ typedef struct target_sigaltstack {
 	abi_ulong ss_size;
 } target_stack_t;
 
-
-static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
-{
-    return state->regs[R_ESP];
-}
-
 #endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/main.c b/bsd-user/main.c
index f9246aa..3b8fb60 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -1,7 +1,8 @@
 /*
- *  qemu user main
+ *  qemu bsd user main
  *
  *  Copyright (c) 2003-2008 Fabrice Bellard
+ *  Copyright (c) 2013 Stacey Son
  *
  *  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
@@ -23,17 +24,20 @@
 #include <errno.h>
 #include <unistd.h>
 #include <machine/trap.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
 #include <sys/mman.h>
 
 #include "qemu.h"
 #include "qemu-common.h"
-/* For tb_lock */
 #include "cpu.h"
 #include "tcg.h"
 #include "qemu/timer.h"
 #include "qemu/envlist.h"
 
+#include "host_os.h"
+#include "target_arch_cpu.h"
+
 int singlestep;
 #if defined(CONFIG_USE_GUEST_BASE)
 unsigned long mmap_min_addr;
@@ -47,44 +51,16 @@ const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 extern char **environ;
 enum BSDType bsd_type;
 
-/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
-   we allocate a bigger stack. Need a better solution, for example
-   by remapping the process stack directly at the right place */
-unsigned long x86_stack_size = 512 * 1024;
-
-void gemu_log(const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-}
+unsigned long target_maxtsiz = TARGET_MAXTSIZ;   /* max text size */
+unsigned long target_dfldsiz = TARGET_DFLDSIZ;   /* initial data size limit */
+unsigned long target_maxdsiz = TARGET_MAXDSIZ;   /* max data size */
+unsigned long target_dflssiz = TARGET_DFLSSIZ;   /* initial data size limit */
+unsigned long target_maxssiz = TARGET_MAXSSIZ;   /* max stack size */
+unsigned long target_sgrowsiz = TARGET_SGROWSIZ; /* amount to grow stack */
 
-#if defined(TARGET_I386)
-int cpu_get_pic_interrupt(CPUX86State *env)
-{
-    return -1;
-}
-#endif
+char qemu_proc_pathname[PATH_MAX];  /* full path to exeutable */
 
 /* These are no-ops because we are not threadsafe.  */
-static inline void cpu_exec_start(CPUArchState *env)
-{
-}
-
-static inline void cpu_exec_end(CPUArchState *env)
-{
-}
-
-static inline void start_exclusive(void)
-{
-}
-
-static inline void end_exclusive(void)
-{
-}
-
 void fork_start(void)
 {
 }
@@ -96,579 +72,41 @@ void fork_end(int child)
     }
 }
 
-void cpu_list_lock(void)
-{
-}
-
-void cpu_list_unlock(void)
-{
-}
-
-#ifdef TARGET_I386
-/***********************************************************/
-/* CPUX86 core interface */
-
-void cpu_smm_update(CPUX86State *env)
+static inline void exclusive_idle(void)
 {
 }
 
-uint64_t cpu_get_tsc(CPUX86State *env)
-{
-    return cpu_get_real_ticks();
-}
-
-static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
-                     int flags)
-{
-    unsigned int e1, e2;
-    uint32_t *p;
-    e1 = (addr << 16) | (limit & 0xffff);
-    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
-    e2 |= flags;
-    p = ptr;
-    p[0] = tswap32(e1);
-    p[1] = tswap32(e2);
-}
-
-static uint64_t *idt_table;
-#ifdef TARGET_X86_64
-static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
-                       uint64_t addr, unsigned int sel)
-{
-    uint32_t *p, e1, e2;
-    e1 = (addr & 0xffff) | (sel << 16);
-    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
-    p = ptr;
-    p[0] = tswap32(e1);
-    p[1] = tswap32(e2);
-    p[2] = tswap32(addr >> 32);
-    p[3] = 0;
-}
-/* only dpl matters as we do only user space emulation */
-static void set_idt(int n, unsigned int dpl)
-{
-    set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
-}
-#else
-static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
-                     uint32_t addr, unsigned int sel)
+static inline void start_exclusive(void)
 {
-    uint32_t *p, e1, e2;
-    e1 = (addr & 0xffff) | (sel << 16);
-    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
-    p = ptr;
-    p[0] = tswap32(e1);
-    p[1] = tswap32(e2);
 }
 
-/* only dpl matters as we do only user space emulation */
-static void set_idt(int n, unsigned int dpl)
+static inline void end_exclusive(void)
 {
-    set_gate(idt_table + n, 0, dpl, 0, 0);
 }
-#endif
 
-void cpu_loop(CPUX86State *env)
+static inline void cpu_exec_start(CPUState *env)
 {
-    int trapnr;
-    abi_ulong pc;
-    //target_siginfo_t info;
-
-    for(;;) {
-        trapnr = cpu_x86_exec(env);
-        switch(trapnr) {
-        case 0x80:
-            /* syscall from int $0x80 */
-            if (bsd_type == target_freebsd) {
-                abi_ulong params = (abi_ulong) env->regs[R_ESP] +
-                    sizeof(int32_t);
-                int32_t syscall_nr = env->regs[R_EAX];
-                int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
-
-                if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
-                    get_user_s32(syscall_nr, params);
-                    params += sizeof(int32_t);
-                } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
-                    get_user_s32(syscall_nr, params);
-                    params += sizeof(int64_t);
-                }
-                get_user_s32(arg1, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg2, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg3, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg4, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg5, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg6, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg7, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg8, params);
-                env->regs[R_EAX] = do_freebsd_syscall(env,
-                                                      syscall_nr,
-                                                      arg1,
-                                                      arg2,
-                                                      arg3,
-                                                      arg4,
-                                                      arg5,
-                                                      arg6,
-                                                      arg7,
-                                                      arg8);
-            } else { //if (bsd_type == target_openbsd)
-                env->regs[R_EAX] = do_openbsd_syscall(env,
-                                                      env->regs[R_EAX],
-                                                      env->regs[R_EBX],
-                                                      env->regs[R_ECX],
-                                                      env->regs[R_EDX],
-                                                      env->regs[R_ESI],
-                                                      env->regs[R_EDI],
-                                                      env->regs[R_EBP]);
-            }
-            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
-                env->regs[R_EAX] = -env->regs[R_EAX];
-                env->eflags |= CC_C;
-            } else {
-                env->eflags &= ~CC_C;
-            }
-            break;
-#ifndef TARGET_ABI32
-        case EXCP_SYSCALL:
-            /* syscall from syscall instruction */
-            if (bsd_type == target_freebsd)
-                env->regs[R_EAX] = do_freebsd_syscall(env,
-                                                      env->regs[R_EAX],
-                                                      env->regs[R_EDI],
-                                                      env->regs[R_ESI],
-                                                      env->regs[R_EDX],
-                                                      env->regs[R_ECX],
-                                                      env->regs[8],
-                                                      env->regs[9], 0, 0);
-            else { //if (bsd_type == target_openbsd)
-                env->regs[R_EAX] = do_openbsd_syscall(env,
-                                                      env->regs[R_EAX],
-                                                      env->regs[R_EDI],
-                                                      env->regs[R_ESI],
-                                                      env->regs[R_EDX],
-                                                      env->regs[10],
-                                                      env->regs[8],
-                                                      env->regs[9]);
-            }
-            env->eip = env->exception_next_eip;
-            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
-                env->regs[R_EAX] = -env->regs[R_EAX];
-                env->eflags |= CC_C;
-            } else {
-                env->eflags &= ~CC_C;
-            }
-            break;
-#endif
-#if 0
-        case EXCP0B_NOSEG:
-        case EXCP0C_STACK:
-            info.si_signo = SIGBUS;
-            info.si_errno = 0;
-            info.si_code = TARGET_SI_KERNEL;
-            info._sifields._sigfault._addr = 0;
-            queue_signal(env, info.si_signo, &info);
-            break;
-        case EXCP0D_GPF:
-            /* XXX: potential problem if ABI32 */
-#ifndef TARGET_X86_64
-            if (env->eflags & VM_MASK) {
-                handle_vm86_fault(env);
-            } else
-#endif
-            {
-                info.si_signo = SIGSEGV;
-                info.si_errno = 0;
-                info.si_code = TARGET_SI_KERNEL;
-                info._sifields._sigfault._addr = 0;
-                queue_signal(env, info.si_signo, &info);
-            }
-            break;
-        case EXCP0E_PAGE:
-            info.si_signo = SIGSEGV;
-            info.si_errno = 0;
-            if (!(env->error_code & 1))
-                info.si_code = TARGET_SEGV_MAPERR;
-            else
-                info.si_code = TARGET_SEGV_ACCERR;
-            info._sifields._sigfault._addr = env->cr[2];
-            queue_signal(env, info.si_signo, &info);
-            break;
-        case EXCP00_DIVZ:
-#ifndef TARGET_X86_64
-            if (env->eflags & VM_MASK) {
-                handle_vm86_trap(env, trapnr);
-            } else
-#endif
-            {
-                /* division by zero */
-                info.si_signo = SIGFPE;
-                info.si_errno = 0;
-                info.si_code = TARGET_FPE_INTDIV;
-                info._sifields._sigfault._addr = env->eip;
-                queue_signal(env, info.si_signo, &info);
-            }
-            break;
-        case EXCP01_DB:
-        case EXCP03_INT3:
-#ifndef TARGET_X86_64
-            if (env->eflags & VM_MASK) {
-                handle_vm86_trap(env, trapnr);
-            } else
-#endif
-            {
-                info.si_signo = SIGTRAP;
-                info.si_errno = 0;
-                if (trapnr == EXCP01_DB) {
-                    info.si_code = TARGET_TRAP_BRKPT;
-                    info._sifields._sigfault._addr = env->eip;
-                } else {
-                    info.si_code = TARGET_SI_KERNEL;
-                    info._sifields._sigfault._addr = 0;
-                }
-                queue_signal(env, info.si_signo, &info);
-            }
-            break;
-        case EXCP04_INTO:
-        case EXCP05_BOUND:
-#ifndef TARGET_X86_64
-            if (env->eflags & VM_MASK) {
-                handle_vm86_trap(env, trapnr);
-            } else
-#endif
-            {
-                info.si_signo = SIGSEGV;
-                info.si_errno = 0;
-                info.si_code = TARGET_SI_KERNEL;
-                info._sifields._sigfault._addr = 0;
-                queue_signal(env, info.si_signo, &info);
-            }
-            break;
-        case EXCP06_ILLOP:
-            info.si_signo = SIGILL;
-            info.si_errno = 0;
-            info.si_code = TARGET_ILL_ILLOPN;
-            info._sifields._sigfault._addr = env->eip;
-            queue_signal(env, info.si_signo, &info);
-            break;
-#endif
-        case EXCP_INTERRUPT:
-            /* just indicate that signals should be handled asap */
-            break;
-#if 0
-        case EXCP_DEBUG:
-            {
-                int sig;
-
-                sig = gdb_handlesig (env, TARGET_SIGTRAP);
-                if (sig)
-                  {
-                    info.si_signo = sig;
-                    info.si_errno = 0;
-                    info.si_code = TARGET_TRAP_BRKPT;
-                    queue_signal(env, info.si_signo, &info);
-                  }
-            }
-            break;
-#endif
-        default:
-            pc = env->segs[R_CS].base + env->eip;
-            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
-                    (long)pc, trapnr);
-            abort();
-        }
-        process_pending_signals(env);
-    }
 }
-#endif
 
-#ifdef TARGET_SPARC
-#define SPARC64_STACK_BIAS 2047
 
-//#define DEBUG_WIN
-/* WARNING: dealing with register windows _is_ complicated. More info
-   can be found at http://www.sics.se/~psm/sparcstack.html */
-static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
+static inline void cpu_exec_end(CPUState *env)
 {
-    index = (index + cwp * 16) % (16 * env->nwindows);
-    /* wrap handling : if cwp is on the last window, then we use the
-       registers 'after' the end */
-    if (index < 8 && env->cwp == env->nwindows - 1)
-        index += 16 * env->nwindows;
-    return index;
 }
 
-/* save the register window 'cwp1' */
-static inline void save_window_offset(CPUSPARCState *env, int cwp1)
-{
-    unsigned int i;
-    abi_ulong sp_ptr;
-
-    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
-#ifdef TARGET_SPARC64
-    if (sp_ptr & 3)
-        sp_ptr += SPARC64_STACK_BIAS;
-#endif
-#if defined(DEBUG_WIN)
-    printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
-           sp_ptr, cwp1);
-#endif
-    for(i = 0; i < 16; i++) {
-        /* FIXME - what to do if put_user() fails? */
-        put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
-        sp_ptr += sizeof(abi_ulong);
-    }
-}
-
-static void save_window(CPUSPARCState *env)
-{
-#ifndef TARGET_SPARC64
-    unsigned int new_wim;
-    new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
-        ((1LL << env->nwindows) - 1);
-    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
-    env->wim = new_wim;
-#else
-    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
-    env->cansave++;
-    env->canrestore--;
-#endif
-}
-
-static void restore_window(CPUSPARCState *env)
+void cpu_list_lock(void)
 {
-#ifndef TARGET_SPARC64
-    unsigned int new_wim;
-#endif
-    unsigned int i, cwp1;
-    abi_ulong sp_ptr;
-
-#ifndef TARGET_SPARC64
-    new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
-        ((1LL << env->nwindows) - 1);
-#endif
-
-    /* restore the invalid window */
-    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
-    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
-#ifdef TARGET_SPARC64
-    if (sp_ptr & 3)
-        sp_ptr += SPARC64_STACK_BIAS;
-#endif
-#if defined(DEBUG_WIN)
-    printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
-           sp_ptr, cwp1);
-#endif
-    for(i = 0; i < 16; i++) {
-        /* FIXME - what to do if get_user() fails? */
-        get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
-        sp_ptr += sizeof(abi_ulong);
-    }
-#ifdef TARGET_SPARC64
-    env->canrestore++;
-    if (env->cleanwin < env->nwindows - 1)
-        env->cleanwin++;
-    env->cansave--;
-#else
-    env->wim = new_wim;
-#endif
 }
 
-static void flush_windows(CPUSPARCState *env)
+void cpu_list_unlock(void)
 {
-    int offset, cwp1;
-
-    offset = 1;
-    for(;;) {
-        /* if restore would invoke restore_window(), then we can stop */
-        cwp1 = cpu_cwp_inc(env, env->cwp + offset);
-#ifndef TARGET_SPARC64
-        if (env->wim & (1 << cwp1))
-            break;
-#else
-        if (env->canrestore == 0)
-            break;
-        env->cansave++;
-        env->canrestore--;
-#endif
-        save_window_offset(env, cwp1);
-        offset++;
-    }
-    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
-#ifndef TARGET_SPARC64
-    /* set wim so that restore will reload the registers */
-    env->wim = 1 << cwp1;
-#endif
-#if defined(DEBUG_WIN)
-    printf("flush_windows: nb=%d\n", offset - 1);
-#endif
 }
 
-void cpu_loop(CPUSPARCState *env)
+void cpu_loop(CPUArchState *env)
 {
-    CPUState *cs = CPU(sparc_env_get_cpu(env));
-    int trapnr, ret, syscall_nr;
-    //target_siginfo_t info;
 
-    while (1) {
-        trapnr = cpu_sparc_exec (env);
-
-        switch (trapnr) {
-#ifndef TARGET_SPARC64
-        case 0x80:
-#else
-        /* FreeBSD uses 0x141 for syscalls too */
-        case 0x141:
-            if (bsd_type != target_freebsd)
-                goto badtrap;
-        case 0x100:
-#endif
-            syscall_nr = env->gregs[1];
-            if (bsd_type == target_freebsd)
-                ret = do_freebsd_syscall(env, syscall_nr,
-                                         env->regwptr[0], env->regwptr[1],
-                                         env->regwptr[2], env->regwptr[3],
-                                         env->regwptr[4], env->regwptr[5], 0, 0);
-            else if (bsd_type == target_netbsd)
-                ret = do_netbsd_syscall(env, syscall_nr,
-                                        env->regwptr[0], env->regwptr[1],
-                                        env->regwptr[2], env->regwptr[3],
-                                        env->regwptr[4], env->regwptr[5]);
-            else { //if (bsd_type == target_openbsd)
-#if defined(TARGET_SPARC64)
-                syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
-                                TARGET_OPENBSD_SYSCALL_G2RFLAG);
-#endif
-                ret = do_openbsd_syscall(env, syscall_nr,
-                                         env->regwptr[0], env->regwptr[1],
-                                         env->regwptr[2], env->regwptr[3],
-                                         env->regwptr[4], env->regwptr[5]);
-            }
-            if ((unsigned int)ret >= (unsigned int)(-515)) {
-                ret = -ret;
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
-                env->xcc |= PSR_CARRY;
-#else
-                env->psr |= PSR_CARRY;
-#endif
-            } else {
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
-                env->xcc &= ~PSR_CARRY;
-#else
-                env->psr &= ~PSR_CARRY;
-#endif
-            }
-            env->regwptr[0] = ret;
-            /* next instruction */
-#if defined(TARGET_SPARC64)
-            if (bsd_type == target_openbsd &&
-                env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
-                env->pc = env->gregs[2];
-                env->npc = env->pc + 4;
-            } else if (bsd_type == target_openbsd &&
-                       env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
-                env->pc = env->gregs[7];
-                env->npc = env->pc + 4;
-            } else {
-                env->pc = env->npc;
-                env->npc = env->npc + 4;
-            }
-#else
-            env->pc = env->npc;
-            env->npc = env->npc + 4;
-#endif
-            break;
-        case 0x83: /* flush windows */
-#ifdef TARGET_ABI32
-        case 0x103:
-#endif
-            flush_windows(env);
-            /* next instruction */
-            env->pc = env->npc;
-            env->npc = env->npc + 4;
-            break;
-#ifndef TARGET_SPARC64
-        case TT_WIN_OVF: /* window overflow */
-            save_window(env);
-            break;
-        case TT_WIN_UNF: /* window underflow */
-            restore_window(env);
-            break;
-        case TT_TFAULT:
-        case TT_DFAULT:
-#if 0
-            {
-                info.si_signo = SIGSEGV;
-                info.si_errno = 0;
-                /* XXX: check env->error_code */
-                info.si_code = TARGET_SEGV_MAPERR;
-                info._sifields._sigfault._addr = env->mmuregs[4];
-                queue_signal(env, info.si_signo, &info);
-            }
-#endif
-            break;
-#else
-        case TT_SPILL: /* window overflow */
-            save_window(env);
-            break;
-        case TT_FILL: /* window underflow */
-            restore_window(env);
-            break;
-        case TT_TFAULT:
-        case TT_DFAULT:
-#if 0
-            {
-                info.si_signo = SIGSEGV;
-                info.si_errno = 0;
-                /* XXX: check env->error_code */
-                info.si_code = TARGET_SEGV_MAPERR;
-                if (trapnr == TT_DFAULT)
-                    info._sifields._sigfault._addr = env->dmmuregs[4];
-                else
-                    info._sifields._sigfault._addr = env->tsptr->tpc;
-                //queue_signal(env, info.si_signo, &info);
-            }
-#endif
-            break;
-#endif
-        case EXCP_INTERRUPT:
-            /* just indicate that signals should be handled asap */
-            break;
-        case EXCP_DEBUG:
-            {
-                int sig;
-
-                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
-#if 0
-                if (sig)
-                  {
-                    info.si_signo = sig;
-                    info.si_errno = 0;
-                    info.si_code = TARGET_TRAP_BRKPT;
-                    //queue_signal(env, info.si_signo, &info);
-                  }
-#endif
-            }
-            break;
-        default:
-#ifdef TARGET_SPARC64
-        badtrap:
-#endif
-            printf ("Unhandled trap: 0x%x\n", trapnr);
-            cpu_dump_state(cs, stderr, fprintf, 0);
-            exit (1);
-        }
-        process_pending_signals (env);
-    }
+    target_cpu_loop(env);
 }
 
-#endif
-
 static void usage(void)
 {
     printf("qemu-" TARGET_NAME " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
@@ -709,12 +147,21 @@ static void usage(void)
            ,
            TARGET_NAME,
            interp_prefix,
-           x86_stack_size);
+           target_dflssiz);
     exit(1);
 }
 
 THREAD CPUState *thread_cpu;
 
+void stop_all_tasks(void)
+{
+    /*
+     * We trust when using NPTL (pthreads) start_exclusive() handles thread
+     * stopping correctly.
+     */
+    start_exclusive();
+}
+
 /* Assumes contents are already zeroed.  */
 void init_task_state(TaskState *ts)
 {
@@ -728,6 +175,15 @@ void init_task_state(TaskState *ts)
     ts->sigqueue_table[i].next = NULL;
 }
 
+void gemu_log(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+}
+
 int main(int argc, char **argv)
 {
     const char *filename;
@@ -744,11 +200,13 @@ int main(int argc, char **argv)
     int gdbstub_port = 0;
     char **target_environ, **wrk;
     envlist_t *envlist = NULL;
-    bsd_type = target_openbsd;
+    bsd_type = HOST_DEFAULT_BSD_TYPE;
 
     if (argc <= 1)
         usage();
 
+    save_proc_pathname(argv[0]);
+
     module_call_init(MODULE_INIT_QOM);
 
     if ((envlist = envlist_create()) == NULL) {
@@ -767,7 +225,7 @@ int main(int argc, char **argv)
 #endif
 
     optind = 1;
-    for(;;) {
+    for (;;) {
         if (optind >= argc)
             break;
         r = argv[optind];
@@ -803,13 +261,18 @@ int main(int argc, char **argv)
                 usage();
         } else if (!strcmp(r, "s")) {
             r = argv[optind++];
-            x86_stack_size = strtol(r, (char **)&r, 0);
-            if (x86_stack_size <= 0)
+            target_dflssiz = strtol(r, (char **)&r, 0);
+            if (target_dflssiz <= 0) {
+                usage();
+            }
+            if (*r == 'M') {
+                target_dflssiz *= 1024 * 1024;
+            } else if (*r == 'k' || *r == 'K') {
+                target_dflssiz *= 1024;
+            }
+            if (target_dflssiz > target_maxssiz) {
                 usage();
-            if (*r == 'M')
-                x86_stack_size *= 1024 * 1024;
-            else if (*r == 'k' || *r == 'K')
-                x86_stack_size *= 1024;
+            }
         } else if (!strcmp(r, "L")) {
             interp_prefix = argv[optind++];
         } else if (!strcmp(r, "p")) {
@@ -888,21 +351,7 @@ int main(int argc, char **argv)
     init_paths(interp_prefix);
 
     if (cpu_model == NULL) {
-#if defined(TARGET_I386)
-#ifdef TARGET_X86_64
-        cpu_model = "qemu64";
-#else
-        cpu_model = "qemu32";
-#endif
-#elif defined(TARGET_SPARC)
-#ifdef TARGET_SPARC64
-        cpu_model = "TI UltraSparc II";
-#else
-        cpu_model = "Fujitsu MB86904";
-#endif
-#else
-        cpu_model = "any";
-#endif
+        cpu_model = TARGET_DEFAULT_CPU_MODEL;
     }
     tcg_exec_init(0);
     cpu_exec_init_all();
@@ -914,9 +363,7 @@ int main(int argc, char **argv)
         exit(1);
     }
     cpu = ENV_GET_CPU(env);
-#if defined(TARGET_SPARC) || defined(TARGET_PPC)
-    cpu_reset(cpu);
-#endif
+    TARGET_CPU_RESET(env);
     thread_cpu = cpu;
 
     if (getenv("QEMU_STRACE")) {
@@ -955,7 +402,7 @@ int main(int argc, char **argv)
     }
 #endif /* CONFIG_USE_GUEST_BASE */
 
-    if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
+    if (loader_exec(filename, argv+optind, target_environ, regs, info)) {
         printf("Error loading %s\n", filename);
         _exit(1);
     }
@@ -1002,137 +449,7 @@ int main(int argc, char **argv)
     ts->info = info;
     env->opaque = ts;
 
-#if defined(TARGET_I386)
-    cpu_x86_set_cpl(env, 3);
-
-    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
-    env->hflags |= HF_PE_MASK;
-    if (env->features[FEAT_1_EDX] & CPUID_SSE) {
-        env->cr[4] |= CR4_OSFXSR_MASK;
-        env->hflags |= HF_OSFXSR_MASK;
-    }
-#ifndef TARGET_ABI32
-    /* enable 64 bit mode if possible */
-    if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
-        fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
-        exit(1);
-    }
-    env->cr[4] |= CR4_PAE_MASK;
-    env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
-    env->hflags |= HF_LMA_MASK;
-#endif
-
-    /* flags setup : we activate the IRQs by default as in user mode */
-    env->eflags |= IF_MASK;
-
-    /* linux register setup */
-#ifndef TARGET_ABI32
-    env->regs[R_EAX] = regs->rax;
-    env->regs[R_EBX] = regs->rbx;
-    env->regs[R_ECX] = regs->rcx;
-    env->regs[R_EDX] = regs->rdx;
-    env->regs[R_ESI] = regs->rsi;
-    env->regs[R_EDI] = regs->rdi;
-    env->regs[R_EBP] = regs->rbp;
-    env->regs[R_ESP] = regs->rsp;
-    env->eip = regs->rip;
-#else
-    env->regs[R_EAX] = regs->eax;
-    env->regs[R_EBX] = regs->ebx;
-    env->regs[R_ECX] = regs->ecx;
-    env->regs[R_EDX] = regs->edx;
-    env->regs[R_ESI] = regs->esi;
-    env->regs[R_EDI] = regs->edi;
-    env->regs[R_EBP] = regs->ebp;
-    env->regs[R_ESP] = regs->esp;
-    env->eip = regs->eip;
-#endif
-
-    /* linux interrupt setup */
-#ifndef TARGET_ABI32
-    env->idt.limit = 511;
-#else
-    env->idt.limit = 255;
-#endif
-    env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
-                                PROT_READ|PROT_WRITE,
-                                MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-    idt_table = g2h(env->idt.base);
-    set_idt(0, 0);
-    set_idt(1, 0);
-    set_idt(2, 0);
-    set_idt(3, 3);
-    set_idt(4, 3);
-    set_idt(5, 0);
-    set_idt(6, 0);
-    set_idt(7, 0);
-    set_idt(8, 0);
-    set_idt(9, 0);
-    set_idt(10, 0);
-    set_idt(11, 0);
-    set_idt(12, 0);
-    set_idt(13, 0);
-    set_idt(14, 0);
-    set_idt(15, 0);
-    set_idt(16, 0);
-    set_idt(17, 0);
-    set_idt(18, 0);
-    set_idt(19, 0);
-    set_idt(0x80, 3);
-
-    /* linux segment setup */
-    {
-        uint64_t *gdt_table;
-        env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
-                                    PROT_READ|PROT_WRITE,
-                                    MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-        env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
-        gdt_table = g2h(env->gdt.base);
-#ifdef TARGET_ABI32
-        write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
-                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
-                 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
-#else
-        /* 64 bit code segment */
-        write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
-                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
-                 DESC_L_MASK |
-                 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
-#endif
-        write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
-                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
-                 (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
-    }
-
-    cpu_x86_load_seg(env, R_CS, __USER_CS);
-    cpu_x86_load_seg(env, R_SS, __USER_DS);
-#ifdef TARGET_ABI32
-    cpu_x86_load_seg(env, R_DS, __USER_DS);
-    cpu_x86_load_seg(env, R_ES, __USER_DS);
-    cpu_x86_load_seg(env, R_FS, __USER_DS);
-    cpu_x86_load_seg(env, R_GS, __USER_DS);
-    /* This hack makes Wine work... */
-    env->segs[R_FS].selector = 0;
-#else
-    cpu_x86_load_seg(env, R_DS, 0);
-    cpu_x86_load_seg(env, R_ES, 0);
-    cpu_x86_load_seg(env, R_FS, 0);
-    cpu_x86_load_seg(env, R_GS, 0);
-#endif
-#elif defined(TARGET_SPARC)
-    {
-        int i;
-        env->pc = regs->pc;
-        env->npc = regs->npc;
-        env->y = regs->y;
-        for(i = 0; i < 8; i++)
-            env->gregs[i] = regs->u_regs[i];
-        for(i = 0; i < 8; i++)
-            env->regwptr[i] = regs->u_regs[i + 8];
-    }
-#else
-#error unsupported target CPU
-#endif
+    target_cpu_init(env, regs);
 
     if (gdbstub_port) {
         gdbserver_start (gdbstub_port);
diff --git a/bsd-user/mips/target_arch.h b/bsd-user/mips/target_arch.h
new file mode 100644
index 0000000..b3d32ba
--- /dev/null
+++ b/bsd-user/mips/target_arch.h
@@ -0,0 +1,10 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+#include "qemu.h"
+
+void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls);
+target_ulong target_cpu_get_tls(CPUMIPSState *env);
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/mips/target_arch_cpu.c b/bsd-user/mips/target_arch_cpu.c
new file mode 100644
index 0000000..dd59435
--- /dev/null
+++ b/bsd-user/mips/target_arch_cpu.c
@@ -0,0 +1,27 @@
+/*
+ *  mips cpu related code
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "target_arch.h"
+
+void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls)
+{
+    env->tls_value = newtls;
+}
+
+target_ulong target_cpu_get_tls(CPUMIPSState *env)
+{
+    return (env->tls_value);
+}
diff --git a/bsd-user/mips/target_arch_cpu.h b/bsd-user/mips/target_arch_cpu.h
new file mode 100644
index 0000000..b92deb6
--- /dev/null
+++ b/bsd-user/mips/target_arch_cpu.h
@@ -0,0 +1,243 @@
+/*
+ *  mips cpu init and loop
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#if defined(TARGET_ABI_MIPSN32)
+#  define TARGET_DEFAULT_CPU_MODEL "20Kc"
+#else
+#  define TARGET_DEFAULT_CPU_MODEL "24f"
+#endif
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUMIPSState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    for (i = 0; i < 32; i++) {
+        env->active_tc.gpr[i] = regs->regs[i];
+    }
+    env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
+    if (regs->cp0_epc & 1) {
+        env->hflags |= MIPS_HFLAG_M16;
+    }
+}
+
+static int do_store_exclusive(CPUMIPSState *env)
+{
+    target_ulong addr;
+    target_ulong page_addr;
+    target_ulong val;
+    int flags;
+    int segv = 0;
+    int reg;
+    int d;
+
+    addr = env->lladdr;
+    page_addr = addr & TARGET_PAGE_MASK;
+    start_exclusive();
+    mmap_lock();
+    flags = page_get_flags(page_addr);
+    if ((flags & PAGE_READ) == 0) {
+        segv = 1;
+    } else {
+        reg = env->llreg & 0x1f;
+        d = (env->llreg & 0x20) != 0;
+        if (d) {
+            segv = get_user_s64(val, addr);
+        } else {
+            segv = get_user_s32(val, addr);
+        }
+        if (!segv) {
+            if (val != env->llval) {
+                env->active_tc.gpr[reg] = 0;
+            } else {
+                if (d) {
+                    segv = put_user_u64(env->llnewval, addr);
+                } else {
+                    segv = put_user_u32(env->llnewval, addr);
+                }
+                if (!segv) {
+                    env->active_tc.gpr[reg] = 1;
+                }
+            }
+        }
+    }
+    env->lladdr = -1;
+    if (!segv) {
+        env->active_tc.PC += 4;
+    }
+    mmap_unlock();
+    end_exclusive();
+    return segv;
+}
+
+static inline void target_cpu_loop(CPUMIPSState *env)
+{
+    CPUState *cs = CPU(mips_env_get_cpu(env));
+    target_siginfo_t info;
+    int trapnr;
+    abi_long ret;
+    unsigned int syscall_num;
+
+    for (;;) {
+        cpu_exec_start(cs);
+        trapnr = cpu_mips_exec(env);
+        cpu_exec_end(cs);
+        switch (trapnr) {
+        case EXCP_SYSCALL: /* syscall exception */
+            if (bsd_type == target_freebsd) {
+                syscall_num = env->active_tc.gpr[2]; /* v0 */
+                env->active_tc.PC += TARGET_INSN_SIZE;
+                if (syscall_num >= TARGET_FREEBSD_NR_MAXSYSCALL) {
+                    ret = -TARGET_ENOSYS;
+                } else {
+                    /* mips(32) uses regs 4-7,12-15 for args */
+                    if (TARGET_FREEBSD_NR___syscall == syscall_num ||
+                            TARGET_FREEBSD_NR_syscall == syscall_num) {
+                        /* indirect syscall */
+                        ret = do_freebsd_syscall(env,
+                                env->active_tc.gpr[4],/* syscall #*/
+                                env->active_tc.gpr[5], /* a1/arg0 */
+                                env->active_tc.gpr[6], /* a2/arg1 */
+                                env->active_tc.gpr[7], /* a3/arg2 */
+                                env->active_tc.gpr[12],/* t4/arg3 */
+                                env->active_tc.gpr[13],/* t5/arg4 */
+                                env->active_tc.gpr[14],/* t6/arg5 */
+                                env->active_tc.gpr[15],/* t7/arg6 */
+                                0  /* no arg7 */
+                                );
+                    } else {
+                        /* direct syscall */
+                        ret = do_freebsd_syscall(env,
+                                syscall_num,
+                                env->active_tc.gpr[4], /* a0/arg0 */
+                                env->active_tc.gpr[5], /* a1/arg1 */
+                                env->active_tc.gpr[6], /* a2/arg2 */
+                                env->active_tc.gpr[7], /* a3/arg3 */
+                                env->active_tc.gpr[12],/* t4/arg4 */
+                                env->active_tc.gpr[13],/* t5/arg5 */
+                                env->active_tc.gpr[14],/* t6/arg6 */
+                                env->active_tc.gpr[15] /* t7/arg7 */
+                                );
+                    }
+                }
+                /* Compare to mips/mips/vm_machdep.c cpu_set_syscall_retval() */
+                if (-TARGET_EJUSTRETURN == ret) {
+                    /*
+                     * Returning from a successful sigreturn
+                     * syscall.  Avoid clobbering register state.
+                     */
+                    break;
+                }
+                if (-TARGET_ERESTART == ret) {
+                    /* Backup the pc to point at the swi. */
+                    env->active_tc.PC -= TARGET_INSN_SIZE;
+                    break;
+                }
+                if ((unsigned int)ret >= (unsigned int)(-1133)) {
+                    env->active_tc.gpr[7] = 1;
+                    ret = -ret;
+                } else {
+                    env->active_tc.gpr[7] = 0;
+                }
+                env->active_tc.gpr[2] = ret; /* v0 <- ret */
+            } /* else if (bsd_type == target_openbsd)... */
+            else {
+                fprintf(stderr, "qemu: bsd_type (= %d) syscall not supported\n",
+                        bsd_type);
+            }
+            break;
+
+        case EXCP_TLBL: /* TLB miss on load */
+        case EXCP_TLBS: /* TLB miss on store */
+        case EXCP_AdEL: /* bad address on load */
+        case EXCP_AdES: /* bad address on store */
+            info.target_si_signo = TARGET_SIGSEGV;
+            info.target_si_errno = 0;
+            /* XXX: check env->error_code */
+            info.target_si_code = TARGET_SEGV_MAPERR;
+            info.target_si_addr = env->CP0_BadVAddr;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP_CpU: /* coprocessor unusable */
+        case EXCP_RI:  /* reserved instruction */
+            info.target_si_signo = TARGET_SIGILL;
+            info.target_si_errno = 0;
+            info.target_si_code = 0;
+            queue_signal(env, info.target_si_signo, &info);
+            break;
+
+        case EXCP_INTERRUPT: /* async interrupt */
+            /* just indicate that signals should be handled asap */
+            break;
+
+        case EXCP_DEBUG: /* cpu stopped after a breakpoint */
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+                if (sig) {
+                    info.target_si_signo = sig;
+                    info.target_si_errno = 0;
+                    info.target_si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.target_si_signo, &info);
+                }
+            }
+            break;
+
+        case EXCP_SC:
+            if (do_store_exclusive(env)) {
+                info.target_si_signo = TARGET_SIGSEGV;
+                info.target_si_errno = 0;
+                info.target_si_code = TARGET_SEGV_MAPERR;
+                info.target_si_addr = env->active_tc.PC;
+                queue_signal(env, info.target_si_signo, &info);
+            }
+            break;
+
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception "
+                "0x%x - aborting\n", trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUMIPSState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->active_tc.gpr[29] = newsp;
+    env->active_tc.gpr[7] = 0;
+    env->active_tc.gpr[2] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/mips/target_arch_vmparam.h b/bsd-user/mips/target_arch_vmparam.h
new file mode 100644
index 0000000..f9e54ce
--- /dev/null
+++ b/bsd-user/mips/target_arch_vmparam.h
@@ -0,0 +1,47 @@
+/*
+ *  mips VM parameters definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to sys/mips/include/vmparam.h */
+#define TARGET_MAXTSIZ      (128UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ      (128UL*1024*1024)   /* initial data size limit */
+#define TARGET_MAXDSIZ      (1*1024UL*1024*1024)    /* max data size */
+#define TARGET_DFLSSIZ      (8UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ      (64UL*1024*1024)    /* max stack size */
+#define TARGET_SGROWSIZ     (128UL*1024)        /* amount to grow stack */
+
+#define TARGET_VM_MINUSER_ADDRESS   (0x00000000)
+#define TARGET_VM_MAXUSER_ADDRESS   (0x80000000)
+
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
+{
+    return state->active_tc.gpr[29];
+}
+
+static inline void set_second_rval(CPUMIPSState *state, abi_ulong retval2)
+{
+    state->active_tc.gpr[3] = retval2;
+}
+
+#endif  /* ! _TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/mips64/target_arch.h b/bsd-user/mips64/target_arch.h
new file mode 100644
index 0000000..b3d32ba
--- /dev/null
+++ b/bsd-user/mips64/target_arch.h
@@ -0,0 +1,10 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+#include "qemu.h"
+
+void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls);
+target_ulong target_cpu_get_tls(CPUMIPSState *env);
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/mips64/target_arch_cpu.c b/bsd-user/mips64/target_arch_cpu.c
new file mode 100644
index 0000000..9d016a3
--- /dev/null
+++ b/bsd-user/mips64/target_arch_cpu.c
@@ -0,0 +1,27 @@
+/*
+ *  mips64 cpu related code
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "target_arch.h"
+
+void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls)
+{
+    env->tls_value = newtls;
+}
+
+target_ulong target_cpu_get_tls(CPUMIPSState *env)
+{
+    return (env->tls_value);
+}
diff --git a/bsd-user/mips64/target_arch_cpu.h b/bsd-user/mips64/target_arch_cpu.h
new file mode 100644
index 0000000..c5a4acd
--- /dev/null
+++ b/bsd-user/mips64/target_arch_cpu.h
@@ -0,0 +1,243 @@
+/*
+ *  mips64 cpu init and loop
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
+#  define TARGET_DEFAULT_CPU_MODEL "20Kc"
+#else
+#  define TARGET_DEFAULT_CPU_MODEL "24f"
+#endif
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUMIPSState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    for (i = 0; i < 32; i++) {
+        env->active_tc.gpr[i] = regs->regs[i];
+    }
+    env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
+    if (regs->cp0_epc & 1) {
+        env->hflags |= MIPS_HFLAG_M16;
+    }
+    env->hflags |= MIPS_HFLAG_UX | MIPS_HFLAG_64;
+}
+
+static int do_store_exclusive(CPUMIPSState *env)
+{
+    target_ulong addr;
+    target_ulong page_addr;
+    target_ulong val;
+    int flags;
+    int segv = 0;
+    int reg;
+    int d;
+
+    addr = env->lladdr;
+    page_addr = addr & TARGET_PAGE_MASK;
+    start_exclusive();
+    mmap_lock();
+    flags = page_get_flags(page_addr);
+    if ((flags & PAGE_READ) == 0) {
+        segv = 1;
+    } else {
+        reg = env->llreg & 0x1f;
+        d = (env->llreg & 0x20) != 0;
+        if (d) {
+            segv = get_user_s64(val, addr);
+        } else {
+            segv = get_user_s32(val, addr);
+        }
+        if (!segv) {
+            if (val != env->llval) {
+                env->active_tc.gpr[reg] = 0;
+            } else {
+                if (d) {
+                    segv = put_user_u64(env->llnewval, addr);
+                } else {
+                    segv = put_user_u32(env->llnewval, addr);
+                }
+                if (!segv) {
+                    env->active_tc.gpr[reg] = 1;
+                }
+            }
+        }
+    }
+    env->lladdr = -1;
+    if (!segv) {
+        env->active_tc.PC += 4;
+    }
+    mmap_unlock();
+    end_exclusive();
+    return segv;
+}
+
+static inline void target_cpu_loop(CPUMIPSState *env)
+{
+    CPUState *cs = CPU(mips_env_get_cpu(env));
+    target_siginfo_t info;
+    int trapnr;
+    abi_long ret;
+    unsigned int syscall_num;
+
+    for (;;) {
+        cpu_exec_start(cs);
+        trapnr = cpu_mips_exec(env);
+        cpu_exec_end(cs);
+        switch (trapnr) {
+        case EXCP_SYSCALL: /* syscall exception */
+            if (bsd_type == target_freebsd) {
+                syscall_num = env->active_tc.gpr[2]; /* v0 */
+                env->active_tc.PC += TARGET_INSN_SIZE;
+                if (syscall_num >= TARGET_FREEBSD_NR_MAXSYSCALL) {
+                    ret = -TARGET_ENOSYS;
+                } else {
+                    /* mips64 uses regs 4-11 for args */
+                    if (TARGET_FREEBSD_NR___syscall == syscall_num ||
+                            TARGET_FREEBSD_NR_syscall == syscall_num) {
+                        /* indirect syscall */
+                        ret = do_freebsd_syscall(env,
+                                env->active_tc.gpr[4],/* syscall #*/
+                                env->active_tc.gpr[5], /* arg0 */
+                                env->active_tc.gpr[6], /* arg1 */
+                                env->active_tc.gpr[7], /* arg2 */
+                                env->active_tc.gpr[8], /* arg3 */
+                                env->active_tc.gpr[9], /* arg4 */
+                                env->active_tc.gpr[10],/* arg5 */
+                                env->active_tc.gpr[11],/* arg6 */
+                                0 /* no arg 7 */);
+                    } else {
+                        /* direct syscall */
+                        ret = do_freebsd_syscall(env,
+                                syscall_num,
+                                env->active_tc.gpr[4],
+                                env->active_tc.gpr[5],
+                                env->active_tc.gpr[6],
+                                env->active_tc.gpr[7],
+                                env->active_tc.gpr[8],
+                                env->active_tc.gpr[9],
+                                env->active_tc.gpr[10],
+                                env->active_tc.gpr[11]
+                                );
+                    }
+                }
+                /* Compare to mips/mips/vm_machdep.c cpu_set_syscall_retval() */
+                if (-TARGET_EJUSTRETURN == ret) {
+                    /*
+                     * Returning from a successful sigreturn
+                     * syscall.  Avoid clobbering register state.
+                     */
+                    break;
+                }
+                if (-TARGET_ERESTART == ret) {
+                    /* Backup the pc to point at the swi. */
+                    env->active_tc.PC -= TARGET_INSN_SIZE;
+                    break;
+                }
+                if ((unsigned int)ret >= (unsigned int)(-1133)) {
+                    env->active_tc.gpr[7] = 1;
+                    ret = -ret;
+                } else {
+                    env->active_tc.gpr[7] = 0;
+                }
+                env->active_tc.gpr[2] = ret; /* v0 <- ret */
+            } /* else if (bsd_type == target_openbsd)... */
+            else {
+                fprintf(stderr, "qemu: bsd_type (= %d) syscall not supported\n",
+                        bsd_type);
+            }
+            break;
+
+        case EXCP_TLBL: /* TLB miss on load */
+        case EXCP_TLBS: /* TLB miss on store */
+        case EXCP_AdEL: /* bad address on load */
+        case EXCP_AdES: /* bad address on store */
+            info.target_si_signo = TARGET_SIGSEGV;
+            info.target_si_errno = 0;
+            /* XXX: check env->error_code */
+            info.target_si_code = TARGET_SEGV_MAPERR;
+            info.target_si_addr = env->CP0_BadVAddr;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP_CpU: /* coprocessor unusable */
+        case EXCP_RI:  /* reserved instruction */
+            info.target_si_signo = TARGET_SIGILL;
+            info.target_si_errno = 0;
+            info.target_si_code = 0;
+            queue_signal(env, info.target_si_signo, &info);
+            break;
+
+        case EXCP_INTERRUPT: /* async interrupt */
+            /* just indicate that signals should be handled asap */
+            break;
+
+        case EXCP_DEBUG: /* cpu stopped after a breakpoint */
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+                if (sig) {
+                    info.target_si_signo = sig;
+                    info.target_si_errno = 0;
+                    info.target_si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.target_si_signo, &info);
+                }
+            }
+            break;
+
+        case EXCP_SC:
+            if (do_store_exclusive(env)) {
+                info.target_si_signo = TARGET_SIGSEGV;
+                info.target_si_errno = 0;
+                info.target_si_code = TARGET_SEGV_MAPERR;
+                info.target_si_addr = env->active_tc.PC;
+                queue_signal(env, info.target_si_signo, &info);
+            }
+            break;
+
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception "
+                "0x%x - aborting\n", trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUMIPSState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->active_tc.gpr[29] = newsp;
+    env->active_tc.gpr[7] = 0;
+    env->active_tc.gpr[2] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/mips64/target_arch_vmparam.h b/bsd-user/mips64/target_arch_vmparam.h
new file mode 100644
index 0000000..1ba09e0
--- /dev/null
+++ b/bsd-user/mips64/target_arch_vmparam.h
@@ -0,0 +1,47 @@
+/*
+ *  mips64 VM parameters definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to sys/mips/include/vmparam.h */
+#define TARGET_MAXTSIZ      (128UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ      (128UL*1024*1024)   /* initial data size limit */
+#define TARGET_MAXDSIZ      (1*1024UL*1024*1024)    /* max data size */
+#define TARGET_DFLSSIZ      (8UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ      (64UL*1024*1024)    /* max stack size */
+#define TARGET_SGROWSIZ     (128UL*1024)        /* amount to grow stack */
+
+#define TARGET_VM_MINUSER_ADDRESS   (0x0000000000000000UL)
+#define TARGET_VM_MAXUSER_ADDRESS   (0x0000008000000000UL)
+
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
+{
+    return state->active_tc.gpr[29];
+}
+
+static inline void set_second_rval(CPUMIPSState *state, abi_ulong retval2)
+{
+    state->active_tc.gpr[3] = retval2;
+}
+
+#endif  /* ! _TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/netbsd/host_os.h b/bsd-user/netbsd/host_os.h
new file mode 100644
index 0000000..5c492e3
--- /dev/null
+++ b/bsd-user/netbsd/host_os.h
@@ -0,0 +1,31 @@
+/*
+ *  NetBSD host dependent code and definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST_OS_H_
+#define __HOST_OS_H_
+
+#include "qemu.h"
+
+#define HOST_DEFAULT_BSD_TYPE target_netbsd
+
+static inline void save_proc_pathname(char *argv0)
+{
+    /* XXX */
+}
+
+#endif /*!__HOST_OS_H_ */
diff --git a/bsd-user/openbsd/host_os.h b/bsd-user/openbsd/host_os.h
new file mode 100644
index 0000000..162ce58
--- /dev/null
+++ b/bsd-user/openbsd/host_os.h
@@ -0,0 +1,31 @@
+/*
+ *  OpenBSD host dependent code and definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST_OS_H_
+#define __HOST_OS_H_
+
+#include "qemu.h"
+
+#define HOST_DEFAULT_BSD_TYPE target_openbsd
+
+static inline void save_proc_pathname(char *argv0)
+{
+    /* XXX */
+}
+
+#endif /*!__HOST_OS_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index b8a34c7..cb77069 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -38,6 +38,7 @@ extern enum BSDType bsd_type;
 
 #include "syscall_defs.h"
 #include "syscall.h"
+#include "target_os_vmparam.h"
 #include "target_signal.h"
 #include "exec/gdbstub.h"
 
@@ -99,6 +100,7 @@ typedef struct TaskState {
 } __attribute__((aligned(16))) TaskState;
 
 void init_task_state(TaskState *ts);
+void stop_all_tasks(void);
 extern const char *qemu_uname_release;
 #if defined(CONFIG_USE_GUEST_BASE)
 extern unsigned long mmap_min_addr;
@@ -222,7 +224,13 @@ void mmap_fork_end(int child);
 #endif
 
 /* main.c */
-extern unsigned long x86_stack_size;
+extern unsigned long target_maxtsiz;
+extern unsigned long target_dfldsiz;
+extern unsigned long target_maxdsiz;
+extern unsigned long target_dflssiz;
+extern unsigned long target_maxssiz;
+extern unsigned long target_sgrowsiz;
+extern char qemu_proc_pathname[];
 
 /* user access */
 
diff --git a/bsd-user/sparc/target_arch.h b/bsd-user/sparc/target_arch.h
new file mode 100644
index 0000000..5ee479b
--- /dev/null
+++ b/bsd-user/sparc/target_arch.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+void bsd_sparc_save_window(CPUSPARCState *env);
+void bsd_sparc_restore_window(CPUSPARCState *env);
+void bsd_sparc_flush_windows(CPUSPARCState *env);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* ! _TARGET_ARCH_H_ */
diff --git a/bsd-user/sparc/target_arch_cpu.c b/bsd-user/sparc/target_arch_cpu.c
new file mode 100644
index 0000000..0af5c7e
--- /dev/null
+++ b/bsd-user/sparc/target_arch_cpu.c
@@ -0,0 +1,113 @@
+/*
+ *  sparc cpu related code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+
+#include "target_arch.h"
+
+/* #define DEBUG_WIN */
+/* WARNING: dealing with register windows _is_ complicated. More info
+   can be found at http://www.sics.se/~psm/sparcstack.html */
+static int get_reg_index(CPUSPARCState *env, int cwp, int index)
+{
+    index = (index + cwp * 16) % (16 * env->nwindows);
+    /* wrap handling : if cwp is on the last window, then we use the
+       registers 'after' the end */
+    if (index < 8 && env->cwp == env->nwindows - 1) {
+        index += 16 * env->nwindows;
+    }
+    return index;
+}
+
+/* save the register window 'cwp1' */
+static void save_window_offset(CPUSPARCState *env, int cwp1)
+{
+    unsigned int i;
+    abi_ulong sp_ptr;
+
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#if defined(DEBUG_WIN)
+    printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for (i = 0; i < 16; i++) {
+        /* FIXME - what to do if put_user() fails? */
+        put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+}
+
+void bsd_sparc_save_window(CPUSPARCState *env)
+{
+    unsigned int new_wim;
+
+    new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
+        ((1LL << env->nwindows) - 1);
+    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+    env->wim = new_wim;
+}
+
+void bsd_sparc_restore_window(CPUSPARCState *env)
+{
+    unsigned int new_wim;
+    unsigned int i, cwp1;
+    abi_ulong sp_ptr;
+
+    new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
+        ((1LL << env->nwindows) - 1);
+
+    /* restore the invalid window */
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#if defined(DEBUG_WIN)
+    printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for (i = 0; i < 16; i++) {
+        /* FIXME - what to do if get_user() fails? */
+        get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+    env->wim = new_wim;
+}
+
+void bsd_sparc_flush_windows(CPUSPARCState *env)
+{
+    int offset, cwp1;
+
+    offset = 1;
+    for (;;) {
+        /* if restore would invoke restore_window(), then we can stop */
+        cwp1 = cpu_cwp_inc(env, env->cwp + offset);
+        if (env->wim & (1 << cwp1)) {
+            break;
+        }
+        save_window_offset(env, cwp1);
+        offset++;
+    }
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+    /* set wim so that restore will reload the registers */
+    env->wim = 1 << cwp1;
+#if defined(DEBUG_WIN)
+    printf("bsd_sparc_flush_windows: nb=%d\n", offset - 1);
+#endif
+}
+
diff --git a/bsd-user/sparc/target_arch_cpu.h b/bsd-user/sparc/target_arch_cpu.h
new file mode 100644
index 0000000..2eabff6
--- /dev/null
+++ b/bsd-user/sparc/target_arch_cpu.h
@@ -0,0 +1,158 @@
+/*
+ *  sparc cpu init and loop
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "Fujitsu MB86904"
+
+#define TARGET_CPU_RESET(env) cpu_reset(ENV_GET_CPU(env))
+
+static inline void target_cpu_init(CPUSPARCState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    env->pc = regs->pc;
+    env->npc = regs->npc;
+    env->y = regs->y;
+    for (i = 0; i < 8; i++) {
+        env->gregs[i] = regs->u_regs[i];
+    }
+    for (i = 0; i < 8; i++) {
+        env->regwptr[i] = regs->u_regs[i + 8];
+    }
+}
+
+static inline void target_cpu_loop(CPUSPARCState *env)
+{
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
+    int trapnr, ret, syscall_nr;
+    /* target_siginfo_t info; */
+
+    while (1) {
+        trapnr = cpu_sparc_exec(env);
+
+        switch (trapnr) {
+        case 0x80:
+            syscall_nr = env->gregs[1];
+            if (bsd_type == target_freebsd) {
+                ret = do_freebsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5], 0, 0);
+            } else if (bsd_type == target_netbsd) {
+                ret = do_netbsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5]);
+            } else { /* if (bsd_type == target_openbsd) */
+                ret = do_openbsd_syscall(env, syscall_nr,
+                                         env->regwptr[0], env->regwptr[1],
+                                         env->regwptr[2], env->regwptr[3],
+                                         env->regwptr[4], env->regwptr[5]);
+            }
+            if ((unsigned int)ret >= (unsigned int)(-515)) {
+                ret = -ret;
+                env->psr |= PSR_CARRY;
+            } else {
+                env->psr &= ~PSR_CARRY;
+            }
+            env->regwptr[0] = ret;
+            /* next instruction */
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+            break;
+        case 0x83: /* flush windows */
+#ifdef TARGET_ABI32
+        case 0x103:
+#endif
+            bsd_sparc_flush_windows(env);
+            /* next instruction */
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+            break;
+
+        case TT_WIN_OVF: /* window overflow */
+            bsd_sparc_save_window(env);
+            break;
+
+        case TT_WIN_UNF: /* window underflow */
+            bsd_sparc_restore_window(env);
+            break;
+
+        case TT_TFAULT:
+        case TT_DFAULT:
+#if 0
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = env->mmuregs[4];
+                queue_signal(env, info.si_signo, &info);
+            }
+#endif
+            break;
+
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+#if 0
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    /* queue_signal(env, info.si_signo, &info); */
+                }
+#endif
+            }
+            break;
+        default:
+            printf("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            exit(1);
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUSPARCState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regwptr[22] = newsp;
+    env->regwptr[0] = 0;
+    /* FIXME: Do we also need to clear CF?  */
+    /* XXXXX */
+    printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+    cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/sparc/target_arch_vmparam.h b/bsd-user/sparc/target_arch_vmparam.h
new file mode 100644
index 0000000..75bbeeb
--- /dev/null
+++ b/bsd-user/sparc/target_arch_vmparam.h
@@ -0,0 +1,35 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+#define TARGET_MAXTSIZ  (1*1024*1024*1024)  /* max text size */
+#define TARGET_DFLDSIZ  (128*1024*1024)     /* initial data size limit */
+#define TARGET_MAXDSIZ  (1*1024*1024*1024)  /* max data size */
+#define TARGET_DFLSSIZ  (128*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ  (1*1024*1024*1024)  /* max stack size */
+#define TARGET_SGROWSIZ (128*1024)      /* amount to grow stack */
+
+/* XXX this may not be right */
+#define TARGET_VM_MAXUSER_ADDRESS   (0xc0000000 - (512 * 1024 * 1024))
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+#ifndef UREG_I6
+#define UREG_I6        6
+#endif
+#ifndef UREG_FP
+#define UREG_FP        UREG_I6
+#endif
+
+static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+    return state->regwptr[UREG_FP];
+}
+
+static inline void set_second_rval(CPUSPARCState *state, abi_ulong retval2)
+{
+    state->regwptr[1] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
+
diff --git a/bsd-user/sparc/target_signal.h b/bsd-user/sparc/target_signal.h
index 5b2abba..181867a 100644
--- a/bsd-user/sparc/target_signal.h
+++ b/bsd-user/sparc/target_signal.h
@@ -19,9 +19,4 @@ typedef struct target_sigaltstack {
 #define UREG_FP        UREG_I6
 #endif
 
-static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
-{
-    return state->regwptr[UREG_FP];
-}
-
 #endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/sparc64/target_arch.h b/bsd-user/sparc64/target_arch.h
new file mode 100644
index 0000000..46bbcf8
--- /dev/null
+++ b/bsd-user/sparc64/target_arch.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+void bsd_sparc64_save_window(CPUSPARCState *env);
+void bsd_sparc64_restore_window(CPUSPARCState *env);
+void bsd_sparc64_flush_windows(CPUSPARCState *env);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* ! _TARGET_ARCH_H_ */
diff --git a/bsd-user/sparc64/target_arch_cpu.c b/bsd-user/sparc64/target_arch_cpu.c
new file mode 100644
index 0000000..e7bede8
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_cpu.c
@@ -0,0 +1,118 @@
+/*
+ *  sparc64 cpu related code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+
+#include "target_arch.h"
+
+#define SPARC64_STACK_BIAS 2047
+
+/* #define DEBUG_WIN */
+/* WARNING: dealing with register windows _is_ complicated. More info
+   can be found at http://www.sics.se/~psm/sparcstack.html */
+static int get_reg_index(CPUSPARCState *env, int cwp, int index)
+{
+    index = (index + cwp * 16) % (16 * env->nwindows);
+    /* wrap handling : if cwp is on the last window, then we use the
+       registers 'after' the end */
+    if (index < 8 && env->cwp == env->nwindows - 1) {
+        index += 16 * env->nwindows;
+    }
+    return index;
+}
+
+/* save the register window 'cwp1' */
+static void save_window_offset(CPUSPARCState *env, int cwp1)
+{
+    unsigned int i;
+    abi_ulong sp_ptr;
+
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+    if (sp_ptr & 3) {
+        sp_ptr += SPARC64_STACK_BIAS;
+    }
+#if defined(DEBUG_WIN)
+    printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for (i = 0; i < 16; i++) {
+        /* FIXME - what to do if put_user() fails? */
+        put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+}
+
+void bsd_sparc64_save_window(CPUSPARCState *env)
+{
+    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+    env->cansave++;
+    env->canrestore--;
+}
+
+void bsd_sparc64_restore_window(CPUSPARCState *env)
+{
+    unsigned int i, cwp1;
+    abi_ulong sp_ptr;
+
+    /* restore the invalid window */
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+    if (sp_ptr & 3) {
+        sp_ptr += SPARC64_STACK_BIAS;
+    }
+#if defined(DEBUG_WIN)
+    printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for (i = 0; i < 16; i++) {
+        /* FIXME - what to do if get_user() fails? */
+        get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+    env->canrestore++;
+    if (env->cleanwin < env->nwindows - 1) {
+        env->cleanwin++;
+    }
+    env->cansave--;
+}
+
+void bsd_sparc64_flush_windows(CPUSPARCState *env)
+{
+    int offset, cwp1;
+
+    offset = 1;
+    for (;;) {
+        /* if restore would invoke restore_window(), then we can stop */
+        cwp1 = cpu_cwp_inc(env, env->cwp + offset);
+        if (env->canrestore == 0) {
+            break;
+        }
+        env->cansave++;
+        env->canrestore--;
+        save_window_offset(env, cwp1);
+        offset++;
+    }
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+#if defined(DEBUG_WIN)
+    printf("bsd_sparc64_flush_windows: nb=%d\n", offset - 1);
+#endif
+}
+
diff --git a/bsd-user/sparc64/target_arch_cpu.h b/bsd-user/sparc64/target_arch_cpu.h
new file mode 100644
index 0000000..e497711
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_cpu.h
@@ -0,0 +1,191 @@
+/*
+ *  sparc64 cpu init and loop
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "TI UltraSparc II"
+
+#define TARGET_CPU_RESET(env) cpu_reset(ENV_GET_CPU(env))
+
+static inline void target_cpu_init(CPUSPARCState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    env->pc = regs->pc;
+    env->npc = regs->npc;
+    env->y = regs->y;
+    for (i = 0; i < 8; i++) {
+        env->gregs[i] = regs->u_regs[i];
+    }
+    for (i = 0; i < 8; i++) {
+        env->regwptr[i] = regs->u_regs[i + 8];
+    }
+}
+
+
+static inline void target_cpu_loop(CPUSPARCState *env)
+{
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
+    int trapnr, ret, syscall_nr;
+    /* target_siginfo_t info; */
+
+    while (1) {
+        trapnr = cpu_sparc_exec(env);
+
+        switch (trapnr) {
+        /* FreeBSD uses 0x141 for syscalls too */
+        case 0x141:
+            if (bsd_type != target_freebsd) {
+                goto badtrap;
+            }
+        case 0x100:
+            syscall_nr = env->gregs[1];
+            if (bsd_type == target_freebsd) {
+                ret = do_freebsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5], 0, 0);
+            } else if (bsd_type == target_netbsd) {
+                ret = do_netbsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5]);
+            } else { /* if (bsd_type == target_openbsd) */
+                syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
+                                TARGET_OPENBSD_SYSCALL_G2RFLAG);
+                ret = do_openbsd_syscall(env, syscall_nr,
+                                         env->regwptr[0], env->regwptr[1],
+                                         env->regwptr[2], env->regwptr[3],
+                                         env->regwptr[4], env->regwptr[5]);
+            }
+            if ((unsigned int)ret >= (unsigned int)(-515)) {
+                ret = -ret;
+#if !defined(TARGET_ABI32)
+                env->xcc |= PSR_CARRY;
+#else
+                env->psr |= PSR_CARRY;
+#endif
+            } else {
+#if !defined(TARGET_ABI32)
+                env->xcc &= ~PSR_CARRY;
+#else
+                env->psr &= ~PSR_CARRY;
+#endif
+            }
+            env->regwptr[0] = ret;
+            /* next instruction */
+            if (bsd_type == target_openbsd &&
+                env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
+                env->pc = env->gregs[2];
+                env->npc = env->pc + 4;
+            } else if (bsd_type == target_openbsd &&
+                       env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
+                env->pc = env->gregs[7];
+                env->npc = env->pc + 4;
+            } else {
+                env->pc = env->npc;
+                env->npc = env->npc + 4;
+            }
+            break;
+
+        case 0x83: /* flush windows */
+#ifdef TARGET_ABI32
+        case 0x103:
+#endif
+            bsd_sparc64_flush_windows(env);
+            /* next instruction */
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+            break;
+
+        case TT_SPILL: /* window overflow */
+            bsd_sparc64_save_window(env);
+            break;
+
+        case TT_FILL: /* window underflow */
+            bsd_sparc64_restore_window(env);
+            break;
+
+        case TT_TFAULT:
+        case TT_DFAULT:
+#if 0
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                if (trapnr == TT_DFAULT) {
+                    info._sifields._sigfault._addr = env->dmmuregs[4];
+                } else {
+                    info._sifields._sigfault._addr = env->tsptr->tpc;
+                    /* queue_signal(env, info.si_signo, &info); */
+                }
+            }
+#endif
+            break;
+
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+#if 0
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    /* queue_signal(env, info.si_signo, &info); */
+                }
+#endif
+            }
+            break;
+
+        default:
+badtrap:
+            printf("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            exit(1);
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUSPARCState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regwptr[22] = newsp;
+    env->regwptr[0] = 0;
+    /* FIXME: Do we also need to clear CF?  */
+    /* XXXXX */
+    printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+    cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/sparc64/target_arch_vmparam.h b/bsd-user/sparc64/target_arch_vmparam.h
new file mode 100644
index 0000000..2c2323b
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_vmparam.h
@@ -0,0 +1,37 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to amd64/include/vmparam.h */
+#define TARGET_MAXTSIZ  (1*1024*1024*1024)  /* max text size */
+#define TARGET_DFLDSIZ  (128*1024*1024)     /* initial data size limit */
+#define TARGET_MAXDSIZ  (1*1024*1024*1024)  /* max data size */
+#define TARGET_DFLSSIZ  (128*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ  (1*1024*1024*1024)  /* max stack size */
+#define TARGET_SGROWSIZ (128*1024)      /* amount to grow stack */
+
+/* XXX */
+#define TARGET_VM_MINUSER_ADDRESS   (0x0000000000000000UL)
+#define TARGET_VM_MAXUSER_ADDRESS   (0x000007fe00000000UL)
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+#ifndef UREG_I6
+#define UREG_I6        6
+#endif
+#ifndef UREG_FP
+#define UREG_FP        UREG_I6
+#endif
+
+static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+    return state->regwptr[UREG_FP];
+}
+
+static inline void set_second_rval(CPUSPARCState *state, abi_ulong retval2)
+{
+    state->regwptr[1] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
+
diff --git a/bsd-user/sparc64/target_signal.h b/bsd-user/sparc64/target_signal.h
index 5b2abba..181867a 100644
--- a/bsd-user/sparc64/target_signal.h
+++ b/bsd-user/sparc64/target_signal.h
@@ -19,9 +19,4 @@ typedef struct target_sigaltstack {
 #define UREG_FP        UREG_I6
 #endif
 
-static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
-{
-    return state->regwptr[UREG_FP];
-}
-
 #endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/x86_64/target_arch.h b/bsd-user/x86_64/target_arch.h
new file mode 100644
index 0000000..7fe81dc
--- /dev/null
+++ b/bsd-user/x86_64/target_arch.h
@@ -0,0 +1,13 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+/* target_arch_cpu.c */
+void bsd_x86_64_write_dt(void *ptr, unsigned long addr, unsigned long limit,
+                int flags);
+void bsd_x86_64_set_idt(int n, unsigned int dpl);
+void bsd_x86_64_set_idt_base(uint64_t base);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/x86_64/target_arch_cpu.c b/bsd-user/x86_64/target_arch_cpu.c
new file mode 100644
index 0000000..5cfdfca
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_cpu.c
@@ -0,0 +1,79 @@
+/*
+ *  x86_64 cpu related code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+#include "qemu/timer.h"
+
+#include "target_arch.h"
+
+static uint64_t *idt_table;
+
+/* CPUX86 core interface */
+void cpu_smm_update(CPUX86State *env)
+{
+}
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+    return cpu_get_real_ticks();
+}
+
+int cpu_get_pic_interrupt(CPUX86State *env)
+{
+    return -1;
+}
+
+void bsd_x86_64_write_dt(void *ptr, unsigned long addr,
+        unsigned long limit, int flags)
+{
+    unsigned int e1, e2;
+    uint32_t *p;
+    e1 = (addr << 16) | (limit & 0xffff);
+    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+    e2 |= flags;
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
+        uint64_t addr, unsigned int sel)
+{
+    uint32_t *p, e1, e2;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+    p[2] = tswap32(addr >> 32);
+    p[3] = 0;
+}
+
+/* only dpl matters as we do only user space emulation */
+void bsd_x86_64_set_idt(int n, unsigned int dpl)
+{
+    set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
+}
+
+void bsd_x86_64_set_idt_base(uint64_t base)
+{
+    idt_table = g2h(base);
+}
diff --git a/bsd-user/x86_64/target_arch_cpu.h b/bsd-user/x86_64/target_arch_cpu.h
new file mode 100644
index 0000000..9a66b67
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_cpu.h
@@ -0,0 +1,324 @@
+/*
+ *  x86_64 cpu init and loop
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "qemu64"
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUX86State *env,
+        struct target_pt_regs *regs)
+{
+    uint64_t *gdt_table;
+
+    cpu_x86_set_cpl(env, 3);
+
+    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+    env->hflags |= HF_PE_MASK;
+    if (env->features[FEAT_1_EDX] & CPUID_SSE) {
+        env->cr[4] |= CR4_OSFXSR_MASK;
+        env->hflags |= HF_OSFXSR_MASK;
+    }
+
+    /* enable 64 bit mode if possible */
+    if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
+        fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
+        exit(1);
+    }
+    env->cr[4] |= CR4_PAE_MASK;
+    env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
+    env->hflags |= HF_LMA_MASK;
+
+    /* flags setup : we activate the IRQs by default as in user mode */
+    env->eflags |= IF_MASK;
+
+    /* register setup */
+    env->regs[R_EAX] = regs->rax;
+    env->regs[R_EBX] = regs->rbx;
+    env->regs[R_ECX] = regs->rcx;
+    env->regs[R_EDX] = regs->rdx;
+    env->regs[R_ESI] = regs->rsi;
+    env->regs[R_EDI] = regs->rdi;
+    env->regs[R_EBP] = regs->rbp;
+    env->regs[R_ESP] = regs->rsp;
+    env->eip = regs->rip;
+
+    /* interrupt setup */
+    env->idt.limit = 511;
+
+    env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+        PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    bsd_x86_64_set_idt_base(env->idt.base);
+    bsd_x86_64_set_idt(0, 0);
+    bsd_x86_64_set_idt(1, 0);
+    bsd_x86_64_set_idt(2, 0);
+    bsd_x86_64_set_idt(3, 3);
+    bsd_x86_64_set_idt(4, 3);
+    bsd_x86_64_set_idt(5, 0);
+    bsd_x86_64_set_idt(6, 0);
+    bsd_x86_64_set_idt(7, 0);
+    bsd_x86_64_set_idt(8, 0);
+    bsd_x86_64_set_idt(9, 0);
+    bsd_x86_64_set_idt(10, 0);
+    bsd_x86_64_set_idt(11, 0);
+    bsd_x86_64_set_idt(12, 0);
+    bsd_x86_64_set_idt(13, 0);
+    bsd_x86_64_set_idt(14, 0);
+    bsd_x86_64_set_idt(15, 0);
+    bsd_x86_64_set_idt(16, 0);
+    bsd_x86_64_set_idt(17, 0);
+    bsd_x86_64_set_idt(18, 0);
+    bsd_x86_64_set_idt(19, 0);
+    bsd_x86_64_set_idt(0x80, 3);
+
+    /* segment setup */
+    env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+            PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+    gdt_table = g2h(env->gdt.base);
+
+    /* 64 bit code segment */
+    bsd_x86_64_write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_L_MASK
+            | (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+
+    bsd_x86_64_write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+            (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+
+    cpu_x86_load_seg(env, R_CS, __USER_CS);
+    cpu_x86_load_seg(env, R_SS, __USER_DS);
+    cpu_x86_load_seg(env, R_DS, 0);
+    cpu_x86_load_seg(env, R_ES, 0);
+    cpu_x86_load_seg(env, R_FS, 0);
+    cpu_x86_load_seg(env, R_GS, 0);
+}
+
+static inline void target_cpu_loop(CPUX86State *env)
+{
+    int trapnr;
+    abi_ulong pc;
+    /* target_siginfo_t info; */
+
+    for (;;) {
+        trapnr = cpu_x86_exec(env);
+        switch (trapnr) {
+        case 0x80:
+            /* syscall from int $0x80 */
+            if (bsd_type == target_freebsd) {
+                abi_ulong params = (abi_ulong) env->regs[R_ESP] +
+                    sizeof(int32_t);
+                int32_t syscall_nr = env->regs[R_EAX];
+                int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+                if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int32_t);
+                } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int64_t);
+                }
+                get_user_s32(arg1, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg2, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg3, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg4, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg5, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg6, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg7, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg8, params);
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      syscall_nr,
+                                                      arg1,
+                                                      arg2,
+                                                      arg3,
+                                                      arg4,
+                                                      arg5,
+                                                      arg6,
+                                                      arg7,
+                                                      arg8);
+            } else { /* if (bsd_type == target_openbsd) */
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EBX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_EBP]);
+            }
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
+            break;
+
+        case EXCP_SYSCALL:
+            /* syscall from syscall instruction */
+            if (bsd_type == target_freebsd) {
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[8],
+                                                      env->regs[9], 0, 0);
+            } else { /* if (bsd_type == target_openbsd) */
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDX],
+                                                      env->regs[10],
+                                                      env->regs[8],
+                                                      env->regs[9]);
+            }
+            env->eip = env->exception_next_eip;
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
+            break;
+
+#if 0
+        case EXCP0B_NOSEG:
+        case EXCP0C_STACK:
+            info.si_signo = SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP0D_GPF:
+            /* XXX: potential problem if ABI32 */
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP0E_PAGE:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            if (!(env->error_code & 1)) {
+                info.si_code = TARGET_SEGV_MAPERR;
+            } else {
+                info.si_code = TARGET_SEGV_ACCERR;
+            }
+            info._sifields._sigfault._addr = env->cr[2];
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP00_DIVZ:
+            /* division by zero */
+            info.si_signo = SIGFPE;
+            info.si_errno = 0;
+            info.si_code = TARGET_FPE_INTDIV;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP01_DB:
+        case EXCP03_INT3:
+            info.si_signo = SIGTRAP;
+            info.si_errno = 0;
+            if (trapnr == EXCP01_DB) {
+                info.si_code = TARGET_TRAP_BRKPT;
+                info._sifields._sigfault._addr = env->eip;
+            } else {
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+            }
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP04_INTO:
+        case EXCP05_BOUND:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP06_ILLOP:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(env, info.si_signo, &info);
+            break;
+#endif
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+#if 0
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(env, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                }
+            }
+            break;
+#endif
+        default:
+            pc = env->segs[R_CS].base + env->eip;
+            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - "
+                    "aborting\n", (long)pc, trapnr);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[R_ESP] = newsp;
+    env->regs[R_EAX] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+    cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/x86_64/target_arch_vmparam.h b/bsd-user/x86_64/target_arch_vmparam.h
new file mode 100644
index 0000000..5e13076
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_vmparam.h
@@ -0,0 +1,28 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to amd64/include/vmparam.h */
+#define TARGET_MAXTSIZ  (128UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ  (32768UL*1024*1024) /* initial data size limit */
+#define TARGET_MAXDSIZ  (32768UL*1024*1024) /* max data size */
+#define TARGET_DFLSSIZ  (8UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ  (512UL*1024*1024)   /* max stack size */
+#define TARGET_SGROWSIZ (128UL*1024)        /* amount to grow stack */
+
+#define TARGET_VM_MAXUSER_ADDRESS   (0x0000800000000000UL)
+
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+    return state->regs[R_ESP];
+}
+
+static inline void set_second_rval(CPUX86State *state, abi_ulong retval2)
+{
+    state->regs[R_EDX] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/x86_64/target_signal.h b/bsd-user/x86_64/target_signal.h
index 659cd40..5491687 100644
--- a/bsd-user/x86_64/target_signal.h
+++ b/bsd-user/x86_64/target_signal.h
@@ -11,9 +11,4 @@ typedef struct target_sigaltstack {
 	abi_ulong ss_size;
 } target_stack_t;
 
-static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
-{
-    return state->regs[R_ESP];
-}
-
 #endif /* TARGET_SIGNAL_H */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 05/18] bsd-user: move target arch and host OS dependent code out of syscall.c
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (3 preceding siblings ...)
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 04/18] bsd-user: move target arch and host OS dependent code out of main.c Stacey Son
@ 2013-10-16 14:36 ` Stacey Son
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 06/18] bsd-user: add support for freebsd time related system calls Stacey Son
                   ` (34 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change moves the system call handler for sysctl(2) and sysarch(2)
from syscall.c to the OS and arch dependent directories.  This
eliminates many of the #ifdef's in syscall.c.  These system call
handlers are now located in the host os and target arch directories.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs                  |    2 +-
 bsd-user/arm/target_arch_sigtramp.h     |   33 ++++
 bsd-user/bsdload.c                      |  147 ++++++++++++++---
 bsd-user/elfload.c                      |    9 +-
 bsd-user/freebsd/os-sys.c               |  268 +++++++++++++++++++++++++++++++
 bsd-user/freebsd/target_os_stack.h      |  157 ++++++++++++++++++
 bsd-user/i386/target_arch_sigtramp.h    |   11 ++
 bsd-user/main.c                         |    6 +-
 bsd-user/mips/target_arch_sigtramp.h    |   23 +++
 bsd-user/mips64/target_arch_sigtramp.h  |   23 +++
 bsd-user/netbsd/os-sys.c                |   46 ++++++
 bsd-user/netbsd/target_os_stack.h       |   33 ++++
 bsd-user/openbsd/os-sys.c               |   46 ++++++
 bsd-user/openbsd/target_os_stack.h      |   33 ++++
 bsd-user/qemu.h                         |   30 +++-
 bsd-user/sparc/target_arch_sigtramp.h   |   11 ++
 bsd-user/sparc64/target_arch_sigtramp.h |   11 ++
 bsd-user/syscall.c                      |  210 +++---------------------
 bsd-user/x86_64/target_arch_sigtramp.h  |   11 ++
 19 files changed, 889 insertions(+), 221 deletions(-)
 create mode 100644 bsd-user/arm/target_arch_sigtramp.h
 create mode 100644 bsd-user/freebsd/os-sys.c
 create mode 100644 bsd-user/freebsd/target_os_stack.h
 create mode 100644 bsd-user/i386/target_arch_sigtramp.h
 create mode 100644 bsd-user/mips/target_arch_sigtramp.h
 create mode 100644 bsd-user/mips64/target_arch_sigtramp.h
 create mode 100644 bsd-user/netbsd/os-sys.c
 create mode 100644 bsd-user/netbsd/target_os_stack.h
 create mode 100644 bsd-user/openbsd/os-sys.c
 create mode 100644 bsd-user/openbsd/target_os_stack.h
 create mode 100644 bsd-user/sparc/target_arch_sigtramp.h
 create mode 100644 bsd-user/sparc64/target_arch_sigtramp.h
 create mode 100644 bsd-user/x86_64/target_arch_sigtramp.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 41e8dce..b5ed89e 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,2 +1,2 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o $(TARGET_ABI_DIR)/target_arch_cpu.o
+	        uaccess.o $(HOST_ABI_DIR)/os-sys.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/arm/target_arch_sigtramp.h b/bsd-user/arm/target_arch_sigtramp.h
new file mode 100644
index 0000000..98dc313
--- /dev/null
+++ b/bsd-user/arm/target_arch_sigtramp.h
@@ -0,0 +1,33 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+/* Compare to arm/arm/locore.S ENTRY_NP(sigcode) */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+    int i;
+    uint32_t sys_exit = TARGET_FREEBSD_NR_exit;
+    /*
+     * The code has to load r7 manually rather than using
+     * "ldr r7, =SYS_return to make sure the size of the
+     * code is correct.
+     */
+    uint32_t sigtramp_code[] = {
+    /* 1 */ 0xE1A0000D,         /* mov r0, sp */
+    /* 2 */ 0xE59F700C,         /* ldr r7, [pc, #12] */
+    /* 3 */ 0xEF000000 + sys_sigreturn, /* swi (SYS_sigreturn) */
+    /* 4 */ 0xE59F7008,         /* ldr r7, [pc, #8] */
+    /* 5 */ 0xEF000000 + sys_exit,      /* swi (SYS_exit)*/
+    /* 6 */ 0xEAFFFFFA,         /* b . -16 */
+    /* 7 */ sys_sigreturn,
+    /* 8 */ sys_exit
+    };
+
+    for (i = 0; i < 8; i++) {
+        tswap32s(&sigtramp_code[i]);
+    }
+
+    return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c
index 2abc713..4d5a008 100644
--- a/bsd-user/bsdload.c
+++ b/bsd-user/bsdload.c
@@ -1,4 +1,19 @@
-/* Code for loading BSD executables.  Mostly linux kernel code.  */
+/*
+ *  Load BSD executables.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -34,7 +49,7 @@ static int in_group_p(gid_t g)
     gid_t       grouplist[TARGET_NGROUPS];
 
     ngroup = getgroups(TARGET_NGROUPS, grouplist);
-    for(i = 0; i < ngroup; i++) {
+    for (i = 0; i < ngroup; i++) {
         if(grouplist[i] == g) {
             return 1;
         }
@@ -46,14 +61,14 @@ static int count(char ** vec)
 {
     int         i;
 
-    for(i = 0; *vec; i++) {
+    for (i = 0; *vec; i++) {
         vec++;
     }
 
     return(i);
 }
 
-static int prepare_binprm(struct linux_binprm *bprm)
+static int prepare_binprm(struct bsd_binprm *bprm)
 {
     struct stat         st;
     int mode;
@@ -154,34 +169,116 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
     return sp;
 }
 
+static int is_there(const char *candidate)
+{
+    struct stat fin;
+
+    /* XXX work around access(2) false positives for superuser */
+    if (access(candidate, X_OK) == 0 && stat(candidate, &fin) == 0 &&
+            S_ISREG(fin.st_mode) && (getuid() != 0 ||
+                (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static int find_in_path(char *path, const char *filename, char *retpath,
+        size_t rpsize)
+{
+    const char *d;
+    int found;
+
+    if (strchr(filename, '/') != NULL) {
+        if (is_there(filename)) {
+                if (!realpath(filename, retpath)) {
+                    return -1;
+                }
+                return 0;
+        } else {
+            return -1;
+        }
+    }
+
+    found = 0;
+    while ((d = strsep(&path, ":")) != NULL) {
+        if (*d == '\0') {
+            d = ".";
+        }
+        if (snprintf(retpath, rpsize, "%s/%s", d, filename) >= (int)rpsize) {
+            continue;
+        }
+        if (is_there((const char *)retpath)) {
+            found = 1;
+            break;
+        }
+    }
+    return found;
+}
+
 int loader_exec(const char * filename, char ** argv, char ** envp,
-             struct target_pt_regs * regs, struct image_info *infop)
+             struct target_pt_regs *regs, struct image_info *infop,
+             struct bsd_binprm *bprm)
 {
-    struct linux_binprm bprm;
-    int retval;
-    int i;
+    char *p, *path = NULL, fullpath[PATH_MAX];
+    const char *execname = NULL;
+    int retval, i, found;
 
-    bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
+    bprm->p = TARGET_PAGE_SIZE * MAX_ARG_PAGES; /* -sizeof(unsigned int); */
     for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
-            bprm.page[i] = NULL;
-    retval = open(filename, O_RDONLY);
-    if (retval < 0)
+            bprm->page[i] = NULL;
+
+    /* Find target executable in path, if not already an absolute path. */
+    p = getenv("PATH");
+    if (p != NULL) {
+        path = g_strdup(p);
+        if (path == NULL) {
+            fprintf(stderr, "Out of memory\n");
+            return -1;
+        }
+        execname = realpath(filename, NULL);
+        if (execname == NULL) {
+            execname = g_strdup(filename);
+        }
+        found = find_in_path(path, execname, fullpath, sizeof(fullpath));
+        /* Absolute path specified but not found? */
+        if (found == -1) {
+            return -1;
+        }
+        if (found) {
+            retval = open(fullpath, O_RDONLY);
+            bprm->fullpath = g_strdup(fullpath);
+        } else {
+            retval = open(execname, O_RDONLY);
+            bprm->fullpath = NULL;
+        }
+        if (execname) {
+            g_free((void *)execname);
+        }
+        g_free(path);
+    } else {
+        retval = open(filename, O_RDONLY);
+        bprm->fullpath = NULL;
+    }
+    if (retval < 0) {
         return retval;
-    bprm.fd = retval;
-    bprm.filename = (char *)filename;
-    bprm.argc = count(argv);
-    bprm.argv = argv;
-    bprm.envc = count(envp);
-    bprm.envp = envp;
+    }
+
+    bprm->fd = retval;
+    bprm->filename = (char *)filename;
+    bprm->argc = count(argv);
+    bprm->argv = argv;
+    bprm->envc = count(envp);
+    bprm->envp = envp;
 
-    retval = prepare_binprm(&bprm);
+    retval = prepare_binprm(bprm);
 
     if(retval>=0) {
-        if (bprm.buf[0] == 0x7f
-                && bprm.buf[1] == 'E'
-                && bprm.buf[2] == 'L'
-                && bprm.buf[3] == 'F') {
-            retval = load_elf_binary(&bprm,regs,infop);
+        if (bprm->buf[0] == 0x7f
+                && bprm->buf[1] == 'E'
+                && bprm->buf[2] == 'L'
+                && bprm->buf[3] == 'F') {
+            retval = load_elf_binary(bprm, regs, infop);
         } else {
             fprintf(stderr, "Unknown binary format\n");
             return -1;
@@ -196,7 +293,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
 
     /* Something went wrong, return the inode and free the argument pages*/
     for (i=0 ; i<MAX_ARG_PAGES ; i++) {
-        g_free(bprm.page[i]);
+        g_free(bprm->page[i]);
     }
     return(retval);
 }
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index ccf72d1..68d0209 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -91,6 +91,9 @@ enum {
 #define ELIBBAD 80
 #endif
 
+abi_ulong target_stksiz;
+abi_ulong target_stkbas;
+
 #ifdef TARGET_I386
 
 #define ELF_PLATFORM get_elf_platform()
@@ -665,7 +668,7 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
     return p;
 }
 
-static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
+static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm,
                                  struct image_info *info)
 {
     abi_ulong stack_base, size, error;
@@ -1147,8 +1150,8 @@ static void load_symbols(struct elfhdr *hdr, int fd)
     syminfos = s;
 }
 
-int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
-                    struct image_info * info)
+int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
+                    struct image_info *info)
 {
     struct elfhdr elf_ex;
     struct elfhdr interp_elf_ex;
diff --git a/bsd-user/freebsd/os-sys.c b/bsd-user/freebsd/os-sys.c
new file mode 100644
index 0000000..86b2826
--- /dev/null
+++ b/bsd-user/freebsd/os-sys.c
@@ -0,0 +1,268 @@
+/*
+ *  FreeBSD sysctl() and sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+#include "qemu.h"
+
+#include "target_arch_sysarch.h"
+#include "target_os_vmparam.h"
+
+/*
+ * XXX this uses the undocumented oidfmt interface to find the kind of
+ * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
+ * (compare to src/sbin/sysctl/sysctl.c)
+ */
+static int
+oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
+{
+    int qoid[CTL_MAXNAME+2];
+    uint8_t buf[BUFSIZ];
+    int i;
+    size_t j;
+
+    qoid[0] = 0;
+    qoid[1] = 4;
+    memcpy(qoid + 2, oid, len * sizeof(int));
+
+    j = sizeof(buf);
+    i = sysctl(qoid, len + 2, buf, &j, 0, 0);
+    if (i) {
+        return i;
+    }
+
+    if (kind) {
+        *kind = *(uint32_t *)buf;
+    }
+
+    if (fmt) {
+        strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
+    }
+    return 0;
+}
+
+/*
+ * try and convert sysctl return data for the target.
+ * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT.
+ */
+static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
+{
+    switch (kind & CTLTYPE) {
+    case CTLTYPE_INT:
+    case CTLTYPE_UINT:
+        *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp);
+        break;
+
+#ifdef TARGET_ABI32
+    case CTLTYPE_LONG:
+    case CTLTYPE_ULONG:
+        *(uint32_t *)holdp = tswap32(*(long *)holdp);
+        break;
+#else
+    case CTLTYPE_LONG:
+        *(uint64_t *)holdp = tswap64(*(long *)holdp);
+    case CTLTYPE_ULONG:
+        *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
+        break;
+#endif
+#if !defined(__FreeBSD_version) || __FreeBSD_version < 900031
+    case CTLTYPE_QUAD:
+#else
+    case CTLTYPE_U64:
+    case CTLTYPE_S64:
+#endif
+        *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
+        break;
+
+    case CTLTYPE_STRING:
+        break;
+
+    default:
+        /* XXX unhandled */
+        return -1;
+    }
+    return 0;
+}
+
+/*
+ * Convert the undocmented name2oid sysctl data for the target.
+ */
+static inline void sysctl_name2oid(uint32_t *holdp, size_t holdlen)
+{
+    size_t i;
+
+    for (i = 0; i < holdlen; i++) {
+        holdp[i] = tswap32(holdp[i]);
+    }
+}
+
+static inline void sysctl_oidfmt(uint32_t *holdp)
+{
+    /* byte swap the kind */
+    holdp[0] = tswap32(holdp[0]);
+}
+
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+    abi_long ret;
+    void *hnamep, *holdp = NULL, *hnewp = NULL;
+    size_t holdlen;
+    abi_ulong oldlen = 0;
+    int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
+    uint32_t kind = 0;
+    TaskState *ts = (TaskState *)env->opaque;
+
+    if (oldlenp) {
+        if (get_user_ual(oldlen, oldlenp)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    hnamep = lock_user(VERIFY_READ, namep, namelen, 1);
+    if (hnamep == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (newp) {
+        hnewp = lock_user(VERIFY_READ, newp, newlen, 1);
+        if (hnewp == NULL) {
+            return -TARGET_EFAULT;
+        }
+    }
+    if (oldp) {
+        holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0);
+        if (holdp == NULL) {
+            return -TARGET_EFAULT;
+        }
+    }
+    holdlen = oldlen;
+    for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++) {
+        *q++ = tswap32(*p);
+    }
+    oidfmt(snamep, namelen, NULL, &kind);
+
+    /* Handle some arch/emulator dependent sysctl()'s here. */
+    switch (snamep[0]) {
+    case CTL_KERN:
+        switch (snamep[1]) {
+        case KERN_USRSTACK:
+#if TARGET_USRSTACK != 0
+            (*(abi_ulong *)holdp) = tswapal(TARGET_USRSTACK);
+            holdlen = sizeof(abi_ulong);
+            ret = 0;
+#else
+            ret = -TARGET_ENOENT;
+#endif
+            goto out;
+
+        case KERN_PS_STRINGS:
+#if defined(TARGET_PS_STRINGS)
+            (*(abi_ulong *)holdp) = tswapal(TARGET_PS_STRINGS);
+            holdlen = sizeof(abi_ulong);
+            ret = 0;
+#else
+            ret = -TARGET_ENOENT;
+#endif
+            goto out;
+
+        case KERN_PROC:
+            switch (snamep[2]) {
+            case KERN_PROC_PATHNAME:
+                holdlen = strlen(ts->bprm->fullpath) + 1;
+                if (holdp) {
+                    if (oldlen < holdlen) {
+                        ret = -TARGET_EINVAL;
+                        goto out;
+                    }
+                    strlcpy(holdp, ts->bprm->fullpath, oldlen);
+                }
+                ret = 0;
+                goto out;
+
+            default:
+                break;
+            }
+            break;
+
+        default:
+            break;
+        }
+        break;
+
+    case CTL_HW:
+        switch (snamep[1]) {
+        case HW_MACHINE:
+            strlcpy(holdp, TARGET_HW_MACHINE, oldlen);
+            ret = 0;
+            goto out;
+
+        case HW_MACHINE_ARCH:
+            strlcpy(holdp, TARGET_HW_MACHINE_ARCH, oldlen);
+            ret = 0;
+            goto out;
+
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
+    if (!ret && (holdp != 0 && holdlen != 0)) {
+        if (0 == snamep[0] && (3 == snamep[1] || 4 == snamep[1])) {
+            if (3 == snamep[1]) {
+                /* Handle the undocumented name2oid special case. */
+                sysctl_name2oid(holdp, holdlen);
+            } else {
+                /* Handle oidfmt */
+                sysctl_oidfmt(holdp);
+            }
+        } else {
+            sysctl_oldcvt(holdp, holdlen, kind);
+        }
+    }
+#ifdef DEBUG
+    else {
+        printf("sysctl(mib[0]=%d, mib[1]=%d, mib[3]=%d...) returned %d\n",
+        snamep[0], snamep[1], snamep[2], (int)ret);
+    }
+#endif
+
+out:
+    if (oldlenp) {
+        put_user_ual(holdlen, oldlenp);
+    }
+    unlock_user(hnamep, namep, 0);
+    unlock_user(holdp, oldp, holdlen);
+    if (hnewp) {
+        unlock_user(hnewp, newp, 0);
+    }
+    g_free(snamep);
+    return ret;
+}
+
+/* sysarch() is architecture dependent. */
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+{
+
+    return do_freebsd_arch_sysarch(cpu_env, arg1, arg2);
+}
diff --git a/bsd-user/freebsd/target_os_stack.h b/bsd-user/freebsd/target_os_stack.h
new file mode 100644
index 0000000..c84b69e
--- /dev/null
+++ b/bsd-user/freebsd/target_os_stack.h
@@ -0,0 +1,157 @@
+#ifndef _TARGET_OS_STACK_H_
+#define _TARGET_OS_STACK_H_
+
+#include <sys/param.h>
+#include "target_arch_sigtramp.h"
+
+/*
+ * The inital FreeBSD stack is as follows:
+ * (see kern/kern_exec.c exec_copyout_strings() )
+ *
+ *  Hi Address -> char **ps_argvstr  (struct ps_strings for ps, w, etc.)
+ *                unsigned ps_nargvstr
+ *                char **ps_envstr
+ *  PS_STRINGS -> unsigned ps_nenvstr
+ *
+ *                machine dependent sigcode (sv_sigcode of size
+ *                                           sv_szsigcode)
+ *
+ *                execpath          (absolute image path for rtld)
+ *
+ *                SSP Canary        (sizeof(long) * 8)
+ *
+ *                page sizes array  (usually sizeof(u_long) )
+ *
+ *  "destp" ->    argv, env strings (up to 262144 bytes)
+ */
+static inline int setup_initial_stack(struct bsd_binprm *bprm,
+        abi_ulong *ret_addr)
+{
+    int i;
+    abi_ulong stack_hi_addr;
+    size_t execpath_len, stringspace;
+    abi_ulong destp, argvp, envp, p;
+    struct target_ps_strings ps_strs;
+    char canary[sizeof(abi_long) * 8];
+
+    stack_hi_addr = p = target_stkbas + target_stksiz;
+
+    /* Save some space for ps_strings. */
+    p -= sizeof(struct target_ps_strings);
+
+#ifdef TARGET_SZSIGCODE
+    /* Add machine depedent sigcode. */
+    p -= TARGET_SZSIGCODE;
+    if (setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc),
+            TARGET_FREEBSD_NR_sigreturn)) {
+        errno = EFAULT;
+        return -1;
+    }
+#endif
+    if (bprm->fullpath) {
+        execpath_len = strlen(bprm->fullpath) + 1;
+        p -= roundup(execpath_len, sizeof(abi_ulong));
+        if (memcpy_to_target(p, bprm->fullpath, execpath_len)) {
+            errno = EFAULT;
+            return -1;
+        }
+    }
+    /* Add canary for SSP. */
+    arc4random_buf(canary, sizeof(canary));
+    p -= roundup(sizeof(canary), sizeof(abi_ulong));
+    if (memcpy_to_target(p, canary, sizeof(canary))) {
+        errno = EFAULT;
+        return -1;
+    }
+    /* Add page sizes array. */
+    /* p -= sizeof(int); */
+    p -= sizeof(abi_ulong);
+    /* if (put_user_u32(TARGET_PAGE_SIZE, p)) { */
+    if (put_user_ual(TARGET_PAGE_SIZE, p)) {
+        errno = EFAULT;
+        return -1;
+    }
+    /* Calculate the string space needed */
+    stringspace = 0;
+    for (i = 0; i < bprm->argc; ++i) {
+        stringspace += strlen(bprm->argv[i]) + 1;
+    }
+    for (i = 0; i < bprm->envc; ++i) {
+        stringspace += strlen(bprm->envp[i]) + 1;
+    }
+    if (stringspace > TARGET_ARG_MAX) {
+       errno = ENOMEM;
+       return -1;
+    }
+
+    /* Make room for the argv and envp strings */
+    /* p = destp = roundup(p - TARGET_SPACE_USRSPACE - (TARGET_ARG_MAX - stringspace), sizeof(abi_ulong)); */
+    argvp = p - TARGET_SPACE_USRSPACE;
+    p = destp = roundup(p - TARGET_SPACE_USRSPACE - TARGET_ARG_MAX, sizeof(abi_ulong));
+
+    /*
+     * Add argv strings.  Note that the argv[] vectors are added by
+     * loader_build_argptr()
+     */
+    /* XXX need to make room for auxargs */
+    /* argvp = destp - ((bprm->argc + bprm->envc + 2) * sizeof(abi_ulong)); */
+    /* envp = argvp + (bprm->argc + 2) * sizeof(abi_ulong); */
+    envp = argvp + (bprm->argc + 1) * sizeof(abi_ulong);
+    ps_strs.ps_argvstr = tswapl(argvp);
+    ps_strs.ps_nargvstr = tswap32(bprm->argc);
+    for (i = 0; i < bprm->argc; ++i) {
+        size_t len = strlen(bprm->argv[i]) + 1;
+
+        if (memcpy_to_target(destp, bprm->argv[i], len)) {
+            errno = EFAULT;
+            return -1;
+        }
+        if (put_user_ual(destp, argvp)) {
+            errno = EFAULT;
+            return -1;
+        }
+        argvp += sizeof(abi_ulong);
+        destp += len;
+    }
+    if (put_user_ual(0, argvp)) {
+        errno = EFAULT;
+        return -1;
+    }
+    /*
+     * Add env strings. Note that the envp[] vectors are added by
+     * loader_build_argptr().
+     */
+    ps_strs.ps_envstr = tswapl(envp);
+    ps_strs.ps_nenvstr = tswap32(bprm->envc);
+    for (i = 0; i < bprm->envc; ++i) {
+        size_t len = strlen(bprm->envp[i]) + 1;
+
+        if (memcpy_to_target(destp, bprm->envp[i], len)) {
+            errno = EFAULT;
+            return -1;
+        }
+        if (put_user_ual(destp, envp)) {
+            errno = EFAULT;
+            return -1;
+        }
+        envp += sizeof(abi_ulong);
+        destp += len;
+    }
+    if (put_user_ual(0, envp)) {
+        errno = EFAULT;
+        return -1;
+    }
+    if (memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs,
+                sizeof(ps_strs))) {
+        errno = EFAULT;
+        return -1;
+    }
+
+    if (ret_addr) {
+       *ret_addr = p;
+    }
+
+    return 0;
+ }
+
+#endif /* !_TARGET_OS_STACK_H_ */
diff --git a/bsd-user/i386/target_arch_sigtramp.h b/bsd-user/i386/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/i386/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 3b8fb60..03053b0 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -192,6 +192,7 @@ int main(int argc, char **argv)
     const char *log_mask = NULL;
     struct target_pt_regs regs1, *regs = &regs1;
     struct image_info info1, *info = &info1;
+    struct bsd_binprm bprm;
     TaskState ts1, *ts = &ts1;
     CPUArchState *env;
     CPUState *cpu;
@@ -344,6 +345,8 @@ int main(int argc, char **argv)
     /* Zero out regs */
     memset(regs, 0, sizeof(struct target_pt_regs));
 
+    memset(&bprm, 0, sizeof(bprm));
+
     /* Zero out image_info */
     memset(info, 0, sizeof(struct image_info));
 
@@ -402,7 +405,7 @@ int main(int argc, char **argv)
     }
 #endif /* CONFIG_USE_GUEST_BASE */
 
-    if (loader_exec(filename, argv+optind, target_environ, regs, info)) {
+    if (loader_exec(filename, argv+optind, target_environ, regs, info, &bprm)) {
         printf("Error loading %s\n", filename);
         _exit(1);
     }
@@ -447,6 +450,7 @@ int main(int argc, char **argv)
     memset(ts, 0, sizeof(TaskState));
     init_task_state(ts);
     ts->info = info;
+    ts->bprm = &bprm;
     env->opaque = ts;
 
     target_cpu_init(env, regs);
diff --git a/bsd-user/mips/target_arch_sigtramp.h b/bsd-user/mips/target_arch_sigtramp.h
new file mode 100644
index 0000000..5e3c69a
--- /dev/null
+++ b/bsd-user/mips/target_arch_sigtramp.h
@@ -0,0 +1,23 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+/* Compare to mips/mips/locore.S sigcode() */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+    int i;
+    uint32_t sigtramp_code[TARGET_SZSIGCODE/TARGET_INSN_SIZE] = {
+    /* 1 */ 0x67A40000 + sigf_uc,       /* daddu   $a0, $sp, (sigf_uc) */
+    /* 2 */ 0x24020000 + sys_sigreturn, /* li      $v0, (sys_sigreturn) */
+    /* 3 */ 0x0000000C,                 /* syscall */
+    /* 4 */ 0x0000000D                  /* break */
+    };
+
+    for (i = 0; i < 4; i++) {
+        tswap32s(&sigtramp_code[i]);
+    }
+
+    return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/mips64/target_arch_sigtramp.h b/bsd-user/mips64/target_arch_sigtramp.h
new file mode 100644
index 0000000..5e3c69a
--- /dev/null
+++ b/bsd-user/mips64/target_arch_sigtramp.h
@@ -0,0 +1,23 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+/* Compare to mips/mips/locore.S sigcode() */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+    int i;
+    uint32_t sigtramp_code[TARGET_SZSIGCODE/TARGET_INSN_SIZE] = {
+    /* 1 */ 0x67A40000 + sigf_uc,       /* daddu   $a0, $sp, (sigf_uc) */
+    /* 2 */ 0x24020000 + sys_sigreturn, /* li      $v0, (sys_sigreturn) */
+    /* 3 */ 0x0000000C,                 /* syscall */
+    /* 4 */ 0x0000000D                  /* break */
+    };
+
+    for (i = 0; i < 4; i++) {
+        tswap32s(&sigtramp_code[i]);
+    }
+
+    return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/netbsd/os-sys.c b/bsd-user/netbsd/os-sys.c
new file mode 100644
index 0000000..68ea0e1
--- /dev/null
+++ b/bsd-user/netbsd/os-sys.c
@@ -0,0 +1,46 @@
+/*
+ *  NetBSD sysctl() and sysarch() system call emulation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+#include "qemu.h"
+
+#include "target_arch_sysarch.h"
+#include "target_os_vmparam.h"
+
+
+/* This must be emulated to support FreeBSD target binaries on NetBSD host. */
+
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+
+    qemu_log("qemu: Unsupported syscall __sysctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sysarch() is architecture dependent. */
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall sysarch()\n");
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/netbsd/target_os_stack.h b/bsd-user/netbsd/target_os_stack.h
new file mode 100644
index 0000000..1a26c3f
--- /dev/null
+++ b/bsd-user/netbsd/target_os_stack.h
@@ -0,0 +1,33 @@
+#ifndef _TARGET_OS_STACK_H_
+#define _TARGET_OS_STACK_H_
+
+#include "target_arch_sigtramp.h"
+
+static inline int setup_initial_stack(struct bsd_binprm *bprm, abi_ulong *p)
+{
+    int i;
+    abi_ulong stack_base;
+
+    stack_base = (target_stkbas + target_stksiz) -
+                  MAX_ARG_PAGES * TARGET_PAGE_SIZE;
+    if (p) {
+        *p = stack_base;
+    }
+
+    for (i = 0; i < MAX_ARG_PAGES; i++) {
+        if (bprm->page[i]) {
+            info->rss++;
+            if (!memcpy_to_target(stack_base, bprm->page[i],
+                        TARGET_PAGE_SIZE)) {
+                errno = EFAULT;
+                return -1;
+            }
+            g_free(bprm->page[i]);
+        }
+        stack_base += TARGET_PAGE_SIZE;
+    }
+
+    return 0;
+}
+
+#endif /* !_TARGET_OS_STACK_H_ */
diff --git a/bsd-user/openbsd/os-sys.c b/bsd-user/openbsd/os-sys.c
new file mode 100644
index 0000000..30df472
--- /dev/null
+++ b/bsd-user/openbsd/os-sys.c
@@ -0,0 +1,46 @@
+/*
+ *  OpenBSD sysctl() and sysarch() system call emulation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+#include "qemu.h"
+
+#include "target_arch_sysarch.h"
+#include "target_os_vmparam.h"
+
+
+/* This must be emulated to support FreeBSD target binaries on NetBSD host. */
+
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+
+    qemu_log("qemu: Unsupported syscall __sysctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sysarch() is architecture dependent. */
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall sysarch()\n");
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/openbsd/target_os_stack.h b/bsd-user/openbsd/target_os_stack.h
new file mode 100644
index 0000000..1a26c3f
--- /dev/null
+++ b/bsd-user/openbsd/target_os_stack.h
@@ -0,0 +1,33 @@
+#ifndef _TARGET_OS_STACK_H_
+#define _TARGET_OS_STACK_H_
+
+#include "target_arch_sigtramp.h"
+
+static inline int setup_initial_stack(struct bsd_binprm *bprm, abi_ulong *p)
+{
+    int i;
+    abi_ulong stack_base;
+
+    stack_base = (target_stkbas + target_stksiz) -
+                  MAX_ARG_PAGES * TARGET_PAGE_SIZE;
+    if (p) {
+        *p = stack_base;
+    }
+
+    for (i = 0; i < MAX_ARG_PAGES; i++) {
+        if (bprm->page[i]) {
+            info->rss++;
+            if (!memcpy_to_target(stack_base, bprm->page[i],
+                        TARGET_PAGE_SIZE)) {
+                errno = EFAULT;
+                return -1;
+            }
+            g_free(bprm->page[i]);
+        }
+        stack_base += TARGET_PAGE_SIZE;
+    }
+
+    return 0;
+}
+
+#endif /* !_TARGET_OS_STACK_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index cb77069..594de5c 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -90,6 +90,7 @@ typedef struct TaskState {
     struct TaskState *next;
     int used; /* non zero if used */
     struct image_info *info;
+    struct bsd_binprm *bprm;
 
     struct emulated_sigtable sigtab[TARGET_NSIG];
     struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
@@ -118,7 +119,7 @@ extern unsigned long mmap_min_addr;
  * This structure is used to hold the arguments that are
  * used when loading binaries.
  */
-struct linux_binprm {
+struct bsd_binprm {
         char buf[128];
         void *page[MAX_ARG_PAGES];
         abi_ulong p;
@@ -127,19 +128,23 @@ struct linux_binprm {
         int argc, envc;
         char **argv;
         char **envp;
-        char * filename;        /* Name of binary */
+        char *filename;         /* (Given) Name of binary */
+        char *fullpath;         /* Full path of binary */
+        int (*core_dump)(int, const CPUArchState *);
 };
 
 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
                               abi_ulong stringp, int push_ptr);
-int loader_exec(const char * filename, char ** argv, char ** envp,
-             struct target_pt_regs * regs, struct image_info *infop);
+int loader_exec(const char *filename, char **argv, char **envp,
+             struct target_pt_regs *regs, struct image_info *infop,
+             struct bsd_binprm *bprm);
 
-int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
-                    struct image_info * info);
-int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
-                    struct image_info * info);
+int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
+                    struct image_info *info);
+int load_flt_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
+                    struct image_info *info);
+int is_target_elf_binary(int fd);
 
 abi_long memcpy_to_target(abi_ulong dest, const void *src,
                           unsigned long len);
@@ -232,6 +237,15 @@ extern unsigned long target_maxssiz;
 extern unsigned long target_sgrowsiz;
 extern char qemu_proc_pathname[];
 
+/* syscall.c */
+abi_long get_errno(abi_long ret);
+int is_error(abi_long ret);
+
+/* os-sys.c */
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen);
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2);
+
 /* user access */
 
 #define VERIFY_READ 0
diff --git a/bsd-user/sparc/target_arch_sigtramp.h b/bsd-user/sparc/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/sparc/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/sparc64/target_arch_sigtramp.h b/bsd-user/sparc64/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index a4d1583..dbc212d 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -2,6 +2,7 @@
  *  BSD syscalls
  *
  *  Copyright (c) 2003 - 2008 Fabrice Bellard
+ *  Copyright (c) 2013 Stacey D. Son
  *
  *  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
@@ -36,12 +37,17 @@
 #include "qemu.h"
 #include "qemu-common.h"
 
-//#define DEBUG
+#define target_to_host_bitmask(x, tbl) (x)
+
+/* #define DEBUG */
 
 static abi_ulong target_brk;
 static abi_ulong target_original_brk;
 
-static inline abi_long get_errno(abi_long ret)
+/*
+ * errno conversion.
+ */
+abi_long get_errno(abi_long ret)
 {
     if (ret == -1)
         /* XXX need to translate host -> target errnos here */
@@ -50,9 +56,7 @@ static inline abi_long get_errno(abi_long ret)
         return ret;
 }
 
-#define target_to_host_bitmask(x, tbl) (x)
-
-static inline int is_error(abi_long ret)
+int is_error(abi_long ret)
 {
     return (abi_ulong)ret >= (abi_ulong)(-4096);
 }
@@ -96,175 +100,6 @@ static abi_long do_obreak(abi_ulong new_brk)
     return 0;
 }
 
-#if defined(TARGET_I386)
-static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms)
-{
-    abi_long ret = 0;
-    abi_ulong val;
-    int idx;
-
-    switch(op) {
-#ifdef TARGET_ABI32
-    case TARGET_FREEBSD_I386_SET_GSBASE:
-    case TARGET_FREEBSD_I386_SET_FSBASE:
-        if (op == TARGET_FREEBSD_I386_SET_GSBASE)
-#else
-    case TARGET_FREEBSD_AMD64_SET_GSBASE:
-    case TARGET_FREEBSD_AMD64_SET_FSBASE:
-        if (op == TARGET_FREEBSD_AMD64_SET_GSBASE)
-#endif
-            idx = R_GS;
-        else
-            idx = R_FS;
-        if (get_user(val, parms, abi_ulong))
-            return -TARGET_EFAULT;
-        cpu_x86_load_seg(env, idx, 0);
-        env->segs[idx].base = val;
-        break;
-#ifdef TARGET_ABI32
-    case TARGET_FREEBSD_I386_GET_GSBASE:
-    case TARGET_FREEBSD_I386_GET_FSBASE:
-        if (op == TARGET_FREEBSD_I386_GET_GSBASE)
-#else
-    case TARGET_FREEBSD_AMD64_GET_GSBASE:
-    case TARGET_FREEBSD_AMD64_GET_FSBASE:
-        if (op == TARGET_FREEBSD_AMD64_GET_GSBASE)
-#endif
-            idx = R_GS;
-        else
-            idx = R_FS;
-        val = env->segs[idx].base;
-        if (put_user(val, parms, abi_ulong))
-            return -TARGET_EFAULT;
-        break;
-    /* XXX handle the others... */
-    default:
-        ret = -TARGET_EINVAL;
-        break;
-    }
-    return ret;
-}
-#endif
-
-#ifdef TARGET_SPARC
-static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms)
-{
-    /* XXX handle
-     * TARGET_FREEBSD_SPARC_UTRAP_INSTALL,
-     * TARGET_FREEBSD_SPARC_SIGTRAMP_INSTALL
-     */
-    return -TARGET_EINVAL;
-}
-#endif
-
-#ifdef __FreeBSD__
-/*
- * XXX this uses the undocumented oidfmt interface to find the kind of
- * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
- * (this is mostly copied from src/sbin/sysctl/sysctl.c)
- */
-static int
-oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
-{
-    int qoid[CTL_MAXNAME+2];
-    uint8_t buf[BUFSIZ];
-    int i;
-    size_t j;
-
-    qoid[0] = 0;
-    qoid[1] = 4;
-    memcpy(qoid + 2, oid, len * sizeof(int));
-
-    j = sizeof(buf);
-    i = sysctl(qoid, len + 2, buf, &j, 0, 0);
-    if (i)
-        return i;
-
-    if (kind)
-        *kind = *(uint32_t *)buf;
-
-    if (fmt)
-        strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
-    return (0);
-}
-
-/*
- * try and convert sysctl return data for the target.
- * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT.
- */
-static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
-{
-    switch (kind & CTLTYPE) {
-    case CTLTYPE_INT:
-    case CTLTYPE_UINT:
-        *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp);
-        break;
-#ifdef TARGET_ABI32
-    case CTLTYPE_LONG:
-    case CTLTYPE_ULONG:
-        *(uint32_t *)holdp = tswap32(*(long *)holdp);
-        break;
-#else
-    case CTLTYPE_LONG:
-        *(uint64_t *)holdp = tswap64(*(long *)holdp);
-    case CTLTYPE_ULONG:
-        *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
-        break;
-#endif
-#ifdef CTLTYPE_U64
-    case CTLTYPE_S64:
-    case CTLTYPE_U64:
-#else
-    case CTLTYPE_QUAD:
-#endif
-        *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
-        break;
-    case CTLTYPE_STRING:
-        break;
-    default:
-        /* XXX unhandled */
-        return -1;
-    }
-    return 0;
-}
-
-/* XXX this needs to be emulated on non-FreeBSD hosts... */
-static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp,
-                          abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
-{
-    abi_long ret;
-    void *hnamep, *holdp, *hnewp = NULL;
-    size_t holdlen;
-    abi_ulong oldlen = 0;
-    int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
-    uint32_t kind = 0;
-
-    if (oldlenp)
-        get_user_ual(oldlen, oldlenp);
-    if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1)))
-        return -TARGET_EFAULT;
-    if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1)))
-        return -TARGET_EFAULT;
-    if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0)))
-        return -TARGET_EFAULT;
-    holdlen = oldlen;
-    for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++)
-       *q++ = tswap32(*p);
-    oidfmt(snamep, namelen, NULL, &kind);
-    /* XXX swap hnewp */
-    ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
-    if (!ret)
-        sysctl_oldcvt(holdp, holdlen, kind);
-    put_user_ual(holdlen, oldlenp);
-    unlock_user(hnamep, namep, 0);
-    unlock_user(holdp, oldp, holdlen);
-    if (hnewp)
-        unlock_user(hnewp, newp, 0);
-    g_free(snamep);
-    return ret;
-}
-#endif
-
 /* 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.
@@ -387,20 +222,27 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_FREEBSD_NR_break:
         ret = do_obreak(arg1);
         break;
-#ifdef __FreeBSD__
-    case TARGET_FREEBSD_NR___sysctl:
-        ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6);
+
+        /*
+         * sys{ctl, arch, call}
+         */
+    case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
+        ret = do_freebsd_sysctl(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
-#endif
-    case TARGET_FREEBSD_NR_sysarch:
+
+    case TARGET_FREEBSD_NR_sysarch: /* sysarch(2) */
         ret = do_freebsd_sysarch(cpu_env, arg1, arg2);
         break;
-    case TARGET_FREEBSD_NR_syscall:
-    case TARGET_FREEBSD_NR___syscall:
-        ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0);
+
+    case TARGET_FREEBSD_NR_syscall: /* syscall(2) */
+    case TARGET_FREEBSD_NR___syscall: /* __syscall(2) */
+        ret = do_freebsd_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4,
+                arg5, arg6, arg7, arg8, 0);
         break;
+
     default:
-        ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
+        ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+                    arg8));
         break;
     }
  fail:
@@ -467,6 +309,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NETBSD_NR_mprotect:
         ret = get_errno(target_mprotect(arg1, arg2, arg3));
         break;
+
     case TARGET_NETBSD_NR_syscall:
     case TARGET_NETBSD_NR___syscall:
         ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
@@ -539,6 +382,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_OPENBSD_NR_mprotect:
         ret = get_errno(target_mprotect(arg1, arg2, arg3));
         break;
+
     case TARGET_OPENBSD_NR_syscall:
     case TARGET_OPENBSD_NR___syscall:
         ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
diff --git a/bsd-user/x86_64/target_arch_sigtramp.h b/bsd-user/x86_64/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 06/18] bsd-user: add support for freebsd time related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (4 preceding siblings ...)
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 05/18] bsd-user: move target arch and host OS dependent code out of syscall.c Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 07/18] bsd-user: add support for freebsd signal " Stacey Son
                   ` (33 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for time related system calls including
nanosleep(2), clock_gettime(2), clock_settime(2), clock_getres(2),
gettimeofday(2), settimeofday(2), adjtime(2), ntp_adjtime(2),
ntp_gettime(2), utimes(2), lutimes(2), futimes(2), futimesat(2),
select(2), pselect(2), kqueue(2), kevent(2), setitimer(2),
getitimer(2), and the undocumented ktimer_*() calls.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs     |    3 +-
 bsd-user/freebsd/os-time.c |  205 ++++++++++++
 bsd-user/freebsd/os-time.h |  643 +++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h |   53 +++
 bsd-user/netbsd/os-time.c  |    1 +
 bsd-user/netbsd/os-time.h  |  179 ++++++++++
 bsd-user/netbsd/qemu-os.h  |    1 +
 bsd-user/openbsd/os-time.c |    1 +
 bsd-user/openbsd/os-time.h |  179 ++++++++++
 bsd-user/openbsd/qemu-os.h |    1 +
 bsd-user/syscall.c         |  102 ++++++
 bsd-user/syscall_defs.h    |  796 ++++++++++++++++++++++++++++++++++++++------
 12 files changed, 2061 insertions(+), 103 deletions(-)
 create mode 100644 bsd-user/freebsd/os-time.c
 create mode 100644 bsd-user/freebsd/os-time.h
 create mode 100644 bsd-user/freebsd/qemu-os.h
 create mode 100644 bsd-user/netbsd/os-time.c
 create mode 100644 bsd-user/netbsd/os-time.h
 create mode 100644 bsd-user/netbsd/qemu-os.h
 create mode 100644 bsd-user/openbsd/os-time.c
 create mode 100644 bsd-user/openbsd/os-time.h
 create mode 100644 bsd-user/openbsd/qemu-os.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index b5ed89e..d92961a 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,2 +1,3 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o $(HOST_ABI_DIR)/os-sys.o $(TARGET_ABI_DIR)/target_arch_cpu.o
+	        uaccess.o $(HOST_ABI_DIR)/os-sys.o \
+			$(HOST_ABI_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/freebsd/os-time.c b/bsd-user/freebsd/os-time.c
new file mode 100644
index 0000000..7ac4397
--- /dev/null
+++ b/bsd-user/freebsd/os-time.c
@@ -0,0 +1,205 @@
+/*
+ *  FreeBSD time related system call helpers
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <time.h>
+#include <sys/timex.h>
+#include <sys/select.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+/*
+ * FreeBSD time conversion functions
+ */
+abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr)
+{
+    struct target_freebsd_timeval *target_tv;
+
+    if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __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, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr)
+{
+    struct target_freebsd_timeval *target_tv;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __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);
+
+    return 0;
+}
+
+abi_long t2h_freebsd_timespec(struct timespec *ts, abi_ulong target_ts_addr)
+{
+    struct target_freebsd_timespec *target_ts;
+
+    if (!lock_user_struct(VERIFY_READ, target_ts, target_ts_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(ts->tv_sec, &target_ts->tv_sec);
+    __get_user(ts->tv_nsec, &target_ts->tv_nsec);
+    unlock_user_struct(target_ts, target_ts_addr, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_timespec(abi_ulong target_ts_addr, struct timespec *ts)
+{
+    struct target_freebsd_timespec *target_ts;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ts, target_ts_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(ts->tv_sec, &target_ts->tv_sec);
+    __put_user(ts->tv_nsec, &target_ts->tv_nsec);
+    unlock_user_struct(target_ts, target_ts_addr, 1);
+
+    return 0;
+}
+
+abi_long t2h_freebsd_timex(struct timex *host_tx, abi_ulong target_tx_addr)
+{
+    struct target_freebsd_timex *target_tx;
+
+    if (!lock_user_struct(VERIFY_READ, target_tx, target_tx_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_tx->modes, &target_tx->modes);
+    __get_user(host_tx->offset, &target_tx->offset);
+    __get_user(host_tx->freq, &target_tx->freq);
+    __get_user(host_tx->maxerror, &target_tx->maxerror);
+    __get_user(host_tx->esterror, &target_tx->esterror);
+    __get_user(host_tx->status, &target_tx->status);
+    __get_user(host_tx->constant, &target_tx->constant);
+    __get_user(host_tx->precision, &target_tx->precision);
+    __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
+    __get_user(host_tx->jitter, &target_tx->jitter);
+    __get_user(host_tx->shift, &target_tx->shift);
+    __get_user(host_tx->stabil, &target_tx->stabil);
+    __get_user(host_tx->jitcnt, &target_tx->jitcnt);
+    __get_user(host_tx->calcnt, &target_tx->calcnt);
+    __get_user(host_tx->errcnt, &target_tx->errcnt);
+    __get_user(host_tx->stbcnt, &target_tx->stbcnt);
+    unlock_user_struct(target_tx, target_tx_addr, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_ntptimeval(abi_ulong target_ntv_addr,
+        struct ntptimeval *ntv)
+{
+    struct target_freebsd_ntptimeval *target_ntv;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ntv, target_ntv_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(ntv->time.tv_sec, &target_ntv->time.tv_sec);
+    __put_user(ntv->time.tv_nsec, &target_ntv->time.tv_nsec);
+    __put_user(ntv->maxerror, &target_ntv->maxerror);
+    __put_user(ntv->esterror, &target_ntv->esterror);
+    __put_user(ntv->tai, &target_ntv->tai);
+    __put_user(ntv->time_state, &target_ntv->time_state);
+
+    return 0;
+}
+
+/*
+ * select(2) fdset copy functions
+ */
+abi_ulong copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n)
+{
+    int i, nw, j, k;
+    abi_ulong b, *target_fds;
+
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    target_fds = lock_user(VERIFY_READ, target_fds_addr,
+            sizeof(abi_ulong) * nw, 1);
+    if (target_fds == NULL) {
+        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++;
+        }
+    }
+    unlock_user(target_fds, target_fds_addr, 0);
+
+    return 0;
+}
+
+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;
+}
+
+abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds, int n)
+{
+    int i, nw, j, k;
+    abi_long v;
+    abi_ulong *target_fds;
+
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    target_fds = lock_user(VERIFY_WRITE, target_fds_addr,
+            sizeof(abi_ulong) * nw, 0);
+    if (target_fds == NULL) {
+        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++;
+        }
+        __put_user(v, &target_fds[i]);
+    }
+    unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
+
+    return 0;
+}
+
diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h
new file mode 100644
index 0000000..c6b5b28
--- /dev/null
+++ b/bsd-user/freebsd/os-time.h
@@ -0,0 +1,643 @@
+/*
+ *  FreeBSD time related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_OS_TIME_H_
+#define __FREEBSD_OS_TIME_H_
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/select.h>
+#include <sys/timex.h>
+#include <signal.h>
+#include <time.h>
+
+#include "qemu-os.h"
+
+/* nanosleep(2) */
+static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct timespec req, rem;
+
+    ret = t2h_freebsd_timespec(&req, arg1);
+    if (!is_error(ret)) {
+        ret = get_errno(nanosleep(&req, &rem));
+        if (!is_error(ret) && arg2) {
+            h2t_freebsd_timespec(arg2, &rem);
+        }
+    }
+
+    return ret;
+}
+
+/* clock_gettime(2) */
+static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct timespec ts;
+
+    ret = get_errno(clock_gettime(arg1, &ts));
+    if (!is_error(ret)) {
+        if (h2t_freebsd_timespec(arg2, &ts)) {
+            return -TARGET_EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/* clock_settime(2) */
+static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2)
+{
+    struct timespec ts;
+
+    if (t2h_freebsd_timespec(&ts, arg2) != 0) {
+        return -TARGET_EFAULT;
+    }
+
+    return get_errno(clock_settime(arg1, &ts));
+}
+
+/* clock_getres(2) */
+static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct timespec ts;
+
+    ret = get_errno(clock_getres(arg1, &ts));
+    if (!is_error(ret)) {
+        if (h2t_freebsd_timespec(arg2, &ts)) {
+            return -TARGET_EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/* gettimeofday(2) */
+static inline abi_long do_freebsd_gettimeofday(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    struct timeval tv;
+    struct timezone tz, *target_tz; /* XXX */
+
+    if (arg2 != 0) {
+        if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
+        __get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
+        unlock_user_struct(target_tz, arg2, 1);
+    }
+    ret = get_errno(gettimeofday(&tv, arg2 != 0 ? &tz : NULL));
+    if (!is_error(ret)) {
+        if (h2t_freebsd_timeval(&tv, arg1)) {
+            return -TARGET_EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/* settimeofday(2) */
+static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2)
+{
+    struct timeval tv;
+    struct timezone tz, *target_tz; /* XXX */
+
+    if (arg2 != 0) {
+        if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
+        __get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
+        unlock_user_struct(target_tz, arg2, 1);
+    }
+    if (t2h_freebsd_timeval(&tv, arg1)) {
+        return -TARGET_EFAULT;
+    }
+
+    return get_errno(settimeofday(&tv, arg2 != 0 ? &tz : NULL));
+}
+
+/* adjtime(2) */
+static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr,
+        abi_ulong target_old_addr)
+{
+    abi_long ret;
+    struct timeval host_delta, host_old;
+
+    ret = t2h_freebsd_timeval(&host_delta, target_delta_addr);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    if (target_old_addr) {
+        ret = get_errno(adjtime(&host_delta, &host_old));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = h2t_freebsd_timeval(&host_old, target_old_addr);
+    } else {
+        ret = get_errno(adjtime(&host_delta, NULL));
+    }
+
+    return ret;
+}
+
+/* ntp_adjtime(2) */
+static abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr)
+{
+    abi_long ret;
+    struct timex host_tx;
+
+    ret = t2h_freebsd_timex(&host_tx, target_tx_addr);
+    if (ret == 0) {
+        ret = get_errno(ntp_adjtime(&host_tx));
+    }
+
+    return ret;
+}
+
+/* ntp_gettime(2) */
+static abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr)
+{
+    abi_long ret;
+    struct ntptimeval host_ntv;
+
+    ret = get_errno(ntp_gettime(&host_ntv));
+    if (ret == 0) {
+        ret = h2t_freebsd_ntptimeval(target_ntv_addr, &host_ntv);
+    }
+
+    return ret;
+}
+
+
+/* utimes(2) */
+static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct timeval *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg2) ||
+                t2h_freebsd_timeval(&tv[1], arg2 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(utimes(p, tvp));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* lutimes(2) */
+static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct timeval *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg2) ||
+                t2h_freebsd_timeval(&tv[1], arg2 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(lutimes(p, tvp));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* futimes(2) */
+static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2)
+{
+    struct timeval *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg2) ||
+                t2h_freebsd_timeval(&tv[1], arg2 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+
+    return get_errno(futimes(arg1, tvp));
+}
+
+/* futimesat(2) */
+static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    struct timeval *tvp, tv[2];
+
+    if (arg3 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg3) ||
+                t2h_freebsd_timeval(&tv[1], arg3 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+
+    p = lock_user_string(arg2);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(futimesat(arg1, p, tvp));
+    unlock_user(p, arg2, 0);
+
+    return ret;
+}
+
+/*
+ * undocumented ktimer_create(clockid_t clock_id,  struct sigevent *evp,
+ * int *timerid) syscall
+ */
+static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocumented ktimer_delete(int timerid) syscall */
+static inline abi_long do_freebsd_ktimer_delete(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_delete()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented ktimer_settime(int timerid, int flags,
+ * const struct itimerspec *value, struct itimerspec *ovalue) syscall
+ */
+static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_settime()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented ktimer_gettime(int timerid, struct itimerspec *value)
+ * syscall
+ */
+static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_gettime()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented ktimer_getoverrun(int timerid) syscall
+ */
+static inline abi_long do_freebsd_ktimer_getoverrun(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_getoverrun()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* select(2) */
+static inline abi_long do_freebsd_select(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong target_tv_addr)
+{
+    fd_set rfds, wfds, efds;
+    fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+    struct timeval tv, *tv_ptr;
+    abi_long ret, error;
+
+    ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+    if (ret != 0) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+    if (ret != 0) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+    if (ret != 0) {
+        return ret;
+    }
+
+    if (target_tv_addr != 0) {
+        if (t2h_freebsd_timeval(&tv, target_tv_addr)) {
+            return -TARGET_EFAULT;
+        }
+        tv_ptr = &tv;
+    } else {
+        tv_ptr = NULL;
+    }
+
+    ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
+
+    if (!is_error(ret)) {
+        if (rfd_addr != 0) {
+            error = copy_to_user_fdset(rfd_addr, &rfds, n);
+            if (error != 0) {
+                return error;
+            }
+        }
+        if (wfd_addr != 0) {
+            error = copy_to_user_fdset(wfd_addr, &wfds, n);
+            if (error != 0) {
+                return error;
+            }
+        }
+        if (efd_addr != 0) {
+            error = copy_to_user_fdset(efd_addr, &efds, n);
+            if (error != 0) {
+                return error;
+            }
+        }
+        if (target_tv_addr != 0) {
+            error = h2t_freebsd_timeval(&tv, target_tv_addr);
+            if (is_error(error)) {
+                return error;
+            }
+        }
+    }
+    return ret;
+}
+
+/* pselect(2) */
+static inline abi_long do_freebsd_pselect(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong ts_addr,
+        abi_ulong set_addr)
+{
+    fd_set rfds, wfds, efds;
+    fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+    sigset_t set, *set_ptr;
+    struct timespec ts, *ts_ptr;
+    void *p;
+    abi_long ret;
+
+    ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    /* Unlike select(), pselect() uses struct timespec instead of timeval */
+    if (ts_addr) {
+        if (t2h_freebsd_timespec(&ts, ts_addr)) {
+            return -TARGET_EFAULT;
+        }
+        ts_ptr = &ts;
+    } else {
+        ts_ptr = NULL;
+    }
+
+    if (set_addr != 0) {
+        p = lock_user(VERIFY_READ, set_addr, sizeof(target_sigset_t), 1);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        target_to_host_sigset(&set, p);
+        unlock_user(p, set_addr, 0);
+        set_ptr = &set;
+    } else {
+        set_ptr = NULL;
+    }
+
+    ret = get_errno(pselect(n, rfds_ptr, wfds_ptr, efds_ptr, ts_ptr, set_ptr));
+
+    if (!is_error(ret)) {
+        if (rfd_addr != 0) {
+            ret = copy_to_user_fdset(rfd_addr, &rfds, n);
+            if (is_error(ret)) {
+                return ret;
+            }
+        }
+        if (wfd_addr != 0) {
+            ret = copy_to_user_fdset(wfd_addr, &wfds, n);
+            if (is_error(ret)) {
+                return ret;
+            }
+        }
+        if (efd_addr != 0) {
+            ret = copy_to_user_fdset(efd_addr, &efds, n);
+            if (is_error(ret)) {
+                return ret;
+            }
+        }
+        if (ts_addr != 0) {
+            ret = h2t_freebsd_timespec(ts_addr, &ts);
+            if (is_error(ret)) {
+                return ret;
+            }
+        }
+    }
+    return ret;
+}
+
+/* kqueue(2) */
+static inline abi_long do_freebsd_kqueue(void)
+{
+
+    return get_errno(kqueue());
+}
+
+/* kevent(2) */
+static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
+        abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    struct kevent *changelist = NULL, *eventlist = NULL;
+    struct target_freebsd_kevent *target_changelist, *target_eventlist;
+    struct timespec ts;
+    int i;
+
+    if (arg3 != 0) {
+        target_changelist = lock_user(VERIFY_READ, arg2,
+                sizeof(struct target_freebsd_kevent) * arg3, 1);
+        if (target_changelist == NULL) {
+            return -TARGET_EFAULT;
+        }
+
+        changelist = alloca(sizeof(struct kevent) * arg3);
+        for (i = 0; i < arg3; i++) {
+            __get_user(changelist[i].ident, &target_changelist[i].ident);
+            __get_user(changelist[i].filter, &target_changelist[i].filter);
+            __get_user(changelist[i].flags, &target_changelist[i].flags);
+            __get_user(changelist[i].fflags, &target_changelist[i].fflags);
+            __get_user(changelist[i].data, &target_changelist[i].data);
+            /* __get_user(changelist[i].udata, &target_changelist[i].udata); */
+#if TARGET_ABI_BITS == 32
+            changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata;
+            tswap32s((uint32_t *)&changelist[i].udata);
+#else
+            changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata;
+            tswap64s((uint64_t *)&changelist[i].udata);
+#endif
+        }
+        unlock_user(target_changelist, arg2, 0);
+    }
+
+    if (arg5 != 0) {
+        eventlist = alloca(sizeof(struct kevent) * arg5);
+    }
+    if (arg6 != 0) {
+        if (t2h_freebsd_timespec(&ts, arg6)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    ret = get_errno(kevent(arg1, changelist, arg3, eventlist, arg5,
+                arg6 != 0 ? &ts : NULL));
+    if (!is_error(ret)) {
+        target_eventlist = lock_user(VERIFY_WRITE, arg4,
+                sizeof(struct target_freebsd_kevent) * arg5, 0);
+        if (target_eventlist == NULL) {
+                return -TARGET_EFAULT;
+        }
+        for (i = 0; i < arg5; i++) {
+            __put_user(eventlist[i].ident, &target_eventlist[i].ident);
+            __put_user(eventlist[i].filter, &target_eventlist[i].filter);
+            __put_user(eventlist[i].flags, &target_eventlist[i].flags);
+            __put_user(eventlist[i].fflags, &target_eventlist[i].fflags);
+            __put_user(eventlist[i].data, &target_eventlist[i].data);
+            /* __put_user(eventlist[i].udata, &target_eventlist[i].udata);*/
+#if TARGET_ABI_BITS == 32
+            tswap32s((uint32_t *)&eventlist[i].data);
+            target_eventlist[i].data = (uintptr_t)eventlist[i].data;
+#else
+            tswap64s((uint64_t *)&eventlist[i].data);
+            target_eventlist[i].data = (uintptr_t)eventlist[i].data;
+#endif
+        }
+        unlock_user(target_eventlist, arg4,
+                sizeof(struct target_freebsd_kevent) * arg5);
+    }
+    return ret;
+}
+
+/* sigtimedwait(2) */
+static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    struct timespec uts, *puts;
+    siginfo_t uinfo;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    if (arg3) {
+        puts = &uts;
+        t2h_freebsd_timespec(puts, arg3);
+    } else {
+        puts = NULL;
+    }
+    ret = get_errno(sigtimedwait(&set, &uinfo, puts));
+    if (!is_error(ret) && arg2) {
+        p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_siginfo(p, &uinfo);
+        unlock_user(p, arg2, sizeof(target_siginfo_t));
+    }
+    return ret;
+}
+
+/* setitimer(2) */
+static inline abi_long do_freebsd_setitimer(int arg1, abi_ulong arg2, abi_ulong arg3)
+{
+   abi_long ret = 0;
+   struct itimerval value, ovalue, *pvalue;
+
+   if (arg2) {
+       pvalue = &value;
+       if (t2h_freebsd_timeval(&pvalue->it_interval, arg2) ||
+           t2h_freebsd_timeval(&pvalue->it_value, arg2 + sizeof(struct target_freebsd_timeval))) {
+             return -TARGET_EFAULT;
+       } 
+   } else {
+       pvalue = NULL;
+   }
+   ret = get_errno(setitimer(arg1, pvalue, &ovalue));
+   if (!is_error(ret) && arg3) {
+       if (h2t_freebsd_timeval(&ovalue.it_interval, arg3)
+          || h2t_freebsd_timeval(&ovalue.it_value, arg3 + sizeof(struct target_freebsd_timeval))) {
+             return -TARGET_EFAULT;
+       }
+   }
+   return ret;
+}
+
+/* getitimer(2) */
+static inline abi_long do_freebsd_getitimer(int arg1, abi_ulong arg2)
+{
+   abi_long ret = 0;
+   struct itimerval value;
+
+   ret = get_errno(getitimer(arg1, &value));
+   if (!is_error(ret) && arg2) {
+       if (h2t_freebsd_timeval(&value.it_interval, arg2) ||
+           h2t_freebsd_timeval(&value.it_value, arg2 + sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+       }
+   }
+   return ret;
+}
+
+#endif /* __FREEBSD_OS_TIME_H_ */
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
new file mode 100644
index 0000000..bde610e
--- /dev/null
+++ b/bsd-user/freebsd/qemu-os.h
@@ -0,0 +1,53 @@
+/*
+ *  FreeBSD conversion extern declarations
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _QEMU_OS_H_
+#define _QEMU_OS_H_
+
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/mount.h>
+#include <sys/timex.h>
+#include <sys/rtprio.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#include <time.h>
+
+/* os-time.c */
+abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr);
+abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr);
+
+abi_long t2h_freebsd_timespec(struct timespec *ts, abi_ulong target_ts_addr);
+abi_long h2t_freebsd_timespec(abi_ulong target_ts_addr, struct timespec *ts);
+
+abi_long t2h_freebsd_timex(struct timex *host_tx, abi_ulong target_tx_addr);
+
+abi_long h2t_freebsd_ntptimeval(abi_ulong target_ntv_addr,
+        struct ntptimeval *ntv);
+
+abi_ulong copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n);
+abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
+        abi_ulong target_fds_addr, int n);
+abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds,
+        int n);
+
+#endif /* !_QEMU_OS_H_ */
diff --git a/bsd-user/netbsd/os-time.c b/bsd-user/netbsd/os-time.c
new file mode 100644
index 0000000..ee2c7a0
--- /dev/null
+++ b/bsd-user/netbsd/os-time.c
@@ -0,0 +1 @@
+/* XXX NetBSD time related helpers */
diff --git a/bsd-user/netbsd/os-time.h b/bsd-user/netbsd/os-time.h
new file mode 100644
index 0000000..6d0f1de
--- /dev/null
+++ b/bsd-user/netbsd/os-time.h
@@ -0,0 +1,179 @@
+#ifndef __NETBSD_OS_TIME_H_
+#define __NETBSD_OS_TIME_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need to
+ * be emulated.
+ */
+static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_gettimeofday(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr,
+        abi_ulong target_old_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_delete(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_getoverrun(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_select(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong target_tv_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+
+static inline abi_long do_freebsd_pselect(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong ts_addr,
+        abi_ulong set_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_kqueue(void)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
+        abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __NETBSD_OS_TIME_H_ */
diff --git a/bsd-user/netbsd/qemu-os.h b/bsd-user/netbsd/qemu-os.h
new file mode 100644
index 0000000..016618b
--- /dev/null
+++ b/bsd-user/netbsd/qemu-os.h
@@ -0,0 +1 @@
+/* NetBSD conversion extern declarations */
diff --git a/bsd-user/openbsd/os-time.c b/bsd-user/openbsd/os-time.c
new file mode 100644
index 0000000..accd886
--- /dev/null
+++ b/bsd-user/openbsd/os-time.c
@@ -0,0 +1 @@
+/* XXX OpenBSD time related helpers */
diff --git a/bsd-user/openbsd/os-time.h b/bsd-user/openbsd/os-time.h
new file mode 100644
index 0000000..fc444bb
--- /dev/null
+++ b/bsd-user/openbsd/os-time.h
@@ -0,0 +1,179 @@
+#ifndef __OPENBSD_OS_TIME_H_
+#define __OPENBSD_OS_TIME_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need to
+ * be emulated.
+ */
+static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_gettimeofday(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr,
+        abi_ulong target_old_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_delete(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_getoverrun(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_select(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong target_tv_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+
+static inline abi_long do_freebsd_pselect(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong ts_addr,
+        abi_ulong set_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_kqueue(void)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
+        abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_OS_TIME_H_ */
diff --git a/bsd-user/openbsd/qemu-os.h b/bsd-user/openbsd/qemu-os.h
new file mode 100644
index 0000000..f4ad3be
--- /dev/null
+++ b/bsd-user/openbsd/qemu-os.h
@@ -0,0 +1 @@
+/* OpenBSD conversion extern declarations */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index dbc212d..0996787 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -39,6 +39,9 @@
 
 #define target_to_host_bitmask(x, tbl) (x)
 
+/* *BSD dependent syscall shims */
+#include "os-time.h"
+
 /* #define DEBUG */
 
 static abi_ulong target_brk;
@@ -224,6 +227,105 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * time related system calls.
+         */
+    case TARGET_FREEBSD_NR_nanosleep: /* nanosleep(2) */
+        ret = do_freebsd_nanosleep(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_gettime: /* clock_gettime(2) */
+        ret = do_freebsd_clock_gettime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_settime: /* clock_settime(2) */
+        ret = do_freebsd_clock_settime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_getres: /* clock_getres(2) */
+        ret = do_freebsd_clock_getres(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_gettimeofday: /* gettimeofday(2) */
+        ret = do_freebsd_gettimeofday(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_settimeofday: /* settimeofday(2) */
+        ret = do_freebsd_settimeofday(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_adjtime: /* adjtime(2) */
+        ret = do_freebsd_adjtime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_ntp_adjtime: /* ntp_adjtime(2) */
+        ret = do_freebsd_ntp_adjtime(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_ntp_gettime: /* ntp_gettime(2) */
+        ret = do_freebsd_ntp_gettime(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_utimes: /* utimes(2) */
+        ret = do_freebsd_utimes(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lutimes: /* lutimes(2) */
+        ret = do_freebsd_lutimes(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_futimes: /* futimes(2) */
+        ret = do_freebsd_futimes(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_futimesat: /* futimesat(2) */
+        ret = do_freebsd_futimesat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_create: /* undocumented */
+        ret = do_freebsd_ktimer_create(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_delete: /* undocumented */
+        ret = do_freebsd_ktimer_delete(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_settime: /* undocumented */
+        ret = do_freebsd_ktimer_settime(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_gettime: /* undocumented */
+        ret = do_freebsd_ktimer_gettime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_getoverrun: /* undocumented */
+        ret = do_freebsd_ktimer_getoverrun(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_select: /* select(2) */
+        ret = do_freebsd_select(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_pselect: /* pselect(2) */
+        ret = do_freebsd_pselect(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_kqueue: /* kqueue(2) */
+        ret = do_freebsd_kqueue();
+        break;
+
+    case TARGET_FREEBSD_NR_kevent: /* kevent(2) */
+        ret = do_freebsd_kevent(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_setitimer: /* setitimer(2) */
+        ret = do_freebsd_setitimer(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getitimer: /* getitimer(2) */
+        ret = do_freebsd_getitimer(arg1, arg2);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 207ddee..bd6d276 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -1,105 +1,5 @@
-/*      $OpenBSD: signal.h,v 1.19 2006/01/08 14:20:16 millert Exp $     */
-/*      $NetBSD: signal.h,v 1.21 1996/02/09 18:25:32 christos Exp $     */
-
-/*
- * Copyright (c) 1982, 1986, 1989, 1991, 1993
- *      The Regents of the University of California.  All rights reserved.
- * (c) UNIX System Laboratories, Inc.
- * All or some portions of this file are derived from material licensed
- * to the University of California by American Telephone and Telegraph
- * Co. or Unix System Laboratories, Inc. and are reproduced herein with
- * the permission of UNIX System Laboratories, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *      @(#)signal.h    8.2 (Berkeley) 1/21/94
- */
-
-#define TARGET_NSIG     32              /* counting 0; could be 33 (mask is 1-32) */
-
-#define TARGET_SIGHUP  1       /* hangup */
-#define TARGET_SIGINT  2       /* interrupt */
-#define TARGET_SIGQUIT 3       /* quit */
-#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
-#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
-#define TARGET_SIGABRT 6       /* abort() */
-#define TARGET_SIGIOT  SIGABRT /* compatibility */
-#define TARGET_SIGEMT  7       /* EMT instruction */
-#define TARGET_SIGFPE  8       /* floating point exception */
-#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
-#define TARGET_SIGBUS  10      /* bus error */
-#define TARGET_SIGSEGV 11      /* segmentation violation */
-#define TARGET_SIGSYS  12      /* bad argument to system call */
-#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
-#define TARGET_SIGALRM 14      /* alarm clock */
-#define TARGET_SIGTERM 15      /* software termination signal from kill */
-#define TARGET_SIGURG  16      /* urgent condition on IO channel */
-#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
-#define TARGET_SIGTSTP 18      /* stop signal from tty */
-#define TARGET_SIGCONT 19      /* continue a stopped process */
-#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
-#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
-#define TARGET_SIGTTOU 22      /* like TTIN for output if (tp->t_local&LTOSTOP) */
-#define TARGET_SIGIO   23      /* input/output possible signal */
-#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
-#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
-#define TARGET_SIGVTALRM 26    /* virtual time alarm */
-#define TARGET_SIGPROF 27      /* profiling time alarm */
-#define TARGET_SIGWINCH 28      /* window size changes */
-#define TARGET_SIGINFO  29      /* information request */
-#define TARGET_SIGUSR1 30       /* user defined signal 1 */
-#define TARGET_SIGUSR2 31       /* user defined signal 2 */
-
-/*
- * Language spec says we must list exactly one parameter, even though we
- * actually supply three.  Ugh!
- */
-#define TARGET_SIG_DFL         (void (*)(int))0
-#define TARGET_SIG_IGN         (void (*)(int))1
-#define TARGET_SIG_ERR         (void (*)(int))-1
-
-#define TARGET_SA_ONSTACK       0x0001  /* take signal on signal stack */
-#define TARGET_SA_RESTART       0x0002  /* restart system on signal return */
-#define TARGET_SA_RESETHAND     0x0004  /* reset to SIG_DFL when taking signal */
-#define TARGET_SA_NODEFER       0x0010  /* don't mask the signal we're delivering */
-#define TARGET_SA_NOCLDWAIT     0x0020  /* don't create zombies (assign to pid 1) */
-#define TARGET_SA_USERTRAMP    0x0100  /* do not bounce off kernel's sigtramp */
-#define TARGET_SA_NOCLDSTOP     0x0008  /* do not generate SIGCHLD on child stop */
-#define TARGET_SA_SIGINFO       0x0040  /* generate siginfo_t */
-
-/*
- * Flags for sigprocmask:
- */
-#define TARGET_SIG_BLOCK       1       /* block specified signal set */
-#define TARGET_SIG_UNBLOCK     2       /* unblock specified signal set */
-#define TARGET_SIG_SETMASK     3       /* set specified signal set */
-
-#define TARGET_BADSIG          SIG_ERR
-
-#define TARGET_SS_ONSTACK       0x0001  /* take signals on alternate stack */
-#define TARGET_SS_DISABLE       0x0004  /* disable taking signals on alternate stack */
+#ifndef _SYSCALL_DEFS_H_
+#define _SYSCALL_DEFS_H_
 
 #include "errno_defs.h"
 
@@ -112,3 +12,695 @@ struct target_iovec {
     abi_long iov_len;   /* Number of bytes */
 };
 
+/*
+ * sys/ipc.h
+ */
+struct target_ipc_perm {
+    uint32_t    cuid;       /* creator user id */
+    uint32_t    cgid;       /* creator group id */
+    uint32_t    uid;        /* user id */
+    uint32_t    gid;        /* group id */
+    uint16_t    mode;       /* r/w permission */
+    uint16_t    seq;        /* sequence # */
+    abi_long    key;        /* user specified msg/sem/shm key */
+};
+
+#define TARGET_IPC_RMID 0   /* remove identifier */
+#define TARGET_IPC_SET  1   /* set options */
+#define TARGET_IPC_STAT 2   /* get options */
+
+/*
+ * sys/sem.h
+ */
+#define TARGET_GETNCNT  3   /* Return the value of semncnt {READ} */
+#define TARGET_GETPID   4   /* Return the value of sempid {READ} */
+#define TARGET_GETVAL   5   /* Return the value of semval {READ} */
+#define TARGET_GETALL   6   /* Return semvals into arg.array {READ} */
+#define TARGET_GETZCNT  7   /* Return the value of semzcnt {READ} */
+#define TARGET_SETVAL   8   /* Set the value of semval to arg.val {ALTER} */
+#define TARGET_SETALL   9   /* Set semvals from arg.array {ALTER} */
+#define TARGET_SEM_STAT 10 /* Like IPC_STAT but treats semid as sema-index */
+#define TARGET_SEM_INFO 11 /* Like IPC_INFO but treats semid as sema-index */
+
+struct target_sembuf {
+    unsigned short  sem_num;    /* semaphore # */
+    short       sem_op;         /* semaphore operation */
+    short       sem_flg;        /* operation flags */
+};
+
+union target_semun {
+    int     val;        /* value for SETVAL */
+    abi_ulong   buf;        /* buffer for IPC_STAT & IPC_SET */
+    abi_ulong   array;      /* array for GETALL & SETALL */
+};
+
+struct target_semid_ds {
+    struct target_ipc_perm sem_perm; /* operation permission struct */
+    abi_ulong   sem_base;   /* pointer to first semaphore in set */
+    uint16_t    sem_nsems;  /* number of sems in set */
+    abi_ulong   sem_otime;  /* last operation time */
+    abi_ulong   sem_ctime;  /* times measured in secs */
+};
+
+/*
+ * sys/shm.h
+ */
+struct target_shmid_ds {
+    struct  target_ipc_perm shm_perm; /* peration permission structure */
+    abi_ulong   shm_segsz;  /* size of segment in bytes */
+    int32_t     shm_lpid;   /* process ID of last shared memory op */
+    int32_t     shm_cpid;   /* process ID of creator */
+    int32_t     shm_nattch; /* number of current attaches */
+    abi_ulong   shm_atime;  /* time of last shmat() */
+    abi_ulong   shm_dtime;  /* time of last shmdt() */
+    abi_ulong   shm_ctime;  /* time of last change by shmctl() */
+};
+
+#define N_BSD_SHM_REGIONS   32
+struct bsd_shm_regions {
+    abi_long start;
+    abi_long size;
+};
+
+/*
+ * sys/msg.h
+ */
+struct target_msqid_ds {
+    struct  target_ipc_perm msg_perm; /* msg queue permission bits */
+    abi_ulong   msg_first;  /* first message in the queue */
+    abi_ulong   msg_last;   /* last message in the queue */
+    abi_ulong   msg_cbytes; /* # of bytes in use on the queue */
+    abi_ulong   msg_qnum;   /* number of msgs in the queue */
+    abi_ulong   msg_qbytes; /* max # of bytes on the queue */
+    int32_t     msg_lspid;  /* pid of last msgsnd() */
+    int32_t     msg_lrpid;  /* pid of last msgrcv() */
+    abi_ulong   msg_stime;  /* time of last msgsnd() */
+    abi_ulong   msg_rtime;  /* time of last msgrcv() */
+    abi_ulong   msg_ctime;  /* time of last msgctl() */
+};
+
+struct target_msgbuf {
+    abi_long    mtype;      /* message type */
+    char        mtext[1];   /* body of message */
+};
+
+/*
+ * sched.h
+ */
+struct target_sched_param {
+        int32_t sched_priority;
+};
+
+/*
+ *  sys/mman.h
+ */
+#define TARGET_FREEBSD_MAP_RESERVED0080 0x0080  /* previously misimplemented
+                                                   MAP_INHERIT */
+#define TARGET_FREEBSD_MAP_RESERVED0100 0x0100  /* previously unimplemented
+                                                   MAP_NOEXTEND */
+#define TARGET_FREEBSD_MAP_STACK        0x0400  /* region grows down, like a
+                                                   stack */
+#define TARGET_FREEBSD_MAP_NOSYNC       0x0800  /* page to but do not sync
+                                                   underlying file */
+
+#define TARGET_FREEBSD_MAP_FLAGMASK     0x1ff7
+
+#define TARGET_NETBSD_MAP_INHERIT       0x0080  /* region is retained after
+                                                   exec */
+#define TARGET_NETBSD_MAP_TRYFIXED      0x0400 /* attempt hint address, even
+                                                  within break */
+#define TARGET_NETBSD_MAP_WIRED         0x0800  /* mlock() mapping when it is
+                                                   established */
+
+#define TARGET_NETBSD_MAP_STACK         0x2000  /* allocated from memory, swap
+                                                   space (stack) */
+
+#define TARGET_NETBSD_MAP_FLAGMASK      0x3ff7
+
+#define TARGET_OPENBSD_MAP_INHERIT      0x0080  /* region is retained after
+                                                   exec */
+#define TARGET_OPENBSD_MAP_NOEXTEND     0x0100  /* for MAP_FILE, don't change
+                                                   file size */
+#define TARGET_OPENBSD_MAP_TRYFIXED     0x0400  /* attempt hint address,
+                                                   even within heap */
+
+#define TARGET_OPENBSD_MAP_FLAGMASK     0x17f7
+
+/* XXX */
+#define TARGET_BSD_MAP_FLAGMASK         0x3ff7
+
+/*
+ * sys/time.h
+ * sys/timex.h
+ */
+
+/*
+ * time_t seems to be very inconsistly defined for the different *BSD's...
+ *
+ * FreeBSD/{arm, mips} uses a 64bits time_t, even in 32bits mode,
+ * so we have to add a special case here.
+ *
+ * On NetBSD time_t is always defined as an int64_t.  On OpenBSD time_t
+ * is always defined as an int.
+ *
+ */
+#if (defined(TARGET_ARM) || defined(TARGET_MIPS))
+typedef int64_t target_freebsd_time_t;
+#else
+typedef abi_long target_freebsd_time_t;
+#endif
+
+typedef abi_long target_freebsd_suseconds_t;
+
+/* compare to sys/timespec.h */
+struct target_freebsd_timespec {
+    target_freebsd_time_t   tv_sec;     /* seconds */
+    abi_long                tv_nsec;    /* and nanoseconds */
+#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
+    abi_long _pad;
+#endif
+} __packed;
+
+struct target_freebsd_timeval {
+    target_freebsd_time_t       tv_sec; /* seconds */
+    target_freebsd_suseconds_t  tv_usec;/* and microseconds */
+#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
+    abi_long _pad;
+#endif
+} __packed;
+
+/* compare to sys/timex.h */
+struct target_freebsd_ntptimeval {
+    struct target_freebsd_timespec  time;
+    abi_long    maxerror;
+    abi_long    esterror;
+    abi_long    tai;
+    int32_t     time_state;
+};
+
+struct target_freebsd_timex {
+    uint32_t    modes;
+    abi_long    offset;
+    abi_long    freq;
+    abi_long    maxerror;
+    abi_long    esterror;
+    int32_t     status;
+    abi_long    constant;
+    abi_long    precision;
+    abi_long    tolerance;
+
+    abi_long    ppsfreq;
+    abi_long    jitter;
+    int32_t     shift;
+    abi_long    stabil;
+    abi_long    jitcnt;
+    abi_long    calcnt;
+    abi_long    errcnt;
+    abi_long    stbcnt;
+};
+
+/*
+ * sys/event.h
+ */
+struct target_freebsd_kevent {
+    abi_ulong  ident;
+    int16_t    filter;
+    uint16_t   flags;
+    uint32_t   fflags;
+    abi_long   data;
+    abi_ulong  udata;
+} __packed;
+
+/*
+ *  sys/resource.h
+ */
+#if defined(__FreeBSD__) && defined(TARGET_ALPHA)
+#define TARGET_RLIM_INFINITY    0x7fffffffffffffffull
+#elif defined(__FreeBSD__) && (defined(TARGET_MIPS) || \
+        (defined(TARGET_SPARC) && TARGET_ABI_BITS == 32))
+#define TARGET_RLIM_INFINITY    0x7fffffffUL
+#else
+#define TARGET_RLIM_INFINITY    ((abi_ulong)-1)
+#endif
+
+#define TARGET_RLIMIT_CPU       0
+#define TARGET_RLIMIT_FSIZE     1
+#define TARGET_RLIMIT_DATA      2
+#define TARGET_RLIMIT_STACK     3
+#define TARGET_RLIMIT_CORE      4
+#define TARGET_RLIMIT_RSS       5
+#define TARGET_RLIMIT_MEMLOCK   6
+#define TARGET_RLIMIT_NPROC     7
+#define TARGET_RLIMIT_NOFILE    8
+#define TARGET_RLIMIT_SBSIZE    9
+#define TARGET_RLIMIT_AS        10
+#define TARGET_RLIMIT_NPTS      11
+#define TARGET_RLIMIT_SWAP      12
+
+struct target_rlimit {
+    uint64_t rlim_cur;
+    uint64_t rlim_max;
+};
+
+struct target_freebsd_rusage {
+    struct target_freebsd_timeval ru_utime; /* user time used */
+    struct target_freebsd_timeval ru_stime; /* system time used */
+    abi_long    ru_maxrss;      /* maximum resident set size */
+    abi_long    ru_ixrss;       /* integral shared memory size */
+    abi_long    ru_idrss;       /* integral unshared data size */
+    abi_long    ru_isrss;       /* integral unshared stack size */
+    abi_long    ru_minflt;      /* page reclaims */
+    abi_long    ru_majflt;      /* page faults */
+    abi_long    ru_nswap;       /* swaps */
+    abi_long    ru_inblock;     /* block input operations */
+    abi_long    ru_oublock;     /* block output operations */
+    abi_long    ru_msgsnd;      /* messages sent */
+    abi_long    ru_msgrcv;      /* messages received */
+    abi_long    ru_nsignals;    /* signals received */
+    abi_long    ru_nvcsw;       /* voluntary context switches */
+    abi_long    ru_nivcsw;      /* involuntary context switches */
+};
+
+/*
+ * sys/socket.h
+ */
+
+/*
+ * Types
+ */
+#define TARGET_SOCK_STREAM      1   /* stream socket */
+#define TARGET_SOCK_DGRAM       2   /* datagram socket */
+#define TARGET_SOCK_RAW         3   /* raw-protocol interface */
+#define TARGET_SOCK_RDM         4   /* reliably-delivered message */
+#define TARGET_SOCK_SEQPACKET   5   /* sequenced packet stream */
+
+
+/*
+ * Option flags per-socket.
+ */
+
+#define TARGET_SO_DEBUG         0x0001  /* turn on debugging info recording */
+#define TARGET_SO_ACCEPTCONN    0x0002  /* socket has had listen() */
+#define TARGET_SO_REUSEADDR     0x0004  /* allow local address reuse */
+#define TARGET_SO_KEEPALIVE     0x0008  /* keep connections alive */
+#define TARGET_SO_DONTROUTE     0x0010  /* just use interface addresses */
+#define TARGET_SO_BROADCAST     0x0020  /* permit sending of broadcast msgs */
+#define TARGET_SO_USELOOPBACK   0x0040  /* bypass hardware when possible */
+#define TARGET_SO_LINGER        0x0080  /* linger on close if data present */
+#define TARGET_SO_OOBINLINE     0x0100  /* leave received OOB data in line */
+#define TARGET_SO_REUSEPORT     0x0200  /* allow local address & port reuse */
+#define TARGET_SO_TIMESTAMP     0x0400  /* timestamp received dgram traffic */
+#define TARGET_SO_NOSIGPIPE     0x0800  /* no SIGPIPE from EPIPE */
+#define TARGET_SO_ACCEPTFILTER  0x1000  /* there is an accept filter */
+#define TARGET_SO_BINTIME       0x2000  /* timestamp received dgram traffic */
+#define TARGET_SO_NO_OFFLOAD    0x4000  /* socket cannot be offloaded */
+#define TARGET_SO_NO_DDP        0x8000  /* disable direct data placement */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define TARGET_SO_SNDBUF        0x1001  /* send buffer size */
+#define TARGET_SO_RCVBUF        0x1002  /* receive buffer size */
+#define TARGET_SO_SNDLOWAT      0x1003  /* send low-water mark */
+#define TARGET_SO_RCVLOWAT      0x1004  /* receive low-water mark */
+#define TARGET_SO_SNDTIMEO      0x1005  /* send timeout */
+#define TARGET_SO_RCVTIMEO      0x1006  /* receive timeout */
+#define TARGET_SO_ERROR         0x1007  /* get error status and clear */
+#define TARGET_SO_TYPE          0x1008  /* get socket type */
+#define TARGET_SO_LABEL         0x1009  /* socket's MAC label */
+#define TARGET_SO_PEERLABEL     0x1010  /* socket's peer's MAC label */
+#define TARGET_SO_LISTENQLIMIT  0x1011  /* socket's backlog limit */
+#define TARGET_SO_LISTENQLEN    0x1012  /* socket's complete queue length */
+#define TARGET_SO_LISTENINCQLEN 0x1013  /* socket's incomplete queue length */
+#define TARGET_SO_SETFIB        0x1014  /* use this FIB to route */
+#define TARGET_SO_USER_COOKIE   0x1015  /* user cookie (dummynet etc.) */
+#define TARGET_SO_PROTOCOL      0x1016  /* get socket protocol (Linux name) */
+
+/* alias for SO_PROTOCOL (SunOS name) */
+#define TARGET_SO_PROTOTYPE     TARGET_SO_PROTOCOL
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define TARGET_SOL_SOCKET       0xffff  /* options for socket level */
+
+#ifndef CMSG_ALIGN
+#define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1))
+#endif
+
+struct target_msghdr {
+    abi_long    msg_name;       /* So cket name */
+    int32_t     msg_namelen;    /* Length of name */
+    abi_long    msg_iov;        /* Data blocks */
+    abi_long    msg_iovlen;     /* Number of blocks */
+    abi_long    msg_control;    /* Per protocol magic
+                                   (eg BSD file descriptor passing) */
+    abi_long    msg_controllen; /* Length of cmsg list */
+    int32_t     msg_flags;      /* flags on received message */
+};
+
+struct target_sockaddr {
+    uint8_t sa_len;
+    uint8_t sa_family;
+    uint8_t sa_data[14];
+} QEMU_PACKED;
+
+struct target_in_addr {
+    uint32_t s_addr; /* big endian */
+};
+
+struct target_cmsghdr {
+    abi_long    cmsg_len;
+    int32_t     cmsg_level;
+    int32_t     cmsg_type;
+};
+
+#define TARGET_CMSG_DATA(cmsg)  \
+    ((unsigned char *)((struct target_cmsghdr *) (cmsg) + 1))
+#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr(mhdr, cmsg)
+#define TARGET_CMSG_ALIGN(len) (((len) + sizeof(abi_long) - 1) \
+    & (size_t) ~(sizeof(abi_long) - 1))
+#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN(len) \
+    + TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr)))
+#define TARGET_CMSG_LEN(len)  \
+    (TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr)) + (len))
+
+static inline struct target_cmsghdr *__target_cmsg_nxthdr(
+        struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg)
+{
+    struct target_cmsghdr *__ptr;
+
+    __ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg +
+        TARGET_CMSG_ALIGN(tswapal(__cmsg->cmsg_len)));
+    if ((unsigned long)((char *)(__ptr+1) -
+        (char *)(size_t)tswapal(__mhdr->msg_control)) >
+        tswapal(__mhdr->msg_controllen)) {
+        /* No more entries.  */
+        return (struct target_cmsghdr *)0;
+    }
+    return __cmsg;
+}
+
+/*
+ * netinet/in.h
+ */
+struct target_ip_mreq {
+    struct target_in_addr   imr_multiaddr;
+    struct target_in_addr   imr_interface;
+};
+
+struct target_ip_mreqn {
+    struct target_in_addr   imr_multiaddr;
+    struct target_in_addr   imr_address;
+    int32_t                 imr_ifindex;
+};
+
+/*
+ * sys/stat.h
+ */
+#if defined(__FreeBSD_version) && __FreeBSD_version < 900000
+#define st_atim st_atimespec
+#define st_ctim st_ctimespec
+#define st_mtim st_mtimespec
+#define st_birthtim st_birthtimespec
+#endif
+
+struct target_freebsd_stat {
+    uint32_t  st_dev;       /* inode's device */
+    uint32_t  st_ino;       /* inode's number */
+    int16_t   st_mode;      /* inode protection mode */
+    int16_t   st_nlink;     /* number of hard links */
+    uint32_t  st_uid;       /* user ID of the file's owner */
+    uint32_t  st_gid;       /* group ID of the file's group */
+    uint32_t  st_rdev;      /* device type */
+    struct  target_freebsd_timespec st_atim; /* time last accessed */
+    struct  target_freebsd_timespec st_mtim; /* time last data modification */
+    struct  target_freebsd_timespec st_ctim; /* time last file status change */
+    int64_t    st_size;     /* file size, in bytes */
+    int64_t    st_blocks;   /* blocks allocated for file */
+    uint32_t   st_blksize;  /* optimal blocksize for I/O */
+    uint32_t   st_flags;    /* user defined flags for file */
+    __uint32_t st_gen;      /* file generation number */
+    __int32_t  st_lspare;
+    struct target_freebsd_timespec st_birthtim; /* time of file creation */
+    /*
+     * Explicitly pad st_birthtim to 16 bytes so that the size of
+     * struct stat is backwards compatible.  We use bitfields instead
+     * of an array of chars so that this doesn't require a C99 compiler
+     * to compile if the size of the padding is 0.  We use 2 bitfields
+     * to cover up to 64 bits on 32-bit machines.  We assume that
+     * CHAR_BIT is 8...
+     */
+    unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec));
+    unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec));
+} __packed;
+
+/* struct nstat is the same as stat above but without the st_lspare field */
+struct target_freebsd_nstat {
+    uint32_t  st_dev;       /* inode's device */
+    uint32_t  st_ino;       /* inode's number */
+    int16_t   st_mode;      /* inode protection mode */
+    int16_t   st_nlink;     /* number of hard links */
+    uint32_t  st_uid;       /* user ID of the file's owner */
+    uint32_t  st_gid;       /* group ID of the file's group */
+    uint32_t  st_rdev;      /* device type */
+    struct  target_freebsd_timespec st_atim; /* time last accessed */
+    struct  target_freebsd_timespec st_mtim; /* time last data modification */
+    struct  target_freebsd_timespec st_ctim; /* time last file status change */
+    int64_t    st_size;     /* file size, in bytes */
+    int64_t    st_blocks;   /* blocks allocated for file */
+    uint32_t   st_blksize;  /* optimal blocksize for I/O */
+    uint32_t   st_flags;    /* user defined flags for file */
+    __uint32_t st_gen;      /* file generation number */
+    /* __int32_t  st_lspare; */
+    struct target_freebsd_timespec st_birthtim; /* time of file creation */
+    /*
+     * Explicitly pad st_birthtim to 16 bytes so that the size of
+     * struct stat is backwards compatible.  We use bitfields instead
+     * of an array of chars so that this doesn't require a C99 compiler
+     * to compile if the size of the padding is 0.  We use 2 bitfields
+     * to cover up to 64 bits on 32-bit machines.  We assume that
+     * CHAR_BIT is 8...
+     */
+    unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec));
+    unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec));
+} __packed;
+
+/*
+ * sys/mount.h
+ */
+
+/* filesystem id type */
+typedef struct target_freebsd_fsid { int32_t val[2]; } target_freebsd_fsid_t;
+
+/* filesystem statistics */
+#define TARGET_MFSNAMELEN   16  /* length of type name include null */
+#define TARGET_MNAMELEN     88  /* size of on/from name bufs */
+#define TARGET_STATFS_VERSION   0x20030518  /* current version number */
+struct target_freebsd_statfs {
+    uint32_t f_version; /* structure version number */
+    uint32_t f_type;    /* type of filesystem */
+    uint64_t f_flags;   /* copy of mount exported flags */
+    uint64_t f_bsize;   /* filesystem fragment size */
+    uint64_t f_iosize;  /* optimal transfer block size */
+    uint64_t f_blocks;  /* total data blocks in filesystem */
+    uint64_t f_bfree;   /* free blocks in filesystem */
+    int64_t  f_bavail;  /* free blocks avail to non-superuser */
+    uint64_t f_files;   /* total file nodes in filesystem */
+    int64_t  f_ffree;   /* free nodes avail to non-superuser */
+    uint64_t f_syncwrites;  /* count of sync writes since mount */
+    uint64_t f_asyncwrites; /* count of async writes since mount */
+    uint64_t f_syncreads;   /* count of sync reads since mount */
+    uint64_t f_asyncreads;  /* count of async reads since mount */
+    uint64_t f_spare[10];   /* unused spare */
+    uint32_t f_namemax; /* maximum filename length */
+    uint32_t f_owner;   /* user that mounted the filesystem */
+    target_freebsd_fsid_t   f_fsid; /* filesystem id */
+    char     f_charspare[80];           /* spare string space */
+    char     f_fstypename[TARGET_MFSNAMELEN];   /* filesys type name */
+    char     f_mntfromname[TARGET_MNAMELEN];    /* mount filesystem */
+    char     f_mntonname[TARGET_MNAMELEN];      /* dir on which mounted*/
+};
+
+/* File identifier. These are unique per filesystem on a single machine. */
+#define TARGET_MAXFIDSZ     16
+
+struct target_freebsd_fid {
+    u_short     fid_len;            /* len of data in bytes */
+    u_short     fid_data0;          /* force longword align */
+    char        fid_data[TARGET_MAXFIDSZ];  /* data (variable len) */
+};
+
+/* Generic file handle */
+struct target_freebsd_fhandle {
+    target_freebsd_fsid_t   fh_fsid;    /* Filesystem id of mount point */
+    struct target_freebsd_fid fh_fid;   /* Filesys specific id */
+};
+typedef struct target_freebsd_fhandle target_freebsd_fhandle_t;
+
+/*
+ * sys/fcntl.h
+ */
+#define TARGET_F_DUPFD              0
+#define TARGET_F_GETFD              1
+#define TARGET_F_SETFD              2
+#define TARGET_F_GETFL              3
+#define TARGET_F_SETFL              4
+#define TARGET_F_GETOWN             5
+#define TARGET_F_SETOWN             6
+#define TARGET_F_OGETLK             7
+#define TARGET_F_OSETLK             8
+#define TARGET_F_OSETLKW            9
+#define TARGET_F_DUP2FD             10
+#define TARGET_F_GETLK              11
+#define TARGET_F_SETLK              12
+#define TARGET_F_SETLKW             13
+#define TARGET_F_SETLK_REMOTE       14
+#define TARGET_F_READAHEAD          15
+#define TARGET_F_RDAHEAD            16
+#define TARGET_F_DUPFD_CLOEXEC     17
+#define TARGET_F_DUP2FD_CLOEXEC    18
+
+struct target_freebsd_flock {
+    int64_t l_start;
+    int64_t l_len;
+    int32_t l_pid;
+    int16_t l_type;
+    int16_t l_whence;
+    int32_t l_sysid;
+} QEMU_PACKED;
+
+/*
+ * FreeBSD thread and user mutex support.
+ */
+
+/* sys/thr.h */
+#define TARGET_THR_SUSPENDED    0x0001
+#define TARGET_THR_SYSTEM_SCOPE 0x0002
+
+struct target_freebsd_thr_param {
+    abi_ulong   start_func; /* thread entry function. */
+    abi_ulong   arg;        /* argument for entry function. */
+    abi_ulong   stack_base; /* stack base address. */
+    abi_ulong   stack_size; /* stack size. */
+    abi_ulong   tls_base;   /* tls base address. */
+    abi_ulong   tls_size;   /* tls size. */
+    abi_ulong   child_tid;  /* address to store new TID. */
+    abi_ulong   parent_tid; /* parent access the new TID here. */
+    int32_t     flags;      /* thread flags. */
+    abi_ulong   rtp;        /* Real-time scheduling priority. */
+    abi_ulong   spare[3];   /* spares. */
+};
+
+/* sys/rtprio.h */
+struct target_freebsd_rtprio {
+    uint16_t    type;
+    uint16_t    prio;
+};
+
+typedef struct {
+    CPUArchState *env;
+    long parent_tid;
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    pthread_t thread;
+    sigset_t sigmask;
+    struct target_freebsd_thr_param param;
+} new_freebsd_thread_info_t;
+
+/* sys/utmx.h */
+/* op code for _umtx_op */
+#define TARGET_UMTX_OP_LOCK                 0
+#define TARGET_UMTX_OP_UNLOCK               1
+#define TARGET_UMTX_OP_WAIT                 2
+#define TARGET_UMTX_OP_WAKE                 3
+#define TARGET_UMTX_OP_MUTEX_TRYLOCK        4
+#define TARGET_UMTX_OP_MUTEX_LOCK           5
+#define TARGET_UMTX_OP_MUTEX_UNLOCK         6
+#define TARGET_UMTX_OP_SET_CEILING          7
+#define TARGET_UMTX_OP_CV_WAIT              8
+#define TARGET_UMTX_OP_CV_SIGNAL            9
+#define TARGET_UMTX_OP_CV_BROADCAST         10
+#define TARGET_UMTX_OP_WAIT_UINT            11
+#define TARGET_UMTX_OP_RW_RDLOCK            12
+#define TARGET_UMTX_OP_RW_WRLOCK            13
+#define TARGET_UMTX_OP_RW_UNLOCK            14
+#define TARGET_UMTX_OP_WAIT_UINT_PRIVATE    15
+#define TARGET_UMTX_OP_WAKE_PRIVATE         16
+#define TARGET_UMTX_OP_MUTEX_WAIT           17
+#define TARGET_UMTX_OP_MUTEX_WAKE           18
+#define TARGET_UMTX_OP_SEM_WAIT             19
+#define TARGET_UMTX_OP_SEM_WAKE             20
+#define TARGET_UMTX_OP_NWAKE_PRIVATE        21
+#define TARGET_UMTX_OP_MUTEX_WAKE2          22
+#define TARGET_UMTX_OP_MAX                  23
+
+/* flags for UMTX_OP_CV_WAIT */
+#define TARGET_CVWAIT_CHECK_UNPARKING       0x01
+#define TARGET_CVWAIT_ABSTIME               0x02
+#define TARGET_CVWAIT_CLOCKID               0x04
+
+#define TARGET_UMTX_UNOWNED                 0x0
+#define TARGET_UMUTEX_UNOWNED               0x0
+#define TARGET_UMTX_CONTESTED               (abi_long)(0x8000000000000000)
+#define TARGET_UMUTEX_CONTESTED             0x80000000U
+
+/* flags for umutex */
+#define TARGET_UMUTEX_ERROR_CHECK   0x0002  /* Error-checking mutex */
+#define TARGET_UMUTEX_PRIO_INHERIT  0x0004  /* Priority inherited mutex */
+#define TARGET_UMUTEX_PRIO_PROTECT  0x0008  /* Priority protect mutex */
+
+#define TARGET_UMUTEX_TRY           1
+#define TARGET_UMUTEX_WAIT          2
+
+/* urwlock flags */
+#define TARGET_URWLOCK_PREFER_READER    0x0002
+#define TARGET_URWLOCK_WRITE_OWNER      0x80000000U
+#define TARGET_URWLOCK_WRITE_WAITERS    0x40000000U
+#define TARGET_URWLOCK_READ_WAITERS     0x20000000U
+#define TARGET_URWLOCK_MAX_READERS      0x1fffffffU
+#define TARGET_URWLOCK_READER_COUNT(c)  ((c) & TARGET_URWLOCK_MAX_READERS)
+
+/*
+ * sys/acl.h
+ */
+#define TARGET_FREEBSD_ACL_MAX_ENTRIES          254
+
+/* vaild acl_type_t arguments */
+#define TARGET_FREEBSD_ACL_TYPE_ACCESS_OLD      0x00000000
+#define TARGET_FREEBSD_ACL_TYPE_DEFAULT_OLD     0x00000001
+#define TARGET_FREEBSD_ACL_TYPE_ACCESS          0x00000002
+#define TARGET_FREEBSD_ACL_TYPE_DEFAULT         0x00000003
+#define TARGET_FREEBSD_ACL_TYPE_NFS4            0x00000004
+
+struct target_freebsd_acl_entry {
+    int32_t     ae_tag;
+    uint32_t    ae_id;
+    uint16_t    ae_perm;
+    uint16_t    ae_entry_type;
+    uint16_t    ae_flags;
+};
+
+struct target_freebsd_acl {
+    uint32_t            acl_maxcnt;
+    uint32_t            acl_cnt;
+    int32_t             acl_space[4];
+    struct target_freebsd_acl_entry  acl_entry[TARGET_FREEBSD_ACL_MAX_ENTRIES];
+};
+
+/*
+ *  sys/uuid.h
+ */
+
+#define TARGET_UUID_NODE_LEN    6
+
+struct target_uuid {
+    uint32_t    time_low;
+    uint16_t    time_mid;
+    uint16_t    time_hi_and_version;
+    uint8_t     clock_seq_hi_and_reserved;
+    uint8_t     clock_seq_low;
+    uint8_t     node[TARGET_UUID_NODE_LEN];
+};
+
+#endif /* ! _SYSCALL_DEFS_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 07/18] bsd-user: add support for freebsd signal related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (5 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 06/18] bsd-user: add support for freebsd time related system calls Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 08/18] bsd-user: move target arch and host OS dependent code out of elfload.c Stacey Son
                   ` (32 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for signal related system calls including
sigtimedwait(2), sigaction(2), sigprocmask(2), sigpending(2), sigsuspend(2),
sigreturn(2), sigwait(2), sigwaitinfo(2), sigqueue(2), sigaltstack(2),
kill(2), killpg(2), and pdkill(2).

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/arm/target_arch_signal.h     |  257 ++++++++++
 bsd-user/bsd-signal.h                 |  232 +++++++++
 bsd-user/errno_defs.h                 |   13 +-
 bsd-user/freebsd/os-signal.h          |   43 ++
 bsd-user/freebsd/target_os_siginfo.h  |  100 ++++
 bsd-user/freebsd/target_os_signal.h   |   79 +++
 bsd-user/i386/target_arch_signal.h    |   94 ++++
 bsd-user/mips/target_arch_signal.h    |  237 +++++++++
 bsd-user/mips64/target_arch_signal.h  |  236 +++++++++
 bsd-user/netbsd/target_os_siginfo.h   |   82 +++
 bsd-user/netbsd/target_os_signal.h    |   70 +++
 bsd-user/openbsd/target_os_siginfo.h  |   82 +++
 bsd-user/openbsd/target_os_signal.h   |   70 +++
 bsd-user/qemu.h                       |   33 +-
 bsd-user/signal.c                     |  907 ++++++++++++++++++++++++++++++++-
 bsd-user/sparc/target_arch_signal.h   |   77 +++
 bsd-user/sparc64/target_arch_signal.h |   94 ++++
 bsd-user/syscall.c                    |   59 +++
 bsd-user/x86_64/target_arch_signal.h  |   94 ++++
 19 files changed, 2842 insertions(+), 17 deletions(-)
 create mode 100644 bsd-user/arm/target_arch_signal.h
 create mode 100644 bsd-user/bsd-signal.h
 create mode 100644 bsd-user/freebsd/os-signal.h
 create mode 100644 bsd-user/freebsd/target_os_siginfo.h
 create mode 100644 bsd-user/freebsd/target_os_signal.h
 create mode 100644 bsd-user/i386/target_arch_signal.h
 create mode 100644 bsd-user/mips/target_arch_signal.h
 create mode 100644 bsd-user/mips64/target_arch_signal.h
 create mode 100644 bsd-user/netbsd/target_os_siginfo.h
 create mode 100644 bsd-user/netbsd/target_os_signal.h
 create mode 100644 bsd-user/openbsd/target_os_siginfo.h
 create mode 100644 bsd-user/openbsd/target_os_signal.h
 create mode 100644 bsd-user/sparc/target_arch_signal.h
 create mode 100644 bsd-user/sparc64/target_arch_signal.h
 create mode 100644 bsd-user/x86_64/target_arch_signal.h

diff --git a/bsd-user/arm/target_arch_signal.h b/bsd-user/arm/target_arch_signal.h
new file mode 100644
index 0000000..048bd4f
--- /dev/null
+++ b/bsd-user/arm/target_arch_signal.h
@@ -0,0 +1,257 @@
+/*
+ *  arm signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+#define TARGET_REG_R0   0
+#define TARGET_REG_R1   1
+#define TARGET_REG_R2   2
+#define TARGET_REG_R3   3
+#define TARGET_REG_R4   4
+#define TARGET_REG_R5   5
+#define TARGET_REG_R6   6
+#define TARGET_REG_R7   7
+#define TARGET_REG_R8   8
+#define TARGET_REG_R9   9
+#define TARGET_REG_R10  10
+#define TARGET_REG_R11  11
+#define TARGET_REG_R12  12
+#define TARGET_REG_R13  13
+#define TARGET_REG_R14  14
+#define TARGET_REG_R15  15
+#define TARGET_REG_CPSR 16
+#define TARGET__NGREG   17
+/* Convenience synonyms */
+#define TARGET_REG_FP   TARGET_REG_R11
+#define TARGET_REG_SP   TARGET_REG_R13
+#define TARGET_REG_LR   TARGET_REG_R14
+#define TARGET_REG_PC   TARGET_REG_R15
+
+#define TARGET_INSN_SIZE    4       /* arm instruction size */
+
+/* Size of the signal trampolin code. See _sigtramp(). */
+#define TARGET_SZSIGCODE    ((abi_ulong)(8 * TARGET_INSN_SIZE))
+
+/* compare to arm/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (1024 * 4)                  /* min sig stack size */
+#define TARGET_SIGSTKSZ     (TARGET_MINSIGSTKSZ + 32768)  /* recommended size */
+
+/* arm/arm/machdep.c */
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC     0x0002
+#define TARGET_MC_SET_ONSTACK   0x0004
+
+struct target_sigcontext {
+    target_sigset_t sc_mask;    /* signal mask to retstore */
+    int32_t     sc_onstack;     /* sigstack state to restore */
+    abi_long    sc_pc;          /* pc at time of signal */
+    abi_long    sc_reg[32];     /* processor regs 0 to 31 */
+    abi_long    mullo, mulhi;   /* mullo and mulhi registers */
+    int32_t     sc_fpused;      /* fp has been used */
+    abi_long    sc_fpregs[33];  /* fp regs 0 to 31 & csr */
+    abi_long    sc_fpc_eir;     /* fp exception instr reg */
+    /* int32_t reserved[8]; */
+};
+
+typedef struct {
+    uint32_t    __fp_fpsr;
+    struct {
+        uint32_t    __fp_exponent;
+        uint32_t    __fp_mantissa_hi;
+        uint32_t    __fp_mantissa_lo;
+    }       __fp_fr[8];
+} target__fpregset_t;
+
+typedef struct {
+    uint32_t    __vfp_fpscr;
+    uint32_t    __vfp_fstmx[33];
+    uint32_t    __vfp_fpsid;
+} target__vfpregset_t;
+
+typedef struct target_mcontext {
+    uint32_t        __gregs[TARGET__NGREG];
+    union {
+        target__fpregset_t  __fpregs;
+        target__vfpregset_t __vfpregs;
+    } __fpu;
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t     uc_sigmask;
+    target_mcontext_t   uc_mcontext;
+    abi_ulong           uc_link;
+    target_stack_t      uc_stack;
+    int32_t             uc_flags;
+    int32_t             __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    target_siginfo_t    sf_si;  /* saved siginfo */
+    target_ucontext_t   sf_uc;  /* saved ucontext */
+};
+
+
+/* compare to sys/arm/include/frame.h */
+struct target_trapframe {
+    abi_ulong tf_spsr; /* Zero on arm26 */
+    abi_ulong tf_r0;
+    abi_ulong tf_r1;
+    abi_ulong tf_r2;
+    abi_ulong tf_r3;
+    abi_ulong tf_r4;
+    abi_ulong tf_r5;
+    abi_ulong tf_r6;
+    abi_ulong tf_r7;
+    abi_ulong tf_r8;
+    abi_ulong tf_r9;
+    abi_ulong tf_r10;
+    abi_ulong tf_r11;
+    abi_ulong tf_r12;
+    abi_ulong tf_usr_sp;
+    abi_ulong tf_usr_lr;
+    abi_ulong tf_svc_sp; /* Not used on arm26 */
+    abi_ulong tf_svc_lr; /* Not used on arm26 */
+    abi_ulong tf_pc;
+};
+
+/*
+ * Compare to arm/arm/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUARMState *regs, int sig, struct target_sigframe *frame,
+    abi_ulong frame_addr, struct target_sigaction *ka)
+{
+    /*
+     * Arguments to signal handler:
+     *  r0 = signal number
+     *  r1 = siginfo pointer
+     *  r2 = ucontext pointer
+     *  r5 = ucontext pointer
+     *  pc = signal handler pointer
+     *  sp = sigframe struct pointer
+     *  lr = sigtramp at base of user stack
+     */
+
+    regs->regs[0] = sig;
+    regs->regs[1] = frame_addr +
+        offsetof(struct target_sigframe, sf_si);
+    regs->regs[2] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+
+    /* the trampoline uses r5 as the uc address */
+    regs->regs[5] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+    regs->regs[TARGET_REG_PC] = ka->_sa_handler;
+    regs->regs[TARGET_REG_SP] = frame_addr;
+    regs->regs[TARGET_REG_LR] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+
+    return 0;
+}
+
+/*
+ * Compare to arm/arm/machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long get_mcontext(CPUARMState *regs, target_mcontext_t *mcp,
+        int flags)
+{
+    int err = 0;
+    uint32_t *gr = mcp->__gregs;
+
+
+    if (flags & TARGET_MC_GET_CLEAR_RET) {
+        gr[TARGET_REG_R0] = 0;
+    } else {
+        gr[TARGET_REG_R0] = tswap32(regs->regs[0]);
+    }
+
+    gr[TARGET_REG_R1] = tswap32(regs->regs[1]);
+    gr[TARGET_REG_R2] = tswap32(regs->regs[2]);
+    gr[TARGET_REG_R3] = tswap32(regs->regs[3]);
+    gr[TARGET_REG_R4] = tswap32(regs->regs[4]);
+    gr[TARGET_REG_R5] = tswap32(regs->regs[5]);
+    gr[TARGET_REG_R6] = tswap32(regs->regs[6]);
+    gr[TARGET_REG_R7] = tswap32(regs->regs[7]);
+    gr[TARGET_REG_R8] = tswap32(regs->regs[8]);
+    gr[TARGET_REG_R9] = tswap32(regs->regs[9]);
+    gr[TARGET_REG_R10] = tswap32(regs->regs[10]);
+    gr[TARGET_REG_R11] = tswap32(regs->regs[11]);
+    gr[TARGET_REG_R12] = tswap32(regs->regs[12]);
+
+    gr[TARGET_REG_SP] = tswap32(regs->regs[13]);
+    gr[TARGET_REG_LR] = tswap32(regs->regs[14]);
+    gr[TARGET_REG_PC] = tswap32(regs->regs[15]);
+    gr[TARGET_REG_CPSR] = tswap32(cpsr_read(regs));
+
+    return err;
+}
+
+/* Compare to arm/arm/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUARMState *regs, target_mcontext_t *mcp,
+        int srflag)
+{
+    int err = 0;
+    const uint32_t *gr = mcp->__gregs;
+    uint32_t cpsr;
+
+    regs->regs[0] = tswap32(gr[TARGET_REG_R0]);
+    regs->regs[1] = tswap32(gr[TARGET_REG_R1]);
+    regs->regs[2] = tswap32(gr[TARGET_REG_R2]);
+    regs->regs[3] = tswap32(gr[TARGET_REG_R3]);
+    regs->regs[4] = tswap32(gr[TARGET_REG_R4]);
+    regs->regs[5] = tswap32(gr[TARGET_REG_R5]);
+    regs->regs[6] = tswap32(gr[TARGET_REG_R6]);
+    regs->regs[7] = tswap32(gr[TARGET_REG_R7]);
+    regs->regs[8] = tswap32(gr[TARGET_REG_R8]);
+    regs->regs[9] = tswap32(gr[TARGET_REG_R9]);
+    regs->regs[10] = tswap32(gr[TARGET_REG_R10]);
+    regs->regs[11] = tswap32(gr[TARGET_REG_R11]);
+    regs->regs[12] = tswap32(gr[TARGET_REG_R12]);
+
+    regs->regs[13] = tswap32(gr[TARGET_REG_SP]);
+    regs->regs[14] = tswap32(gr[TARGET_REG_LR]);
+    regs->regs[15] = tswap32(gr[TARGET_REG_PC]);
+    cpsr = tswap32(gr[TARGET_REG_CPSR]);
+    cpsr_write(regs, cpsr, CPSR_USER | CPSR_EXEC);
+
+    return err;
+}
+
+/* Compare to arm/arm/machdep.c sys_sigreturn() */
+static inline abi_long get_ucontext_sigreturn(CPUARMState *regs,
+        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    uint32_t cpsr = cpsr_read(regs);
+
+    *target_uc = 0;
+
+    if ((cpsr & CPSR_M) != ARM_CPU_MODE_USR ||
+            (cpsr & (CPSR_I | CPSR_F)) != 0) {
+        return -TARGET_EINVAL;
+    }
+
+    *target_uc = target_sf + offsetof(struct target_sigframe, sf_uc);
+
+    return 0;
+}
+
+
+#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/bsd-signal.h b/bsd-user/bsd-signal.h
new file mode 100644
index 0000000..48a8b56
--- /dev/null
+++ b/bsd-user/bsd-signal.h
@@ -0,0 +1,232 @@
+/*
+ *  signal related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_SIGNAL_H_
+#define __BSD_SIGNAL_H_
+
+/* sigaction(2) */
+static inline abi_long do_bsd_sigaction(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    struct target_sigaction *old_act, act, oact, *pact;
+
+    if (arg2) {
+        if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) {
+            return -TARGET_EFAULT;
+        }
+        act._sa_handler = old_act->_sa_handler;
+        act.sa_flags = old_act->sa_flags;
+        memcpy(&act.sa_mask, &old_act->sa_mask, sizeof(target_sigset_t));
+        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)) {
+            return -TARGET_EFAULT;
+        }
+        old_act->_sa_handler = oact._sa_handler;
+        old_act->sa_flags = oact.sa_flags;
+        memcpy(&old_act->sa_mask, &oact.sa_mask, sizeof(target_sigset_t));
+        unlock_user_struct(old_act, arg3, 1);
+    }
+    return ret;
+}
+
+
+/* sigprocmask(2) */
+static inline abi_long do_bsd_sigprocmask(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set, oldset, *set_ptr;
+    int how;
+
+    if (arg2) {
+        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:
+            return -TARGET_EFAULT;
+        }
+        p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        target_to_host_sigset(&set, p);
+        unlock_user(p, arg2, 0);
+        set_ptr = &set;
+    } else {
+        how = 0;
+        set_ptr = NULL;
+    }
+    ret = get_errno(sigprocmask(how, set_ptr, &oldset));
+    if (!is_error(ret) && arg3) {
+        p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_sigset(p, &oldset);
+        unlock_user(p, arg3, sizeof(target_sigset_t));
+    }
+    return ret;
+}
+
+/* sigpending(2) */
+static inline abi_long do_bsd_sigpending(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+
+    ret = get_errno(sigpending(&set));
+    if (!is_error(ret)) {
+        p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_sigset(p, &set);
+        unlock_user(p, arg1, sizeof(target_sigset_t));
+    }
+    return ret;
+}
+
+/* sigsuspend(2) */
+static inline abi_long do_bsd_sigsuspend(abi_long arg1, abi_long arg2)
+{
+    void *p;
+    sigset_t set;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+
+    return get_errno(sigsuspend(&set));
+}
+
+/* sigreturn(2) */
+static inline abi_long do_bsd_sigreturn(void *cpu_env, abi_long arg1)
+{
+
+    return do_sigreturn(cpu_env, arg1);
+}
+
+/* sigvec(2) - not defined */
+/* sigblock(2) - not defined */
+/* sigsetmask(2) - not defined */
+/* sigstack(2) - not defined */
+
+/* sigwait(2) */
+static inline abi_long do_bsd_sigwait(abi_ulong arg1, abi_ulong arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    int sig;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    ret = get_errno(sigwait(&set, &sig));
+    if (!is_error(ret) && arg2) {
+        ret = put_user_s32(sig, arg2);
+    }
+    return ret;
+}
+
+/* sigwaitinfo(2) */
+static inline abi_long do_bsd_sigwaitinfo(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    siginfo_t uinfo;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    ret = get_errno(sigwaitinfo(&set, &uinfo));
+    if (!is_error(ret) && arg2) {
+        p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_siginfo(p, &uinfo);
+        unlock_user(p, arg2, sizeof(target_siginfo_t));
+    }
+    return ret;
+}
+
+/* sigqueue(2) */
+static inline abi_long do_bsd_sigqueue(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    union sigval value;
+
+    value.sival_ptr = (void *)(uintptr_t)arg3;
+    return get_errno(sigqueue(arg1, target_to_host_signal(arg2), value));
+}
+
+/* sigaltstck(2) */
+static inline abi_long do_bsd_sigaltstack(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    return do_sigaltstack(arg1, arg2, get_sp_from_cpustate(cpu_env));
+}
+
+/* kill(2) */
+static inline abi_long do_bsd_kill(abi_long pid, abi_long sig)
+{
+
+    return get_errno(kill(pid, target_to_host_signal(sig)));
+}
+
+/* killpg(2) */
+static inline abi_long do_bsd_killpg(abi_long pg, abi_long sig)
+{
+
+    return get_errno(killpg(pg, target_to_host_signal(sig)));
+}
+
+#endif /* !  __BSD_SIGNAL_H_ */
diff --git a/bsd-user/errno_defs.h b/bsd-user/errno_defs.h
index 1efa502..f01181d 100644
--- a/bsd-user/errno_defs.h
+++ b/bsd-user/errno_defs.h
@@ -1,6 +1,3 @@
-/*      $OpenBSD: errno.h,v 1.20 2007/09/03 14:37:52 millert Exp $      */
-/*      $NetBSD: errno.h,v 1.10 1996/01/20 01:33:53 jtc Exp $   */
-
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
  *      The Regents of the University of California.  All rights reserved.
@@ -37,6 +34,9 @@
  *      @(#)errno.h     8.5 (Berkeley) 1/21/94
  */
 
+#ifndef _ERRNO_DEFS_H_
+#define _ERRNO_DEFS_H_
+
 #define TARGET_EPERM            1               /* Operation not permitted */
 #define TARGET_ENOENT           2               /* No such file or directory */
 #define TARGET_ESRCH            3               /* No such process */
@@ -147,3 +147,10 @@
 #define TARGET_EIDRM            89              /* Identifier removed */
 #define TARGET_ENOMSG           90              /* No message of desired type */
 #define TARGET_ELAST            90              /* Must be equal largest errno */
+
+/* Internal errors: */
+#define TARGET_EJUSTRETURN      254             /* Just return without
+                                                   modifing regs */
+#define TARGET_ERESTART         255             /* Restart syscall */
+
+#endif /* !  _ERRNO_DEFS_H_ */
diff --git a/bsd-user/freebsd/os-signal.h b/bsd-user/freebsd/os-signal.h
new file mode 100644
index 0000000..d4a26da
--- /dev/null
+++ b/bsd-user/freebsd/os-signal.h
@@ -0,0 +1,43 @@
+/*
+ *  FreeBSD signal system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_OS_SIGNAL_H_
+#define __FREEBSD_OS_SIGNAL_H_
+
+#include <sys/procdesc.h>
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+/* pdkill(2) */
+static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(pdkill(arg1, arg2));
+}
+
+#else
+
+static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdkill()\n");
+    return -TARGET_ENOSYS;
+}
+#endif /* ! __FreeBSD_version > 900000 */
+
+#endif /* ! __FREEBSD_OS_SIGNAL_H_ */
diff --git a/bsd-user/freebsd/target_os_siginfo.h b/bsd-user/freebsd/target_os_siginfo.h
new file mode 100644
index 0000000..597b443
--- /dev/null
+++ b/bsd-user/freebsd/target_os_siginfo.h
@@ -0,0 +1,100 @@
+/*
+ *  FreeBSD siginfo related definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_OS_SIGINFO_H_
+#define _TARGET_OS_SIGINFO_H_
+
+#define TARGET_NSIG         128
+#define TARGET_NSIG_BPW     (sizeof(uint32_t) * 8)
+#define TARGET_NSIG_WORDS   (TARGET_NSIG / TARGET_NSIG_BPW)
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+    abi_long    ss_sp;
+    abi_ulong   ss_size;
+    abi_long    ss_flags;
+} target_stack_t;
+
+typedef struct {
+    uint32_t __bits[TARGET_NSIG_WORDS];
+} target_sigset_t;
+
+struct target_sigaction {
+    abi_ulong   _sa_handler;
+    int32_t     sa_flags;
+    target_sigset_t sa_mask;
+};
+
+union target_sigval {
+    int32_t sival_int;
+    abi_ulong sival_ptr;
+    int32_t sigval_int;
+    abi_ulong sigval_ptr;
+};
+
+typedef struct target_siginfo {
+    int32_t si_signo;   /* signal number */
+    int32_t si_errno;   /* errno association */
+    int32_t si_code;    /* signal code */
+    int32_t si_pid;     /* sending process */
+    int32_t si_uid;     /* sender's ruid */
+    int32_t si_status;  /* exit value */
+    abi_ulong si_addr;  /* faulting instruction */
+    union target_sigval si_value;   /* signal value */
+    union {
+        struct {
+            int32_t _trapno;    /* machine specific trap code */
+        } _fault;
+
+        /* POSIX.1b timers */
+        struct {
+            int32_t _timerid;
+            int32_t _overrun;
+        } _timer;
+
+        struct {
+            int32_t _mqd;
+        } _mesgp;
+
+        /* SIGPOLL */
+        struct {
+            int _band;  /* POLL_IN, POLL_OUT, POLL_MSG */
+        } _poll;
+
+        struct {
+            abi_long __spare1__;
+            int32_t  __spare2_[7];
+        } __spare__;
+    } _reason;
+} target_siginfo_t;
+
+#define target_si_signo     si_signo
+#define target_si_code      si_code
+#define target_si_errno     si_errno
+#define target_si_addr      si_addr
+
+/* SIGSEGV si_codes */
+#define TARGET_SEGV_MAPERR  (1) /* address not mapped to object */
+#define TARGET_SEGV_ACCERR  (2) /* invalid permissions for mapped
+                                           object */
+
+/* SIGTRAP si_codes */
+#define TARGET_TRAP_BRKPT   (1) /* process beakpoint */
+#define TARGET_TRAP_TRACE   (2) /* process trace trap */
+
+#endif /* !_TARGET_OS_SIGINFO_H_ */
diff --git a/bsd-user/freebsd/target_os_signal.h b/bsd-user/freebsd/target_os_signal.h
new file mode 100644
index 0000000..d7004c8
--- /dev/null
+++ b/bsd-user/freebsd/target_os_signal.h
@@ -0,0 +1,79 @@
+#ifndef _TARGET_OS_SIGNAL_H_
+#define _TARGET_OS_SIGNAL_H_
+
+#include "target_os_siginfo.h"
+#include "target_arch_signal.h"
+
+/* Compare to sys/signal.h */
+#define TARGET_SIGHUP  1       /* hangup */
+#define TARGET_SIGINT  2       /* interrupt */
+#define TARGET_SIGQUIT 3       /* quit */
+#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
+#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
+#define TARGET_SIGABRT 6       /* abort() */
+#define TARGET_SIGIOT  SIGABRT /* compatibility */
+#define TARGET_SIGEMT  7       /* EMT instruction */
+#define TARGET_SIGFPE  8       /* floating point exception */
+#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
+#define TARGET_SIGBUS  10      /* bus error */
+#define TARGET_SIGSEGV 11      /* segmentation violation */
+#define TARGET_SIGSYS  12      /* bad argument to system call */
+#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
+#define TARGET_SIGALRM 14      /* alarm clock */
+#define TARGET_SIGTERM 15      /* software termination signal from kill */
+#define TARGET_SIGURG  16      /* urgent condition on IO channel */
+#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
+#define TARGET_SIGTSTP 18      /* stop signal from tty */
+#define TARGET_SIGCONT 19      /* continue a stopped process */
+#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
+#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
+#define TARGET_SIGTTOU 22      /* like TTIN for output if(tp->t_local&LTOSTOP)*/
+#define TARGET_SIGIO   23      /* input/output possible signal */
+#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
+#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
+#define TARGET_SIGVTALRM 26    /* virtual time alarm */
+#define TARGET_SIGPROF 27      /* profiling time alarm */
+#define TARGET_SIGWINCH 28     /* window size changes */
+#define TARGET_SIGINFO  29     /* information request */
+#define TARGET_SIGUSR1 30      /* user defined signal 1 */
+#define TARGET_SIGUSR2 31      /* user defined signal 2 */
+#define TARGET_SIGTHR 32       /* reserved by thread library */
+#define TARGET_SIGLWP SIGTHR   /* compatibility */
+#define TARGET_SIGLIBRT 33     /* reserved by the real-time library */
+#define TARGET_SIGRTMIN 65
+#define TARGET_SIGRTMAX 126
+#define TARGET_QEMU_ESIGRETURN  255 /* fake errno value for use by sigreturn */
+
+/*
+ * Language spec says we must list exactly one parameter, even though we
+ * actually supply three.  Ugh!
+ */
+#define TARGET_SIG_DFL      ((abi_long)0)   /* default signal handling */
+#define TARGET_SIG_IGN      ((abi_long)1)   /* ignore signal */
+#define TARGET_SIG_ERR      ((abi_long)-1)  /* error return from signal */
+
+#define TARGET_SA_ONSTACK   0x0001  /* take signal on signal stack */
+#define TARGET_SA_RESTART   0x0002  /* restart system on signal return */
+#define TARGET_SA_RESETHAND 0x0004  /* reset to SIG_DFL when taking signal */
+#define TARGET_SA_NODEFER   0x0010  /* don't mask the signal we're delivering */
+#define TARGET_SA_NOCLDWAIT 0x0020  /* don't create zombies (assign to pid 1) */
+#define TARGET_SA_USERTRAMP 0x0100  /* do not bounce off kernel's sigtramp */
+#define TARGET_SA_NOCLDSTOP 0x0008  /* do not generate SIGCHLD on child stop */
+#define TARGET_SA_SIGINFO   0x0040  /* generate siginfo_t */
+
+/*
+ * Flags for sigprocmask:
+ */
+#define TARGET_SIG_BLOCK        1   /* block specified signal set */
+#define TARGET_SIG_UNBLOCK      2   /* unblock specified signal set */
+#define TARGET_SIG_SETMASK      3   /* set specified signal set */
+
+#define TARGET_BADSIG           SIG_ERR
+
+/*
+ * sigaltstack control
+ */
+#define TARGET_SS_ONSTACK 0x0001  /* take signals on alternate stack */
+#define TARGET_SS_DISABLE 0x0004  /* disable taking signals on alternate stack*/
+
+#endif /* !_TARGET_OS_SIGNAL_H_ */
diff --git a/bsd-user/i386/target_arch_signal.h b/bsd-user/i386/target_arch_signal.h
new file mode 100644
index 0000000..e2387b2
--- /dev/null
+++ b/bsd-user/i386/target_arch_signal.h
@@ -0,0 +1,94 @@
+/*
+ *  i386 dependent signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef TARGET_ARCH_SIGNAL_H
+#define TARGET_ARCH_SIGNAL_H
+
+#include "cpu.h"
+
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE    (0) */      /* XXX to be added. */
+
+/* compare to  x86/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (512 * 4)               /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to i386/i386/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long set_sigtramp_args(CPUX86State *regs,
+        int sig, struct target_sigframe *frame, abi_ulong frame_addr,
+        struct target_sigaction *ka)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to i386/i386/machdep.c get_mcontext() */
+static inline abi_long get_mcontext(CPUX86State *regs,
+        target_mcontext_t *mcp, int flags)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to i386/i386/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUX86State *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUX86State *regs,
+                        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    /* XXX */
+    *target_uc = 0;
+    return -TARGET_EOPNOTSUPP;
+}
+
+#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/mips/target_arch_signal.h b/bsd-user/mips/target_arch_signal.h
new file mode 100644
index 0000000..79d6f65
--- /dev/null
+++ b/bsd-user/mips/target_arch_signal.h
@@ -0,0 +1,237 @@
+/*
+ *  mips signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+#define TARGET_INSN_SIZE    4       /* mips instruction size */
+
+/* Size of the signal trampolin code. See insall_sigtramp(). */
+#define TARGET_SZSIGCODE    ((abi_ulong)(4 * TARGET_INSN_SIZE))
+
+/* compare to mips/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (512 * 4)                   /* min sig stack size */
+#define TARGET_SIGSTKSZ     (TARGET_MINSIGSTKSZ + 32768)  /* recommended size */
+
+/* compare to sys/mips/include/asm.h */
+#define TARGET_SZREG        8
+#define TARGET_CALLFRAME_SIZ    (TARGET_SZREG * 4)
+
+/* mips/mips/pm_machdep.c */
+#define TARGET_UCONTEXT_MAGIC   0xACEDBADE
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC     0x0002
+#define TARGET_MC_SET_ONSTACK   0x0004
+
+struct target_sigcontext {
+    target_sigset_t sc_mask;    /* signal mask to retstore */
+    int32_t     sc_onstack;     /* sigstack state to restore */
+    abi_long    sc_pc;          /* pc at time of signal */
+    abi_long    sc_reg[32];     /* processor regs 0 to 31 */
+    abi_long    mullo, mulhi;   /* mullo and mulhi registers */
+    int32_t     sc_fpused;      /* fp has been used */
+    abi_long    sc_fpregs[33];  /* fp regs 0 to 31 & csr */
+    abi_long    sc_fpc_eir;     /* fp exception instr reg */
+    /* int32_t reserved[8]; */
+};
+
+typedef struct target_mcontext {
+    int32_t     mc_onstack;     /* sigstack state to restore */
+    abi_long    mc_pc;          /* pc at time of signal */
+    abi_long    mc_regs[32];    /* process regs 0 to 31 */
+    abi_long    sr;             /* status register */
+    abi_long    mullo, mulhi;
+    int32_t     mc_fpused;      /* fp has been used */
+    abi_long    mc_fpregs[33];  /* fp regs 0 to 32 & csr */
+    abi_long    mc_fpc_eir;     /* fp exception instr reg */
+    abi_ulong   mc_tls;         /* pointer to TLS area */
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to mips/mips/pm_machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
+    abi_ulong frame_addr, struct target_sigaction *ka)
+{
+
+    /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */
+
+    /* MIPS only struct target_sigframe members: */
+    frame->sf_signum = sig;
+    frame->sf_siginfo = frame_addr + offsetof(struct target_sigframe, sf_si);
+    frame->sf_ucontext = frame_addr + offsetof(struct target_sigframe, sf_uc);
+
+    /*
+     * Arguments to signal handler:
+     *  a0 ($4) = signal number
+     *  a1 ($5) = siginfo pointer
+     *  a2 ($6) = ucontext pointer
+     *  PC = signal handler pointer
+     *  t9 ($25) = signal handler pointer
+     *  $29 = point to sigframe struct
+     *  ra ($31) = sigtramp at base of user stack
+     */
+    regs->active_tc.gpr[4] = sig;
+    regs->active_tc.gpr[5] = frame_addr +
+        offsetof(struct target_sigframe, sf_si);
+    regs->active_tc.gpr[6] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+    regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler;
+    regs->active_tc.gpr[29] = frame_addr;
+    regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+
+    return 0;
+}
+
+/*
+ * Compare to mips/mips/pm_machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
+        int flags)
+{
+    int i, err = 0;
+
+    if (flags & TARGET_MC_ADD_MAGIC) {
+        mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC);
+    } else {
+        mcp->mc_regs[0] = 0;
+    }
+
+    if (flags & TARGET_MC_SET_ONSTACK) {
+        mcp->mc_onstack = tswapal(1);
+    } else {
+        mcp->mc_onstack = 0;
+    }
+
+    for (i = 1; i < 32; i++) {
+        mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]);
+    }
+
+#if 0 /* XXX FP is not used right now */
+    abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0;
+
+    mcp->mc_fpused = used_fp;
+    if (used_fp) {
+        preempt_disable();
+        if (!is_fpu_owner()) {
+            own_fpu();
+            for (i = 0; i < 33; i++) {
+                mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]);
+            }
+        }
+        preempt_enable();
+    }
+#else
+    mcp->mc_fpused = 0;
+#endif
+
+    if (flags & TARGET_MC_GET_CLEAR_RET) {
+        mcp->mc_regs[2] = 0;    /* v0 = 0 */
+        mcp->mc_regs[3] = 0;    /* v1 = 0 */
+        mcp->mc_regs[7] = 0;    /* a3 = 0 */
+    }
+
+    mcp->mc_pc = tswapal(regs->active_tc.PC);
+    mcp->mullo = tswapal(regs->active_tc.LO[0]);
+    mcp->mulhi = tswapal(regs->active_tc.HI[0]);
+    mcp->mc_tls = tswapal(regs->tls_value);
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+/* Compare to mips/mips/pm_machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
+        int srflag)
+{
+    int i, err = 0;
+
+    for (i = 1; i < 32; i++) {
+        regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]);
+    }
+
+#if 0  /* XXX FP is not used right now */
+    abi_ulong used_fp = 0;
+
+    used_fp = tswapal(mcp->mc_fpused)
+    conditional_used_math(used_fp);
+
+    preempt_disabled();
+    if (used_math()) {
+        /* restore fpu context if we have used it before */
+        own_fpu();
+        for (i = 0; i < 32; i++) {
+            regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]);
+        }
+    } else {
+        /* Signal handler may have used FPU.  Give it up. */
+        lose_fpu();
+    }
+    preempt_enable();
+#endif
+
+    regs->CP0_EPC = tswapal(mcp->mc_pc);
+    regs->active_tc.LO[0] = tswapal(mcp->mullo);
+    regs->active_tc.HI[0] = tswapal(mcp->mulhi);
+    regs->tls_value = tswapal(mcp->mc_tls);
+
+    if (srflag) {
+        /* doing sigreturn() */
+        regs->active_tc.PC = regs->CP0_EPC;
+        regs->CP0_EPC = 0;  /* XXX  for nested signals ? */
+    }
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUMIPSState *regs,
+                abi_ulong target_sf, abi_ulong *target_uc)
+{
+
+    *target_uc = target_sf;
+    return 0;
+}
+
+
+#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/mips64/target_arch_signal.h b/bsd-user/mips64/target_arch_signal.h
new file mode 100644
index 0000000..07d281e
--- /dev/null
+++ b/bsd-user/mips64/target_arch_signal.h
@@ -0,0 +1,236 @@
+/*
+ *  mips64 signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+#define TARGET_INSN_SIZE     4  /* mips64 instruction size */
+
+/* Size of the signal trampolin code placed on the stack. */
+#define TARGET_SZSIGCODE    ((abi_ulong)(4 * TARGET_INSN_SIZE))
+
+#define TARGET_MINSIGSTKSZ  (512 * 4)
+#define TARGET_SIGSTKSZ     (TARGET_MINSIGSTKSZ + 32768)
+
+/* compare to sys/mips/include/asm.h */
+#define TARGET_SZREG        8
+#define TARGET_CALLFRAME_SIZ    (TARGET_SZREG * 4)
+
+/* mips/mips/pm_machdep.c */
+#define TARGET_UCONTEXT_MAGIC   0xACEDBADE
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC     0x0002
+#define TARGET_MC_SET_ONSTACK   0x0004
+
+struct target_sigcontext {
+    target_sigset_t sc_mask;    /* signal mask to retstore */
+    int32_t     sc_onstack;     /* sigstack state to restore */
+    abi_long    sc_pc;          /* pc at time of signal */
+    abi_long    sc_reg[32];     /* processor regs 0 to 31 */
+    abi_long    mullo, mulhi;   /* mullo and mulhi registers */
+    int32_t     sc_fpused;      /* fp has been used */
+    abi_long    sc_fpregs[33];  /* fp regs 0 to 31 & csr */
+    abi_long    sc_fpc_eir;     /* fp exception instr reg */
+    /* int32_t reserved[8]; */
+};
+
+typedef struct target_mcontext {
+    int32_t     mc_onstack;     /* sigstack state to restore */
+    abi_long    mc_pc;          /* pc at time of signal */
+    abi_long    mc_regs[32];    /* process regs 0 to 31 */
+    abi_long    sr;             /* status register */
+    abi_long    mullo, mulhi;
+    int32_t     mc_fpused;      /* fp has been used */
+    abi_long    mc_fpregs[33];  /* fp regs 0 to 32 & csr */
+    abi_long    mc_fpc_eir;     /* fp exception instr reg */
+    abi_ulong   mc_tls;         /* pointer to TLS area */
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to mips/mips/pm_machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
+    abi_ulong frame_addr, struct target_sigaction *ka)
+{
+
+    /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */
+
+    /* MIPS only struct target_sigframe members: */
+    frame->sf_signum = sig;
+    frame->sf_siginfo = frame_addr + offsetof(struct target_sigframe, sf_si);
+    frame->sf_ucontext = frame_addr + offsetof(struct target_sigframe, sf_uc);
+
+    /*
+     * Arguments to signal handler:
+     *  a0 ($4) = signal number
+     *  a1 ($5) = siginfo pointer
+     *  a2 ($6) = ucontext pointer
+     *  PC = signal handler pointer
+     *  t9 ($25) = signal handler pointer
+     *  $29 = point to sigframe struct
+     *  ra ($31) = sigtramp at base of user stack
+     */
+    regs->active_tc.gpr[4] = sig;
+    regs->active_tc.gpr[5] = frame_addr +
+        offsetof(struct target_sigframe, sf_si);
+    regs->active_tc.gpr[6] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+    regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler;
+    regs->active_tc.gpr[29] = frame_addr;
+    regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+
+    return 0;
+}
+
+/*
+ * Compare to mips/mips/pm_machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
+        int flags)
+{
+    int i, err = 0;
+
+    if (flags & TARGET_MC_ADD_MAGIC) {
+        mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC);
+    } else {
+        mcp->mc_regs[0] = 0;
+    }
+
+    if (flags & TARGET_MC_SET_ONSTACK) {
+        mcp->mc_onstack = tswapal(1);
+    } else {
+        mcp->mc_onstack = 0;
+    }
+
+    for (i = 1; i < 32; i++) {
+        mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]);
+    }
+
+#if 0 /* XXX FP is not used right now */
+    abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0;
+
+    mcp->mc_fpused = used_fp;
+    if (used_fp) {
+        preempt_disable();
+        if (!is_fpu_owner()) {
+            own_fpu();
+            for (i = 0; i < 33; i++) {
+                mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]);
+            }
+        }
+        preempt_enable();
+    }
+#else
+    mcp->mc_fpused = 0;
+#endif
+
+    if (flags & TARGET_MC_GET_CLEAR_RET) {
+        mcp->mc_regs[2] = 0;    /* v0 = 0 */
+        mcp->mc_regs[3] = 0;    /* v1 = 0 */
+        mcp->mc_regs[7] = 0;    /* a3 = 0 */
+    }
+
+    mcp->mc_pc = tswapal(regs->active_tc.PC);
+    mcp->mullo = tswapal(regs->active_tc.LO[0]);
+    mcp->mulhi = tswapal(regs->active_tc.HI[0]);
+    mcp->mc_tls = tswapal(regs->tls_value);
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+/* Compare to mips/mips/pm_machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
+        int srflag)
+{
+    int i, err = 0;
+
+    for (i = 1; i < 32; i++) {
+        regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]);
+    }
+
+#if 0  /* XXX FP is not used right now */
+    abi_ulong used_fp = 0;
+
+    used_fp = tswapal(mcp->mc_fpused)
+    conditional_used_math(used_fp);
+
+    preempt_disabled();
+    if (used_math()) {
+        /* restore fpu context if we have used it before */
+        own_fpu();
+        for (i = 0; i < 32; i++) {
+            regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]);
+        }
+    } else {
+        /* Signal handler may have used FPU.  Give it up. */
+        lose_fpu();
+    }
+    preempt_enable();
+#endif
+
+    regs->CP0_EPC = tswapal(mcp->mc_pc);
+    regs->active_tc.LO[0] = tswapal(mcp->mullo);
+    regs->active_tc.HI[0] = tswapal(mcp->mulhi);
+    regs->tls_value = tswapal(mcp->mc_tls);
+
+    if (srflag) {
+        /* doing sigreturn() */
+        regs->active_tc.PC = regs->CP0_EPC;
+        regs->CP0_EPC = 0;  /* XXX  for nested signals ? */
+    }
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUMIPSState *regs,
+                        abi_ulong target_sf, abi_ulong *target_uc)
+{
+
+    /* mips passes ucontext struct as the stack frame */
+    *target_uc = target_sf;
+    return 0;
+}
+
+#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/netbsd/target_os_siginfo.h b/bsd-user/netbsd/target_os_siginfo.h
new file mode 100644
index 0000000..667c19c
--- /dev/null
+++ b/bsd-user/netbsd/target_os_siginfo.h
@@ -0,0 +1,82 @@
+#ifndef _TARGET_OS_SIGINFO_H_
+#define _TARGET_OS_SIGINFO_H_
+
+#define TARGET_NSIG     32  /* counting 0; could be 33 (mask is 1-32) */
+#define TARGET_NSIG_BPW     (sizeof(uint32_t) * 8)
+#define TARGET_NSIG_WORDS   (TARGET_NSIG / TARGET_NSIG_BPW)
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+    abi_long    ss_sp;
+    abi_ulong   ss_size;
+    abi_long    ss_flags;
+} target_stack_t;
+
+typedef struct {
+    uint32_t __bits[TARGET_NSIG_WORDS];
+} target_sigset_t
+
+struct target_sigaction {
+    abi_ulong   _sa_handler;
+    int32_t     sa_flags;
+    target_sigset_t sa_mask;
+};
+
+/* Compare to sys/siginfo.h */
+typedef union target_sigval {
+    int         sival_int;
+    abi_ulong   sival_ptr;
+} target_sigval_t;
+
+struct target_ksiginfo {
+    int32_t     _signo;
+    int32_t     _code;
+    int32_t     _errno;
+#if TARGET_ABI_BITS == 64
+    int32_t     _pad;
+#endif
+    union {
+        struct {
+            int32_t             _pid;
+            int32_t             _uid;
+            target_sigval_t    _value;
+        } _rt;
+
+        struct {
+            int32_t             _pid;
+            int32_t             _uid;
+            int32_t             _struct;
+            /* clock_t          _utime; */
+            /* clock_t          _stime; */
+        } _child;
+
+        struct {
+            abi_ulong           _addr;
+            int32_t             _trap;
+        } _fault;
+
+        struct {
+            long                _band;
+            int                 _fd;
+        } _poll;
+    } _reason;
+};
+
+typedef union target_siginfo {
+    int8_t     si_pad[128];
+    struct     target_ksiginfo  _info;
+} target_siginfo_t;
+
+#define target_si_signo     _info._signo
+#define target_si_code      _info._code
+#define target_si_errno     _info._errno
+#define target_si_addr      _info._reason._fault._addr
+
+#define TARGET_SEGV_MAPERR  1
+#define TARGET_SEGV_ACCERR  2
+
+#define TARGET_TRAP_BRKPT   1
+#define TARGET_TRAP_TRACE   2
+
+
+#endif /* ! _TARGET_OS_SIGINFO_H_ */
diff --git a/bsd-user/netbsd/target_os_signal.h b/bsd-user/netbsd/target_os_signal.h
new file mode 100644
index 0000000..d39a26f
--- /dev/null
+++ b/bsd-user/netbsd/target_os_signal.h
@@ -0,0 +1,70 @@
+#ifndef _TARGET_OS_SIGNAL_H_
+#define _TARGET_OS_SIGNAL_H_
+
+#include "target_os_siginfo.h"
+#include "target_arch_signal.h"
+
+#define TARGET_SIGHUP  1       /* hangup */
+#define TARGET_SIGINT  2       /* interrupt */
+#define TARGET_SIGQUIT 3       /* quit */
+#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
+#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
+#define TARGET_SIGABRT 6       /* abort() */
+#define TARGET_SIGIOT  SIGABRT /* compatibility */
+#define TARGET_SIGEMT  7       /* EMT instruction */
+#define TARGET_SIGFPE  8       /* floating point exception */
+#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
+#define TARGET_SIGBUS  10      /* bus error */
+#define TARGET_SIGSEGV 11      /* segmentation violation */
+#define TARGET_SIGSYS  12      /* bad argument to system call */
+#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
+#define TARGET_SIGALRM 14      /* alarm clock */
+#define TARGET_SIGTERM 15      /* software termination signal from kill */
+#define TARGET_SIGURG  16      /* urgent condition on IO channel */
+#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
+#define TARGET_SIGTSTP 18      /* stop signal from tty */
+#define TARGET_SIGCONT 19      /* continue a stopped process */
+#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
+#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
+#define TARGET_SIGTTOU 22      /* like TTIN for output if
+                                  (tp->t_local&LTOSTOP) */
+#define TARGET_SIGIO   23      /* input/output possible signal */
+#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
+#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
+#define TARGET_SIGVTALRM 26    /* virtual time alarm */
+#define TARGET_SIGPROF   27    /* profiling time alarm */
+#define TARGET_SIGWINCH  28    /* window size changes */
+#define TARGET_SIGINFO   29    /* information request */
+#define TARGET_SIGUSR1   30    /* user defined signal 1 */
+#define TARGET_SIGUSR2   31    /* user defined signal 2 */
+
+/*
+ * Language spec says we must list exactly one parameter, even though we
+ * actually supply three.  Ugh!
+ */
+#define TARGET_SIG_DFL         ((void (*)(int))0)
+#define TARGET_SIG_IGN         ((void (*)(int))1)
+#define TARGET_SIG_ERR         ((void (*)(int))-1)
+
+#define TARGET_SA_ONSTACK   0x0001  /* take signal on signal stack */
+#define TARGET_SA_RESTART   0x0002  /* restart system on signal return */
+#define TARGET_SA_RESETHAND 0x0004  /* reset to SIG_DFL when taking signal */
+#define TARGET_SA_NODEFER   0x0010  /* don't mask the signal we're delivering */
+#define TARGET_SA_NOCLDWAIT 0x0020  /* don't create zombies (assign to pid 1) */
+#define TARGET_SA_USERTRAMP 0x0100  /* do not bounce off kernel's sigtramp */
+#define TARGET_SA_NOCLDSTOP 0x0008  /* do not generate SIGCHLD on child stop */
+#define TARGET_SA_SIGINFO   0x0040  /* generate siginfo_t */
+
+/*
+ * Flags for sigprocmask:
+ */
+#define TARGET_SIG_BLOCK       1       /* block specified signal set */
+#define TARGET_SIG_UNBLOCK     2       /* unblock specified signal set */
+#define TARGET_SIG_SETMASK     3       /* set specified signal set */
+
+#define TARGET_BADSIG       SIG_ERR
+
+#define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */
+#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */
+
+#endif /* !_TARGET_OS_SIGNAL_H_ */
diff --git a/bsd-user/openbsd/target_os_siginfo.h b/bsd-user/openbsd/target_os_siginfo.h
new file mode 100644
index 0000000..baf646a
--- /dev/null
+++ b/bsd-user/openbsd/target_os_siginfo.h
@@ -0,0 +1,82 @@
+#ifndef _TARGET_OS_SIGINFO_H_
+#define _TARGET_OS_SIGINFO_H_
+
+#define TARGET_NSIG     32   /* counting 0; could be 33 (mask is 1-32) */
+#define TARGET_NSIG_BPW     (sizeof(uint32_t) * 8)
+#define TARGET_NSIG_WORDS   (TARGET_NSIG / TARGET_NSIG_BPW)
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+    abi_long    ss_sp;
+    abi_ulong   ss_size;
+    abi_long    ss_flags;
+} target_stack_t;
+
+typedef struct {
+    uint32_t __bits[TARGET_NSIG_WORDS];
+} target_sigset_t
+
+struct target_sigaction {
+    abi_ulong   _sa_handler;
+    int32_t     sa_flags;
+    target_sigset_t sa_mask;
+};
+
+/* Compare to sys/siginfo.h */
+typedef union target_sigval {
+    int         sival_int;
+    abi_ulong   sival_ptr;
+} target_sigval_t;
+
+struct target_ksiginfo {
+    int32_t     _signo;
+    int32_t     _code;
+    int32_t     _errno;
+#if TARGET_ABI_BITS == 64
+    int32_t     _pad;
+#endif
+    union {
+        struct {
+            int32_t             _pid;
+            int32_t             _uid;
+            target_sigval_t    _value;
+        } _rt;
+
+        struct {
+            int32_t             _pid;
+            int32_t             _uid;
+            int32_t             _struct;
+            /* clock_t          _utime; */
+            /* clock_t          _stime; */
+        } _child;
+
+        struct {
+            abi_ulong           _addr;
+            int32_t             _trap;
+        } _fault;
+
+        struct {
+            long                _band;
+            int                 _fd;
+        } _poll;
+    } _reason;
+};
+
+typedef union target_siginfo {
+    int8_t     si_pad[128];
+    struct     target_ksiginfo  _info;
+} target_siginfo_t;
+
+#define target_si_signo     _info._signo
+#define target_si_code      _info._code
+#define target_si_errno     _info._errno
+#define target_si_addr      _info._reason._fault._addr
+
+#define TARGET_SEGV_MAPERR  1
+#define TARGET_SEGV_ACCERR  2
+
+#define TARGET_TRAP_BRKPT   1
+#define TARGET_TRAP_TRACE   2
+
+
+#endif /* ! _TARGET_OS_SIGINFO_H_ */
diff --git a/bsd-user/openbsd/target_os_signal.h b/bsd-user/openbsd/target_os_signal.h
new file mode 100644
index 0000000..d39a26f
--- /dev/null
+++ b/bsd-user/openbsd/target_os_signal.h
@@ -0,0 +1,70 @@
+#ifndef _TARGET_OS_SIGNAL_H_
+#define _TARGET_OS_SIGNAL_H_
+
+#include "target_os_siginfo.h"
+#include "target_arch_signal.h"
+
+#define TARGET_SIGHUP  1       /* hangup */
+#define TARGET_SIGINT  2       /* interrupt */
+#define TARGET_SIGQUIT 3       /* quit */
+#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
+#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
+#define TARGET_SIGABRT 6       /* abort() */
+#define TARGET_SIGIOT  SIGABRT /* compatibility */
+#define TARGET_SIGEMT  7       /* EMT instruction */
+#define TARGET_SIGFPE  8       /* floating point exception */
+#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
+#define TARGET_SIGBUS  10      /* bus error */
+#define TARGET_SIGSEGV 11      /* segmentation violation */
+#define TARGET_SIGSYS  12      /* bad argument to system call */
+#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
+#define TARGET_SIGALRM 14      /* alarm clock */
+#define TARGET_SIGTERM 15      /* software termination signal from kill */
+#define TARGET_SIGURG  16      /* urgent condition on IO channel */
+#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
+#define TARGET_SIGTSTP 18      /* stop signal from tty */
+#define TARGET_SIGCONT 19      /* continue a stopped process */
+#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
+#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
+#define TARGET_SIGTTOU 22      /* like TTIN for output if
+                                  (tp->t_local&LTOSTOP) */
+#define TARGET_SIGIO   23      /* input/output possible signal */
+#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
+#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
+#define TARGET_SIGVTALRM 26    /* virtual time alarm */
+#define TARGET_SIGPROF   27    /* profiling time alarm */
+#define TARGET_SIGWINCH  28    /* window size changes */
+#define TARGET_SIGINFO   29    /* information request */
+#define TARGET_SIGUSR1   30    /* user defined signal 1 */
+#define TARGET_SIGUSR2   31    /* user defined signal 2 */
+
+/*
+ * Language spec says we must list exactly one parameter, even though we
+ * actually supply three.  Ugh!
+ */
+#define TARGET_SIG_DFL         ((void (*)(int))0)
+#define TARGET_SIG_IGN         ((void (*)(int))1)
+#define TARGET_SIG_ERR         ((void (*)(int))-1)
+
+#define TARGET_SA_ONSTACK   0x0001  /* take signal on signal stack */
+#define TARGET_SA_RESTART   0x0002  /* restart system on signal return */
+#define TARGET_SA_RESETHAND 0x0004  /* reset to SIG_DFL when taking signal */
+#define TARGET_SA_NODEFER   0x0010  /* don't mask the signal we're delivering */
+#define TARGET_SA_NOCLDWAIT 0x0020  /* don't create zombies (assign to pid 1) */
+#define TARGET_SA_USERTRAMP 0x0100  /* do not bounce off kernel's sigtramp */
+#define TARGET_SA_NOCLDSTOP 0x0008  /* do not generate SIGCHLD on child stop */
+#define TARGET_SA_SIGINFO   0x0040  /* generate siginfo_t */
+
+/*
+ * Flags for sigprocmask:
+ */
+#define TARGET_SIG_BLOCK       1       /* block specified signal set */
+#define TARGET_SIG_UNBLOCK     2       /* unblock specified signal set */
+#define TARGET_SIG_SETMASK     3       /* set specified signal set */
+
+#define TARGET_BADSIG       SIG_ERR
+
+#define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */
+#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */
+
+#endif /* !_TARGET_OS_SIGNAL_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 594de5c..0e332af 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -39,7 +39,7 @@ extern enum BSDType bsd_type;
 #include "syscall_defs.h"
 #include "syscall.h"
 #include "target_os_vmparam.h"
-#include "target_signal.h"
+#include "target_os_signal.h"
 #include "exec/gdbstub.h"
 
 #if defined(CONFIG_USE_NPTL)
@@ -72,16 +72,16 @@ struct image_info {
 
 #define MAX_SIGQUEUE_SIZE 1024
 
-struct sigqueue {
-    struct sigqueue *next;
-    //target_siginfo_t info;
+struct qemu_sigqueue {
+    struct qemu_sigqueue *next;
+    target_siginfo_t info;
 };
 
 struct emulated_sigtable {
     int pending; /* true if signal is pending */
-    struct sigqueue *first;
-    struct sigqueue info; /* in order to always have memory for the
-                             first signal, we put it here */
+    struct qemu_sigqueue *first;
+    struct qemu_sigqueue info; /* in order to always have memory for the
+                                  first signal, we put it here */
 };
 
 /* NOTE: we force a big alignment so that the stack stored after is
@@ -93,8 +93,8 @@ typedef struct TaskState {
     struct bsd_binprm *bprm;
 
     struct emulated_sigtable sigtab[TARGET_NSIG];
-    struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
-    struct sigqueue *first_free; /* first free siginfo queue entry */
+    struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
+    struct qemu_sigqueue *first_free; /* first free siginfo queue entry */
     int signal_pending; /* non zero if a signal may be pending */
 
     uint8_t stack[0];
@@ -202,12 +202,19 @@ extern int do_strace;
 /* signal.c */
 void process_pending_signals(CPUArchState *cpu_env);
 void signal_init(void);
-//int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
-//void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
-//void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
-long do_sigreturn(CPUArchState *env);
+int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
+int target_to_host_signal(int sig);
+int host_to_target_signal(int sig);
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
+long do_sigreturn(CPUArchState *env, abi_ulong addr);
 long do_rt_sigreturn(CPUArchState *env);
 abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
+int do_sigaction(int sig, const struct target_sigaction *act,
+                struct target_sigaction *oact);
+void QEMU_NORETURN force_sig(int target_sig);
 
 /* mmap.c */
 int target_mprotect(abi_ulong start, abi_ulong len, int prot);
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index 445f69e..3619b00 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -2,6 +2,7 @@
  *  Emulation of BSD signals
  *
  *  Copyright (c) 2003 - 2008 Fabrice Bellard
+ *  Copyright (c) 2013 Stacey Son
  *
  *  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
@@ -23,16 +24,920 @@
 #include <unistd.h>
 #include <signal.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 
 #include "qemu.h"
-#include "target_signal.h"
 
 //#define DEBUG_SIGNAL
 
+static target_stack_t target_sigaltstack_used = {
+    .ss_sp = 0,
+    .ss_size = 0,
+    .ss_flags = TARGET_SS_DISABLE,
+};
+
+static uint8_t host_to_target_signal_table[TARGET_NSIG] = {
+    [SIGHUP]    =   TARGET_SIGHUP,
+    [SIGINT]    =   TARGET_SIGINT,
+    [SIGQUIT]   =   TARGET_SIGQUIT,
+    [SIGILL]    =   TARGET_SIGILL,
+    [SIGTRAP]   =   TARGET_SIGTRAP,
+    [SIGABRT]   =   TARGET_SIGABRT,
+    [SIGEMT]    =   TARGET_SIGEMT,
+    [SIGFPE]    =   TARGET_SIGFPE,
+    [SIGKILL]   =   TARGET_SIGKILL,
+    [SIGBUS]    =   TARGET_SIGBUS,
+    [SIGSEGV]   =   TARGET_SIGSEGV,
+    [SIGSYS]    =   TARGET_SIGSYS,
+    [SIGPIPE]   =   TARGET_SIGPIPE,
+    [SIGALRM]   =   TARGET_SIGALRM,
+    [SIGTERM]   =   TARGET_SIGTERM,
+    [SIGURG]    =   TARGET_SIGURG,
+    [SIGSTOP]   =   TARGET_SIGSTOP,
+    [SIGTSTP]   =   TARGET_SIGTSTP,
+    [SIGCONT]   =   TARGET_SIGCONT,
+    [SIGCHLD]   =   TARGET_SIGCHLD,
+    [SIGTTIN]   =   TARGET_SIGTTIN,
+    [SIGTTOU]   =   TARGET_SIGTTOU,
+    [SIGIO]     =   TARGET_SIGIO,
+    [SIGXCPU]   =   TARGET_SIGXCPU,
+    [SIGXFSZ]   =   TARGET_SIGXFSZ,
+    [SIGVTALRM] =   TARGET_SIGVTALRM,
+    [SIGPROF]   =   TARGET_SIGPROF,
+    [SIGWINCH]  =   TARGET_SIGWINCH,
+    [SIGINFO]   =   TARGET_SIGINFO,
+    [SIGUSR1]   =   TARGET_SIGUSR1,
+    [SIGUSR2]   =   TARGET_SIGUSR2,
+#ifdef SIGTHR
+    [SIGTHR + 3]    =   TARGET_SIGTHR,
+#endif
+    /* [SIGLWP] =   TARGET_SIGLWP, */
+#ifdef SIGLIBRT
+    [SIGLIBRT]  =   TARGET_SIGLIBRT,
+#endif
+
+    /*
+     * The following signals stay the same.
+     * Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
+     * host libpthread signals.  This assumes no one actually uses
+     * SIGRTMAX.  To fix this properly we need to manual signal delivery
+     * multiplexed over a single host signal.
+     */
+    [SIGRTMIN]  =   SIGRTMAX,
+    [SIGRTMAX]  =   SIGRTMIN,
+};
+
+static uint8_t target_to_host_signal_table[TARGET_NSIG];
+static struct target_sigaction sigact_table[TARGET_NSIG];
+static void host_signal_handler(int host_signum, siginfo_t *info, void *puc);
+static void target_to_host_sigset_internal(sigset_t *d,
+        const target_sigset_t *s);
+
+static inline int on_sig_stack(unsigned long sp)
+{
+    return sp - target_sigaltstack_used.ss_sp < target_sigaltstack_used.ss_size;
+}
+
+static inline int sas_ss_flags(unsigned long sp)
+{
+    return target_sigaltstack_used.ss_size == 0 ? SS_DISABLE : on_sig_stack(sp)
+        ? SS_ONSTACK : 0;
+}
+
+int host_to_target_signal(int sig)
+{
+
+    if (sig < 0 || sig >= TARGET_NSIG) {
+        return sig;
+    }
+
+    return host_to_target_signal_table[sig];
+}
+
+int target_to_host_signal(int sig)
+{
+
+    if (sig >= TARGET_NSIG) {
+        return sig;
+    }
+
+    return target_to_host_signal_table[sig];
+}
+
+static inline void target_sigemptyset(target_sigset_t *set)
+{
+
+    memset(set, 0, sizeof(*set));
+}
+
+static inline void target_sigaddset(target_sigset_t *set, int signum)
+{
+
+    signum--;
+    uint32_t mask = (uint32_t)1 << (signum % TARGET_NSIG_BPW);
+    set->__bits[signum / TARGET_NSIG_BPW] |= mask;
+}
+
+static inline int target_sigismember(const target_sigset_t *set, int signum)
+{
+
+    signum--;
+    abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
+    return (set->__bits[signum / TARGET_NSIG_BPW] & mask) != 0;
+}
+
+static void host_to_target_sigset_internal(target_sigset_t *d,
+        const sigset_t *s)
+{
+    int i;
+
+    target_sigemptyset(d);
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        if (sigismember(s, i)) {
+            target_sigaddset(d, host_to_target_signal(i));
+        }
+    }
+}
+
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
+{
+    target_sigset_t d1;
+    int i;
+
+    host_to_target_sigset_internal(&d1, s);
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        d->__bits[i] = tswap32(d1.__bits[i]);
+    }
+}
+
+static void target_to_host_sigset_internal(sigset_t *d,
+        const target_sigset_t *s)
+{
+    int i;
+
+    sigemptyset(d);
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        if (target_sigismember(s, i)) {
+            sigaddset(d, target_to_host_signal(i));
+        }
+    }
+}
+
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
+{
+    target_sigset_t s1;
+    int i;
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        s1.__bits[i] = tswap32(s->__bits[i]);
+    }
+    target_to_host_sigset_internal(d, &s1);
+}
+
+/* Siginfo conversion. */
+static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
+        const siginfo_t *info)
+{
+    int sig, code;
+
+    sig = host_to_target_signal(info->si_signo);
+    /* XXX should have host_to_target_si_code() */
+    code = tswap32(info->si_code);
+    tinfo->si_signo = sig;
+    tinfo->si_errno = info->si_errno;
+    tinfo->si_code = info->si_code;
+    tinfo->si_pid = info->si_pid;
+    tinfo->si_uid = info->si_uid;
+    tinfo->si_addr = (abi_ulong)(unsigned long)info->si_addr;
+    /* si_value is opaque to kernel */
+    tinfo->si_value.sival_ptr =
+        (abi_ulong)(unsigned long)info->si_value.sival_ptr;
+    if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig ||
+            SIGTRAP == sig) {
+        tinfo->_reason._fault._trapno = info->_reason._fault._trapno;
+    }
+#ifdef SIGPOLL
+    if (SIGPOLL == sig) {
+        tinfo->_reason._poll._band = info->_reason._poll._band;
+    }
+#endif
+    if (SI_TIMER == code) {
+        tinfo->_reason._timer._timerid = info->_reason._timer._timerid;
+        tinfo->_reason._timer._overrun = info->_reason._timer._overrun;
+    }
+}
+
+static void tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info)
+{
+    int sig, code;
+
+    sig = info->si_signo;
+    code = info->si_code;
+    tinfo->si_signo = tswap32(sig);
+    tinfo->si_errno = tswap32(info->si_errno);
+    tinfo->si_code = tswap32(info->si_code);
+    tinfo->si_pid = tswap32(info->si_pid);
+    tinfo->si_uid = tswap32(info->si_uid);
+    tinfo->si_addr = tswapal(info->si_addr);
+    if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig ||
+            SIGTRAP == sig) {
+        tinfo->_reason._fault._trapno = tswap32(info->_reason._fault._trapno);
+    }
+#ifdef SIGPOLL
+    if (SIGPOLL == sig) {
+        tinfo->_reason._poll._band = tswap32(info->_reason._poll._band);
+    }
+#endif
+    if (SI_TIMER == code) {
+        tinfo->_reason._timer._timerid = tswap32(info->_reason._timer._timerid);
+        tinfo->_reason._timer._overrun = tswap32(info->_reason._timer._overrun);
+    }
+}
+
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
+{
+
+    host_to_target_siginfo_noswap(tinfo, info);
+    tswap_siginfo(tinfo, tinfo);
+}
+
+/* Returns 1 if given signal should dump core if not handled. */
+static int core_dump_signal(int sig)
+{
+    switch (sig) {
+    case TARGET_SIGABRT:
+    case TARGET_SIGFPE:
+    case TARGET_SIGILL:
+    case TARGET_SIGQUIT:
+    case TARGET_SIGSEGV:
+    case TARGET_SIGTRAP:
+    case TARGET_SIGBUS:
+        return 1;
+    default:
+        return 0;
+    }
+}
+
+/* Signal queue handling. */
+static inline struct qemu_sigqueue *alloc_sigqueue(CPUArchState *env)
+{
+    TaskState *ts = env->opaque;
+    struct qemu_sigqueue *q = ts->first_free;
+
+    if (!q) {
+        return NULL;
+    }
+    ts->first_free = q->next;
+    return q;
+}
+
+static inline void free_sigqueue(CPUArchState *env, struct qemu_sigqueue *q)
+{
+
+    TaskState *ts = env->opaque;
+    q->next = ts->first_free;
+    ts->first_free = q;
+}
+
+/* Abort execution with signal. */
+void QEMU_NORETURN force_sig(int target_sig)
+{
+    CPUArchState *env = thread_cpu->env_ptr;
+    TaskState *ts = (TaskState *)env->opaque;
+    int core_dumped = 0;
+    int host_sig;
+    struct sigaction act;
+
+    host_sig = target_to_host_signal(target_sig);
+    gdb_signalled(env, target_sig);
+
+    /* Dump core if supported by target binary format */
+    if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
+        stop_all_tasks();
+        core_dumped =
+            ((*ts->bprm->core_dump)(target_sig, env) == 0);
+    }
+    if (core_dumped) {
+        struct rlimit nodump;
+
+        /*
+         * We already dumped the core of target process, we don't want
+         * a coredump of qemu itself.
+         */
+         getrlimit(RLIMIT_CORE, &nodump);
+         nodump.rlim_cur = 0;
+         setrlimit(RLIMIT_CORE, &nodump);
+         (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) "
+             "- %s\n", target_sig, strsignal(host_sig), "core dumped");
+    }
+
+    /*
+     * The proper exit code for dying from an uncaught signal is
+     * -<signal>.  The kernel doesn't allow exit() or _exit() to pass
+     * a negative value.  To get the proper exit code we need to
+     * actually die from an uncaught signal.  Here the default signal
+     * handler is installed, we send ourself a signal and we wait for
+     * it to arrive.
+     */
+    memset(&act, 0, sizeof(act));
+    sigfillset(&act.sa_mask);
+    act.sa_handler = SIG_DFL;
+    sigaction(host_sig, &act, NULL);
+
+    kill(getpid(), host_sig);
+
+    /*
+     * Make sure the signal isn't masked (just reuse the mask inside
+     * of act).
+     */
+    sigdelset(&act.sa_mask, host_sig);
+    sigsuspend(&act.sa_mask);
+
+    /* unreachable */
+    abort();
+}
+
+/*
+ * Queue a signal so that it will be send to the virtual CPU as soon as
+ * possible.
+ */
+int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
+{
+    TaskState *ts = env->opaque;
+    struct emulated_sigtable *k;
+    struct qemu_sigqueue *q, **pq;
+    abi_ulong handler;
+    int queue;
+
+    k = &ts->sigtab[sig - 1];
+    queue = gdb_queuesig();
+    handler = sigact_table[sig - 1]._sa_handler;
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "queue_signal: sig=%d handler=0x%lx flags=0x%x\n", sig,
+        handler, (uint32_t)sigact_table[sig - 1].sa_flags);
+#endif
+    if (!queue && (TARGET_SIG_DFL == handler)) {
+        if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN ||
+            sig == TARGET_SIGTTOU) {
+            kill(getpid(), SIGSTOP);
+            return 0;
+        } else {
+            if (sig != TARGET_SIGCHLD &&
+                sig != TARGET_SIGURG &&
+                sig != TARGET_SIGWINCH &&
+                sig != TARGET_SIGCONT) {
+                force_sig(sig);
+            } else {
+                return 0; /* The signal was ignored. */
+            }
+        }
+    } else if (!queue && (TARGET_SIG_IGN == handler)) {
+        return 0; /* Ignored signal. */
+    } else if (!queue && (TARGET_SIG_ERR == handler)) {
+        force_sig(sig);
+    } else {
+        pq = &k->first;
+
+        /*
+         * FreeBSD signals are always queued.
+         * Linux only queues real time signals.
+         * XXX this code is not thread safe.
+         */
+        if (!k->pending) {
+            /* first signal */
+            q = &k->info;
+        } else {
+            q = alloc_sigqueue(env);
+            if (!q) {
+                return -EAGAIN;
+            }
+            while (*pq != NULL) {
+                pq = &(*pq)->next;
+            }
+        }
+        *pq = q;
+        q->info = *info;
+        q->next = NULL;
+        k->pending = 1;
+        /* Signal that a new signal is pending. */
+        ts->signal_pending = 1;
+        return 1; /* Indicates that the signal was queued. */
+    }
+}
+
+static void host_signal_handler(int host_signum, siginfo_t *info, void *puc)
+{
+    CPUArchState *env = thread_cpu->env_ptr;
+    int sig;
+    target_siginfo_t tinfo;
+
+    /*
+     * The CPU emulator uses some host signal to detect exceptions so
+     * we forward to it some signals.
+     */
+    if ((host_signum == SIGSEGV || host_signum == SIGBUS) &&
+            info->si_code < 0x10000) {
+        if (cpu_signal_handler(host_signum, info, puc)) {
+            return;
+        }
+    }
+
+    /* Get the target signal number. */
+    sig = host_to_target_signal(host_signum);
+    if (sig < 1 || sig > TARGET_NSIG) {
+        return;
+    }
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: got signal %d\n", sig);
+#endif
+    host_to_target_siginfo_noswap(&tinfo, info);
+    if (queue_signal(env, sig, &tinfo) == 1) {
+        /* Interrupt the virtual CPU as soon as possible. */
+        cpu_exit(thread_cpu);
+    }
+}
+
+/* do_sigaltstack() returns target values and errnos.  */
+/* compare to kern/kern_sig.c sys_sigaltstack() and kern_sigaltstack() */
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
+{
+    int ret = 0;
+    target_stack_t ss, oss, *uss;
+
+    if (uoss_addr) {
+        /* Save current signal stack params */
+        oss.ss_sp = tswapl(target_sigaltstack_used.ss_sp);
+        oss.ss_size = tswapl(target_sigaltstack_used.ss_size);
+        oss.ss_flags = tswapl(sas_ss_flags(sp));
+    }
+
+    if (uss_addr) {
+
+        if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1) ||
+            __get_user(ss.ss_sp, &uss->ss_sp) ||
+            __get_user(ss.ss_size, &uss->ss_size) ||
+            __get_user(ss.ss_flags, &uss->ss_flags)) {
+            ret = -TARGET_EFAULT;
+            goto out;
+        }
+        unlock_user_struct(uss, uss_addr, 0);
+
+        if (on_sig_stack(sp)) {
+            ret = -TARGET_EPERM;
+            goto out;
+        }
+
+        if ((ss.ss_flags & ~TARGET_SS_DISABLE) != 0) {
+            ret = -TARGET_EINVAL;
+            goto out;
+        }
+
+        if (!(ss.ss_flags & ~TARGET_SS_DISABLE)) {
+            if (ss.ss_size < TARGET_MINSIGSTKSZ) {
+                ret = -TARGET_ENOMEM;
+                goto out;
+            }
+        } else {
+            ss.ss_size = 0;
+            ss.ss_sp = 0;
+        }
+
+        target_sigaltstack_used.ss_sp = ss.ss_sp;
+        target_sigaltstack_used.ss_size = ss.ss_size;
+    }
+
+    if (uoss_addr) {
+        /* Copy out to user saved signal stack params */
+        if (copy_to_user(uoss_addr, &oss, sizeof(oss))) {
+            ret = -TARGET_EFAULT;
+            goto out;
+        }
+    }
+
+out:
+    return ret;
+}
+
+static int fatal_signal(int sig)
+{
+
+    switch (sig) {
+    case TARGET_SIGCHLD:
+    case TARGET_SIGURG:
+    case TARGET_SIGWINCH:
+        /* Ignored by default. */
+        return 0;
+    case TARGET_SIGCONT:
+    case TARGET_SIGSTOP:
+    case TARGET_SIGTSTP:
+    case TARGET_SIGTTIN:
+    case TARGET_SIGTTOU:
+        /* Job control signals.  */
+        return 0;
+    default:
+        return 1;
+    }
+}
+
+/* do_sigaction() return host values and errnos */
+int do_sigaction(int sig, const struct target_sigaction *act,
+        struct target_sigaction *oact)
+{
+    struct target_sigaction *k;
+    struct sigaction act1;
+    int host_sig;
+    int ret = 0;
+
+    if (sig < 1 || sig > TARGET_NSIG || TARGET_SIGKILL == sig ||
+            TARGET_SIGSTOP == sig) {
+        return -EINVAL;
+    }
+    k = &sigact_table[sig - 1];
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_sigaction sig=%d act=%p, oact=%p\n",
+        sig, act, oact);
+#endif
+    if (oact) {
+        oact->_sa_handler = tswapal(k->_sa_handler);
+        oact->sa_flags = tswap32(k->sa_flags);
+        oact->sa_mask = k->sa_mask;
+    }
+    if (act) {
+        /* XXX: this is most likely not threadsafe. */
+        k->_sa_handler = tswapal(act->_sa_handler);
+        k->sa_flags = tswap32(act->sa_flags);
+        k->sa_mask = act->sa_mask;
+
+        /* Update the host signal state. */
+        host_sig = target_to_host_signal(sig);
+        if (host_sig != SIGSEGV && host_sig != SIGBUS) {
+            memset(&act1, 0, sizeof(struct sigaction));
+            sigfillset(&act1.sa_mask);
+            if (k->sa_flags & TARGET_SA_RESTART) {
+                act1.sa_flags |= SA_RESTART;
+            }
+            /*
+             *  Note: It is important to update the host kernel signal mask to
+             *  avoid getting unexpected interrupted system calls.
+             */
+            if (k->_sa_handler == TARGET_SIG_IGN) {
+                act1.sa_sigaction = (void *)SIG_IGN;
+            } else if (k->_sa_handler == TARGET_SIG_DFL) {
+                if (fatal_signal(sig)) {
+                    act1.sa_flags = SA_SIGINFO;
+                    act1.sa_sigaction = host_signal_handler;
+                } else {
+                    act1.sa_sigaction = (void *)SIG_DFL;
+                }
+            } else {
+                act1.sa_flags = SA_SIGINFO;
+                act1.sa_sigaction = host_signal_handler;
+            }
+            ret = sigaction(host_sig, &act1, NULL);
+#if defined(DEBUG_SIGNAL)
+            fprintf(stderr, "sigaction (action = %p "
+                    "(host_signal_handler = %p)) returned: %d\n",
+                    act1.sa_sigaction, host_signal_handler, ret);
+#endif
+        }
+    }
+    return ret;
+}
+
+static inline abi_ulong get_sigframe(struct target_sigaction *ka,
+        CPUArchState *regs, size_t frame_size)
+{
+    abi_ulong sp;
+
+    /* Use default user stack */
+    sp = get_sp_from_cpustate(regs);
+
+    if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
+        sp = target_sigaltstack_used.ss_sp +
+            target_sigaltstack_used.ss_size;
+    }
+
+#if defined(TARGET_MIPS) || defined(TARGET_ARM)
+    return (sp - frame_size) & ~7;
+#else
+    return sp - frame_size;
+#endif
+}
+
+/* compare to mips/mips/pm_machdep.c and sparc64/sparc64/machdep.c sendsig() */
+static void setup_frame(int sig, int code, struct target_sigaction *ka,
+    target_sigset_t *set, target_siginfo_t *tinfo, CPUArchState *regs)
+{
+    struct target_sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "setup_frame()\n");
+#endif
+    frame_addr = get_sigframe(ka, regs, sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+        goto give_sigsegv;
+    }
+
+    memset(frame, 0, sizeof(*frame));
+#if defined(TARGET_MIPS)
+    int mflags = on_sig_stack(frame_addr) ? TARGET_MC_ADD_MAGIC :
+        TARGET_MC_SET_ONSTACK | TARGET_MC_ADD_MAGIC;
+#else
+    int mflags = 0;
+#endif
+    if (get_mcontext(regs, &frame->sf_uc.uc_mcontext, mflags)) {
+        goto give_sigsegv;
+    }
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        if (__put_user(set->__bits[i], &frame->sf_uc.uc_sigmask.__bits[i])) {
+            goto give_sigsegv;
+        }
+    }
+
+    if (tinfo) {
+        frame->sf_si.si_signo = tinfo->si_signo;
+        frame->sf_si.si_errno = tinfo->si_errno;
+        frame->sf_si.si_code = tinfo->si_code;
+        frame->sf_si.si_pid = tinfo->si_pid;
+        frame->sf_si.si_uid = tinfo->si_uid;
+        frame->sf_si.si_status = tinfo->si_status;
+        frame->sf_si.si_addr = tinfo->si_addr;
+
+        if (TARGET_SIGILL == sig || TARGET_SIGFPE == sig ||
+                TARGET_SIGSEGV == sig || TARGET_SIGBUS == sig ||
+                TARGET_SIGTRAP == sig) {
+            frame->sf_si._reason._fault._trapno = tinfo->_reason._fault._trapno;
+        }
+
+        /*
+         * If si_code is one of SI_QUEUE, SI_TIMER, SI_ASYNCIO, or
+         * SI_MESGQ, then si_value contains the application-specified
+         * signal value. Otherwise, the contents of si_value are
+         * undefined.
+         */
+        if (SI_QUEUE == code || SI_TIMER == code || SI_ASYNCIO == code ||
+                SI_MESGQ == code) {
+            frame->sf_si.si_value.sival_int = tinfo->si_value.sival_int;
+        }
+
+        if (SI_TIMER == code) {
+            frame->sf_si._reason._timer._timerid =
+                tinfo->_reason._timer._timerid;
+            frame->sf_si._reason._timer._overrun =
+                tinfo->_reason._timer._overrun;
+        }
+
+#ifdef SIGPOLL
+        if (SIGPOLL == sig) {
+            frame->sf_si._reason._band = tinfo->_reason._band;
+        }
+#endif
+
+    }
+
+    if (set_sigtramp_args(regs, sig, frame, frame_addr, ka)) {
+        goto give_sigsegv;
+    }
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+static int reset_signal_mask(target_ucontext_t *ucontext)
+{
+    int i;
+    sigset_t blocked;
+    target_sigset_t target_set;
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++)
+        if (__get_user(target_set.__bits[i],
+                    &ucontext->uc_sigmask.__bits[i])) {
+            return -TARGET_EFAULT;
+        }
+    target_to_host_sigset_internal(&blocked, &target_set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    return 0;
+}
+
+long do_sigreturn(CPUArchState *regs, abi_ulong addr)
+{
+    long ret;
+    abi_ulong target_ucontext;
+    target_ucontext_t *ucontext = NULL;
+
+    /* Get the target ucontext address from the stack frame */
+    ret = get_ucontext_sigreturn(regs, addr, &target_ucontext);
+    if (is_error(ret)) {
+        return ret;
+    }
+    if (!lock_user_struct(VERIFY_READ, ucontext, target_ucontext, 0)) {
+        goto badframe;
+    }
+
+    /* Set the register state back to before the signal. */
+    if (set_mcontext(regs, &ucontext->uc_mcontext, 1)) {
+        goto badframe;
+    }
+
+    /* And reset the signal mask. */
+    if (reset_signal_mask(ucontext)) {
+        goto badframe;
+    }
+
+    unlock_user_struct(ucontext, target_ucontext, 0);
+    return -TARGET_EJUSTRETURN;
+
+badframe:
+    if (ucontext != NULL) {
+        unlock_user_struct(ucontext, target_ucontext, 0);
+    }
+    force_sig(TARGET_SIGSEGV);
+    return -TARGET_EFAULT;
+}
+
 void signal_init(void)
 {
+    struct sigaction act;
+    struct sigaction oact;
+    int i, j;
+    int host_sig;
+
+    /* Generate the signal conversion tables.  */
+    for (i = 1; i < TARGET_NSIG; i++) {
+        if (host_to_target_signal_table[i] == 0) {
+            host_to_target_signal_table[i] = i;
+        }
+    }
+    for (i = 1; i < TARGET_NSIG; i++) {
+        j = host_to_target_signal_table[i];
+        target_to_host_signal_table[j] = i;
+    }
+
+    /*
+     * Set all host signal handlers. ALL signals are blocked during the
+     * handlers to serialize them.
+     */
+    memset(sigact_table, 0, sizeof(sigact_table));
+
+    sigfillset(&act.sa_mask);
+    act.sa_sigaction = host_signal_handler;
+    act.sa_flags = SA_SIGINFO;
+
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        host_sig = target_to_host_signal(i);
+        sigaction(host_sig, NULL, &oact);
+        if (oact.sa_sigaction == (void *)SIG_IGN) {
+            sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
+        } else if (oact.sa_sigaction == (void *)SIG_DFL) {
+            sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
+        }
+        /*
+         * If there's already a handler installed then something has
+         * gone horribly wrong, so don't even try to handle that case.
+         * Install some handlers for our own use.  We need at least
+         * SIGSEGV and SIGBUS, to detect exceptions.  We can not just
+         * trap all signals because it affects syscall interrupt
+         * behavior.  But do trap all default-fatal signals.
+         */
+        if (fatal_signal(i)) {
+            sigaction(host_sig, &act, NULL);
+        }
+    }
 }
 
 void process_pending_signals(CPUArchState *cpu_env)
 {
+    CPUState *cpu = ENV_GET_CPU(cpu_env);
+    int sig, code;
+    abi_ulong handler;
+    sigset_t set, old_set;
+    target_sigset_t target_old_set;
+    target_siginfo_t tinfo;
+    struct emulated_sigtable *k;
+    struct target_sigaction *sa;
+    struct qemu_sigqueue *q;
+    TaskState *ts = cpu_env->opaque;
+
+    if (!ts->signal_pending) {
+        return;
+    }
+
+    /* FIXME: This is not threadsafe.  */
+    k  = ts->sigtab;
+    for (sig = 1; sig <= TARGET_NSIG; sig++) {
+        if (k->pending) {
+            goto handle_signal;
+        }
+        k++;
+    }
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: process_pending_signals has no signals\n");
+#endif
+    /* If no signal is pending then just return. */
+    ts->signal_pending = 0;
+    return;
+
+handle_signal:
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: process signal %d\n", sig);
+#endif
+
+    /* Dequeue signal. */
+    q = k->first;
+    k->first = q->next;
+    if (!k->first) {
+        k->pending = 0;
+    }
+
+    sig = gdb_handlesig(cpu, sig);
+    if (!sig) {
+        sa = NULL;
+        handler = TARGET_SIG_IGN;
+    } else {
+        sa = &sigact_table[sig - 1];
+        handler = sa->_sa_handler;
+    }
+
+    if (handler == TARGET_SIG_DFL) {
+#ifdef DEBUG_SIGNAL
+        fprintf(stderr, "qemu: TARGET_SIG_DFL\n");
+#endif
+        /*
+         * default handler : ignore some signal. The other are job
+         * control or fatal.
+         */
+        if (TARGET_SIGTSTP == sig || TARGET_SIGTTIN == sig ||
+                TARGET_SIGTTOU == sig) {
+            kill(getpid(), SIGSTOP);
+        } else if (TARGET_SIGCHLD != sig && TARGET_SIGURG != sig &&
+            TARGET_SIGWINCH != sig && TARGET_SIGCONT != sig) {
+            force_sig(sig);
+        }
+    } else if (TARGET_SIG_IGN == handler) {
+        /* ignore sig */
+#ifdef DEBUG_SIGNAL
+        fprintf(stderr, "qemu: TARGET_SIG_IGN\n");
+#endif
+    } else if (TARGET_SIG_ERR == handler) {
+#ifdef DEBUG_SIGNAL
+        fprintf(stderr, "qemu: TARGET_SIG_ERR\n");
+#endif
+        force_sig(sig);
+    } else {
+        /* compute the blocked signals during the handler execution */
+        target_to_host_sigset(&set, &sa->sa_mask);
+        /*
+         * SA_NODEFER indicates that the current signal should not be
+         * blocked during the handler.
+         */
+        if (!(sa->sa_flags & TARGET_SA_NODEFER)) {
+            sigaddset(&set, target_to_host_signal(sig));
+        }
+
+        /* block signals in the handler */
+        sigprocmask(SIG_BLOCK, &set, &old_set);
+
+        /*
+         * Save the previous blocked signal state to restore it at the
+         * end of the signal execution (see do_sigreturn).
+         */
+        host_to_target_sigset_internal(&target_old_set, &old_set);
+
+#if 0  /* not yet */
+#if defined(TARGET_I386) && !defined(TARGET_X86_64)
+        /* if the CPU is in VM86 mode, we restore the 32 bit values */
+        {
+            CPUX86State *env = cpu_env;
+            if (env->eflags & VM_MASK) {
+                save_v86_state(env);
+            }
+        }
+#endif
+#endif /* not yet */
+
+        code = q->info.si_code;
+        /* prepare the stack frame of the virtual CPU */
+        if (sa->sa_flags & TARGET_SA_SIGINFO) {
+            tswap_siginfo(&tinfo, &q->info);
+            setup_frame(sig, code, sa, &target_old_set, &tinfo, cpu_env);
+        } else {
+            setup_frame(sig, code, sa, &target_old_set, NULL, cpu_env);
+        }
+        if (sa->sa_flags & TARGET_SA_RESETHAND) {
+            sa->_sa_handler = TARGET_SIG_DFL;
+        }
+    }
+    if (q != &k->info) {
+        free_sigqueue(cpu_env, q);
+    }
 }
diff --git a/bsd-user/sparc/target_arch_signal.h b/bsd-user/sparc/target_arch_signal.h
new file mode 100644
index 0000000..f934f8c
--- /dev/null
+++ b/bsd-user/sparc/target_arch_signal.h
@@ -0,0 +1,77 @@
+#ifndef TARGET_ARCH_SIGNAL_H
+#define TARGET_ARCH_SIGNAL_H
+
+#include "cpu.h"
+
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE   (0) */       /* XXX to be added. */
+
+/* compare to  sparc64/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (1024 * 4)              /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to sparc64/sparc64/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long set_sigtramp_args(CPUSPARCState *regs,
+        int sig, struct target_sigframe *frame, abi_ulong frame_addr,
+        struct target_sigaction *ka)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to sparc64/sparc64/machdep.c get_mcontext() */
+static inline abi_long get_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int flags)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to sparc64/space64/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUSPARCState *regs,
+        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    /* XXX */
+    *target_uc = 0;
+    return -TARGET_EOPNOTSUPP;
+}
+
+#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/sparc64/target_arch_signal.h b/bsd-user/sparc64/target_arch_signal.h
new file mode 100644
index 0000000..1529b0f
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_signal.h
@@ -0,0 +1,94 @@
+/*
+ *  sparc64 dependent signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE    (0) */      /* XXX to be added. */
+
+/* compare to  sparc64/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (1024 * 4)              /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to sparc64/sparc64/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long set_sigtramp_args(CPUSPARCState *regs,
+        int sig, struct target_sigframe *frame, abi_ulong frame_addr,
+        struct target_sigaction *ka)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to sparc64/sparc64/machdep.c get_mcontext() */
+static inline abi_long get_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int flags)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to sparc64/space64/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUSPARCState *regs,
+        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    /* XXX */
+    *target_uc = 0;
+    return -TARGET_EOPNOTSUPP;
+}
+
+#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 0996787..bc4a7e4 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -39,8 +39,12 @@
 
 #define target_to_host_bitmask(x, tbl) (x)
 
+/* BSD independent syscall shims */
+#include "bsd-signal.h"
+
 /* *BSD dependent syscall shims */
 #include "os-time.h"
+#include "os-signal.h"
 
 /* #define DEBUG */
 
@@ -326,6 +330,61 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * signal system calls
+         */
+    case TARGET_FREEBSD_NR_sigtimedwait: /* sigtimedwait(2) */
+        ret = do_freebsd_sigtimedwait(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigaction: /* sigaction(2) */
+        ret = do_bsd_sigaction(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigprocmask: /* sigprocmask(2) */
+        ret = do_bsd_sigprocmask(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigpending: /* sigpending(2) */
+        ret = do_bsd_sigpending(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sigsuspend: /* sigsuspend(2) */
+        ret = do_bsd_sigsuspend(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sigreturn: /* sigreturn(2) */
+        ret = do_bsd_sigreturn(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sigwait: /* sigwait(2) */
+        ret = do_bsd_sigwait(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigwaitinfo: /* sigwaitinfo(2) */
+        ret = do_bsd_sigwaitinfo(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sigqueue: /* sigqueue(2) */
+        ret = do_bsd_sigqueue(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigaltstack: /* sigaltstack(2) */
+        ret = do_bsd_sigaltstack(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kill: /* kill(2) */
+        ret = do_bsd_kill(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_killpg: /* killpg(2) */
+        ret = do_bsd_killpg(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_pdkill: /* pdkill(2) */
+        ret = do_freebsd_pdkill(arg1, arg2);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
diff --git a/bsd-user/x86_64/target_arch_signal.h b/bsd-user/x86_64/target_arch_signal.h
new file mode 100644
index 0000000..1998570
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_signal.h
@@ -0,0 +1,94 @@
+/*
+ *  x86_64 signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE    (0) */   /* XXX to be added */
+
+/* compare to  x86/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (512 * 4)               /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to amd64/amd64/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long set_sigtramp_args(CPUX86State *regs,
+        int sig, struct target_sigframe *frame, abi_ulong frame_addr,
+        struct target_sigaction *ka)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to amd64/amd64/machdep.c get_mcontext() */
+static inline abi_long get_mcontext(CPUX86State *regs,
+                target_mcontext_t *mcp, int flags)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to amd64/amd64/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUX86State *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUX86State *regs,
+        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    /* XXX */
+    *target_uc = 0;
+    return -TARGET_EOPNOTSUPP;
+}
+
+#endif /* !TARGET_ARCH_SIGNAL_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 08/18] bsd-user: move target arch and host OS dependent code out of elfload.c
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (6 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 07/18] bsd-user: add support for freebsd signal " Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 09/18] bsd-user: add support for freebsd process related system calls Stacey Son
                   ` (31 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change moves ELF and thread start up code from elfload.c to the host
OS and arch dependent directories.  This eliminates many of the #ifdef's
in elfload.c and moves the target arch and OS dependent code into its own
directories.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/arm/target_arch_elf.h        |   54 ++
 bsd-user/arm/target_arch_thread.h     |   62 +++
 bsd-user/elfload.c                    |  938 +++++++--------------------------
 bsd-user/freebsd/target_os_elf.h      |  145 +++++
 bsd-user/freebsd/target_os_thread.h   |    6 +
 bsd-user/i386/target_arch_elf.h       |   62 +++
 bsd-user/i386/target_arch_thread.h    |   45 ++
 bsd-user/mips/target_arch_elf.h       |   36 ++
 bsd-user/mips/target_arch_thread.h    |   54 ++
 bsd-user/mips64/target_arch_elf.h     |   36 ++
 bsd-user/mips64/target_arch_thread.h  |   54 ++
 bsd-user/netbsd/target_os_elf.h       |  226 ++++++++
 bsd-user/netbsd/target_os_thread.h    |    6 +
 bsd-user/openbsd/target_os_elf.h      |  226 ++++++++
 bsd-user/openbsd/target_os_thread.h   |    6 +
 bsd-user/sparc/target_arch_elf.h      |   30 +
 bsd-user/sparc/target_arch_thread.h   |   39 ++
 bsd-user/sparc64/target_arch_elf.h    |   34 ++
 bsd-user/sparc64/target_arch_thread.h |   55 ++
 bsd-user/syscall_defs.h               |   64 +++
 bsd-user/x86_64/target_arch_elf.h     |   55 ++
 bsd-user/x86_64/target_arch_thread.h  |   40 ++
 22 files changed, 1518 insertions(+), 755 deletions(-)
 create mode 100644 bsd-user/arm/target_arch_elf.h
 create mode 100644 bsd-user/arm/target_arch_thread.h
 create mode 100644 bsd-user/freebsd/target_os_elf.h
 create mode 100644 bsd-user/freebsd/target_os_thread.h
 create mode 100644 bsd-user/i386/target_arch_elf.h
 create mode 100644 bsd-user/i386/target_arch_thread.h
 create mode 100644 bsd-user/mips/target_arch_elf.h
 create mode 100644 bsd-user/mips/target_arch_thread.h
 create mode 100644 bsd-user/mips64/target_arch_elf.h
 create mode 100644 bsd-user/mips64/target_arch_thread.h
 create mode 100644 bsd-user/netbsd/target_os_elf.h
 create mode 100644 bsd-user/netbsd/target_os_thread.h
 create mode 100644 bsd-user/openbsd/target_os_elf.h
 create mode 100644 bsd-user/openbsd/target_os_thread.h
 create mode 100644 bsd-user/sparc/target_arch_elf.h
 create mode 100644 bsd-user/sparc/target_arch_thread.h
 create mode 100644 bsd-user/sparc64/target_arch_elf.h
 create mode 100644 bsd-user/sparc64/target_arch_thread.h
 create mode 100644 bsd-user/x86_64/target_arch_elf.h
 create mode 100644 bsd-user/x86_64/target_arch_thread.h

diff --git a/bsd-user/arm/target_arch_elf.h b/bsd-user/arm/target_arch_elf.h
new file mode 100644
index 0000000..c408cea
--- /dev/null
+++ b/bsd-user/arm/target_arch_elf.h
@@ -0,0 +1,54 @@
+/*
+ *  arm ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_ARM )
+
+#define ELF_CLASS       ELFCLASS32
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+#define ELF_ARCH        EM_ARM
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+enum
+{
+  ARM_HWCAP_ARM_SWP       = 1 << 0,
+  ARM_HWCAP_ARM_HALF      = 1 << 1,
+  ARM_HWCAP_ARM_THUMB     = 1 << 2,
+  ARM_HWCAP_ARM_26BIT     = 1 << 3,
+  ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
+  ARM_HWCAP_ARM_FPA       = 1 << 5,
+  ARM_HWCAP_ARM_VFP       = 1 << 6,
+  ARM_HWCAP_ARM_EDSP      = 1 << 7,
+};
+
+#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
+                    | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
+                    | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
+
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/arm/target_arch_thread.h b/bsd-user/arm/target_arch_thread.h
new file mode 100644
index 0000000..de6615b
--- /dev/null
+++ b/bsd-user/arm/target_arch_thread.h
@@ -0,0 +1,62 @@
+/*
+ *  arm thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to arm/arm/vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUARMState *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    abi_ulong sp;
+
+    sp = ((stack_base + stack_size) & (8 - 1)) -
+        sizeof(struct target_trapframe);
+
+    /* fp = sp = stack base */
+    regs->regs[11] = regs->regs[13] = sp;
+    /* pc = start function entry */
+    regs->regs[15] = regs->regs[14] = entry & 0xfffffffe;
+    /* r0 = arg */
+    regs->regs[0] = arg;
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    abi_long stack = infop->start_stack;
+    memset(regs, 0, sizeof(*regs));
+    regs->ARM_cpsr = 0x10;
+    if (infop->entry & 1)
+      regs->ARM_cpsr |= CPSR_T;
+    regs->ARM_pc = infop->entry & 0xfffffffe;
+    regs->ARM_sp = infop->start_stack;
+    if (bsd_type == target_freebsd) {
+        regs->ARM_lr = infop->entry & 0xfffffffe;
+    }
+    /* FIXME - what to for failure of get_user()? */
+    get_user_ual(regs->ARM_r2, stack + 8); /* envp */
+    get_user_ual(regs->ARM_r1, stack + 4); /* envp */
+    /* XXX: it seems that r0 is zeroed after ! */
+    regs->ARM_r0 = 0;
+    /* For uClinux PIC binaries.  */
+    /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
+    regs->ARM_r10 = infop->start_data;
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 68d0209..c791a61 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -1,4 +1,20 @@
-/* This is the Linux kernel elf-loading code, ported into user space */
+/*
+ *  ELF loading code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
 
 #include <stdio.h>
 #include <sys/types.h>
@@ -11,548 +27,13 @@
 
 #include "qemu.h"
 #include "disas/disas.h"
-
-#ifdef _ARCH_PPC64
-#undef ARCH_DLINFO
-#undef ELF_PLATFORM
-#undef ELF_HWCAP
-#undef ELF_CLASS
-#undef ELF_DATA
-#undef ELF_ARCH
-#endif
-
-/* from personality.h */
-
-/*
- * Flags for bug emulation.
- *
- * These occupy the top three bytes.
- */
-enum {
-        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA space */
-        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs point to descriptors
-                                                 * (signal handling)
-                                                 */
-        MMAP_PAGE_ZERO =        0x0100000,
-        ADDR_COMPAT_LAYOUT =    0x0200000,
-        READ_IMPLIES_EXEC =     0x0400000,
-        ADDR_LIMIT_32BIT =      0x0800000,
-        SHORT_INODE =           0x1000000,
-        WHOLE_SECONDS =         0x2000000,
-        STICKY_TIMEOUTS =       0x4000000,
-        ADDR_LIMIT_3GB =        0x8000000,
-};
-
-/*
- * Personality types.
- *
- * These go in the low byte.  Avoid using the top bit, it will
- * conflict with error returns.
- */
-enum {
-        PER_LINUX =             0x0000,
-        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
-        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
-        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
-        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
-        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
-                                         WHOLE_SECONDS | SHORT_INODE,
-        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
-        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
-        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
-        PER_BSD =               0x0006,
-        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
-        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
-        PER_LINUX32 =           0x0008,
-        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
-        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
-        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
-        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
-        PER_RISCOS =            0x000c,
-        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
-        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
-        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
-        PER_HPUX =              0x0010,
-        PER_MASK =              0x00ff,
-};
-
-/*
- * Return the base personality without flags.
- */
-#define personality(pers)       (pers & PER_MASK)
-
-/* this flag is uneffective under linux too, should be deleted */
-#ifndef MAP_DENYWRITE
-#define MAP_DENYWRITE 0
-#endif
-
-/* should probably go in elf.h */
-#ifndef ELIBBAD
-#define ELIBBAD 80
-#endif
+#include "target_os_elf.h"
+#include "target_os_stack.h"
+#include "target_os_thread.h"
 
 abi_ulong target_stksiz;
 abi_ulong target_stkbas;
 
-#ifdef TARGET_I386
-
-#define ELF_PLATFORM get_elf_platform()
-
-static const char *get_elf_platform(void)
-{
-    static char elf_platform[] = "i386";
-    int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
-    if (family > 6)
-        family = 6;
-    if (family >= 3)
-        elf_platform[1] = '0' + family;
-    return elf_platform;
-}
-
-#define ELF_HWCAP get_elf_hwcap()
-
-static uint32_t get_elf_hwcap(void)
-{
-    X86CPU *cpu = X86_CPU(thread_cpu);
-
-    return cpu->env.features[FEAT_1_EDX];
-}
-
-#ifdef TARGET_X86_64
-#define ELF_START_MMAP 0x2aaaaab000ULL
-#define elf_check_arch(x) ( ((x) == ELF_ARCH) )
-
-#define ELF_CLASS      ELFCLASS64
-#define ELF_DATA       ELFDATA2LSB
-#define ELF_ARCH       EM_X86_64
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->rax = 0;
-    regs->rsp = infop->start_stack;
-    regs->rip = infop->entry;
-    if (bsd_type == target_freebsd) {
-        regs->rdi = infop->start_stack;
-    }
-}
-
-#else
-
-#define ELF_START_MMAP 0x80000000
-
-/*
- * This is used to ensure we don't load something for the wrong architecture.
- */
-#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
-
-/*
- * These are used to set parameters in the core dumps.
- */
-#define ELF_CLASS       ELFCLASS32
-#define ELF_DATA        ELFDATA2LSB
-#define ELF_ARCH        EM_386
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->esp = infop->start_stack;
-    regs->eip = infop->entry;
-
-    /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
-       starts %edx contains a pointer to a function which might be
-       registered using `atexit'.  This provides a mean for the
-       dynamic linker to call DT_FINI functions for shared libraries
-       that have been loaded before the code runs.
-
-       A value of 0 tells we have no such handler.  */
-    regs->edx = 0;
-}
-#endif
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       4096
-
-#endif
-
-#ifdef TARGET_ARM
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_ARM )
-
-#define ELF_CLASS       ELFCLASS32
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA        ELFDATA2MSB
-#else
-#define ELF_DATA        ELFDATA2LSB
-#endif
-#define ELF_ARCH        EM_ARM
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    abi_long stack = infop->start_stack;
-    memset(regs, 0, sizeof(*regs));
-    regs->ARM_cpsr = 0x10;
-    if (infop->entry & 1)
-      regs->ARM_cpsr |= CPSR_T;
-    regs->ARM_pc = infop->entry & 0xfffffffe;
-    regs->ARM_sp = infop->start_stack;
-    /* FIXME - what to for failure of get_user()? */
-    get_user_ual(regs->ARM_r2, stack + 8); /* envp */
-    get_user_ual(regs->ARM_r1, stack + 4); /* envp */
-    /* XXX: it seems that r0 is zeroed after ! */
-    regs->ARM_r0 = 0;
-    /* For uClinux PIC binaries.  */
-    /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
-    regs->ARM_r10 = infop->start_data;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       4096
-
-enum
-{
-  ARM_HWCAP_ARM_SWP       = 1 << 0,
-  ARM_HWCAP_ARM_HALF      = 1 << 1,
-  ARM_HWCAP_ARM_THUMB     = 1 << 2,
-  ARM_HWCAP_ARM_26BIT     = 1 << 3,
-  ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
-  ARM_HWCAP_ARM_FPA       = 1 << 5,
-  ARM_HWCAP_ARM_VFP       = 1 << 6,
-  ARM_HWCAP_ARM_EDSP      = 1 << 7,
-};
-
-#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
-                    | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
-                    | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
-
-#endif
-
-#ifdef TARGET_SPARC
-#ifdef TARGET_SPARC64
-
-#define ELF_START_MMAP 0x80000000
-
-#ifndef TARGET_ABI32
-#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
-#else
-#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
-#endif
-
-#define ELF_CLASS   ELFCLASS64
-#define ELF_DATA    ELFDATA2MSB
-#define ELF_ARCH    EM_SPARCV9
-
-#define STACK_BIAS              2047
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-#ifndef TARGET_ABI32
-    regs->tstate = 0;
-#endif
-    regs->pc = infop->entry;
-    regs->npc = regs->pc + 4;
-    regs->y = 0;
-#ifdef TARGET_ABI32
-    regs->u_regs[14] = infop->start_stack - 16 * 4;
-#else
-    if (personality(infop->personality) == PER_LINUX32)
-        regs->u_regs[14] = infop->start_stack - 16 * 4;
-    else {
-        regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
-        if (bsd_type == target_freebsd) {
-            regs->u_regs[8] = infop->start_stack;
-            regs->u_regs[11] = infop->start_stack;
-        }
-    }
-#endif
-}
-
-#else
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_SPARC )
-
-#define ELF_CLASS   ELFCLASS32
-#define ELF_DATA    ELFDATA2MSB
-#define ELF_ARCH    EM_SPARC
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->psr = 0;
-    regs->pc = infop->entry;
-    regs->npc = regs->pc + 4;
-    regs->y = 0;
-    regs->u_regs[14] = infop->start_stack - 16 * 4;
-}
-
-#endif
-#endif
-
-#ifdef TARGET_PPC
-
-#define ELF_START_MMAP 0x80000000
-
-#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-
-#define elf_check_arch(x) ( (x) == EM_PPC64 )
-
-#define ELF_CLASS       ELFCLASS64
-
-#else
-
-#define elf_check_arch(x) ( (x) == EM_PPC )
-
-#define ELF_CLASS       ELFCLASS32
-
-#endif
-
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA        ELFDATA2MSB
-#else
-#define ELF_DATA        ELFDATA2LSB
-#endif
-#define ELF_ARCH        EM_PPC
-
-/*
- * We need to put in some extra aux table entries to tell glibc what
- * the cache block size is, so it can use the dcbz instruction safely.
- */
-#define AT_DCACHEBSIZE          19
-#define AT_ICACHEBSIZE          20
-#define AT_UCACHEBSIZE          21
-/* A special ignored type value for PPC, for glibc compatibility.  */
-#define AT_IGNOREPPC            22
-/*
- * The requirements here are:
- * - keep the final alignment of sp (sp & 0xf)
- * - make sure the 32-bit value at the first 16 byte aligned position of
- *   AUXV is greater than 16 for glibc compatibility.
- *   AT_IGNOREPPC is used for that.
- * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
- *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
- */
-#define DLINFO_ARCH_ITEMS       5
-#define ARCH_DLINFO                                                     \
-do {                                                                    \
-        NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);                              \
-        NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);                              \
-        NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                                 \
-        /*                                                              \
-         * Now handle glibc compatibility.                              \
-         */                                                             \
-        NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);                        \
-        NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);                        \
- } while (0)
-
-static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
-{
-    abi_ulong pos = infop->start_stack;
-    abi_ulong tmp;
-#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-    abi_ulong entry, toc;
-#endif
-
-    _regs->gpr[1] = infop->start_stack;
-#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-    entry = ldq_raw(infop->entry) + infop->load_addr;
-    toc = ldq_raw(infop->entry + 8) + infop->load_addr;
-    _regs->gpr[2] = toc;
-    infop->entry = entry;
-#endif
-    _regs->nip = infop->entry;
-    /* Note that isn't exactly what regular kernel does
-     * but this is what the ABI wants and is needed to allow
-     * execution of PPC BSD programs.
-     */
-    /* FIXME - what to for failure of get_user()? */
-    get_user_ual(_regs->gpr[3], pos);
-    pos += sizeof(abi_ulong);
-    _regs->gpr[4] = pos;
-    for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong))
-        tmp = ldl(pos);
-    _regs->gpr[5] = pos;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       4096
-
-#endif
-
-#ifdef TARGET_MIPS
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_MIPS )
-
-#ifdef TARGET_MIPS64
-#define ELF_CLASS   ELFCLASS64
-#else
-#define ELF_CLASS   ELFCLASS32
-#endif
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA        ELFDATA2MSB
-#else
-#define ELF_DATA        ELFDATA2LSB
-#endif
-#define ELF_ARCH    EM_MIPS
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->cp0_status = 2 << CP0St_KSU;
-    regs->cp0_epc = infop->entry;
-    regs->regs[29] = infop->start_stack;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE        4096
-
-#endif /* TARGET_MIPS */
-
-#ifdef TARGET_SH4
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_SH )
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA  ELFDATA2LSB
-#define ELF_ARCH  EM_SH
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-  /* Check other registers XXXXX */
-  regs->pc = infop->entry;
-  regs->regs[15] = infop->start_stack;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE        4096
-
-#endif
-
-#ifdef TARGET_CRIS
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_CRIS )
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA  ELFDATA2LSB
-#define ELF_ARCH  EM_CRIS
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-  regs->erp = infop->entry;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE        8192
-
-#endif
-
-#ifdef TARGET_M68K
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_68K )
-
-#define ELF_CLASS       ELFCLASS32
-#define ELF_DATA        ELFDATA2MSB
-#define ELF_ARCH        EM_68K
-
-/* ??? Does this need to do anything?
-#define ELF_PLAT_INIT(_r) */
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->usp = infop->start_stack;
-    regs->sr = 0;
-    regs->pc = infop->entry;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       8192
-
-#endif
-
-#ifdef TARGET_ALPHA
-
-#define ELF_START_MMAP (0x30000000000ULL)
-
-#define elf_check_arch(x) ( (x) == ELF_ARCH )
-
-#define ELF_CLASS      ELFCLASS64
-#define ELF_DATA       ELFDATA2MSB
-#define ELF_ARCH       EM_ALPHA
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->pc = infop->entry;
-    regs->ps = 8;
-    regs->usp = infop->start_stack;
-    regs->unique = infop->start_data; /* ? */
-    printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n",
-           regs->unique, infop->start_data);
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE        8192
-
-#endif /* TARGET_ALPHA */
-
-#ifndef ELF_PLATFORM
-#define ELF_PLATFORM (NULL)
-#endif
-
-#ifndef ELF_HWCAP
-#define ELF_HWCAP 0
-#endif
-
-#ifdef TARGET_ABI32
-#undef ELF_CLASS
-#define ELF_CLASS ELFCLASS32
-#undef bswaptls
-#define bswaptls(ptr) bswap32s(ptr)
-#endif
-
-#include "elf.h"
-
-struct exec
-{
-  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
-  unsigned int a_text;   /* length of text, in bytes */
-  unsigned int a_data;   /* length of data, in bytes */
-  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
-  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
-  unsigned int a_entry;  /* start address */
-  unsigned int a_trsize; /* length of relocation info for text, in bytes */
-  unsigned int a_drsize; /* length of relocation info for data, in bytes */
-};
-
-
-#define N_MAGIC(exec) ((exec).a_info & 0xffff)
-#define OMAGIC 0407
-#define NMAGIC 0410
-#define ZMAGIC 0413
-#define QMAGIC 0314
-
-/* max code+data+bss space allocated to elf interpreter */
-#define INTERP_MAP_SIZE (32 * 1024 * 1024)
-
-/* max code+data+bss+brk space allocated to ET_DYN executables */
-#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
-
-/* Necessary parameters */
-#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
-#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
-#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
-
-#define INTERPRETER_NONE 0
-#define INTERPRETER_AOUT 1
-#define INTERPRETER_ELF 2
-
-#define DLINFO_ITEMS 12
-
 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
 {
         memcpy(to, from, n);
@@ -563,7 +44,7 @@ static int load_aout_interp(void * exptr, int interp_fd);
 #ifdef BSWAP_NEEDED
 static void bswap_ehdr(struct elfhdr *ehdr)
 {
-    bswap16s(&ehdr->e_type);                    /* Object file type */
+    bswap16s(&ehdr->e_type);            /* Object file type */
     bswap16s(&ehdr->e_machine);         /* Architecture */
     bswap32s(&ehdr->e_version);         /* Object file version */
     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
@@ -571,37 +52,45 @@ static void bswap_ehdr(struct elfhdr *ehdr)
     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
-    bswap16s(&ehdr->e_phentsize);               /* Program header table entry size */
+    bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
-    bswap16s(&ehdr->e_shentsize);               /* Section header table entry size */
+    bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
-    bswap16s(&ehdr->e_shstrndx);                /* Section header string table index */
+    bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
 }
 
-static void bswap_phdr(struct elf_phdr *phdr)
+static void bswap_phdr(struct elf_phdr *phdr, int phnum)
 {
-    bswap32s(&phdr->p_type);                    /* Segment type */
-    bswaptls(&phdr->p_offset);          /* Segment file offset */
-    bswaptls(&phdr->p_vaddr);           /* Segment virtual address */
-    bswaptls(&phdr->p_paddr);           /* Segment physical address */
-    bswaptls(&phdr->p_filesz);          /* Segment size in file */
-    bswaptls(&phdr->p_memsz);           /* Segment size in memory */
-    bswap32s(&phdr->p_flags);           /* Segment flags */
-    bswaptls(&phdr->p_align);           /* Segment alignment */
+    int i;
+
+    for (i = 0; i < phnum; i++, phdr++) {
+        bswap32s(&phdr->p_type);        /* Segment type */
+        bswaptls(&phdr->p_offset);      /* Segment file offset */
+        bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
+        bswaptls(&phdr->p_paddr);       /* Segment physical address */
+        bswaptls(&phdr->p_filesz);      /* Segment size in file */
+        bswaptls(&phdr->p_memsz);       /* Segment size in memory */
+        bswap32s(&phdr->p_flags);       /* Segment flags */
+        bswaptls(&phdr->p_align);       /* Segment alignment */
+    }
 }
 
-static void bswap_shdr(struct elf_shdr *shdr)
+static void bswap_shdr(struct elf_shdr *shdr, int shnum)
 {
-    bswap32s(&shdr->sh_name);
-    bswap32s(&shdr->sh_type);
-    bswaptls(&shdr->sh_flags);
-    bswaptls(&shdr->sh_addr);
-    bswaptls(&shdr->sh_offset);
-    bswaptls(&shdr->sh_size);
-    bswap32s(&shdr->sh_link);
-    bswap32s(&shdr->sh_info);
-    bswaptls(&shdr->sh_addralign);
-    bswaptls(&shdr->sh_entsize);
+    int i;
+
+    for (i = 0; i < shnum; i++, shdr++) {
+        bswap32s(&shdr->sh_name);
+        bswap32s(&shdr->sh_type);
+        bswaptls(&shdr->sh_flags);
+        bswaptls(&shdr->sh_addr);
+        bswaptls(&shdr->sh_offset);
+        bswaptls(&shdr->sh_size);
+        bswap32s(&shdr->sh_link);
+        bswap32s(&shdr->sh_info);
+        bswaptls(&shdr->sh_addralign);
+        bswaptls(&shdr->sh_entsize);
+    }
 }
 
 static void bswap_sym(struct elf_sym *sym)
@@ -611,7 +100,15 @@ static void bswap_sym(struct elf_sym *sym)
     bswaptls(&sym->st_size);
     bswap16s(&sym->st_shndx);
 }
-#endif
+
+#else /* ! BSWAP_NEEDED */
+
+static void bswap_ehdr(struct elfhdr *ehdr) { }
+static void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
+static void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
+static void bswap_sym(struct elf_sym *sym) { }
+
+#endif /* ! BSWAP_NEEDED */
 
 /*
  * 'copy_elf_strings()' copies argument/envelope strings from user
@@ -671,39 +168,31 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
 static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm,
                                  struct image_info *info)
 {
-    abi_ulong stack_base, size, error;
-    int i;
+    abi_ulong stack_base, size;
+    abi_long addr;
 
     /* Create enough stack to hold everything.  If we don't use
      * it for args, we'll use it for something else...
      */
     size = target_dflssiz;
-    if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
-        size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
-    error = target_mmap(0,
-                        size + qemu_host_page_size,
-                        PROT_READ | PROT_WRITE,
-                        MAP_PRIVATE | MAP_ANON,
-                        -1, 0);
-    if (error == -1) {
+    stack_base = TARGET_USRSTACK - size;
+    addr = target_mmap(stack_base , size + qemu_host_page_size,
+            PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+    if (addr == -1) {
         perror("stk mmap");
         exit(-1);
     }
     /* we reserve one extra page at the top of the stack as guard */
-    target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
+    target_mprotect(addr + size, qemu_host_page_size, PROT_NONE);
 
-    stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
-    p += stack_base;
+    target_stksiz = size;
+    target_stkbas = addr;
 
-    for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-        if (bprm->page[i]) {
-            info->rss++;
-            /* FIXME - check return value of memcpy_to_target() for failure */
-            memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
-            g_free(bprm->page[i]);
-        }
-        stack_base += TARGET_PAGE_SIZE;
+    if (setup_initial_stack(bprm, &p) != 0) {
+        perror("stk setup");
+        exit(-1);
     }
+
     return p;
 }
 
@@ -761,86 +250,6 @@ static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
         }
 }
 
-
-static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
-                                   struct elfhdr * exec,
-                                   abi_ulong load_addr,
-                                   abi_ulong load_bias,
-                                   abi_ulong interp_load_addr, int ibcs,
-                                   struct image_info *info)
-{
-        abi_ulong sp;
-        int size;
-        abi_ulong u_platform;
-        const char *k_platform;
-        const int n = sizeof(elf_addr_t);
-
-        sp = p;
-        u_platform = 0;
-        k_platform = ELF_PLATFORM;
-        if (k_platform) {
-            size_t len = strlen(k_platform) + 1;
-            sp -= (len + n - 1) & ~(n - 1);
-            u_platform = sp;
-            /* FIXME - check return value of memcpy_to_target() for failure */
-            memcpy_to_target(sp, k_platform, len);
-        }
-        /*
-         * Force 16 byte _final_ alignment here for generality.
-         */
-        sp = sp &~ (abi_ulong)15;
-        size = (DLINFO_ITEMS + 1) * 2;
-        if (k_platform)
-          size += 2;
-#ifdef DLINFO_ARCH_ITEMS
-        size += DLINFO_ARCH_ITEMS * 2;
-#endif
-        size += envc + argc + 2;
-        size += (!ibcs ? 3 : 1);        /* argc itself */
-        size *= n;
-        if (size & 15)
-            sp -= 16 - (size & 15);
-
-        /* This is correct because Linux defines
-         * elf_addr_t as Elf32_Off / Elf64_Off
-         */
-#define NEW_AUX_ENT(id, val) do {               \
-            sp -= n; put_user_ual(val, sp);     \
-            sp -= n; put_user_ual(id, sp);      \
-          } while(0)
-
-        NEW_AUX_ENT (AT_NULL, 0);
-
-        /* There must be exactly DLINFO_ITEMS entries here.  */
-        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
-        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
-        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
-        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
-        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
-        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
-        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
-        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
-        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
-        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
-        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
-        NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
-        NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
-        if (k_platform)
-            NEW_AUX_ENT(AT_PLATFORM, u_platform);
-#ifdef ARCH_DLINFO
-        /*
-         * ARCH_DLINFO must come last so platform specific code can enforce
-         * special alignment requirements on the AUXV if necessary (eg. PPC).
-         */
-        ARCH_DLINFO;
-#endif
-#undef NEW_AUX_ENT
-
-        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
-        return sp;
-}
-
-
 static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                                  int interpreter_fd,
                                  abi_ulong *interp_load_addr)
@@ -858,9 +267,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
         last_bss = 0;
         error = 0;
 
-#ifdef BSWAP_NEEDED
         bswap_ehdr(interp_elf_ex);
-#endif
         /* First of all, some simple consistency checks */
         if ((interp_elf_ex->e_type != ET_EXEC &&
              interp_elf_ex->e_type != ET_DYN) ||
@@ -901,12 +308,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                 free (elf_phdata);
                 return retval;
         }
-#ifdef BSWAP_NEEDED
-        eppnt = elf_phdata;
-        for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
-            bswap_phdr(eppnt);
-        }
-#endif
+        bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
 
         if (interp_elf_ex->e_type == ET_DYN) {
             /* in order to avoid hardcoding the interpreter load
@@ -923,54 +325,57 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
         }
 
         eppnt = elf_phdata;
-        for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
-          if (eppnt->p_type == PT_LOAD) {
-            int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
-            int elf_prot = 0;
-            abi_ulong vaddr = 0;
-            abi_ulong k;
-
-            if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
-            if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-            if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-            if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
-                elf_type |= MAP_FIXED;
-                vaddr = eppnt->p_vaddr;
-            }
-            error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
-                 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
-                 elf_prot,
-                 elf_type,
-                 interpreter_fd,
-                 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
-
-            if (error == -1) {
-              /* Real error */
-              close(interpreter_fd);
-              free(elf_phdata);
-              return ~((abi_ulong)0UL);
-            }
-
-            if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
-              load_addr = error;
-              load_addr_set = 1;
+        for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++)
+            if (eppnt->p_type == PT_LOAD) {
+                int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+                int elf_prot = 0;
+                abi_ulong vaddr = 0;
+                abi_ulong k;
+
+                if (eppnt->p_flags & PF_R) {
+                    elf_prot =  PROT_READ;
+                }
+                if (eppnt->p_flags & PF_W) {
+                    elf_prot |= PROT_WRITE;
+                }
+                if (eppnt->p_flags & PF_X) {
+                    elf_prot |= PROT_EXEC;
+                }
+                if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
+                    elf_type |= MAP_FIXED;
+                    vaddr = eppnt->p_vaddr;
+                }
+                error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
+                        eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
+                        elf_prot, elf_type, interpreter_fd, eppnt->p_offset -
+                        TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
+                if (error == -1) {
+                    /* Real error */
+                    close(interpreter_fd);
+                    free(elf_phdata);
+                    return ~((abi_ulong)0UL);
+                }
+                if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+                    load_addr = error;
+                    load_addr_set = 1;
+                }
+                /*
+                 * Find the end of the file  mapping for this phdr, and keep
+                 * track of the largest address we see for this.
+                 */
+                k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
+                if (k > elf_bss) {
+                    elf_bss = k;
+                }
+                /*
+                 * Do the same thing for the memory mapping - between
+                 * elf_bss and last_bss is the bss section.
+                 */
+                k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+                if (k > last_bss) {
+                    last_bss = k;
+                }
             }
-
-            /*
-             * Find the end of the file  mapping for this phdr, and keep
-             * track of the largest address we see for this.
-             */
-            k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
-            if (k > elf_bss) elf_bss = k;
-
-            /*
-             * Do the same thing for the memory mapping - between
-             * elf_bss and last_bss is the bss section.
-             */
-            k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
-            if (k > last_bss) last_bss = k;
-          }
-
         /* Now use mmap to map the library into memory. */
 
         close(interpreter_fd);
@@ -982,7 +387,8 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
          * bss page.
          */
         padzero(elf_bss, last_bss);
-        elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
+        /* What we have mapped so far */
+        elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1);
 
         /* Map the last of the bss segment */
         if (last_bss > elf_bss) {
@@ -1051,9 +457,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
     for (i = 0; i < hdr->e_shnum; i++) {
         if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
             return;
-#ifdef BSWAP_NEEDED
-        bswap_shdr(&sechdr);
-#endif
+        bswap_shdr(&sechdr, 1);
         if (sechdr.sh_type == SHT_SYMTAB) {
             symtab = sechdr;
             lseek(fd, hdr->e_shoff
@@ -1061,9 +465,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
             if (read(fd, &strtab, sizeof(strtab))
                 != sizeof(strtab))
                 return;
-#ifdef BSWAP_NEEDED
-            bswap_shdr(&strtab);
-#endif
+            bswap_shdr(&strtab, 1);
             goto found;
         }
     }
@@ -1096,9 +498,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
 
     i = 0;
     while (i < nsyms) {
-#ifdef BSWAP_NEEDED
         bswap_sym(syms + i);
-#endif
         // Throw away entries which we do not need.
         if (syms[i].st_shndx == SHN_UNDEF ||
                 syms[i].st_shndx >= SHN_LORESERVE ||
@@ -1150,6 +550,30 @@ static void load_symbols(struct elfhdr *hdr, int fd)
     syminfos = s;
 }
 
+/* Check the elf header and see if this a target elf binary. */
+int is_target_elf_binary(int fd)
+{
+    uint8_t buf[128];
+    struct elfhdr elf_ex;
+
+    if (lseek(fd, 0L, SEEK_SET) < 0) {
+        return 0;
+    }
+    if (read(fd, buf, sizeof(buf)) < 0) {
+        return 0;
+    }
+
+    elf_ex = *((struct elfhdr *)buf);
+    bswap_ehdr(&elf_ex);
+
+    if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
+        (!elf_check_arch(elf_ex.e_machine))) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
 int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
                     struct image_info *info)
 {
@@ -1180,9 +604,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
     load_addr = 0;
     load_bias = 0;
     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
-#ifdef BSWAP_NEEDED
     bswap_ehdr(&elf_ex);
-#endif
 
     /* First of all, some simple consistency checks */
     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
@@ -1190,12 +612,14 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
             return -ENOEXEC;
     }
 
+#ifndef __FreeBSD__
     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
     if (!bprm->p) {
         retval = -E2BIG;
     }
+#endif /* ! __FreeBSD__ */
 
     /* Now read in all of the header information */
     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
@@ -1216,12 +640,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
         return -errno;
     }
 
-#ifdef BSWAP_NEEDED
-    elf_ppnt = elf_phdata;
-    for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
-        bswap_phdr(elf_ppnt);
-    }
-#endif
+    bswap_phdr(elf_phdata, elf_ex.e_phnum);
     elf_ppnt = elf_phdata;
 
     elf_bss = 0;
@@ -1236,7 +655,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
     end_data = 0;
     interp_ex.a_info = 0;
 
-    for(i=0;i < elf_ex.e_phnum; i++) {
+    for (i = 0; i < elf_ex.e_phnum; i++) {
         if (elf_ppnt->p_type == PT_INTERP) {
             if ( elf_interpreter != NULL )
             {
@@ -1274,9 +693,9 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
 
             /* JRP - Need to add X86 lib dir stuff here... */
 
-            if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
-                strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
-              ibcs2_interpreter = 1;
+            if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0 ||
+                    strcmp(elf_interpreter, "/usr/lib/ld-elf.so.1") == 0) {
+                ibcs2_interpreter = 1;
             }
 
 #if 0
@@ -1406,7 +825,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
      * address.
      */
 
-    for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+    for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
         int elf_prot = 0;
         int elf_flags = 0;
         abi_ulong error;
@@ -1423,7 +842,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
         } else if (elf_ex.e_type == ET_DYN) {
             /* Try and get dynamic programs out of the way of the default mmap
                base, as well as whatever program they might try to exec.  This
-               is because the brk will follow the loader, and is not movable.  */
+               is because the brk will follow the loader, and is not movable. */
             /* NOTE: for qemu, we do a big mmap to get enough space
                without hardcoding any address */
             error = target_mmap(0, ET_DYN_MAP_SIZE,
@@ -1520,7 +939,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
 #ifdef LOW_ELF_STACK
     info->start_stack = bprm->p = elf_stack - 4;
 #endif
-    bprm->p = create_elf_tables(bprm->p,
+    bprm->p = target_create_elf_tables(bprm->p,
                     bprm->argc,
                     bprm->envc,
                     &elf_ex,
@@ -1536,19 +955,22 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
     info->end_data = end_data;
     info->start_stack = bprm->p;
 
-    /* Calling set_brk effectively mmaps the pages that we need for the bss and break
-       sections */
+    /*
+     * Calling set_brk effectively mmaps the pages that we need for the bss
+     * and break sections.
+     */
     set_brk(elf_bss, elf_brk);
 
     padzero(elf_bss, elf_brk);
 
 #if 0
-    printf("(start_brk) %x\n" , info->start_brk);
-    printf("(end_code) %x\n" , info->end_code);
-    printf("(start_code) %x\n" , info->start_code);
-    printf("(end_data) %x\n" , info->end_data);
-    printf("(start_stack) %x\n" , info->start_stack);
-    printf("(brk) %x\n" , info->brk);
+    printf("(start_brk) 0x" TARGET_FMT_lx "\n" , info->start_brk);
+    printf("(end_code) 0x" TARGET_FMT_lx "\n" , info->end_code);
+    printf("(start_code) 0x" TARGET_FMT_lx "\n" , info->start_code);
+    printf("(start_data) 0x" TARGET_FMT_lx "\n" , info->start_data);
+    printf("(end_data) 0x" TARGET_FMT_lx "\n" , info->end_data);
+    printf("(start_stack) 0x" TARGET_FMT_lx "\n" , info->start_stack);
+    printf("(brk) 0x" TARGET_FMT_lx "\n" , info->brk);
 #endif
 
     if ( info->personality == PER_SVR4 )
@@ -1557,12 +979,18 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
                and some applications "depend" upon this behavior.
                Since we do not have the power to recompile these, we
                emulate the SVr4 behavior.  Sigh.  */
-            mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
-                                      MAP_FIXED | MAP_PRIVATE, -1, 0);
+            mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ |
+                    PROT_EXEC, MAP_FIXED | MAP_PRIVATE, -1, 0);
     }
 
     info->entry = elf_entry;
 
+#ifdef USE_ELF_CORE_DUMP
+    /* not yet */
+    /* bprm->core_dump = &elf_core_dump; */
+    bprm->core_dump = NULL;
+#endif
+
     return 0;
 }
 
@@ -1574,5 +1002,5 @@ static int load_aout_interp(void * exptr, int interp_fd)
 
 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
 {
-    init_thread(regs, infop);
+    target_thread_init(regs, infop);
 }
diff --git a/bsd-user/freebsd/target_os_elf.h b/bsd-user/freebsd/target_os_elf.h
new file mode 100644
index 0000000..67637a0
--- /dev/null
+++ b/bsd-user/freebsd/target_os_elf.h
@@ -0,0 +1,145 @@
+/*
+ *  freebsd ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_OS_ELF_H_
+#define _TARGET_OS_ELF_H_
+
+#include "target_arch_elf.h"
+#include "elf.h"
+
+/* this flag is uneffective under linux too, should be deleted */
+#ifndef MAP_DENYWRITE
+#define MAP_DENYWRITE 0
+#endif
+
+/* should probably go in elf.h */
+#ifndef ELIBBAD
+#define ELIBBAD 80
+#endif
+
+#ifndef ELF_PLATFORM
+#define ELF_PLATFORM (NULL)
+#endif
+
+#ifndef ELF_HWCAP
+#define ELF_HWCAP 0
+#endif
+
+#ifdef TARGET_ABI32
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+#undef bswaptls
+#define bswaptls(ptr) bswap32s(ptr)
+#endif
+
+struct exec
+{
+  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
+  unsigned int a_text;   /* length of text, in bytes */
+  unsigned int a_data;   /* length of data, in bytes */
+  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
+  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
+  unsigned int a_entry;  /* start address */
+  unsigned int a_trsize; /* length of relocation info for text, in bytes */
+  unsigned int a_drsize; /* length of relocation info for data, in bytes */
+};
+
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+
+/* max code+data+bss space allocated to elf interpreter */
+#define INTERP_MAP_SIZE (32 * 1024 * 1024)
+
+/* max code+data+bss+brk space allocated to ET_DYN executables */
+#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
+
+/* Necessary parameters */
+#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
+#define TARGET_ELF_PAGESTART(_v) ((_v) & \
+        ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+#define DLINFO_ITEMS 12
+
+static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc,
+                                   struct elfhdr * exec,
+                                   abi_ulong load_addr,
+                                   abi_ulong load_bias,
+                                   abi_ulong interp_load_addr, int ibcs,
+                                   struct image_info *info)
+{
+        abi_ulong sp;
+        int size;
+        const int n = sizeof(elf_addr_t);
+
+        sp = p;
+        /*
+         * Force 16 byte _final_ alignment here for generality.
+         */
+        sp = sp &~ (abi_ulong)15;
+        size = (DLINFO_ITEMS + 1) * 2;
+        size += envc + argc + 2;
+        size += (!ibcs ? 3 : 1);        /* argc itself */
+        size *= n;
+        if (size & 15)
+            sp -= 16 - (size & 15);
+
+        /* This is correct because Linux defines
+         * elf_addr_t as Elf32_Off / Elf64_Off
+         */
+#define NEW_AUX_ENT(id, val) do {               \
+            sp -= n; put_user_ual(val, sp);     \
+            sp -= n; put_user_ual(id, sp);      \
+          } while(0)
+
+        NEW_AUX_ENT (AT_NULL, 0);
+
+        /* There must be exactly DLINFO_ITEMS entries here.  */
+        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+#ifdef ARCH_DLINFO
+        /*
+         * ARCH_DLINFO must come last so platform specific code can enforce
+         * special alignment requirements on the AUXV if necessary (eg. PPC).
+         */
+        ARCH_DLINFO;
+#endif
+#undef NEW_AUX_ENT
+
+        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+        return sp;
+}
+
+#endif /* _TARGET_OS_ELF_H_ */
diff --git a/bsd-user/freebsd/target_os_thread.h b/bsd-user/freebsd/target_os_thread.h
new file mode 100644
index 0000000..519aad8
--- /dev/null
+++ b/bsd-user/freebsd/target_os_thread.h
@@ -0,0 +1,6 @@
+#ifndef _TARGET_OS_THREAD_H_
+#define _TARGET_OS_THREAD_H_
+
+#include "target_arch_thread.h"
+
+#endif /* !_TARGET_OS_THREAD_H_ */
diff --git a/bsd-user/i386/target_arch_elf.h b/bsd-user/i386/target_arch_elf.h
new file mode 100644
index 0000000..83b2197
--- /dev/null
+++ b/bsd-user/i386/target_arch_elf.h
@@ -0,0 +1,62 @@
+/*
+ *  i386 ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x80000000
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS       ELFCLASS32
+#define ELF_DATA        ELFDATA2LSB
+#define ELF_ARCH        EM_386
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+/* XXX */
+#ifndef __FreeBSD__
+#define ELF_PLATFORM target_elf_get_platform()
+
+static const char *target_elf_get_platform(void)
+{
+    static char elf_platform[] = "i386";
+    int family = (thread_env->cpuid_version >> 8) & 0xff;
+    if (family > 6)
+        family = 6;
+    if (family >= 3)
+        elf_platform[1] = '0' + family;
+    return elf_platform;
+}
+
+#define ELF_HWCAP target_elf_get_hwcap()
+
+static uint32_t target_elf_get_hwcap(void)
+{
+    return thread_env->features[FEAT_1_EDX];
+}
+#endif /* ! __FreeBSD__ */
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/i386/target_arch_thread.h b/bsd-user/i386/target_arch_thread.h
new file mode 100644
index 0000000..407aa6c
--- /dev/null
+++ b/bsd-user/i386/target_arch_thread.h
@@ -0,0 +1,45 @@
+/*
+ *  i386 thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUX86State *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    /* XXX */
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    regs->esp = infop->start_stack;
+    regs->eip = infop->entry;
+
+    /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
+       starts %edx contains a pointer to a function which might be
+       registered using `atexit'.  This provides a mean for the
+       dynamic linker to call DT_FINI functions for shared libraries
+       that have been loaded before the code runs.
+
+       A value of 0 tells we have no such handler.  */
+    regs->edx = 0;
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/mips/target_arch_elf.h b/bsd-user/mips/target_arch_elf.h
new file mode 100644
index 0000000..8630f34
--- /dev/null
+++ b/bsd-user/mips/target_arch_elf.h
@@ -0,0 +1,36 @@
+/*
+ *  mips ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define elf_check_arch(x) ( (x) == EM_MIPS )
+#define ELF_START_MMAP 0x80000000
+#define ELF_CLASS   ELFCLASS32
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+#define ELF_ARCH    EM_MIPS
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        4096
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/mips/target_arch_thread.h b/bsd-user/mips/target_arch_thread.h
new file mode 100644
index 0000000..c76b0d6
--- /dev/null
+++ b/bsd-user/mips/target_arch_thread.h
@@ -0,0 +1,54 @@
+/*
+ *  mips thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to mips/mips/vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUMIPSState *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    abi_ulong sp;
+
+    /*
+     * At the point where a function is called, sp must be 8
+     * byte aligned[for compatibility with 64-bit CPUs]
+     * in ``See MIPS Run'' by D. Sweetman, p. 269
+     * align stack
+     */
+    sp = ((stack_base + stack_size) & ~0x7) - TARGET_CALLFRAME_SIZ;
+
+    /* t9 = pc = start function entry */
+    regs->active_tc.gpr[25] = regs->active_tc.PC = entry;
+    /* a0 = arg */
+    regs->active_tc.gpr[4] = arg;
+    /* sp = top of the stack */
+    regs->active_tc.gpr[29] = sp;
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    regs->cp0_status = 2 << CP0St_KSU;
+    regs->regs[25] = regs->cp0_epc = infop->entry & ~3;  /* t9/pc = entry */
+    regs->regs[4] = regs->regs[29] = infop->start_stack; /* a0/sp = stack */
+    regs->regs[5] = regs->regs[6] = 0;                   /* a1/a2 = 0 */
+    regs->regs[7] = TARGET_PS_STRINGS;                   /* a3 = ps_strings */
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/mips64/target_arch_elf.h b/bsd-user/mips64/target_arch_elf.h
new file mode 100644
index 0000000..ca0da03
--- /dev/null
+++ b/bsd-user/mips64/target_arch_elf.h
@@ -0,0 +1,36 @@
+/*
+ *  mips64 ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define elf_check_arch(x) ( (x) == EM_MIPS )
+#define ELF_START_MMAP 0x2aaaaab000ULL
+#define ELF_CLASS   ELFCLASS64
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+#define ELF_ARCH    EM_MIPS
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        4096
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/mips64/target_arch_thread.h b/bsd-user/mips64/target_arch_thread.h
new file mode 100644
index 0000000..7fcd866
--- /dev/null
+++ b/bsd-user/mips64/target_arch_thread.h
@@ -0,0 +1,54 @@
+/*
+ *  mips64 thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _MIPS64_ARCH_THREAD_H_
+#define _MIPS64_ARCH_THREAD_H_
+
+/* Compare to mips/mips/vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUMIPSState *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    abi_ulong sp;
+
+    /*
+     * At the point where a function is called, sp must be 8
+     * byte aligned[for compatibility with 64-bit CPUs]
+     * in ``See MIPS Run'' by D. Sweetman, p. 269
+     * align stack
+     */
+    sp = ((stack_base + stack_size) & ~0x7) - TARGET_CALLFRAME_SIZ;
+
+    /* t9 = pc = start function entry */
+    regs->active_tc.gpr[25] = regs->active_tc.PC = entry;
+    /* a0 = arg */
+    regs->active_tc.gpr[4] = arg;
+    /* sp = top of the stack */
+    regs->active_tc.gpr[29] = sp;
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    regs->cp0_status = 2 << CP0St_KSU;
+    regs->regs[25] = regs->cp0_epc = infop->entry & ~3;  /* t9/pc = entry */
+    regs->regs[4] = regs->regs[29] = infop->start_stack; /* a0/sp = stack */
+    regs->regs[5] = regs->regs[6] = 0;                   /* a1/a2 = 0 */
+    regs->regs[7] = TARGET_PS_STRINGS;                   /* a3 = ps_strings */
+}
+
+#endif /* !_MIPS64_ARCH_THREAD_H_ */
diff --git a/bsd-user/netbsd/target_os_elf.h b/bsd-user/netbsd/target_os_elf.h
new file mode 100644
index 0000000..bf663d2
--- /dev/null
+++ b/bsd-user/netbsd/target_os_elf.h
@@ -0,0 +1,226 @@
+/*
+ *  netbsd ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_OS_ELF_H_
+#define _TARGET_OS_ELF_H_
+
+#include "target_arch_elf.h"
+#include "elf.h"
+
+/* from personality.h */
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA
+                                                   space */
+        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs
+                                                   point to descriptors
+                                                   (signal handling) */
+        MMAP_PAGE_ZERO =        0x0100000,
+        ADDR_COMPAT_LAYOUT =    0x0200000,
+        READ_IMPLIES_EXEC =     0x0400000,
+        ADDR_LIMIT_32BIT =      0x0800000,
+        SHORT_INODE =           0x1000000,
+        WHOLE_SECONDS =         0x2000000,
+        STICKY_TIMEOUTS =       0x4000000,
+        ADDR_LIMIT_3GB =        0x8000000,
+};
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+        PER_LINUX =             0x0000,
+        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
+        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
+        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
+                                         WHOLE_SECONDS | SHORT_INODE,
+        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
+        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
+        PER_BSD =               0x0006,
+        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
+        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_LINUX32 =           0x0008,
+        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
+        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
+        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
+        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
+        PER_RISCOS =            0x000c,
+        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
+        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
+        PER_HPUX =              0x0010,
+        PER_MASK =              0x00ff,
+};
+
+/*
+ * Return the base personality without flags.
+ */
+#define personality(pers)       (pers & PER_MASK)
+
+/* this flag is uneffective under linux too, should be deleted */
+#ifndef MAP_DENYWRITE
+#define MAP_DENYWRITE 0
+#endif
+
+/* should probably go in elf.h */
+#ifndef ELIBBAD
+#define ELIBBAD 80
+#endif
+
+#ifndef ELF_PLATFORM
+#define ELF_PLATFORM (NULL)
+#endif
+
+#ifndef ELF_HWCAP
+#define ELF_HWCAP 0
+#endif
+
+#ifdef TARGET_ABI32
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+#undef bswaptls
+#define bswaptls(ptr) bswap32s(ptr)
+#endif
+
+struct exec
+{
+  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
+  unsigned int a_text;   /* length of text, in bytes */
+  unsigned int a_data;   /* length of data, in bytes */
+  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
+  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
+  unsigned int a_entry;  /* start address */
+  unsigned int a_trsize; /* length of relocation info for text, in bytes */
+  unsigned int a_drsize; /* length of relocation info for data, in bytes */
+};
+
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+
+/* max code+data+bss space allocated to elf interpreter */
+#define INTERP_MAP_SIZE (32 * 1024 * 1024)
+
+/* max code+data+bss+brk space allocated to ET_DYN executables */
+#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
+
+/* Necessary parameters */
+#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
+#define TARGET_ELF_PAGESTART(_v) ((_v) & \
+        ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+#define DLINFO_ITEMS 12
+
+static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc,
+                                   struct elfhdr * exec,
+                                   abi_ulong load_addr,
+                                   abi_ulong load_bias,
+                                   abi_ulong interp_load_addr, int ibcs,
+                                   struct image_info *info)
+{
+        abi_ulong sp;
+        int size;
+        abi_ulong u_platform;
+        const char *k_platform;
+        const int n = sizeof(elf_addr_t);
+
+        sp = p;
+        u_platform = 0;
+        k_platform = ELF_PLATFORM;
+        if (k_platform) {
+            size_t len = strlen(k_platform) + 1;
+            sp -= (len + n - 1) & ~(n - 1);
+            u_platform = sp;
+            /* FIXME - check return value of memcpy_to_target() for failure */
+            memcpy_to_target(sp, k_platform, len);
+        }
+        /*
+         * Force 16 byte _final_ alignment here for generality.
+         */
+        sp = sp &~ (abi_ulong)15;
+        size = (DLINFO_ITEMS + 1) * 2;
+        if (k_platform)
+          size += 2;
+#ifdef DLINFO_ARCH_ITEMS
+        size += DLINFO_ARCH_ITEMS * 2;
+#endif
+        size += envc + argc + 2;
+        size += (!ibcs ? 3 : 1);        /* argc itself */
+        size *= n;
+        if (size & 15)
+            sp -= 16 - (size & 15);
+
+        /* This is correct because Linux defines
+         * elf_addr_t as Elf32_Off / Elf64_Off
+         */
+#define NEW_AUX_ENT(id, val) do {               \
+            sp -= n; put_user_ual(val, sp);     \
+            sp -= n; put_user_ual(id, sp);      \
+          } while(0)
+
+        NEW_AUX_ENT (AT_NULL, 0);
+
+        /* There must be exactly DLINFO_ITEMS entries here.  */
+        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+        NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
+        NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+        if (k_platform)
+            NEW_AUX_ENT(AT_PLATFORM, u_platform);
+#ifdef ARCH_DLINFO
+        /*
+         * ARCH_DLINFO must come last so platform specific code can enforce
+         * special alignment requirements on the AUXV if necessary (eg. PPC).
+         */
+        ARCH_DLINFO;
+#endif
+#undef NEW_AUX_ENT
+
+        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+        return sp;
+}
+
+#endif /* _TARGET_OS_ELF_H_ */
diff --git a/bsd-user/netbsd/target_os_thread.h b/bsd-user/netbsd/target_os_thread.h
new file mode 100644
index 0000000..519aad8
--- /dev/null
+++ b/bsd-user/netbsd/target_os_thread.h
@@ -0,0 +1,6 @@
+#ifndef _TARGET_OS_THREAD_H_
+#define _TARGET_OS_THREAD_H_
+
+#include "target_arch_thread.h"
+
+#endif /* !_TARGET_OS_THREAD_H_ */
diff --git a/bsd-user/openbsd/target_os_elf.h b/bsd-user/openbsd/target_os_elf.h
new file mode 100644
index 0000000..978d944
--- /dev/null
+++ b/bsd-user/openbsd/target_os_elf.h
@@ -0,0 +1,226 @@
+/*
+ *  openbsd ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_OS_ELF_H_
+#define _TARGET_OS_ELF_H_
+
+#include "target_arch_elf.h"
+#include "elf.h"
+
+/* from personality.h */
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA
+                                                   space */
+        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs
+                                                   point to descriptors
+                                                   (signal handling) */
+        MMAP_PAGE_ZERO =        0x0100000,
+        ADDR_COMPAT_LAYOUT =    0x0200000,
+        READ_IMPLIES_EXEC =     0x0400000,
+        ADDR_LIMIT_32BIT =      0x0800000,
+        SHORT_INODE =           0x1000000,
+        WHOLE_SECONDS =         0x2000000,
+        STICKY_TIMEOUTS =       0x4000000,
+        ADDR_LIMIT_3GB =        0x8000000,
+};
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+        PER_LINUX =             0x0000,
+        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
+        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
+        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
+                                         WHOLE_SECONDS | SHORT_INODE,
+        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
+        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
+        PER_BSD =               0x0006,
+        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
+        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_LINUX32 =           0x0008,
+        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
+        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
+        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
+        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
+        PER_RISCOS =            0x000c,
+        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
+        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
+        PER_HPUX =              0x0010,
+        PER_MASK =              0x00ff,
+};
+
+/*
+ * Return the base personality without flags.
+ */
+#define personality(pers)       (pers & PER_MASK)
+
+/* this flag is uneffective under linux too, should be deleted */
+#ifndef MAP_DENYWRITE
+#define MAP_DENYWRITE 0
+#endif
+
+/* should probably go in elf.h */
+#ifndef ELIBBAD
+#define ELIBBAD 80
+#endif
+
+#ifndef ELF_PLATFORM
+#define ELF_PLATFORM (NULL)
+#endif
+
+#ifndef ELF_HWCAP
+#define ELF_HWCAP 0
+#endif
+
+#ifdef TARGET_ABI32
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+#undef bswaptls
+#define bswaptls(ptr) bswap32s(ptr)
+#endif
+
+struct exec
+{
+  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
+  unsigned int a_text;   /* length of text, in bytes */
+  unsigned int a_data;   /* length of data, in bytes */
+  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
+  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
+  unsigned int a_entry;  /* start address */
+  unsigned int a_trsize; /* length of relocation info for text, in bytes */
+  unsigned int a_drsize; /* length of relocation info for data, in bytes */
+};
+
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+
+/* max code+data+bss space allocated to elf interpreter */
+#define INTERP_MAP_SIZE (32 * 1024 * 1024)
+
+/* max code+data+bss+brk space allocated to ET_DYN executables */
+#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
+
+/* Necessary parameters */
+#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
+#define TARGET_ELF_PAGESTART(_v) ((_v) & \
+        ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+#define DLINFO_ITEMS 12
+
+static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc,
+                                   struct elfhdr * exec,
+                                   abi_ulong load_addr,
+                                   abi_ulong load_bias,
+                                   abi_ulong interp_load_addr, int ibcs,
+                                   struct image_info *info)
+{
+        abi_ulong sp;
+        int size;
+        abi_ulong u_platform;
+        const char *k_platform;
+        const int n = sizeof(elf_addr_t);
+
+        sp = p;
+        u_platform = 0;
+        k_platform = ELF_PLATFORM;
+        if (k_platform) {
+            size_t len = strlen(k_platform) + 1;
+            sp -= (len + n - 1) & ~(n - 1);
+            u_platform = sp;
+            /* FIXME - check return value of memcpy_to_target() for failure */
+            memcpy_to_target(sp, k_platform, len);
+        }
+        /*
+         * Force 16 byte _final_ alignment here for generality.
+         */
+        sp = sp &~ (abi_ulong)15;
+        size = (DLINFO_ITEMS + 1) * 2;
+        if (k_platform)
+          size += 2;
+#ifdef DLINFO_ARCH_ITEMS
+        size += DLINFO_ARCH_ITEMS * 2;
+#endif
+        size += envc + argc + 2;
+        size += (!ibcs ? 3 : 1);        /* argc itself */
+        size *= n;
+        if (size & 15)
+            sp -= 16 - (size & 15);
+
+        /* This is correct because Linux defines
+         * elf_addr_t as Elf32_Off / Elf64_Off
+         */
+#define NEW_AUX_ENT(id, val) do {               \
+            sp -= n; put_user_ual(val, sp);     \
+            sp -= n; put_user_ual(id, sp);      \
+          } while(0)
+
+        NEW_AUX_ENT (AT_NULL, 0);
+
+        /* There must be exactly DLINFO_ITEMS entries here.  */
+        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+        NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
+        NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+        if (k_platform)
+            NEW_AUX_ENT(AT_PLATFORM, u_platform);
+#ifdef ARCH_DLINFO
+        /*
+         * ARCH_DLINFO must come last so platform specific code can enforce
+         * special alignment requirements on the AUXV if necessary (eg. PPC).
+         */
+        ARCH_DLINFO;
+#endif
+#undef NEW_AUX_ENT
+
+        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+        return sp;
+}
+
+#endif /* _TARGET_OS_ELF_H_ */
diff --git a/bsd-user/openbsd/target_os_thread.h b/bsd-user/openbsd/target_os_thread.h
new file mode 100644
index 0000000..519aad8
--- /dev/null
+++ b/bsd-user/openbsd/target_os_thread.h
@@ -0,0 +1,6 @@
+#ifndef _TARGET_OS_THREAD_H_
+#define _TARGET_OS_THREAD_H_
+
+#include "target_arch_thread.h"
+
+#endif /* !_TARGET_OS_THREAD_H_ */
diff --git a/bsd-user/sparc/target_arch_elf.h b/bsd-user/sparc/target_arch_elf.h
new file mode 100644
index 0000000..b93e2ed
--- /dev/null
+++ b/bsd-user/sparc/target_arch_elf.h
@@ -0,0 +1,30 @@
+/*
+ *  sparc ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_SPARC )
+
+#define ELF_CLASS   ELFCLASS32
+#define ELF_DATA    ELFDATA2MSB
+#define ELF_ARCH    EM_SPARC
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/sparc/target_arch_thread.h b/bsd-user/sparc/target_arch_thread.h
new file mode 100644
index 0000000..fe607be
--- /dev/null
+++ b/bsd-user/sparc/target_arch_thread.h
@@ -0,0 +1,39 @@
+/*
+ *  sparc thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUSPARCState *regs,
+    abi_ulong entry, abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    /* XXX */
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    regs->psr = 0;
+    regs->pc = infop->entry;
+    regs->npc = regs->pc + 4;
+    regs->y = 0;
+    regs->u_regs[14] = infop->start_stack - 16 * 4;
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/sparc64/target_arch_elf.h b/bsd-user/sparc64/target_arch_elf.h
new file mode 100644
index 0000000..f2b8e12
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_elf.h
@@ -0,0 +1,34 @@
+/*
+ *  sparc64 ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x80000000
+
+#ifndef TARGET_ABI32
+#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
+#else
+#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
+#endif
+
+#define ELF_CLASS   ELFCLASS64
+#define ELF_DATA    ELFDATA2MSB
+#define ELF_ARCH    EM_SPARCV9
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/sparc64/target_arch_thread.h b/bsd-user/sparc64/target_arch_thread.h
new file mode 100644
index 0000000..2e5585a
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_thread.h
@@ -0,0 +1,55 @@
+/*
+ *  sparc64 thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+#define STACK_BIAS              2047
+
+/* Compare to vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUSPARCState *regs,
+    abi_ulong entry, abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    /* XXX */
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+#ifndef TARGET_ABI32
+    regs->tstate = 0;
+#endif
+    regs->pc = infop->entry;
+    regs->npc = regs->pc + 4;
+    regs->y = 0;
+#ifdef TARGET_ABI32
+    regs->u_regs[14] = infop->start_stack - 16 * 4;
+#else
+    if (personality(infop->personality) == PER_LINUX32)
+        regs->u_regs[14] = infop->start_stack - 16 * 4;
+    else {
+        regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
+        if (bsd_type == target_freebsd) {
+            regs->u_regs[8] = infop->start_stack;
+            regs->u_regs[11] = infop->start_stack;
+        }
+    }
+#endif
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index bd6d276..2b79c35 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -703,4 +703,68 @@ struct target_uuid {
     uint8_t     node[TARGET_UUID_NODE_LEN];
 };
 
+
+/*
+ * from personality.h
+ */
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA
+                                                   space */
+        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs
+                                                   point to descriptors
+                                                   (signal handling) */
+        MMAP_PAGE_ZERO =        0x0100000,
+        ADDR_COMPAT_LAYOUT =    0x0200000,
+        READ_IMPLIES_EXEC =     0x0400000,
+        ADDR_LIMIT_32BIT =      0x0800000,
+        SHORT_INODE =           0x1000000,
+        WHOLE_SECONDS =         0x2000000,
+        STICKY_TIMEOUTS =       0x4000000,
+        ADDR_LIMIT_3GB =        0x8000000,
+};
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+        PER_LINUX =             0x0000,
+        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
+        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
+        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
+                                         WHOLE_SECONDS | SHORT_INODE,
+        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
+        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
+        PER_BSD =               0x0006,
+        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
+        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_LINUX32 =           0x0008,
+        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
+        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
+        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
+        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
+        PER_RISCOS =            0x000c,
+        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
+        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
+        PER_HPUX =              0x0010,
+        PER_MASK =              0x00ff,
+};
+
+/*
+ * Return the base personality without flags.
+ */
+#define personality(pers)       (pers & PER_MASK)
+
 #endif /* ! _SYSCALL_DEFS_H_ */
diff --git a/bsd-user/x86_64/target_arch_elf.h b/bsd-user/x86_64/target_arch_elf.h
new file mode 100644
index 0000000..bc7c6a1
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_elf.h
@@ -0,0 +1,55 @@
+/*
+ *  x86_64 ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x2aaaaab000ULL
+#define elf_check_arch(x) ( ((x) == ELF_ARCH) )
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_DATA       ELFDATA2LSB
+#define ELF_ARCH       EM_X86_64
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+/* XXX */
+#ifndef __FreeBSD__
+#define ELF_PLATFORM target_elf_get_platform()
+
+static const char *target_elf_get_platform(void)
+{
+    static char elf_platform[] = "i386";
+    int family = (thread_env->cpuid_version >> 8) & 0xff;
+    if (family > 6)
+        family = 6;
+    if (family >= 3)
+        elf_platform[1] = '0' + family;
+    return elf_platform;
+}
+
+#define ELF_HWCAP target_elf_get_hwcap()
+
+static uint32_t target_elf_get_hwcap(void)
+{
+    return thread_env->features[FEAT_1_EDX];
+}
+#endif /* ! __FreeBSD__ */
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/x86_64/target_arch_thread.h b/bsd-user/x86_64/target_arch_thread.h
new file mode 100644
index 0000000..d105e43
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_thread.h
@@ -0,0 +1,40 @@
+/*
+ *  x86_64 thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUX86State *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    /* XXX */
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+    struct image_info *infop)
+{
+    regs->rax = 0;
+    regs->rsp = infop->start_stack;
+    regs->rip = infop->entry;
+    if (bsd_type == target_freebsd) {
+        regs->rdi = infop->start_stack;
+    }
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 09/18] bsd-user: add support for freebsd process related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (7 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 08/18] bsd-user: move target arch and host OS dependent code out of elfload.c Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 10/18] bsd-user: add support for file system " Stacey Son
                   ` (30 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change add support or stubs for process related system calls including
fork(2), vfork(2), rfork(2), pdfork(2), execve(2), fexecve(2), wait4(2), exit(2),
getgroups(2), setgroups(2), umask(2), setlogin(2), getlogin(2), getrusage(2),
getrlimit(2), setrlimit(2), getpid(2), getppid(2), getuid(2), geteuid(2),
getgid(2), getegid(2), setuid(2), seteuid(2), setgid(2), setegid(2), getpgrp(2),
setreuid(2), setregid(2), getresuid(2), getresgid(2), getsid(2), setsid(2),
issetugid(2), profil(2), ktrace(2), setloginclass(2), getloginclass(2),
pdgetpid(2), jail*(2), cap_*(2), *audit*(2), utrace(2), ptrace(2), getpriority(2),
and setpriority(2).

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs     |    4 +-
 bsd-user/bsd-proc.c        |  160 ++++++++++++++++
 bsd-user/bsd-proc.h        |  434 ++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-proc.c |  234 ++++++++++++++++++++++++
 bsd-user/freebsd/os-proc.h |  428 +++++++++++++++++++++++++++++++++++++++++++
 bsd-user/netbsd/os-proc.c  |   11 +
 bsd-user/netbsd/os-proc.h  |  243 +++++++++++++++++++++++++
 bsd-user/openbsd/os-proc.c |   11 +
 bsd-user/openbsd/os-proc.h |  243 +++++++++++++++++++++++++
 bsd-user/qemu-bsd.h        |   43 +++++
 bsd-user/qemu.h            |    4 +
 bsd-user/syscall.c         |  262 ++++++++++++++++++++++++++-
 12 files changed, 2069 insertions(+), 8 deletions(-)
 create mode 100644 bsd-user/bsd-proc.c
 create mode 100644 bsd-user/bsd-proc.h
 create mode 100644 bsd-user/freebsd/os-proc.c
 create mode 100644 bsd-user/freebsd/os-proc.h
 create mode 100644 bsd-user/netbsd/os-proc.c
 create mode 100644 bsd-user/netbsd/os-proc.h
 create mode 100644 bsd-user/openbsd/os-proc.c
 create mode 100644 bsd-user/openbsd/os-proc.h
 create mode 100644 bsd-user/qemu-bsd.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index d92961a..6a2fc37 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,3 +1,5 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o $(HOST_ABI_DIR)/os-sys.o \
+	        uaccess.o bsd-proc.o \
+			$(HOST_ABI_DIR)/os-proc.o \
+			$(HOST_ABI_DIR)/os-sys.o \
 			$(HOST_ABI_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/bsd-proc.c b/bsd-user/bsd-proc.c
new file mode 100644
index 0000000..a4bcdc8
--- /dev/null
+++ b/bsd-user/bsd-proc.c
@@ -0,0 +1,160 @@
+/*
+ *  BSD process related system call helpers
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+/*
+ * resource/rusage conversion
+ */
+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_MEMLOCK:
+        return RLIMIT_MEMLOCK;
+
+    case TARGET_RLIMIT_NOFILE:
+        return RLIMIT_NOFILE;
+
+    case TARGET_RLIMIT_NPROC:
+        return RLIMIT_NPROC;
+
+    case TARGET_RLIMIT_RSS:
+        return RLIMIT_RSS;
+
+    case TARGET_RLIMIT_SBSIZE:
+        return RLIMIT_SBSIZE;
+
+    case TARGET_RLIMIT_STACK:
+        return RLIMIT_STACK;
+
+    case TARGET_RLIMIT_SWAP:
+        return RLIMIT_SWAP;
+
+    case TARGET_RLIMIT_NPTS:
+        return RLIMIT_NPTS;
+
+    default:
+        return code;
+    }
+}
+
+rlim_t target_to_host_rlim(abi_ulong target_rlim)
+{
+    abi_ulong target_rlim_swap;
+    rlim_t result;
+
+    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;
+    }
+
+    return result;
+}
+
+abi_ulong host_to_target_rlim(rlim_t rlim)
+{
+    abi_ulong target_rlim_swap;
+    abi_ulong result;
+
+    if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim) {
+        target_rlim_swap = TARGET_RLIM_INFINITY;
+    } else {
+        target_rlim_swap = rlim;
+    }
+    result = tswapal(target_rlim_swap);
+
+    return result;
+}
+
+abi_long host_to_target_rusage(abi_ulong target_addr,
+        const struct rusage *rusage)
+{
+    struct target_freebsd_rusage *target_rusage;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(rusage->ru_utime.tv_sec, &target_rusage->ru_utime.tv_sec);
+    __put_user(rusage->ru_utime.tv_usec, &target_rusage->ru_utime.tv_usec);
+
+    __put_user(rusage->ru_stime.tv_sec, &target_rusage->ru_stime.tv_sec);
+    __put_user(rusage->ru_stime.tv_usec, &target_rusage->ru_stime.tv_usec);
+
+    __put_user(rusage->ru_maxrss, &target_rusage->ru_maxrss);
+    __put_user(rusage->ru_idrss, &target_rusage->ru_idrss);
+    __put_user(rusage->ru_idrss, &target_rusage->ru_idrss);
+    __put_user(rusage->ru_isrss, &target_rusage->ru_isrss);
+    __put_user(rusage->ru_minflt, &target_rusage->ru_minflt);
+    __put_user(rusage->ru_majflt, &target_rusage->ru_majflt);
+    __put_user(rusage->ru_nswap, &target_rusage->ru_nswap);
+    __put_user(rusage->ru_inblock, &target_rusage->ru_inblock);
+    __put_user(rusage->ru_oublock, &target_rusage->ru_oublock);
+    __put_user(rusage->ru_msgsnd, &target_rusage->ru_msgsnd);
+    __put_user(rusage->ru_msgrcv, &target_rusage->ru_msgrcv);
+    __put_user(rusage->ru_nsignals, &target_rusage->ru_nsignals);
+    __put_user(rusage->ru_nvcsw, &target_rusage->ru_nvcsw);
+    __put_user(rusage->ru_nivcsw, &target_rusage->ru_nivcsw);
+    unlock_user_struct(target_rusage, target_addr, 1);
+
+    return 0;
+}
+
+/*
+ * wait status conversion.
+ *
+ * Map host to target signal numbers for the wait family of syscalls.
+ * Assume all other status bits are the same.
+ */
+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;
+}
+
diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h
new file mode 100644
index 0000000..d1c732a
--- /dev/null
+++ b/bsd-user/bsd-proc.h
@@ -0,0 +1,434 @@
+/*
+ *  process related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_PROC_H_
+#define __BSD_PROC_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#include "qemu-bsd.h"
+
+extern int _getlogin(char*, int);
+
+/* exit(2) */
+static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1)
+{
+#ifdef TARGET_GPROF
+    _mcleanup();
+#endif
+    gdb_exit(cpu_env, arg1);
+    /* XXX: should free thread stack and CPU env here  */
+    _exit(arg1);
+
+    return 0;
+}
+
+/* getgroups(2) */
+static inline abi_long do_bsd_getgroups(abi_long gidsetsize, abi_long arg2)
+{
+    abi_long ret;
+    uint32_t *target_grouplist;
+    gid_t *grouplist;
+    int i;
+
+    grouplist = alloca(gidsetsize * sizeof(gid_t));
+    ret = get_errno(getgroups(gidsetsize, grouplist));
+    if (gidsetsize != 0) {
+        if (!is_error(ret)) {
+            target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
+            if (!target_grouplist) {
+                return -TARGET_EFAULT;
+            }
+            for (i = 0; i < ret; i++) {
+                target_grouplist[i] = tswap32(grouplist[i]);
+            }
+            unlock_user(target_grouplist, arg2, gidsetsize * 2);
+        }
+    }
+    return ret;
+}
+
+/* setgroups(2) */
+static inline abi_long do_bsd_setgroups(abi_long gidsetsize, abi_long arg2)
+{
+    uint32_t *target_grouplist;
+    gid_t *grouplist;
+    int i;
+
+    grouplist = alloca(gidsetsize * sizeof(gid_t));
+    target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
+    if (!target_grouplist) {
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < gidsetsize; i++) {
+        grouplist[i] = tswap32(target_grouplist[i]);
+    }
+    unlock_user(target_grouplist, arg2, 0);
+    return get_errno(setgroups(gidsetsize, grouplist));
+}
+
+/* umask(2) */
+static inline abi_long do_bsd_umask(abi_long arg1)
+{
+
+    return get_errno(umask(arg1));
+}
+
+/* setlogin(2) */
+static inline abi_long do_bsd_setlogin(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(setlogin(p));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* getlogin(2) */
+static inline abi_long do_bsd_getlogin(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(_getlogin(p, arg2));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* getrusage(2) */
+static inline abi_long do_bsd_getrusage(abi_long who, abi_ulong target_addr)
+{
+    abi_long ret;
+    struct rusage rusage;
+
+    ret = get_errno(getrusage(who, &rusage));
+    if (!is_error(ret)) {
+        host_to_target_rusage(target_addr, &rusage);
+    }
+    return ret;
+}
+
+/* getrlimit(2) */
+static inline abi_long do_bsd_getrlimit(abi_long arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    int resource = target_to_host_resource(arg1);
+    struct target_rlimit *target_rlim;
+    struct rlimit rlim;
+
+    switch (resource) {
+    case RLIMIT_STACK:
+        rlim.rlim_cur = target_dflssiz;
+        rlim.rlim_max = target_maxssiz;
+        ret = 0;
+        break;
+
+    case RLIMIT_DATA:
+        rlim.rlim_cur = target_dfldsiz;
+        rlim.rlim_max = target_maxdsiz;
+        ret = 0;
+        break;
+
+    default:
+        ret = get_errno(getrlimit(resource, &rlim));
+        break;
+    }
+    if (!is_error(ret)) {
+        if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) {
+            return -TARGET_EFAULT;
+        }
+        target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
+        target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
+        unlock_user_struct(target_rlim, arg2, 1);
+    }
+    return ret;
+}
+
+/* setrlimit(2) */
+static inline abi_long do_bsd_setrlimit(abi_long arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    int resource = target_to_host_resource(arg1);
+    struct target_rlimit *target_rlim;
+    struct rlimit rlim;
+
+    if (RLIMIT_STACK == resource) {
+        /* XXX We should, maybe, allow the stack size to shrink */
+        ret = -TARGET_EPERM;
+    } else {
+        if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) {
+            return -TARGET_EFAULT;
+        }
+        rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
+        rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
+        unlock_user_struct(target_rlim, arg2, 0);
+        ret = get_errno(setrlimit(resource, &rlim));
+    }
+    return ret;
+}
+
+/* getpid(2) */
+static inline abi_long do_bsd_getpid(void)
+{
+
+    return get_errno(getpid());
+}
+
+/* getppid(2) */
+static inline abi_long do_bsd_getppid(void)
+{
+
+    return get_errno(getppid());
+}
+
+/* getuid(2) */
+static inline abi_long do_bsd_getuid(void)
+{
+
+    return get_errno(getuid());
+}
+
+/* geteuid(2) */
+static inline abi_long do_bsd_geteuid(void)
+{
+
+    return get_errno(geteuid());
+}
+
+/* getgid(2) */
+static inline abi_long do_bsd_getgid(void)
+{
+
+    return get_errno(getgid());
+}
+
+/* getegid(2) */
+static inline abi_long do_bsd_getegid(void)
+{
+
+    return get_errno(getegid());
+}
+
+/* setuid(2) */
+static inline abi_long do_bsd_setuid(abi_long arg1)
+{
+
+    return get_errno(setuid(arg1));
+}
+
+/* seteuid(2) */
+static inline abi_long do_bsd_seteuid(abi_long arg1)
+{
+
+    return get_errno(seteuid(arg1));
+}
+
+/* setgid(2) */
+static inline abi_long do_bsd_setgid(abi_long arg1)
+{
+
+    return get_errno(setgid(arg1));
+}
+
+/* setegid(2) */
+static inline abi_long do_bsd_setegid(abi_long arg1)
+{
+
+    return get_errno(setegid(arg1));
+}
+
+/* getpgrp(2) */
+static inline abi_long do_bsd_getpgrp(void)
+{
+
+    return get_errno(getpgrp());
+}
+
+/* setreuid(2) */
+static inline abi_long do_bsd_setreuid(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(setreuid(arg1, arg2));
+}
+
+/* setregid(2) */
+static inline abi_long do_bsd_setregid(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(setregid(arg1, arg2));
+}
+
+/* setresuid(2) */
+static inline abi_long do_bsd_setresuid(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    return get_errno(setresuid(arg1, arg2, arg3));
+}
+
+/* getresuid(2) */
+static inline abi_long do_bsd_getresuid(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    uid_t ruid, euid, suid;
+
+    ret = get_errno(getresuid(&ruid, &euid, &suid));
+    if (is_error(ret)) {
+            return ret;
+    }
+    if (put_user_s32(ruid, arg1)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(euid, arg2)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(suid, arg3)) {
+        return -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+/* getresgid(2) */
+static inline abi_long do_bsd_getresgid(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    uid_t ruid, euid, suid;
+
+    ret = get_errno(getresgid(&ruid, &euid, &suid));
+    if (is_error(ret)) {
+            return ret;
+    }
+    if (put_user_s32(ruid, arg1)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(euid, arg2)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(suid, arg3)) {
+        return -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+/* getsid(2) */
+static inline abi_long do_bsd_getsid(abi_long arg1)
+{
+
+    return get_errno(getsid(arg1));
+}
+
+/* setsid(2) */
+static inline abi_long do_bsd_setsid(void)
+{
+
+    return get_errno(setsid());
+}
+
+/* issetugid(2) */
+static inline abi_long do_bsd_issetugid(void)
+{
+
+    return get_errno(issetugid());
+}
+
+/* profil(2) */
+static inline abi_long do_bsd_profil(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall profil()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* ktrace(2) */
+static inline abi_long do_bsd_ktrace(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall ktrace()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* utrace(2) */
+static inline abi_long do_bsd_utrace(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall ptrace()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* ptrace(2) */
+static inline abi_long do_bsd_ptrace(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall ptrace()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getpriority(2) */
+static inline abi_long do_bsd_getpriority(abi_long which, abi_long who)
+{
+    abi_long ret;
+    /*
+     * Note that negative values are valid for getpriority, so we must
+     * differentiate based on errno settings.
+     */
+    errno = 0;
+    ret = getpriority(which, who);
+    if (ret == -1 && errno != 0) {
+        ret = -host_to_target_errno(errno);
+        return ret;
+    }
+    /* Return value is a biased priority to avoid negative numbers. */
+    ret = 20 - ret;
+
+    return ret;
+}
+
+/* setpriority(2) */
+static inline abi_long do_bsd_setpriority(abi_long which, abi_long who,
+        abi_long prio)
+{
+
+    return get_errno(setpriority(which, who, prio));
+}
+
+
+#endif /* !__BSD_PROC_H_ */
+
diff --git a/bsd-user/freebsd/os-proc.c b/bsd-user/freebsd/os-proc.c
new file mode 100644
index 0000000..b696222
--- /dev/null
+++ b/bsd-user/freebsd/os-proc.c
@@ -0,0 +1,234 @@
+/*
+ *  FreeBSD process related emulation code
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#include <libprocstat.h>
+#endif
+
+#include "qemu.h"
+
+/*
+ * Get the filename for the given file descriptor.
+ * Note that this may return NULL (fail) if no longer cached in the kernel.
+ */
+static char *
+get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len)
+{
+    char *ret = NULL;
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+    unsigned int cnt;
+    struct procstat *procstat = NULL;
+    struct kinfo_proc *kipp = NULL;
+    struct filestat_list *head = NULL;
+    struct filestat *fst;
+
+    procstat = procstat_open_sysctl();
+    if (NULL == procstat) {
+        goto out;
+    }
+
+    kipp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt);
+    if (NULL == kipp) {
+        goto out;
+    }
+
+    head = procstat_getfiles(procstat, kipp, 0);
+    if (NULL == head) {
+        goto out;
+    }
+
+    STAILQ_FOREACH(fst, head, next) {
+        if (fd == fst->fs_fd) {
+            if (fst->fs_path != NULL) {
+                (void)strlcpy(filename, fst->fs_path, len);
+                ret = filename;
+            }
+            break;
+        }
+    }
+
+out:
+    if (head != NULL) {
+        procstat_freefiles(procstat, head);
+    }
+    if (kipp != NULL) {
+        procstat_freeprocs(procstat, kipp);
+    }
+    if (procstat != NULL) {
+        procstat_close(procstat);
+    }
+#endif
+    return ret;
+}
+
+/*
+ * execve/fexecve
+ */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec)
+{
+    char **argp, **envp, **qargp, **qarg1;
+    int argc, envc;
+    abi_ulong gp;
+    abi_ulong addr;
+    char **q;
+    int total_size = 0;
+    void *p;
+    abi_long ret;
+
+    argc = 0;
+    for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
+        if (get_user_ual(addr, gp)) {
+            return -TARGET_EFAULT;
+        }
+        if (!addr) {
+            break;
+        }
+        argc++;
+    }
+    envc = 0;
+    for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
+        if (get_user_ual(addr, gp)) {
+            return -TARGET_EFAULT;
+        }
+        if (!addr) {
+            break;
+        }
+        envc++;
+    }
+
+    qargp = argp =  alloca((argc + 3) * sizeof(void *));
+    /* save the first agrument for the emulator */
+    *argp++ = (char *)getprogname();
+    qarg1 = argp;
+    envp = alloca((envc + 1) * sizeof(void *));
+    for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp)) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+        if (!addr) {
+            break;
+        }
+        *q = lock_user_string(addr);
+        if (*q == NULL) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+        total_size += strlen(*q) + 1;
+    }
+    *q = NULL;
+
+    for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp)) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+        if (!addr) {
+            break;
+        }
+        *q = lock_user_string(addr);
+        if (*q == NULL) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+        total_size += strlen(*q) + 1;
+    }
+    *q = NULL;
+
+    /*
+     * 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;
+    }
+
+    if (do_fexec) {
+        if (((int)path_or_fd > 0 &&
+            is_target_elf_binary((int)path_or_fd)) == 1) {
+            char execpath[PATH_MAX];
+
+            /*
+             * The executable is an elf binary for the target
+             * arch.  execve() it using the emulator if we can
+             * determine the filename path from the fd.
+             */
+            if (get_filename_from_fd(getpid(), (int)path_or_fd, execpath,
+                        sizeof(execpath)) != NULL) {
+                *qarg1 = execpath;
+                ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
+            } else {
+                /* Getting the filename path failed. */
+                ret = -TARGET_EBADF;
+                goto execve_end;
+            }
+        } else {
+            ret = get_errno(fexecve((int)path_or_fd, argp, envp));
+        }
+    } else {
+        int fd;
+
+        p = lock_user_string(path_or_fd);
+        if (p == NULL) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+
+        /*
+         * Check the header and see if it a target elf binary.  If so
+         * then execute using qemu user mode emulator.
+         */
+        fd = open(p, O_RDONLY | O_CLOEXEC);
+        if (fd > 0 && is_target_elf_binary(fd) == 1) {
+            close(fd);
+            /* Execve() as a target binary using emulator. */
+            *qarg1 = (char *)p;
+            ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
+        } else {
+            close(fd);
+            /* Execve() as a host native binary. */
+            ret = get_errno(execve(p, argp, envp));
+        }
+        unlock_user(p, path_or_fd, 0);
+    }
+
+execve_end:
+    for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp) || !addr) {
+            break;
+        }
+        unlock_user(*q, addr, 0);
+    }
+
+    for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp) || !addr) {
+            break;
+        }
+        unlock_user(*q, addr, 0);
+    }
+    return ret;
+}
+
+
diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h
new file mode 100644
index 0000000..b31f7c4
--- /dev/null
+++ b/bsd-user/freebsd/os-proc.h
@@ -0,0 +1,428 @@
+/*
+ *  process related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_PROC_H_
+#define __FREEBSD_PROC_H_
+
+#include <sys/types.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#include <sys/procdesc.h>
+#endif
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "target_arch_cpu.h"
+
+extern int __setugid(int flag);
+extern int pdwait4(int fd, int *status, int options, struct rusage *rusage);
+
+/* execve(2) */
+static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    return freebsd_exec_common(path_or_fd, argp, envp, 0);
+}
+
+/* fexecve(2) */
+static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    return freebsd_exec_common(path_or_fd, argp, envp, 1);
+}
+
+/* wait4(2) */
+static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
+        abi_long arg3, abi_ulong target_rusage)
+{
+    abi_long ret;
+    int status;
+    struct rusage rusage, *rusage_ptr = NULL;
+
+    if (target_rusage) {
+        rusage_ptr = &rusage;
+    }
+    ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
+    if (!is_error(ret)) {
+        status = host_to_target_waitstatus(status);
+        if (put_user_s32(status, target_status) != 0) {
+            return -TARGET_EFAULT;
+        }
+        if (target_rusage != 0) {
+            host_to_target_rusage(target_rusage, &rusage);
+        }
+    }
+    return ret;
+}
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(setloginclass(p));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(getloginclass(p, arg2));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+    abi_long ret;
+    int status;
+    struct rusage rusage, *rusage_ptr = NULL;
+
+    if (target_rusage) {
+        rusage_ptr = &rusage;
+    }
+    ret = get_errno(pdwait4(arg1, &status, arg3, rusage_ptr));
+    if (!is_error(ret)) {
+        status = host_to_target_waitstatus(status);
+        if (put_user_s32(status, target_status) != 0) {
+            return -TARGET_EFAULT;
+        }
+        if (target_rusage != 0) {
+            host_to_target_rusage(target_rusage, &rusage);
+        }
+    }
+    return ret;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+    abi_long ret;
+    pid_t pid;
+
+    ret = get_errno(pdgetpid(fd, &pid));
+    if (!is_error(ret)) {
+        if (put_user_u32(pid, target_pidp)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+#else
+
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall pdwait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+
+    qemu_log("qemu: Unsupported syscall pdgetpid()\n");
+    return -TARGET_ENOSYS;
+}
+#endif /* !  __FreeBSD_version > 900000 */
+
+/* undocumented __setugid */
+static inline abi_long do_freebsd___setugid(abi_long arg1)
+{
+
+    return get_errno(__setugid(arg1));
+}
+
+/* fork(2) */
+static inline abi_long do_freebsd_fork(void *cpu_env)
+{
+    abi_long ret;
+    abi_ulong child_flag = 0;
+
+    fork_start();
+    ret = fork();
+    if (ret == 0) {
+        /* child */
+        child_flag = 1;
+        target_cpu_clone_regs(cpu_env, 0);
+    } else {
+        /* parent */
+        fork_end(0);
+    }
+
+    /*
+     * The fork system call sets a child flag in the second return
+     * value: 0 for parent process, 1 for child process.
+     */
+    set_second_rval(cpu_env, child_flag);
+
+    return ret;
+}
+
+/* vfork(2) */
+static inline abi_long do_freebsd_vfork(void *cpu_env)
+{
+
+    return do_freebsd_fork(cpu_env);
+}
+
+/* rfork(2) */
+static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+{
+    abi_long ret;
+    abi_ulong child_flag = 0;
+
+    fork_start();
+    ret = rfork(flags);
+    if (ret == 0) {
+        /* child */
+        child_flag = 1;
+        target_cpu_clone_regs(cpu_env, 0);
+    } else {
+        /* parent */
+        fork_end(0);
+    }
+
+    /*
+     * The fork system call sets a child flag in the second return
+     * value: 0 for parent process, 1 for child process.
+     */
+    set_second_rval(cpu_env, child_flag);
+
+    return ret;
+
+}
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp,
+        abi_long flags)
+{
+    abi_long ret;
+    abi_ulong child_flag = 0;
+    int fd;
+
+    fork_start();
+    ret = pdfork(&fd, flags);
+    if (ret == 0) {
+        /* child */
+        child_flag = 1;
+        target_cpu_clone_regs(cpu_env, 0);
+    } else {
+        /* parent */
+        fork_end(0);
+    }
+    if (put_user_s32(fd, target_fdp)) {
+        return -TARGET_EFAULT;
+    }
+
+    /*
+     * The fork system call sets a child flag in the second return
+     * value: 0 for parent process, 1 for child process.
+     */
+    set_second_rval(cpu_env, child_flag);
+
+    return ret;
+}
+
+#else
+
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* __FreeBSD_version > 900000 */
+
+/* jail(2) */
+static inline abi_long do_freebsd_jail(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_attach(2) */
+static inline abi_long do_freebsd_jail_attach(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_attach()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_remove(2) */
+static inline abi_long do_freebsd_jail_remove(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_remove()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_get(2) */
+static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_get()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_set(2) */
+static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_set()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_enter(2) */
+static inline abi_long do_freebsd_cap_enter(void)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_enter()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_new(2) */
+static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getrights(2) */
+static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getrights()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getmode(2) */
+static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getmode()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* audit(2) */
+static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall audit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditon(2) */
+static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall auditon()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit(2) */
+static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit(2) */
+static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit_addr(2) */
+static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit_addr(2) */
+static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditctl(2) */
+static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall auditctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __FREEBSD_PROC_H_ */
diff --git a/bsd-user/netbsd/os-proc.c b/bsd-user/netbsd/os-proc.c
new file mode 100644
index 0000000..bc11d29
--- /dev/null
+++ b/bsd-user/netbsd/os-proc.c
@@ -0,0 +1,11 @@
+/*
+ * XXX To support FreeBSD binaries on NetBSD the following will need to be
+ * emulated.
+ */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec)
+{
+
+    qemu_log("qemu: Unsupported %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/netbsd/os-proc.h b/bsd-user/netbsd/os-proc.h
new file mode 100644
index 0000000..f34d616
--- /dev/null
+++ b/bsd-user/netbsd/os-proc.h
@@ -0,0 +1,243 @@
+#ifndef __NETBSD_PROC_H_
+#define __NETBSD_PROC_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* execve(2) */
+static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall execve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fexecve(2) */
+static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall fexecve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* wait4(2) */
+static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
+        abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall wait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall pdwait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+
+    qemu_log("qemu: Unsupported syscall pdgetpid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocumented __setugid */
+static inline abi_long do_freebsd___setugid(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall __setugid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fork(2) */
+static inline abi_long do_freebsd_fork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall fork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* vfork(2) */
+static inline abi_long do_freebsd_vfork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall vfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rfork(2) */
+static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall rfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdfork()\n");
+    return -TARGET_ENOSYS
+}
+
+/* jail(2) */
+static inline abi_long do_freebsd_jail(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_attach(2) */
+static inline abi_long do_freebsd_jail_attach(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_attach()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_remove(2) */
+static inline abi_long do_freebsd_jail_remove(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_remove()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_get(2) */
+static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_get()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_set(2) */
+static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_set()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_enter(2) */
+static inline abi_long do_freebsd_cap_enter(void)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_enter()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_new(2) */
+static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getrights(2) */
+static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getrights()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getmode(2) */
+static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getmode()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* audit(2) */
+static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall audit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditon(2) */
+static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall auditon()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit(2) */
+static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit(2) */
+static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit_addr(2) */
+static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit_addr(2) */
+static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditctl(2) */
+static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall auditctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __NETBSD_PROC_H_ */
diff --git a/bsd-user/openbsd/os-proc.c b/bsd-user/openbsd/os-proc.c
new file mode 100644
index 0000000..bc11d29
--- /dev/null
+++ b/bsd-user/openbsd/os-proc.c
@@ -0,0 +1,11 @@
+/*
+ * XXX To support FreeBSD binaries on NetBSD the following will need to be
+ * emulated.
+ */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec)
+{
+
+    qemu_log("qemu: Unsupported %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/openbsd/os-proc.h b/bsd-user/openbsd/os-proc.h
new file mode 100644
index 0000000..9cce719
--- /dev/null
+++ b/bsd-user/openbsd/os-proc.h
@@ -0,0 +1,243 @@
+#ifndef __OPENBSD_PROC_H_
+#define __OPENBSD_PROC_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* execve(2) */
+static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall execve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fexecve(2) */
+static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall fexecve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* wait4(2) */
+static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
+        abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall wait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall pdwait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+
+    qemu_log("qemu: Unsupported syscall pdgetpid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocumented __setugid */
+static inline abi_long do_freebsd___setugid(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall __setugid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fork(2) */
+static inline abi_long do_freebsd_fork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall fork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* vfork(2) */
+static inline abi_long do_freebsd_vfork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall vfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rfork(2) */
+static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall rfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdfork()\n");
+    return -TARGET_ENOSYS
+}
+
+/* jail(2) */
+static inline abi_long do_freebsd_jail(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_attach(2) */
+static inline abi_long do_freebsd_jail_attach(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_attach()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_remove(2) */
+static inline abi_long do_freebsd_jail_remove(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_remove()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_get(2) */
+static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_get()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_set(2) */
+static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_set()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_enter(2) */
+static inline abi_long do_freebsd_cap_enter(void)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_enter()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_new(2) */
+static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
+{
+
+        qemu_log("qemu: Unsupported syscall cap_new()\n");
+            return -TARGET_ENOSYS;
+}
+
+/* cap_getrights(2) */
+static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
+{
+
+        qemu_log("qemu: Unsupported syscall cap_getrights()\n");
+            return -TARGET_ENOSYS;
+}
+
+/* cap_getmode(2) */
+static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getmode()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* audit(2) */
+static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall audit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditon(2) */
+static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall auditon()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit(2) */
+static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit(2) */
+static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit_addr(2) */
+static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit_addr(2) */
+static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditctl(2) */
+static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall auditctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_PROC_H_ */
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
new file mode 100644
index 0000000..590c36b
--- /dev/null
+++ b/bsd-user/qemu-bsd.h
@@ -0,0 +1,43 @@
+/*
+ *  BSD conversion extern declarations
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _QEMU_BSD_H_
+#define _QEMU_BSD_H_
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/resource.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uuid.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+
+/* bsd-proc.c */
+int target_to_host_resource(int code);
+rlim_t target_to_host_rlim(abi_ulong target_rlim);
+abi_ulong host_to_target_rlim(rlim_t rlim);
+abi_long host_to_target_rusage(abi_ulong target_addr,
+        const struct rusage *rusage);
+int host_to_target_waitstatus(int status);
+
+#endif /* !_QEMU_BSD_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 0e332af..a9f5666 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -248,6 +248,10 @@ extern char qemu_proc_pathname[];
 abi_long get_errno(abi_long ret);
 int is_error(abi_long ret);
 
+/* os-proc.c */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec);
+
 /* os-sys.c */
 abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
         abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen);
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index bc4a7e4..f8a40f0 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -38,12 +38,15 @@
 #include "qemu-common.h"
 
 #define target_to_host_bitmask(x, tbl) (x)
+static int host_to_target_errno(int err);
 
 /* BSD independent syscall shims */
+#include "bsd-proc.h"
 #include "bsd-signal.h"
 
 /* *BSD dependent syscall shims */
 #include "os-time.h"
+#include "os-proc.h"
 #include "os-signal.h"
 
 /* #define DEBUG */
@@ -63,6 +66,12 @@ abi_long get_errno(abi_long ret)
         return ret;
 }
 
+static int host_to_target_errno(int err)
+{
+    /* XXX need to translate host errnos here */
+    return err;
+}
+
 int is_error(abi_long ret)
 {
     return (abi_ulong)ret >= (abi_ulong)(-4096);
@@ -176,15 +185,254 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
 
     switch(num) {
-    case TARGET_FREEBSD_NR_exit:
-#ifdef TARGET_GPROF
-        _mcleanup();
+        /*
+         * process system calls
+         */
+    case TARGET_FREEBSD_NR_fork: /* fork(2) */
+        ret = do_freebsd_fork(cpu_env);
+        break;
+
+    case TARGET_FREEBSD_NR_vfork: /* vfork(2) */
+        ret = do_freebsd_vfork(cpu_env);
+        break;
+
+    case TARGET_FREEBSD_NR_rfork: /* rfork(2) */
+        ret = do_freebsd_rfork(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_pdfork: /* pdfork(2) */
+        ret = do_freebsd_pdfork(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_execve: /* execve(2) */
+        ret = do_freebsd_execve(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_fexecve: /* fexecve(2) */
+        ret = do_freebsd_fexecve(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_wait4: /* wait4(2) */
+        ret = do_freebsd_wait4(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_exit: /* exit(2) */
+        ret = do_bsd_exit(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getgroups: /* getgroups(2) */
+        ret = do_bsd_getgroups(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setgroups: /* setgroups(2) */
+        ret = do_bsd_setgroups(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_umask: /* umask(2) */
+        ret = do_bsd_umask(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setlogin: /* setlogin(2) */
+        ret = do_bsd_setlogin(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getlogin: /* getlogin(2) */
+        ret = do_bsd_getlogin(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getrusage: /* getrusage(2) */
+        ret = do_bsd_getrusage(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getrlimit: /* getrlimit(2) */
+        ret = do_bsd_getrlimit(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setrlimit: /* setrlimit(2) */
+        ret = do_bsd_setrlimit(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getpid: /* getpid(2) */
+        ret = do_bsd_getpid();
+        break;
+
+    case TARGET_FREEBSD_NR_getppid: /* getppid(2) */
+        ret = do_bsd_getppid();
+        break;
+
+    case TARGET_FREEBSD_NR_getuid: /* getuid(2) */
+        ret = do_bsd_getuid();
+        break;
+
+    case TARGET_FREEBSD_NR_geteuid: /* geteuid(2) */
+        ret = do_bsd_geteuid();
+        break;
+
+    case TARGET_FREEBSD_NR_getgid: /* getgid(2) */
+        ret = do_bsd_getgid();
+        break;
+
+    case TARGET_FREEBSD_NR_getegid: /* getegid(2) */
+        ret = do_bsd_getegid();
+        break;
+
+    case TARGET_FREEBSD_NR_setuid: /* setuid(2) */
+        ret = do_bsd_setuid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_seteuid: /* seteuid(2) */
+        ret = do_bsd_seteuid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setgid: /* setgid(2) */
+        ret = do_bsd_setgid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setegid: /* setegid(2) */
+        ret = do_bsd_setegid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getpgrp: /* getpgrp(2) */
+        ret = do_bsd_getpgrp();
+        break;
+
+    case TARGET_FREEBSD_NR_setreuid: /* setreuid(2) */
+        ret = do_bsd_setreuid(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setregid: /* setregid(2) */
+        ret = do_bsd_setregid(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getresuid: /* getresuid(2) */
+        ret = do_bsd_getresuid(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getresgid: /* getresgid(2) */
+        ret = do_bsd_getresgid(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getsid: /* getsid(2) */
+        ret = do_bsd_getsid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setsid: /* setsid(2) */
+        ret = do_bsd_setsid();
+        break;
+
+    case TARGET_FREEBSD_NR_issetugid: /* issetugid(2) */
+        ret = do_bsd_issetugid();
+        break;
+
+    case TARGET_FREEBSD_NR_profil: /* profil(2) */
+        ret = do_bsd_profil(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ktrace: /* ktrace(2) */
+        ret = do_bsd_ktrace(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_setloginclass: /* setloginclass(2) */
+        ret = do_freebsd_setloginclass(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getloginclass: /* getloginclass(2) */
+        ret = do_freebsd_getloginclass(arg1, arg2);
+        break;
+#if 0
+    case TARGET_FREEBSD_NR_pdwait4: /* pdwait4(2) */
+        ret = do_freebsd_pdwait4(arg1, arg2, arg3, arg4);
+        break;
 #endif
-        gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
-        _exit(arg1);
-        ret = 0; /* avoid warning */
+
+    case TARGET_FREEBSD_NR_pdgetpid: /* pdgetpid(2) */
+        ret = do_freebsd_pdgetpid(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___setugid: /* undocumented */
+        ret = do_freebsd___setugid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail: /* jail(2) */
+        ret = do_freebsd_jail(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_attach: /* jail_attach(2) */
+        ret = do_freebsd_jail_attach(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_remove: /* jail_remove(2) */
+        ret = do_freebsd_jail_remove(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_get: /* jail_get(2) */
+        ret = do_freebsd_jail_get(arg1, arg2, arg3);
         break;
+
+    case TARGET_FREEBSD_NR_jail_set: /* jail_set(2) */
+        ret = do_freebsd_jail_set(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_cap_enter: /* cap_enter(2) */
+        ret = do_freebsd_cap_enter();
+        break;
+
+    case TARGET_FREEBSD_NR_cap_new: /* cap_new(2) */
+        ret = do_freebsd_cap_new(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_cap_getrights: /* cap_getrights(2) */
+        ret = do_freebsd_cap_getrights(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_cap_getmode: /* cap_getmode(2) */
+        ret = do_freebsd_cap_getmode(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_audit: /* audit(2) */
+        ret = do_freebsd_audit(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_auditon: /* auditon(2) */
+        ret = do_freebsd_auditon(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getaudit: /* getaudit(2) */
+        ret = do_freebsd_getaudit(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setaudit: /* setaudit(2) */
+        ret = do_freebsd_setaudit(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getaudit_addr: /* getaudit_addr(2) */
+        ret = do_freebsd_getaudit_addr(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setaudit_addr: /* setaudit_addr(2) */
+        ret = do_freebsd_setaudit_addr(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_auditctl: /* auditctl(2) */
+        ret = do_freebsd_auditctl(arg1);
+        break;
+    case TARGET_FREEBSD_NR_utrace: /* utrace(2) */
+        ret = do_bsd_utrace(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_ptrace: /* ptrace(2) */
+        ret = do_bsd_ptrace(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_getpriority: /* getpriority(2) */
+        ret = do_bsd_getpriority(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setpriority: /* setpriority(2) */
+        ret = do_bsd_setpriority(arg1, arg2, arg3);
+        break;
+
+
     case TARGET_FREEBSD_NR_read:
         if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
             goto efault;
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 10/18] bsd-user: add support for file system related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (8 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 09/18] bsd-user: add support for freebsd process related system calls Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 11/18] bsd-user: add support for stat, directory, and file control " Stacey Son
                   ` (29 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for file system (except stat) related system
calls including read(2), pread(2), readv(2), write(2), pwrite(2), writev(2),
pwritev(2),  open(2), openat(2), close(2), closefrom(2), revoke(2), access(2),
eaccess(2), faccessat(2), chdir(2), fchdir(2), rename(2), renameat(2), link(2),
linkat(2), unlink(2), unlinkat(2), mkdir(2), mkdirat(2), rmdir(2), __getcwd(),
dup(2), dup2(2), truncate(2), ftruncate(2), acct(2), sync(2), mount(2), nmount(2),
symlink(2), symlinkat(2), readlink(2), readlinkat(2), chmod(2), fchmod(2),
lchmod(2), fchmodat(2), mknod(2), mknodat(2), chown(2), fchown(2), lchown(2),
fchownat(2), chflags(2), lchflags(2), fchflags(2), chroot(2), flock(2), mkfifo(2),
mkfifoat(2), pathconf(2), lpathconf(2), fpathconf(2), undelete(2), poll(2),
lseek(2), pipe(2), swapon(2), swapoff(2), and the undocumented openbsd_poll()
and freebsd6_*() system calls.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/bsd-file.h | 1111 +++++++++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/qemu.h     |   36 ++
 bsd-user/syscall.c  |  391 ++++++++++++++----
 3 files changed, 1454 insertions(+), 84 deletions(-)
 create mode 100644 bsd-user/bsd-file.h

diff --git a/bsd-user/bsd-file.h b/bsd-user/bsd-file.h
new file mode 100644
index 0000000..fc279a8
--- /dev/null
+++ b/bsd-user/bsd-file.h
@@ -0,0 +1,1111 @@
+/*
+ *  file related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_FILE_H_
+#define __BSD_FILE_H_
+
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define target_to_host_bitmask(x, tbl) (x)
+
+#define LOCK_PATH(p, arg)  do {             \
+    (p) =  lock_user_string(arg);           \
+    if ((p) == NULL) {                      \
+        return -TARGET_EFAULT;              \
+    }                                       \
+} while (0)
+
+#define UNLOCK_PATH(p, arg)   unlock_user((p), (arg), 0)
+
+struct target_pollfd {
+    int32_t fd;         /* file descriptor */
+    int16_t events;     /* requested events */
+    int16_t revents;    /* returned events */
+};
+
+static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
+        int count, int copy);
+static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
+        int count, int copy);
+extern int __getcwd(char *path, size_t len);
+
+/* read(2) */
+static inline abi_long do_bsd_read(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(read(arg1, p, arg3));
+    unlock_user(p, arg2, ret);
+
+    return ret;
+}
+
+/* pread(2) */
+static inline abi_long do_bsd_pread(void *cpu_env, abi_long arg1,
+    abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg4 = arg5;
+        arg5 = arg6;
+    }
+    ret = get_errno(pread(arg1, p, arg3, target_offset64(arg4, arg5)));
+    unlock_user(p, arg2, ret);
+
+    return ret;
+}
+
+/* readv(2) */
+static inline abi_long do_bsd_readv(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    int count = arg3;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (vec == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(readv(arg1, vec, count));
+    unlock_iovec(vec, arg2, count, 1);
+
+    return ret;
+}
+
+/* write(2) */
+static inline abi_long do_bsd_write(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_READ, arg2, arg3, 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(write(arg1, p, arg3));
+    unlock_user(p, arg2, 0);
+
+    return ret;
+}
+
+/* pwrite(2) */
+static inline abi_long do_bsd_pwrite(void *cpu_env, abi_long arg1,
+    abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_READ, arg2, arg3, 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg4 = arg5;
+        arg5 = arg6;
+    }
+    ret = get_errno(pwrite(arg1, p, arg3, target_offset64(arg4, arg5)));
+    unlock_user(p, arg2, 0);
+
+    return ret;
+}
+
+/* writev(2) */
+static inline abi_long do_bsd_writev(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    int count = arg3;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (vec == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(writev(arg1, vec, count));
+    unlock_iovec(vec, arg2, count, 0);
+
+    return ret;
+}
+
+/* pwritev(2) */
+static inline abi_long do_bsd_pwritev(void *cpu_env, abi_long arg1,
+    abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    int count = arg3;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (vec == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) {
+        return -TARGET_EFAULT;
+    }
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg4 = arg5;
+        arg5 = arg6;
+    }
+    ret = get_errno(pwritev(arg1, vec, count, target_offset64(arg4, arg5)));
+    unlock_iovec(vec, arg2, count, 0);
+
+    return ret;
+}
+
+/* open(2) */
+static inline abi_long do_bsd_open(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(open(path(p), target_to_host_bitmask(arg2, fcntl_flags_tbl),
+                arg3));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* openat(2) */
+static inline abi_long do_bsd_openat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(openat(arg1, path(p),
+                target_to_host_bitmask(arg3, fcntl_flags_tbl), arg4));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* close(2) */
+static inline abi_long do_bsd_close(abi_long arg1)
+{
+
+    return get_errno(close(arg1));
+}
+
+/* closefrom(2) */
+static inline abi_long do_bsd_closefrom(abi_long arg1)
+{
+
+    closefrom(arg1);  /* returns void */
+    return get_errno(0);
+}
+
+/* revoke(2) */
+static inline abi_long do_bsd_revoke(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(revoke(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* creat(2) (obsolete) */
+static inline abi_long do_bsd_creat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(open(path(p), O_CREAT | O_TRUNC | O_WRONLY, arg2));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+
+/* access(2) */
+static inline abi_long do_bsd_access(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(access(path(p), arg2));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* eaccess(2) */
+static inline abi_long do_bsd_eaccess(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(eaccess(path(p), arg2));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* faccessat(2) */
+static inline abi_long do_bsd_faccessat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(faccessat(arg1, p, arg3, arg4)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* chdir(2) */
+static inline abi_long do_bsd_chdir(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chdir(p)); /* XXX  path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchdir(2) */
+static inline abi_long do_bsd_fchdir(abi_long arg1)
+{
+
+    return get_errno(fchdir(arg1));
+}
+
+/* rename(2) */
+static inline abi_long do_bsd_rename(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(rename(p1, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* renameat(2) */
+static inline abi_long do_bsd_renameat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(renameat(arg1, p1, arg3, p2));
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* link(2) */
+static inline abi_long do_bsd_link(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(link(p1, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* linkat(2) */
+static inline abi_long do_bsd_linkat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg2);
+    LOCK_PATH(p2, arg4);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(linkat(arg1, p1, arg3, p2, arg5));
+    }
+    UNLOCK_PATH(p2, arg4);
+    UNLOCK_PATH(p1, arg2);
+
+    return ret;
+}
+
+/* unlink(2) */
+static inline abi_long do_bsd_unlink(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(unlink(p)); /* XXX path(p) */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* unlinkat(2) */
+static inline abi_long do_bsd_unlinkat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(unlinkat(arg1, p, arg3)); /* XXX path(p) */
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* mkdir(2) */
+static inline abi_long do_bsd_mkdir(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(mkdir(p, arg2)); /* XXX path(p) */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+
+/* mkdirat(2) */
+static inline abi_long do_bsd_mkdirat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(mkdirat(arg1, p, arg3));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+
+/* rmdir(2) */
+static inline abi_long do_bsd_rmdir(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(rmdir(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* undocumented __getcwd(char *buf, size_t len)  system call */
+static inline abi_long do_bsd___getcwd(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__getcwd(p, arg2));
+    unlock_user(p, arg1, ret);
+
+    return ret;
+}
+
+/* dup(2) */
+static inline abi_long do_bsd_dup(abi_long arg1)
+{
+
+    return get_errno(dup(arg1));
+}
+
+/* dup2(2) */
+static inline abi_long do_bsd_dup2(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(dup2(arg1, arg2));
+}
+
+/* truncate(2) */
+static inline abi_long do_bsd_truncate(void *cpu_env, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg2 = arg3;
+        arg3 = arg4;
+    }
+    ret = get_errno(truncate(p, target_offset64(arg2, arg3)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* ftruncate(2) */
+static inline abi_long do_bsd_ftruncate(void *cpu_env, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4)
+{
+
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg2 = arg3;
+        arg3 = arg4;
+    }
+    return get_errno(ftruncate(arg1, target_offset64(arg2, arg3)));
+}
+
+/* acct(2) */
+static inline abi_long do_bsd_acct(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    if (arg1 == 0) {
+        ret = get_errno(acct(NULL));
+    } else {
+        LOCK_PATH(p, arg1);
+        ret = get_errno(acct(path(p)));
+        UNLOCK_PATH(p, arg1);
+    }
+    return ret;
+}
+
+/* sync(2) */
+static inline abi_long do_bsd_sync(void)
+{
+
+    sync();
+    return 0;
+}
+
+/* mount(2) */
+static inline abi_long do_bsd_mount(abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        /*
+         * XXX arg4 should be locked, but it isn't clear how to do that
+         * since it's it may be not be a NULL-terminated string.
+         */
+        if (arg4 == 0) {
+            ret = get_errno(mount(p1, p2, arg3, NULL)); /* XXX path(p2)? */
+        } else {
+            ret = get_errno(mount(p1, p2, arg3, g2h(arg4))); /* XXX path(p2)? */
+        }
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* unmount(2) */
+static inline abi_long do_bsd_unmount(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(unmount(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* nmount(2) */
+static inline abi_long do_bsd_nmount(abi_long arg1, abi_long count,
+        abi_long flags)
+{
+    abi_long ret;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (lock_iovec(VERIFY_READ, vec, arg1, count, 1) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(nmount(vec, count, flags));
+    unlock_iovec(vec, arg1, count, 0);
+
+    return ret;
+}
+
+/* symlink(2) */
+static inline abi_long do_bsd_symlink(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(symlink(p1, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* symlinkat(2) */
+static inline abi_long do_bsd_symlinkat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg3);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(symlinkat(p1, arg2, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg3);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* readlink(2) */
+static inline abi_long do_bsd_readlink(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(readlink(path(p1), p2, arg3));
+    }
+    unlock_user(p2, arg2, ret);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* readlinkat(2) */
+static inline abi_long do_bsd_readlinkat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg2);
+    p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(readlinkat(arg1, p1, p2, arg4));
+    }
+    unlock_user(p2, arg3, ret);
+    UNLOCK_PATH(p1, arg2);
+
+    return ret;
+}
+
+/* chmod(2) */
+static inline abi_long do_bsd_chmod(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chmod(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchmod(2) */
+static inline abi_long do_bsd_fchmod(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(fchmod(arg1, arg2));
+}
+
+/* lchmod(2) */
+static inline abi_long do_bsd_lchmod(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lchmod(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchmodat(2) */
+static inline abi_long do_bsd_fchmodat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(fchmodat(arg1, p, arg3, arg4));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* mknod(2) */
+static inline abi_long do_bsd_mknod(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(mknod(p, arg2, arg3)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* mknodat(2) */
+static inline abi_long do_bsd_mknodat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(mknodat(arg1, p, arg3, arg4));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* chown(2) */
+static inline abi_long do_bsd_chown(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chown(p, arg2, arg3)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchown(2) */
+static inline abi_long do_bsd_fchown(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    return get_errno(fchown(arg1, arg2, arg3));
+}
+
+/* lchown(2) */
+static inline abi_long do_bsd_lchown(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lchown(p, arg2, arg3)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchownat(2) */
+static inline abi_long do_bsd_fchownat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(fchownat(arg1, p, arg3, arg4, arg5)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* chflags(2) */
+static inline abi_long do_bsd_chflags(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chflags(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* lchflags(2) */
+static inline abi_long do_bsd_lchflags(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lchflags(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchflags(2) */
+static inline abi_long do_bsd_fchflags(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(fchflags(arg1, arg2));
+}
+
+/* chroot(2) */
+static inline abi_long do_bsd_chroot(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chroot(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* flock(2) */
+static abi_long do_bsd_flock(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(flock(arg1, arg2));
+}
+
+/* mkfifo(2) */
+static inline abi_long do_bsd_mkfifo(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(mkfifo(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* mkfifoat(2) */
+static inline abi_long do_bsd_mkfifoat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(mkfifoat(arg1, p, arg3));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* pathconf(2) */
+static inline abi_long do_bsd_pathconf(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(pathconf(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* lpathconf(2) */
+static inline abi_long do_bsd_lpathconf(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lpathconf(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fpathconf(2) */
+static inline abi_long do_bsd_fpathconf(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(fpathconf(arg1, arg2));
+}
+
+/* undelete(2) */
+static inline abi_long do_bsd_undelete(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(undelete(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* poll(2) */
+static abi_long do_bsd_poll(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    nfds_t i, nfds = arg2;
+    int timeout = arg3;
+    struct pollfd *pfd;
+    struct target_pollfd *target_pfd;
+
+    target_pfd = lock_user(VERIFY_WRITE, arg1,
+            sizeof(struct target_pollfd) * nfds, 1);
+    if (!target_pfd) {
+        return -TARGET_EFAULT;
+    }
+    pfd = alloca(sizeof(struct pollfd) * nfds);
+    for (i = 0; i < nfds; i++) {
+        pfd[i].fd = tswap32(target_pfd[i].fd);
+        pfd[i].events = tswap16(target_pfd[i].events);
+    } ret = get_errno(poll(pfd, nfds, timeout));
+    if (!is_error(ret)) {
+        for (i = 0; i < nfds; i++) {
+            target_pfd[i].revents = tswap16(pfd[i].revents);
+        }
+    }
+    unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
+
+    return ret;
+}
+
+/*
+ * undocumented openbsd_poll(struct pollfd *fds, u_int nfds, int
+ * timeout) system call.
+ */
+static abi_long do_bsd_openbsd_poll(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall openbsd_poll()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* lseek(2) */
+static abi_long do_bsd_lseek(void *cpu_env, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+#if TARGET_ABI_BITS == 32
+    int64_t res;
+
+    /* 32-bit arch's use two 32 registers for 64 bit return value */
+    if (regpairs_aligned(cpu_env) != 0) {
+    	res = lseek(arg1, target_offset64(arg3, arg4), arg5);
+    } else {
+        res = lseek(arg1, target_offset64(arg2, arg3), arg4);
+    }
+    if (res == -1) {
+        ret = get_errno(res);
+    } else {
+        ret = res & 0xFFFFFFFF;
+        set_second_rval(cpu_env, (res >> 32) & 0xFFFFFFFF);
+    }
+#else
+    ret = get_errno(lseek(arg1, arg2, arg3));
+#endif
+    return ret;
+}
+
+/* pipe(2) */
+static abi_long do_bsd_pipe(void *cpu_env, abi_long arg1)
+{
+    abi_long ret;
+    int host_pipe[2];
+    int host_ret = pipe(host_pipe);
+
+    if (host_ret != -1) {
+        set_second_rval(cpu_env, host_pipe[1]);
+        ret = host_pipe[0];
+    } else {
+        ret = get_errno(host_ret);
+    }
+    return ret;
+}
+
+/* swapon(2) */
+static abi_long do_bsd_swapon(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(swapon(path(p)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* swapoff(2) */
+static abi_long do_bsd_swapoff(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(swapoff(path(p)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/*
+ * undocumented freebsd6_pread(int fd, void *buf, size_t nbyte, int pad,
+ * off_t offset) system call.
+ */
+static abi_long do_bsd_freebsd6_pread(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_pread()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_pwrite(int fd, void *buf, size_t nbyte, int pad,
+ * off_t offset) system call.
+ */
+static abi_long do_bsd_freebsd6_pwrite(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_pwrite()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_lseek(int fd, int pad, off_t offset, int whence)
+ * system call.
+ */
+static abi_long do_bsd_freebsd6_lseek(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_lseek()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_truncate(char *path, int pad, off_t offset) system
+ * call.
+ */
+static abi_long do_bsd_freebsd6_truncate(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_truncate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_ftruncate(int fd, int pad, off_t offset) system
+ * call.
+ */
+static abi_long do_bsd_freebsd6_ftruncate(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_ftruncate()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__BSD_FILE_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index a9f5666..e668a67 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -446,6 +446,42 @@ static inline void *lock_user_string(abi_ulong guest_addr)
 #define unlock_user_struct(host_ptr, guest_addr, copy)          \
     unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
 
+#if TARGET_ABI_BITS == 32
+static inline uint64_t
+target_offset64(uint32_t word0, uint32_t word1)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    return ((uint64_t)word0 << 32) | word1;
+#else
+    return ((uint64_t)word1 << 32) | word0;
+#endif
+}
+#else /* TARGET_ABI_BITS != 32 */
+static inline uint64_t
+target_offset64(uint64_t word0, uint64_t word1)
+{
+    return word0;
+}
+#endif /* TARGET_ABI_BITS != 32 */
+
+/* ARM EABI and MIPS expect 64bit types aligned even on pairs of registers */
+#ifdef TARGET_ARM
+static inline int
+regpairs_aligned(void *cpu_env) {
+    return ((((CPUARMState *)cpu_env)->eabi) == 1);
+}
+#elif defined(TARGET_MIPS) && TARGET_ABI_BITS == 32
+static inline int regpairs_aligned(void *cpu_env)
+{
+    return 1;
+}
+#else
+static inline int regpairs_aligned(void *cpu_env)
+{
+    return 0;
+}
+#endif
+
 #if defined(CONFIG_USE_NPTL)
 #include <pthread.h>
 #endif
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index f8a40f0..15780af 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -41,6 +41,7 @@
 static int host_to_target_errno(int err);
 
 /* BSD independent syscall shims */
+#include "bsd-file.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
 
@@ -176,7 +177,6 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                             abi_long arg8)
 {
     abi_long ret;
-    void *p;
 
 #ifdef DEBUG
     gemu_log("freebsd syscall %d\n", num);
@@ -433,38 +433,305 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
 
-    case TARGET_FREEBSD_NR_read:
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-            goto efault;
-        ret = get_errno(read(arg1, p, arg3));
-        unlock_user(p, arg2, ret);
+        /*
+         * File system calls.
+         */
+    case TARGET_FREEBSD_NR_read: /* read(2) */
+        ret = do_bsd_read(arg1, arg2, arg3);
         break;
-    case TARGET_FREEBSD_NR_write:
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            goto efault;
-        ret = get_errno(write(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
+
+    case TARGET_FREEBSD_NR_pread: /* pread(2) */
+        ret = do_bsd_pread(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
-    case TARGET_FREEBSD_NR_writev:
-        {
-            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(writev(arg1, vec, count));
-            unlock_iovec(vec, arg2, count, 0);
-        }
+    case TARGET_FREEBSD_NR_readv: /* readv(2) */
+        ret = do_bsd_read(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_write: /* write(2) */
+        ret = do_bsd_write(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pwrite: /* pwrite(2) */
+        ret = do_bsd_pwrite(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_writev: /* writev(2) */
+        ret = do_bsd_writev(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pwritev: /* pwritev(2) */
+        ret = do_bsd_pwritev(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_open: /* open(2) */
+        ret = do_bsd_open(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_openat: /* openat(2) */
+        ret = do_bsd_openat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_close: /* close(2) */
+        ret = do_bsd_close(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_closefrom: /* closefrom(2) */
+        ret = do_bsd_closefrom(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_revoke: /* revoke(2) */
+        ret = do_bsd_revoke(arg1);
+        break;
+
+#ifdef TARGET_FREEBSD_NR_creat
+    case TARGET_FREEBSD_NR_creat: /* creat(2) (obsolete) */
+        ret = do_bsd_creat(arg1);
+        break;
+#endif
+
+    case TARGET_FREEBSD_NR_access: /* access(2) */
+        ret = do_bsd_access(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_eaccess: /* eaccess(2) */
+        ret = do_bsd_eaccess(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_faccessat: /* faccessat(2) */
+        ret = do_bsd_faccessat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_chdir: /* chdir(2) */
+        ret = do_bsd_chdir(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_fchdir: /* fchdir(2) */
+        ret = do_bsd_fchdir(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_rename: /* rename(2) */
+        ret = do_bsd_rename(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_renameat: /* renameat(2) */
+        ret = do_bsd_renameat(arg1, arg2, arg3, arg4);
         break;
-    case TARGET_FREEBSD_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
-        unlock_user(p, arg1, 0);
+
+    case TARGET_FREEBSD_NR_link: /* link(2) */
+        ret = do_bsd_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_linkat: /* linkat(2) */
+        ret = do_bsd_linkat(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_unlink: /* unlink(2) */
+        ret = do_bsd_unlink(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_unlinkat: /* unlinkat(2) */
+        ret = do_bsd_unlinkat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mkdir: /* mkdir(2) */
+        ret = do_bsd_mkdir(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mkdirat: /* mkdirat(2) */
+        ret = do_bsd_mkdirat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_rmdir: /* rmdir(2) (XXX no rmdirat()?) */
+        ret = do_bsd_rmdir(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___getcwd: /* undocumented __getcwd() */
+        ret = do_bsd___getcwd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_dup: /* dup(2) */
+        ret = do_bsd_dup(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_dup2: /* dup2(2) */
+        ret = do_bsd_dup2(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_truncate: /* truncate(2) */
+        ret = do_bsd_truncate(cpu_env, arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ftruncate: /* ftruncate(2) */
+        ret = do_bsd_ftruncate(cpu_env, arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_acct: /* acct(2) */
+        ret = do_bsd_acct(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sync: /* sync(2) */
+        ret = do_bsd_sync();
+        break;
+
+    case TARGET_FREEBSD_NR_mount: /* mount(2) */
+        ret = do_bsd_mount(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_unmount: /* unmount(2) */
+        ret = do_bsd_unmount(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_nmount: /* nmount(2) */
+        ret = do_bsd_nmount(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_symlink: /* symlink(2) */
+        ret = do_bsd_symlink(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_symlinkat: /* symlinkat(2) */
+        ret = do_bsd_symlinkat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_readlink: /* readlink(2) */
+        ret = do_bsd_readlink(arg1, arg2, arg3);
         break;
+
+    case TARGET_FREEBSD_NR_readlinkat: /* readlinkat(2) */
+        ret = do_bsd_readlinkat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_chmod: /* chmod(2) */
+        ret = do_bsd_chmod(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fchmod: /* fchmod(2) */
+        ret = do_bsd_fchmod(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lchmod: /* lchmod(2) */
+        ret = do_bsd_lchmod(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fchmodat: /* fchmodat(2) */
+        ret = do_bsd_fchmodat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_mknod: /* mknod(2) */
+        ret = do_bsd_mknod(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mknodat: /* mknodat(2) */
+        ret = do_bsd_mknodat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_chown: /* chown(2) */
+        ret = do_bsd_chown(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_fchown: /* fchown(2) */
+        ret = do_bsd_fchown(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_lchown: /* lchown(2) */
+        ret = do_bsd_lchown(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_fchownat: /* fchownat(2) */
+        ret = do_bsd_fchownat(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_chflags: /* chflags(2) */
+        ret = do_bsd_chflags(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lchflags: /* lchflags(2) */
+        ret = do_bsd_lchflags(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fchflags: /* fchflags(2) */
+        ret = do_bsd_fchflags(arg2, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_chroot: /* chroot(2) */
+        ret = do_bsd_chroot(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_flock: /* flock(2) */
+        ret = do_bsd_flock(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mkfifo: /* mkfifo(2) */
+        ret = do_bsd_mkfifo(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mkfifoat: /* mkfifoat(2) */
+        ret = do_bsd_mkfifoat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pathconf: /* pathconf(2) */
+        ret = do_bsd_pathconf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lpathconf: /* lpathconf(2) */
+        ret = do_bsd_lpathconf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fpathconf: /* fpathconf(2) */
+        ret = do_bsd_fpathconf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_undelete: /* undelete(2) */
+        ret = do_bsd_undelete(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_poll: /* poll(2) */
+        ret = do_bsd_poll(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_openbsd_poll:  /* undocumented openbsd_poll() */
+        ret = do_bsd_openbsd_poll(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_lseek: /* lseek(2) */
+        ret = do_bsd_lseek(cpu_env, arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_pipe: /* pipe(2) */
+        ret = do_bsd_pipe(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_swapon: /* swapon(2) */
+        ret = do_bsd_swapon(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_swapoff: /* swapoff(2) */
+        ret = do_bsd_swapoff(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_pread: /* undocumented freebsd6_pread() */
+        ret = do_bsd_freebsd6_pread(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_pwrite: /* undocumented freebsd6_pwrite() */
+        ret = do_bsd_freebsd6_pwrite(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_lseek: /* undocumented freebsd6_lseek() */
+        ret = do_bsd_freebsd6_lseek(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_truncate: /* undocumented */
+        ret = do_bsd_freebsd6_truncate(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_ftruncate: /* undocumented */
+        ret = do_bsd_freebsd6_ftruncate(arg1, arg2, arg3);
+        break;
+
+
+
     case TARGET_FREEBSD_NR_mmap:
         ret = get_errno(target_mmap(arg1, arg2, arg3,
                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
@@ -654,16 +921,12 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                     arg8));
         break;
     }
- fail:
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
     if (do_strace)
         print_freebsd_syscall_ret(num, ret);
     return ret;
- efault:
-    ret = -TARGET_EFAULT;
-    goto fail;
 }
 
 abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
@@ -671,7 +934,6 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
                            abi_long arg5, abi_long arg6)
 {
     abi_long ret;
-    void *p;
 
 #ifdef DEBUG
     gemu_log("netbsd syscall %d\n", num);
@@ -681,34 +943,19 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
 
     switch(num) {
     case TARGET_NETBSD_NR_exit:
-#ifdef TARGET_GPROF
-        _mcleanup();
-#endif
-        gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
-        _exit(arg1);
-        ret = 0; /* avoid warning */
+        ret = do_bsd_exit(cpu_env, arg1);
         break;
+
     case TARGET_NETBSD_NR_read:
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-            goto efault;
-        ret = get_errno(read(arg1, p, arg3));
-        unlock_user(p, arg2, ret);
+        ret = do_bsd_read(arg1, arg2, arg3);
         break;
     case TARGET_NETBSD_NR_write:
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            goto efault;
-        ret = get_errno(write(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
+        ret = do_bsd_write(arg1, arg2, arg3);
         break;
     case TARGET_NETBSD_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
-        unlock_user(p, arg1, 0);
+        ret = do_bsd_open(arg1, arg2, arg3);
         break;
+
     case TARGET_NETBSD_NR_mmap:
         ret = get_errno(target_mmap(arg1, arg2, arg3,
                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
@@ -727,16 +974,12 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
     }
- fail:
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
     if (do_strace)
         print_netbsd_syscall_ret(num, ret);
     return ret;
- efault:
-    ret = -TARGET_EFAULT;
-    goto fail;
 }
 
 abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
@@ -744,7 +987,6 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
                             abi_long arg5, abi_long arg6)
 {
     abi_long ret;
-    void *p;
 
 #ifdef DEBUG
     gemu_log("openbsd syscall %d\n", num);
@@ -754,34 +996,19 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
 
     switch(num) {
     case TARGET_OPENBSD_NR_exit:
-#ifdef TARGET_GPROF
-        _mcleanup();
-#endif
-        gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
-        _exit(arg1);
-        ret = 0; /* avoid warning */
+        ret = do_bsd_exit(cpu_env, arg1);
         break;
+
     case TARGET_OPENBSD_NR_read:
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-            goto efault;
-        ret = get_errno(read(arg1, p, arg3));
-        unlock_user(p, arg2, ret);
+        ret = do_bsd_read(arg1, arg2, arg3);
         break;
     case TARGET_OPENBSD_NR_write:
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            goto efault;
-        ret = get_errno(write(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
+        ret = do_bsd_write(arg1, arg2, arg3);
         break;
     case TARGET_OPENBSD_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
-        unlock_user(p, arg1, 0);
+        ret = do_bsd_open(arg1, arg2, arg3);
         break;
+
     case TARGET_OPENBSD_NR_mmap:
         ret = get_errno(target_mmap(arg1, arg2, arg3,
                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
@@ -800,16 +1027,12 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
     }
- fail:
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
     if (do_strace)
         print_openbsd_syscall_ret(num, ret);
     return ret;
- efault:
-    ret = -TARGET_EFAULT;
-    goto fail;
 }
 
 void syscall_init(void)
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 11/18] bsd-user: add support for stat, directory, and file control related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (9 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 10/18] bsd-user: add support for file system " Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 12/18] bsd-user: add support for memory management " Stacey Son
                   ` (28 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for stat, directory, and file control related
system calls including stat(2), lstat(2), fstat(2), fstatat(2), nstat(), nfstat(),
nlstat(), getfh(2), lgetfh(2), fhopen(2), fhstat(2), fhstatfs(2), statfs(2),
fstatfs(2), getfsstat(2), getdents(2), getdirentries(2), and fcntl(2).

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs     |    1 +
 bsd-user/freebsd/os-stat.c |  234 +++++++++++++++++++++++
 bsd-user/freebsd/os-stat.h |  437 ++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h |    8 +
 bsd-user/netbsd/os-stat.c  |    1 +
 bsd-user/netbsd/os-stat.h  |    1 +
 bsd-user/openbsd/os-stat.c |    1 +
 bsd-user/openbsd/os-stat.h |  176 ++++++++++++++++++
 bsd-user/syscall.c         |   76 ++++++++
 9 files changed, 935 insertions(+), 0 deletions(-)
 create mode 100644 bsd-user/freebsd/os-stat.c
 create mode 100644 bsd-user/freebsd/os-stat.h
 create mode 100644 bsd-user/netbsd/os-stat.c
 create mode 100644 bsd-user/netbsd/os-stat.h
 create mode 100644 bsd-user/openbsd/os-stat.c
 create mode 100644 bsd-user/openbsd/os-stat.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 6a2fc37..ee70866 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,5 +1,6 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
 	        uaccess.o bsd-proc.o \
 			$(HOST_ABI_DIR)/os-proc.o \
+			$(HOST_ABI_DIR)/os-stat.o \
 			$(HOST_ABI_DIR)/os-sys.o \
 			$(HOST_ABI_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/freebsd/os-stat.c b/bsd-user/freebsd/os-stat.c
new file mode 100644
index 0000000..50885d1
--- /dev/null
+++ b/bsd-user/freebsd/os-stat.c
@@ -0,0 +1,234 @@
+/*
+ *  FreeBSD stat related conversion routines
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+/*
+ * stat conversion
+ */
+abi_long h2t_freebsd_stat(abi_ulong target_addr, struct stat *host_st)
+{
+    struct target_freebsd_stat *target_st;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    memset(target_st, 0, sizeof(*target_st));
+    __put_user(host_st->st_dev, &target_st->st_dev);
+    __put_user(host_st->st_ino, &target_st->st_ino);
+    __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_atim.tv_sec, &target_st->st_atim.tv_sec);
+    __put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec);
+    __put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec);
+    __put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec);
+    __put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec);
+    __put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec);
+    __put_user(host_st->st_size, &target_st->st_size);
+    __put_user(host_st->st_blocks, &target_st->st_blocks);
+    __put_user(host_st->st_blksize, &target_st->st_blksize);
+    __put_user(host_st->st_flags, &target_st->st_flags);
+    __put_user(host_st->st_gen, &target_st->st_gen);
+    /* st_lspare not used */
+    __put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec);
+    __put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec);
+    unlock_user_struct(target_st, target_addr, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_nstat(abi_ulong target_addr, struct stat *host_st)
+{
+    struct target_freebsd_nstat *target_st;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    memset(target_st, 0, sizeof(*target_st));
+    __put_user(host_st->st_dev, &target_st->st_dev);
+    __put_user(host_st->st_ino, &target_st->st_ino);
+    __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_atim.tv_sec, &target_st->st_atim.tv_sec);
+    __put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec);
+    __put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec);
+    __put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec);
+    __put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec);
+    __put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec);
+    __put_user(host_st->st_size, &target_st->st_size);
+    __put_user(host_st->st_blocks, &target_st->st_blocks);
+    __put_user(host_st->st_blksize, &target_st->st_blksize);
+    __put_user(host_st->st_flags, &target_st->st_flags);
+    __put_user(host_st->st_gen, &target_st->st_gen);
+    __put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec);
+    __put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec);
+    unlock_user_struct(target_st, target_addr, 1);
+
+    return 0;
+}
+
+/*
+ * file handle conversion
+ */
+abi_long t2h_freebsd_fhandle(fhandle_t *host_fh, abi_ulong target_addr)
+{
+    target_freebsd_fhandle_t *target_fh;
+
+    if (!lock_user_struct(VERIFY_READ, target_fh, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]);
+    __get_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]);
+    __get_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len);
+    /* u_short         fid_data0; */
+    memcpy(host_fh->fh_fid.fid_data, target_fh->fh_fid.fid_data,
+        TARGET_MAXFIDSZ);
+    unlock_user_struct(target_fh, target_addr, 0);
+    return 0;
+}
+
+abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh)
+{
+    target_freebsd_fhandle_t *target_fh;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_fh, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]);
+    __put_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]);
+    __put_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len);
+    /* u_short         fid_data0; */
+    memcpy(target_fh->fh_fid.fid_data, host_fh->fh_fid.fid_data,
+            TARGET_MAXFIDSZ);
+    unlock_user_struct(target_fh, target_addr, 1);
+    return 0;
+}
+
+/*
+ *  file system stat
+ */
+abi_long h2t_freebsd_statfs(abi_ulong target_addr, struct statfs *host_statfs)
+{
+    struct target_freebsd_statfs *target_statfs;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_statfs, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_statfs->f_version, &target_statfs->f_version);
+    __put_user(host_statfs->f_type, &target_statfs->f_type);
+    __put_user(host_statfs->f_flags, &target_statfs->f_flags);
+    __put_user(host_statfs->f_bsize, &target_statfs->f_bsize);
+    __put_user(host_statfs->f_iosize, &target_statfs->f_iosize);
+    __put_user(host_statfs->f_blocks, &target_statfs->f_blocks);
+    __put_user(host_statfs->f_bfree, &target_statfs->f_bfree);
+    __put_user(host_statfs->f_bavail, &target_statfs->f_bavail);
+    __put_user(host_statfs->f_files, &target_statfs->f_files);
+    __put_user(host_statfs->f_ffree, &target_statfs->f_ffree);
+    __put_user(host_statfs->f_syncwrites, &target_statfs->f_syncwrites);
+    __put_user(host_statfs->f_asyncwrites, &target_statfs->f_asyncwrites);
+    __put_user(host_statfs->f_syncreads, &target_statfs->f_syncreads);
+    __put_user(host_statfs->f_asyncreads, &target_statfs->f_asyncreads);
+    /* uint64_t f_spare[10]; */
+    __put_user(host_statfs->f_namemax, &target_statfs->f_namemax);
+    __put_user(host_statfs->f_owner, &target_statfs->f_owner);
+    __put_user(host_statfs->f_fsid.val[0], &target_statfs->f_fsid.val[0]);
+    __put_user(host_statfs->f_fsid.val[1], &target_statfs->f_fsid.val[1]);
+    /* char f_charspace[80]; */
+    strncpy(&target_statfs->f_fstypename[0], host_statfs->f_fstypename,
+        TARGET_MFSNAMELEN);
+    strncpy(&target_statfs->f_mntfromname[0], host_statfs->f_mntfromname,
+        TARGET_MNAMELEN);
+    strncpy(&target_statfs->f_mntonname[0], host_statfs->f_mntonname,
+        TARGET_MNAMELEN);
+    unlock_user_struct(target_statfs, target_addr, 1);
+    return 0;
+}
+
+/*
+ * fcntl cmd conversion
+ */
+abi_long target_to_host_fcntl_cmd(int cmd)
+{
+
+    switch (cmd) {
+    case TARGET_F_DUPFD:
+        return F_DUPFD;
+
+    case TARGET_F_DUP2FD:
+        return F_DUP2FD;
+
+    case TARGET_F_GETFD:
+        return F_GETFD;
+
+    case TARGET_F_SETFD:
+        return F_SETFD;
+
+    case TARGET_F_GETFL:
+        return F_GETFL;
+
+    case TARGET_F_SETFL:
+        return F_SETFL;
+
+    case TARGET_F_GETOWN:
+        return F_GETOWN;
+
+    case TARGET_F_SETOWN:
+        return F_SETOWN;
+
+    case TARGET_F_GETLK:
+        return F_GETLK;
+
+    case TARGET_F_SETLK:
+        return F_SETLK;
+
+    case TARGET_F_SETLKW:
+        return F_SETLKW;
+
+    case TARGET_F_READAHEAD:
+        return F_READAHEAD;
+
+    case TARGET_F_RDAHEAD:
+        return F_RDAHEAD;
+
+#ifdef F_DUPFD_CLOEXEC
+    case TARGET_F_DUPFD_CLOEXEC:
+        return F_DUPFD_CLOEXEC;
+#endif
+
+#ifdef F_DUP2FD_CLOEXEC
+    case TARGET_F_DUP2FD_CLOEXEC:
+        return F_DUP2FD_CLOEXEC;
+#endif
+
+    default:
+        return -TARGET_EINVAL;
+    }
+}
+
diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h
new file mode 100644
index 0000000..ed6bcab
--- /dev/null
+++ b/bsd-user/freebsd/os-stat.h
@@ -0,0 +1,437 @@
+/*
+ *  stat related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_STAT_H_
+#define __FREEBSD_STAT_H_
+
+#include <sys/types.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include "qemu-os.h"
+
+/* undocumented nstat system calls */
+int nstat(const char *path, struct stat *sb);
+int nlstat(const char *path, struct stat *sb);
+int nfstat(int fd, struct stat *sb);
+
+/* stat(2) */
+static inline abi_long do_freebsd_stat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(stat(path(p), &st));
+    UNLOCK_PATH(p, arg1);
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_stat(arg2, &st);
+    }
+    return ret;
+}
+
+/* lstat(2) */
+static inline abi_long do_freebsd_lstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lstat(path(p), &st));
+    UNLOCK_PATH(p, arg1);
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_stat(arg2, &st);
+    }
+    return ret;
+}
+
+/* fstat(2) */
+static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct stat st;
+
+    ret = get_errno(fstat(arg1, &st));
+    if (!is_error(ret))  {
+        ret = h2t_freebsd_stat(arg2, &st);
+    }
+    return ret;
+}
+
+/* fstatat(2) */
+static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(fstatat(arg1, p, &st, arg4));
+    UNLOCK_PATH(p, arg2);
+    if (!is_error(ret) && arg3) {
+        ret = h2t_freebsd_stat(arg3, &st);
+    }
+    return ret;
+}
+
+/* undocummented nstat(char *path, struct nstat *ub) syscall */
+static abi_long do_freebsd_nstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(nstat(path(p), &st));
+    UNLOCK_PATH(p, arg1);
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_nstat(arg2, &st);
+    }
+    return ret;
+}
+
+/* undocummented nfstat(int fd, struct nstat *sb) syscall */
+static abi_long do_freebsd_nfstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct stat st;
+
+    ret = get_errno(nfstat(arg1, &st));
+    if (!is_error(ret))  {
+        ret = h2t_freebsd_nstat(arg2, &st);
+    }
+    return ret;
+}
+
+/* undocummented nlstat(char *path, struct nstat *ub) syscall */
+static abi_long do_freebsd_nlstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(nlstat(path(p), &st));
+    UNLOCK_PATH(p, arg1);
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_nstat(arg2, &st);
+    }
+    return ret;
+}
+
+/* getfh(2) */
+static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    fhandle_t host_fh;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(getfh(path(p), &host_fh));
+    UNLOCK_PATH(p, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+    return h2t_freebsd_fhandle(arg2, &host_fh);
+}
+
+/* lgetfh(2) */
+static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    fhandle_t host_fh;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lgetfh(path(p), &host_fh));
+    UNLOCK_PATH(p, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+    return h2t_freebsd_fhandle(arg2, &host_fh);
+}
+
+/* fhopen(2) */
+static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    fhandle_t host_fh;
+
+    ret = t2h_freebsd_fhandle(&host_fh, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(fhopen(&host_fh, arg2));
+}
+
+/* fhstat(2) */
+static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    fhandle_t host_fh;
+    struct stat host_sb;
+
+    ret = t2h_freebsd_fhandle(&host_fh, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = get_errno(fhstat(&host_fh, &host_sb));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return h2t_freebsd_stat(arg2, &host_sb);
+}
+
+/* fhstatfs(2) */
+static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr,
+        abi_ulong target_stfs_addr)
+{
+    abi_long ret;
+    fhandle_t host_fh;
+    struct statfs host_stfs;
+
+    ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = get_errno(fhstatfs(&host_fh, &host_stfs));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return h2t_freebsd_statfs(target_stfs_addr, &host_stfs);
+}
+
+/* statfs(2) */
+static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct statfs host_stfs;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(statfs(path(p), &host_stfs));
+    UNLOCK_PATH(p, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return h2t_freebsd_statfs(arg2, &host_stfs);
+}
+
+/* fstatfs(2) */
+static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr)
+{
+    abi_long ret;
+    struct statfs host_stfs;
+
+    ret = get_errno(fstatfs(fd, &host_stfs));
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return h2t_freebsd_statfs(target_addr, &host_stfs);
+}
+
+/* getfsstat(2) */
+static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr,
+        abi_long bufsize, abi_long flags)
+{
+    abi_long ret;
+    struct statfs *host_stfs;
+    int count;
+    long host_bufsize;
+
+    count = bufsize / sizeof(struct target_freebsd_statfs);
+
+    /* if user buffer is NULL then return number of mounted FS's */
+    if (target_addr == 0 || count == 0) {
+        return get_errno(getfsstat(NULL, 0, flags));
+    }
+
+    /* XXX check count to be reasonable */
+    host_bufsize = sizeof(struct statfs) * count;
+    host_stfs = alloca(host_bufsize);
+    if (!host_stfs) {
+        return -TARGET_EINVAL;
+    }
+
+    ret = count = get_errno(getfsstat(host_stfs, host_bufsize, flags));
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    while (count--) {
+        if (h2t_freebsd_statfs((target_addr +
+                        (count * sizeof(struct target_freebsd_statfs))),
+                    &host_stfs[count])) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getdents(2) */
+static inline abi_long do_freebsd_getdents(abi_long arg1, abi_ulong arg2,
+        abi_long nbytes)
+{
+    abi_long ret;
+    struct dirent *dirp;
+
+    dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
+    if (dirp == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(getdents(arg1, (char *)dirp, nbytes));
+    if (!is_error(ret)) {
+        struct dirent *de;
+        int len = ret;
+        int reclen;
+
+        de = dirp;
+        while (len > 0) {
+            reclen = de->d_reclen;
+            if (reclen > len) {
+                return -TARGET_EFAULT;
+            }
+            de->d_reclen = tswap16(reclen);
+            de->d_fileno = tswap32(de->d_fileno);
+            len -= reclen;
+        }
+    }
+    return ret;
+}
+
+/* getdirecentries(2) */
+static inline abi_long do_freebsd_getdirentries(abi_long arg1, abi_ulong arg2,
+        abi_long nbytes, abi_ulong arg4)
+{
+    abi_long ret;
+    struct dirent *dirp;
+    long basep;
+
+    dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
+    if (dirp == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(getdirentries(arg1, (char *)dirp, nbytes, &basep));
+    if (!is_error(ret)) {
+        struct dirent *de;
+        int len = ret;
+        int reclen;
+
+        de = dirp;
+        while (len > 0) {
+            reclen = de->d_reclen;
+            if (reclen > len) {
+                return -TARGET_EFAULT;
+            }
+            de->d_reclen = tswap16(reclen);
+            de->d_fileno = tswap32(de->d_fileno);
+            len -= reclen;
+            de = (struct dirent *)((void *)de + reclen);
+        }
+    }
+    unlock_user(dirp, arg2, ret);
+    if (arg4) {
+        if (put_user(basep, arg4, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* fcntl(2) */
+static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    int host_cmd;
+    struct flock fl;
+    struct target_freebsd_flock *target_fl;
+
+    host_cmd = target_to_host_fcntl_cmd(arg2);
+    if (host_cmd < 0) {
+        return host_cmd;
+    }
+    switch (arg2) {
+    case TARGET_F_GETLK:
+        if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(fl.l_type, &target_fl->l_type);
+        __get_user(fl.l_whence, &target_fl->l_whence);
+        __get_user(fl.l_start, &target_fl->l_start);
+        __get_user(fl.l_len, &target_fl->l_len);
+        __get_user(fl.l_pid, &target_fl->l_pid);
+        __get_user(fl.l_sysid, &target_fl->l_sysid);
+        unlock_user_struct(target_fl, arg3, 0);
+        ret = get_errno(fcntl(arg1, host_cmd, &fl));
+        if (!is_error(ret)) {
+            if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) {
+                return -TARGET_EFAULT;
+            }
+            __put_user(fl.l_type, &target_fl->l_type);
+            __put_user(fl.l_whence, &target_fl->l_whence);
+            __put_user(fl.l_start, &target_fl->l_start);
+            __put_user(fl.l_len, &target_fl->l_len);
+            __put_user(fl.l_pid, &target_fl->l_pid);
+            __put_user(fl.l_sysid, &target_fl->l_sysid);
+            unlock_user_struct(target_fl, arg3, 1);
+        }
+        break;
+
+    case TARGET_F_SETLK:
+    case TARGET_F_SETLKW:
+        if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(fl.l_type, &target_fl->l_type);
+        __get_user(fl.l_whence, &target_fl->l_whence);
+        __get_user(fl.l_start, &target_fl->l_start);
+        __get_user(fl.l_len, &target_fl->l_len);
+        __get_user(fl.l_pid, &target_fl->l_pid);
+        __get_user(fl.l_sysid, &target_fl->l_sysid);
+        unlock_user_struct(target_fl, arg3, 0);
+        ret = get_errno(fcntl(arg1, host_cmd, &fl));
+        break;
+
+    case TARGET_F_DUPFD:
+    case TARGET_F_DUP2FD:
+    case TARGET_F_GETOWN:
+    case TARGET_F_SETOWN:
+    case TARGET_F_GETFD:
+    case TARGET_F_SETFD:
+    case TARGET_F_GETFL:
+    case TARGET_F_SETFL:
+    case TARGET_F_READAHEAD:
+    case TARGET_F_RDAHEAD:
+    default:
+        ret = get_errno(fcntl(arg1, host_cmd, arg3));
+        break;
+    }
+    return ret;
+}
+
+#endif /* ! __FREEBSD_STAT_H_ */
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index bde610e..e915246 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -50,4 +50,12 @@ abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
 abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds,
         int n);
 
+/* os-stat.c */
+abi_long h2t_freebsd_stat(abi_ulong target_addr, struct stat *host_st);
+abi_long h2t_freebsd_nstat(abi_ulong target_addr, struct stat *host_st);
+abi_long t2h_freebsd_fhandle(fhandle_t *host_fh, abi_ulong target_addr);
+abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh);
+abi_long h2t_freebsd_statfs(abi_ulong target_addr, struct statfs *host_statfs);
+abi_long target_to_host_fcntl_cmd(int cmd);
+
 #endif /* !_QEMU_OS_H_ */
diff --git a/bsd-user/netbsd/os-stat.c b/bsd-user/netbsd/os-stat.c
new file mode 100644
index 0000000..11ea122
--- /dev/null
+++ b/bsd-user/netbsd/os-stat.c
@@ -0,0 +1 @@
+/* XXX NetBSD stat related helpers */
diff --git a/bsd-user/netbsd/os-stat.h b/bsd-user/netbsd/os-stat.h
new file mode 100644
index 0000000..11ea122
--- /dev/null
+++ b/bsd-user/netbsd/os-stat.h
@@ -0,0 +1 @@
+/* XXX NetBSD stat related helpers */
diff --git a/bsd-user/openbsd/os-stat.c b/bsd-user/openbsd/os-stat.c
new file mode 100644
index 0000000..de4e3f5
--- /dev/null
+++ b/bsd-user/openbsd/os-stat.c
@@ -0,0 +1 @@
+/* XXX OpenBSD stat related helpers */
diff --git a/bsd-user/openbsd/os-stat.h b/bsd-user/openbsd/os-stat.h
new file mode 100644
index 0000000..1d3850d
--- /dev/null
+++ b/bsd-user/openbsd/os-stat.h
@@ -0,0 +1,176 @@
+/*
+ *  OpenBSD stat related system call shims and definitions
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OPENBSD_STAT_H_
+#define __OPENBSD_STAT_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* stat(2) */
+static inline abi_long do_freebsd_stat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall stat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* lstat(2) */
+static inline abi_long do_freebsd_lstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall lstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fstat(2) */
+static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall fstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fstatat(2) */
+static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall fstatat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocummented nstat(char *path, struct nstat *ub) syscall */
+static abi_long do_freebsd_nstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall nstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocummented nfstat(int fd, struct nstat *sb) syscall */
+static abi_long do_freebsd_nfstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall nfstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocummented nlstat(char *path, struct nstat *ub) syscall */
+static abi_long do_freebsd_nlstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall nlstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getfh(2) */
+static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getfh()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* lgetfh(2) */
+static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall lgetfh()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fhopen(2) */
+static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall fhopen()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fhstat(2) */
+static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall fhstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fhstatfs(2) */
+static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr,
+        abi_ulong target_stfs_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall fhstatfs()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* statfs(2) */
+static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall statfs()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fstatfs(2) */
+static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall fstatfs()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getfsstat(2) */
+static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr,
+        abi_long bufsize, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall getfsstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getdents(2) */
+static inline abi_long do_freebsd_getdents(abi_long arg1, abi_ulong arg2,
+        abi_long nbytes)
+{
+
+    qemu_log("qemu: Unsupported syscall getdents()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getdirecentries(2) */
+static inline abi_long do_freebsd_getdirentries(abi_long arg1, abi_ulong arg2,
+        abi_long nbytes, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall getdirecentries()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fcntl(2) */
+static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall fcntl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_STAT_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 15780af..633d638 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -49,6 +49,7 @@ static int host_to_target_errno(int err);
 #include "os-time.h"
 #include "os-proc.h"
 #include "os-signal.h"
+#include "os-stat.h"
 
 /* #define DEBUG */
 
@@ -730,6 +731,81 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = do_bsd_freebsd6_ftruncate(arg1, arg2, arg3);
         break;
 
+        /*
+         * stat system calls
+         */
+    case TARGET_FREEBSD_NR_stat: /* stat(2) */
+        ret = do_freebsd_stat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lstat: /* lstat(2) */
+        ret = do_freebsd_lstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fstat: /* fstat(2) */
+        ret = do_freebsd_fstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fstatat: /* fstatat(2) */
+        ret = do_freebsd_fstatat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_nstat: /* undocumented */
+        ret = do_freebsd_nstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_nfstat: /* undocumented */
+        ret = do_freebsd_nfstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_nlstat: /* undocumented */
+        ret = do_freebsd_nlstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getfh: /* getfh(2) */
+        ret = do_freebsd_getfh(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lgetfh: /* lgetfh(2) */
+        ret = do_freebsd_lgetfh(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fhopen: /* fhopen(2) */
+        ret = do_freebsd_fhopen(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fhstat: /* fhstat(2) */
+        ret = do_freebsd_fhstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fhstatfs: /* fhstatfs(2) */
+        ret = do_freebsd_fhstatfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_statfs: /* statfs(2) */
+        ret = do_freebsd_statfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fstatfs: /* fstatfs(2) */
+        ret = do_freebsd_fstatfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getfsstat: /* getfsstat(2) */
+        ret = do_freebsd_getfsstat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getdents: /* getdents(2) */
+        ret = do_freebsd_getdents(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getdirentries: /* getdirentries(2) */
+        ret = do_freebsd_getdirentries(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_fcntl: /* fcntl(2) */
+        ret = do_freebsd_fcntl(arg1, arg2, arg3);
+        break;
+
 
 
     case TARGET_FREEBSD_NR_mmap:
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 12/18] bsd-user: add support for memory management related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (10 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 11/18] bsd-user: add support for stat, directory, and file control " Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 13/18] bsd-user: add support for socket " Stacey Son
                   ` (27 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for memory management related system calls
including mmap(2), munmap(2), mprotect(2), msync(2), mlock(2), munlock(2),
mlockall(2), munlockall(2), madvise(2), minherit(2), mincore(2), shm_open(2),
shm_unlink(2), shmget(2), shmctl(2), shmat(2), shmdt(2), vadvise(), sbrk(), sstk(),
and freebsd6_mmap().

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs |    2 +-
 bsd-user/bsd-mem.c     |  122 +++++++++++++++
 bsd-user/bsd-mem.h     |  393 ++++++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/mmap.c        |  160 +++++---------------
 bsd-user/qemu-bsd.h    |   10 ++
 bsd-user/qemu.h        |    3 +-
 bsd-user/syscall.c     |  174 +++++++++++++---------
 7 files changed, 670 insertions(+), 194 deletions(-)
 create mode 100644 bsd-user/bsd-mem.c
 create mode 100644 bsd-user/bsd-mem.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index ee70866..1a33a6d 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,5 +1,5 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-proc.o \
+	        uaccess.o bsd-mem.o bsd-proc.o \
 			$(HOST_ABI_DIR)/os-proc.o \
 			$(HOST_ABI_DIR)/os-stat.o \
 			$(HOST_ABI_DIR)/os-sys.o \
diff --git a/bsd-user/bsd-mem.c b/bsd-user/bsd-mem.c
new file mode 100644
index 0000000..bfe03aa
--- /dev/null
+++ b/bsd-user/bsd-mem.c
@@ -0,0 +1,122 @@
+/*
+ *  memory management system conversion routines
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+struct bsd_shm_regions bsd_shm_regions[N_BSD_SHM_REGIONS];
+
+abi_ulong bsd_target_brk;
+abi_ulong bsd_target_original_brk;
+
+void target_set_brk(abi_ulong new_brk)
+{
+
+    bsd_target_original_brk = bsd_target_brk = HOST_PAGE_ALIGN(new_brk);
+}
+
+abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
+        abi_ulong target_addr)
+{
+    struct target_ipc_perm *target_ip;
+
+    if (!lock_user_struct(VERIFY_READ, target_ip, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_ip->cuid, &target_ip->cuid);
+    __get_user(host_ip->cgid, &target_ip->cgid);
+    __get_user(host_ip->uid, &target_ip->uid);
+    __get_user(host_ip->gid, &target_ip->gid);
+    __get_user(host_ip->mode, &target_ip->mode);
+    __get_user(host_ip->seq, &target_ip->seq);
+    __get_user(host_ip->key, &target_ip->key);
+    unlock_user_struct(target_ip, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_ipc_perm(abi_ulong target_addr,
+        struct ipc_perm *host_ip)
+{
+    struct target_ipc_perm *target_ip;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ip, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_ip->cuid, &target_ip->cuid);
+    __put_user(host_ip->cgid, &target_ip->cgid);
+    __put_user(host_ip->uid, &target_ip->uid);
+    __put_user(host_ip->gid, &target_ip->gid);
+    __put_user(host_ip->mode, &target_ip->mode);
+    __put_user(host_ip->seq, &target_ip->seq);
+    __put_user(host_ip->key, &target_ip->key);
+    unlock_user_struct(target_ip, target_addr, 1);
+
+    return 0;
+}
+
+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_lpid, &target_sd->shm_lpid);
+    __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    __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);
+    unlock_user_struct(target_sd, target_addr, 0);
+
+    return 0;
+}
+
+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_lpid, &target_sd->shm_lpid);
+    __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    __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);
+    unlock_user_struct(target_sd, target_addr, 1);
+
+    return 0;
+}
+
diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h
new file mode 100644
index 0000000..88c01ec
--- /dev/null
+++ b/bsd-user/bsd-mem.h
@@ -0,0 +1,393 @@
+/*
+ *  memory management system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*--
+ * Copyright (c) 1982, 1986, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BSD_MMAN_H_
+#define _BSD_MMAN_H_
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <fcntl.h>
+
+#include "qemu-bsd.h"
+
+extern struct bsd_shm_regions bsd_shm_regions[];
+extern abi_ulong bsd_target_brk;
+extern abi_ulong bsd_target_original_brk;
+
+/* mmap(2) */
+static inline abi_long do_bsd_mmap(void *cpu_env, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7,
+    abi_long arg8)
+{
+
+    if (regpairs_aligned(cpu_env) != 0) {
+       arg6 = arg7;
+       arg7 = arg8;
+    }
+    return get_errno(target_mmap(arg1, arg2, arg3,
+                target_to_host_bitmask(arg4, mmap_flags_tbl), arg5,
+		target_offset64(arg6, arg7)));
+}
+
+/* munmap(2) */
+static inline abi_long do_bsd_munmap(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(target_munmap(arg1, arg2));
+}
+
+/* mprotect(2) */
+static inline abi_long do_bsd_mprotect(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    return get_errno(target_mprotect(arg1, arg2, arg3));
+}
+
+/* msync(2) */
+static inline abi_long do_bsd_msync(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+
+    return get_errno(msync(g2h(arg1), arg2, arg3));
+}
+
+/* mlock(2) */
+static inline abi_long do_bsd_mlock(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(mlock(g2h(arg1), arg2));
+}
+
+/* munlock(2) */
+static inline abi_long do_bsd_munlock(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(munlock(g2h(arg1), arg2));
+}
+
+/* mlockall(2) */
+static inline abi_long do_bsd_mlockall(abi_long arg1)
+{
+
+    return get_errno(mlockall(arg1));
+}
+
+/* munlockall(2) */
+static inline abi_long do_bsd_munlockall(void)
+{
+
+    return get_errno(munlockall());
+}
+
+/* madvise(2) */
+static inline abi_long do_bsd_madvise(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    /*
+     * A straight passthrough may not be safe because qemu sometimes
+     * turns private file-backed mapping into anonymous mappings. This
+     * will break MADV_DONTNEED.  This is a hint, so ignoring and returing
+     * success is ok.
+     */
+    return get_errno(0);
+}
+
+/* minherit(2) */
+static inline abi_long do_bsd_minherit(abi_long addr, abi_long len,
+        abi_long inherit)
+{
+
+    return get_errno(minherit(g2h(addr), len, inherit));
+}
+
+/* mincore(2) */
+static inline abi_long do_bsd_mincore(abi_ulong target_addr, abi_ulong len,
+        abi_ulong target_vec)
+{
+    abi_long ret;
+    void *p, *a;
+
+    a = lock_user(VERIFY_WRITE, target_addr, len, 0);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+    p = lock_user_string(target_vec);
+    if (p == NULL) {
+        unlock_user(a, target_addr, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(mincore(a, len, p));
+    unlock_user(p, target_vec, ret);
+    unlock_user(a, target_addr, 0);
+
+    return ret;
+}
+
+/* break() XXX this needs some more work. */
+static inline abi_long do_obreak(abi_ulong new_brk)
+{
+    abi_ulong brk_page;
+    abi_long mapped_addr;
+    int new_alloc_size;
+
+    return -TARGET_EINVAL;
+
+    if (!new_brk) {
+        return 0;
+    }
+    if (new_brk < bsd_target_original_brk) {
+        return -TARGET_EINVAL;
+    }
+
+    brk_page = HOST_PAGE_ALIGN(bsd_target_brk);
+
+    /* If the new brk is less than this, set it and we're done... */
+    if (new_brk < brk_page) {
+        bsd_target_brk = new_brk;
+        return 0;
+    }
+
+    /* We need to allocate more memory after the brk... */
+    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
+    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
+                PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0));
+
+    if (!is_error(mapped_addr)) {
+        bsd_target_brk = new_brk;
+    } else {
+        return mapped_addr;
+    }
+
+    return 0;
+}
+
+/* shm_open(2) */
+static inline abi_long do_bsd_shm_open(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+    int ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(shm_open(path(p),
+                target_to_host_bitmask(arg2, fcntl_flags_tbl), arg3));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* shm_unlink(2) */
+static inline abi_long do_bsd_shm_unlink(abi_ulong arg1)
+{
+    int ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(shm_unlink(p)); /* XXX path(p)? */
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* shmget(2) */
+static inline abi_long do_bsd_shmget(abi_long arg1, abi_ulong arg2,
+        abi_long arg3)
+{
+
+    return get_errno(shmget(arg1, arg2, arg3));
+}
+
+/* shmctl(2) */
+static inline abi_long do_bsd_shmctl(abi_long shmid, abi_long cmd,
+        abi_ulong buff)
+{
+    struct shmid_ds dsarg;
+    abi_long ret = -TARGET_EINVAL;
+
+    cmd &= 0xff;
+
+    switch (cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+        if (target_to_host_shmid_ds(&dsarg, buff)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(shmctl(shmid, cmd, &dsarg));
+        if (host_to_target_shmid_ds(buff, &dsarg)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    case IPC_RMID:
+        ret = get_errno(shmctl(shmid, cmd, NULL));
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+/* shmat(2) */
+static inline abi_long do_bsd_shmat(int shmid, abi_ulong shmaddr, int shmflg)
+{
+    abi_ulong raddr;
+    abi_long ret;
+    void *host_raddr;
+    struct shmid_ds shm_info;
+    int i;
+
+    /* 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 the length */
+        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_BSD_SHM_REGIONS; i++) {
+        if (bsd_shm_regions[i].start == 0) {
+            bsd_shm_regions[i].start = raddr;
+            bsd_shm_regions[i].size = shm_info.shm_segsz;
+            break;
+        }
+    }
+
+    mmap_unlock();
+    return raddr;
+}
+
+/* shmdt(2) */
+static inline abi_long do_bsd_shmdt(abi_ulong shmaddr)
+{
+    int i;
+
+    for (i = 0; i < N_BSD_SHM_REGIONS; ++i) {
+        if (bsd_shm_regions[i].start == shmaddr) {
+            bsd_shm_regions[i].start = 0;
+            page_set_flags(shmaddr,
+                shmaddr + bsd_shm_regions[i].size, 0);
+            break;
+        }
+    }
+
+    return get_errno(shmdt(g2h(shmaddr)));
+}
+
+
+static inline abi_long do_bsd_vadvise(void)
+{
+    /* See sys_ovadvise() in vm_unix.c */
+    qemu_log("qemu: Unsupported syscall vadvise()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_bsd_sbrk(void)
+{
+    /* see sys_sbrk() in vm_mmap.c */
+    qemu_log("qemu: Unsupported syscall sbrk()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_bsd_sstk(void)
+{
+    /* see sys_sstk() in vm_mmap.c */
+    qemu_log("qemu: Unsupported syscall sstk()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_mmap(caddr_t addr, size_t len, int prot, int
+ * flags, int fd, int pad, off_t pos) system call.
+ */
+static inline abi_long do_bsd_freebsd6_mmap(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6,
+        abi_long arg7)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_mmap()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !_BSD_MMAN_H_ */
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index aae8ea1..f8ef423 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -1,4 +1,4 @@
-/*
+/**
  *  mmap support for qemu
  *
  *  Copyright (c) 2003 - 2008 Fabrice Bellard
@@ -26,44 +26,9 @@
 
 #include "qemu.h"
 #include "qemu-common.h"
-#include "bsd-mman.h"
 
-//#define DEBUG_MMAP
+// #define DEBUG_MMAP
 
-#if defined(CONFIG_USE_NPTL)
-pthread_mutex_t mmap_mutex;
-static int __thread mmap_lock_count;
-
-void mmap_lock(void)
-{
-    if (mmap_lock_count++ == 0) {
-        pthread_mutex_lock(&mmap_mutex);
-    }
-}
-
-void mmap_unlock(void)
-{
-    if (--mmap_lock_count == 0) {
-        pthread_mutex_unlock(&mmap_mutex);
-    }
-}
-
-/* Grab lock to make sure things are in a consistent state after fork().  */
-void mmap_fork_start(void)
-{
-    if (mmap_lock_count)
-        abort();
-    pthread_mutex_lock(&mmap_mutex);
-}
-
-void mmap_fork_end(int child)
-{
-    if (child)
-        pthread_mutex_init(&mmap_mutex, NULL);
-    else
-        pthread_mutex_unlock(&mmap_mutex);
-}
-#else
 /* We aren't threadsafe to start with, so no need to worry about locking.  */
 void mmap_lock(void)
 {
@@ -72,67 +37,6 @@ void mmap_lock(void)
 void mmap_unlock(void)
 {
 }
-#endif
-
-static void *bsd_vmalloc(size_t size)
-{
-    void *p;
-    mmap_lock();
-    /* Use map and mark the pages as used.  */
-    p = mmap(NULL, size, PROT_READ | PROT_WRITE,
-             MAP_PRIVATE | MAP_ANON, -1, 0);
-
-    if (h2g_valid(p)) {
-        /* Allocated region overlaps guest address space.
-           This may recurse.  */
-        abi_ulong addr = h2g(p);
-        page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size),
-                       PAGE_RESERVED);
-    }
-
-    mmap_unlock();
-    return p;
-}
-
-void *g_malloc(size_t size)
-{
-    char * p;
-    size += 16;
-    p = bsd_vmalloc(size);
-    *(size_t *)p = size;
-    return p + 16;
-}
-
-/* We use map, which is always zero initialized.  */
-void * g_malloc0(size_t size)
-{
-    return g_malloc(size);
-}
-
-void g_free(void *ptr)
-{
-    /* FIXME: We should unmark the reserved pages here.  However this gets
-       complicated when one target page spans multiple host pages, so we
-       don't bother.  */
-    size_t *p;
-    p = (size_t *)((char *)ptr - 16);
-    munmap(p, *p);
-}
-
-void *g_realloc(void *ptr, size_t size)
-{
-    size_t old_size, copy;
-    void *new_ptr;
-
-    if (!ptr)
-        return g_malloc(size);
-    old_size = *(size_t *)((char *)ptr - 16);
-    copy = old_size < size ? old_size : size;
-    new_ptr = g_malloc(size);
-    memcpy(new_ptr, ptr, copy);
-    g_free(ptr);
-    return new_ptr;
-}
 
 /* NOTE: all the constants are the HOST ones, but addresses are target. */
 int target_mprotect(abi_ulong start, abi_ulong len, int prot)
@@ -164,11 +68,11 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
     if (start > host_start) {
         /* handle host page containing start */
         prot1 = prot;
-        for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
+        for (addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
             prot1 |= page_get_flags(addr);
         }
         if (host_end == host_start + qemu_host_page_size) {
-            for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+            for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
                 prot1 |= page_get_flags(addr);
             }
             end = host_end;
@@ -180,7 +84,7 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
     }
     if (end < host_end) {
         prot1 = prot;
-        for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+        for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
             prot1 |= page_get_flags(addr);
         }
         ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size,
@@ -218,7 +122,7 @@ static int mmap_frag(abi_ulong real_start,
 
     /* get the protection of the target pages outside the mapping */
     prot1 = 0;
-    for(addr = real_start; addr < real_end; addr++) {
+    for (addr = real_start; addr < real_end; addr++) {
         if (addr < start || addr >= end)
             prot1 |= page_get_flags(addr);
     }
@@ -275,7 +179,7 @@ unsigned long last_brk;
 */
 /* page_init() marks pages used by the host as reserved to be sure not
    to use them. */
-static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
 {
     abi_ulong addr, addr1, addr_start;
     int prot;
@@ -300,9 +204,9 @@ static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
     if (addr == 0)
         addr = mmap_next_start;
     addr_start = addr;
-    for(;;) {
+    for (;;) {
         prot = 0;
-        for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
+        for (addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
             prot |= page_get_flags(addr1);
         }
         if (prot == 0)
@@ -319,9 +223,10 @@ static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
 
 /* NOTE: all the constants are the HOST ones */
 abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
-                     int flags, int fd, abi_ulong offset)
+                     int flags, int fd, off_t offset)
 {
-    abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
+    abi_ulong ret, end, real_start, real_end, retaddr, host_len;
+    off_t host_offset;
     unsigned long host_start;
 
     mmap_lock();
@@ -337,21 +242,30 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
             printf("MAP_FIXED ");
         if (flags & MAP_ANON)
             printf("MAP_ANON ");
-        switch(flags & TARGET_BSD_MAP_FLAGMASK) {
-        case MAP_PRIVATE:
-            printf("MAP_PRIVATE ");
-            break;
-        case MAP_SHARED:
-            printf("MAP_SHARED ");
-            break;
-        default:
-            printf("[MAP_FLAGMASK=0x%x] ", flags & TARGET_BSD_MAP_FLAGMASK);
-            break;
-        }
-        printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset);
+	if (flags & MAP_PRIVATE)
+	    printf("MAP_PRIVATE ");
+	if (flags & MAP_SHARED)
+	    printf("MAP_SHARED ");
+	if (flags & MAP_NOCORE)
+	    printf("MAP_NOCORE ");
+#ifdef MAP_STACK
+	if (flags & MAP_STACK)
+	    printf("MAP_STACK ");
+#endif
+        printf("fd=%d offset=0x%llx\n", fd, offset);
     }
 #endif
 
+#ifdef MAP_STACK
+    if (flags & MAP_STACK) {
+        if ((fd != -1) || ((prot & (PROT_READ | PROT_WRITE)) !=
+                    (PROT_READ | PROT_WRITE))) {
+            errno = EINVAL;
+            goto fail;
+        }
+    }
+#endif /* MAP_STACK */
+
     if (offset & ~TARGET_PAGE_MASK) {
         errno = EINVAL;
         goto fail;
@@ -396,7 +310,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
         end = start + len;
         real_end = HOST_PAGE_ALIGN(end);
 
-        for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) {
+        for (addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) {
             flg = page_get_flags(addr);
             if (flg & PAGE_RESERVED) {
                 errno = ENXIO;
@@ -508,11 +422,11 @@ int target_munmap(abi_ulong start, abi_ulong len)
     if (start > real_start) {
         /* handle host page containing start */
         prot = 0;
-        for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
+        for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
             prot |= page_get_flags(addr);
         }
         if (real_end == real_start + qemu_host_page_size) {
-            for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+            for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
                 prot |= page_get_flags(addr);
             }
             end = real_end;
@@ -522,7 +436,7 @@ int target_munmap(abi_ulong start, abi_ulong len)
     }
     if (end < real_end) {
         prot = 0;
-        for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+        for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
             prot |= page_get_flags(addr);
         }
         if (prot != 0)
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
index 590c36b..f562aad 100644
--- a/bsd-user/qemu-bsd.h
+++ b/bsd-user/qemu-bsd.h
@@ -32,6 +32,16 @@
 #include <sys/wait.h>
 #include <netinet/in.h>
 
+/* bsd-mem.c */
+abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
+        abi_ulong target_addr);
+abi_long host_to_target_ipc_perm(abi_ulong target_addr,
+        struct ipc_perm *host_ip);
+abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
+        abi_ulong target_addr);
+abi_long host_to_target_shmid_ds(abi_ulong target_addr,
+        struct shmid_ds *host_sd);
+
 /* bsd-proc.c */
 int target_to_host_resource(int code);
 rlim_t target_to_host_rlim(abi_ulong target_rlim);
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index e668a67..613a89e 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -219,7 +219,7 @@ void QEMU_NORETURN force_sig(int target_sig);
 /* mmap.c */
 int target_mprotect(abi_ulong start, abi_ulong len, int prot);
 abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
-                     int flags, int fd, abi_ulong offset);
+                     int flags, int fd, off_t offset);
 int target_munmap(abi_ulong start, abi_ulong len);
 abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
                        abi_ulong new_size, unsigned long flags,
@@ -228,6 +228,7 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
 extern unsigned long last_brk;
 void mmap_lock(void);
 void mmap_unlock(void);
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
 void cpu_list_lock(void);
 void cpu_list_unlock(void);
 #if defined(CONFIG_USE_NPTL)
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 633d638..e3967fa 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -17,22 +17,16 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
-#include <stdlib.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdarg.h>
 #include <string.h>
 #include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <time.h>
-#include <limits.h>
 #include <sys/types.h>
-#include <sys/mman.h>
 #include <sys/syscall.h>
 #include <sys/param.h>
 #include <sys/sysctl.h>
-#include <utime.h>
 
 #include "qemu.h"
 #include "qemu-common.h"
@@ -42,6 +36,7 @@ static int host_to_target_errno(int err);
 
 /* BSD independent syscall shims */
 #include "bsd-file.h"
+#include "bsd-mem.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
 
@@ -53,19 +48,18 @@ static int host_to_target_errno(int err);
 
 /* #define DEBUG */
 
-static abi_ulong target_brk;
-static abi_ulong target_original_brk;
-
 /*
  * errno conversion.
  */
 abi_long get_errno(abi_long ret)
 {
-    if (ret == -1)
+
+    if (ret == -1) {
         /* XXX need to translate host -> target errnos here */
         return -(errno);
-    else
+    } else {
         return ret;
+    }
 }
 
 static int host_to_target_errno(int err)
@@ -76,46 +70,8 @@ static int host_to_target_errno(int err)
 
 int is_error(abi_long ret)
 {
-    return (abi_ulong)ret >= (abi_ulong)(-4096);
-}
 
-void target_set_brk(abi_ulong new_brk)
-{
-    target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
-}
-
-/* do_obreak() must return target errnos. */
-static abi_long do_obreak(abi_ulong new_brk)
-{
-    abi_ulong brk_page;
-    abi_long mapped_addr;
-    int new_alloc_size;
-
-    if (!new_brk)
-        return 0;
-    if (new_brk < target_original_brk)
-        return -TARGET_EINVAL;
-
-    brk_page = HOST_PAGE_ALIGN(target_brk);
-
-    /* If the new brk is less than this, set it and we're done... */
-    if (new_brk < brk_page) {
-        target_brk = new_brk;
-        return 0;
-    }
-
-    /* We need to allocate more memory after the brk... */
-    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
-    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
-                                        PROT_READ|PROT_WRITE,
-                                        MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0));
-
-    if (!is_error(mapped_addr))
-        target_brk = new_brk;
-    else
-        return mapped_addr;
-
-    return 0;
+    return (abi_ulong)ret >= (abi_ulong)(-4096);
 }
 
 /* FIXME
@@ -169,6 +125,13 @@ static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
     return 0;
 }
 
+
+/* stub for arm semihosting support */
+abi_long do_brk(abi_ulong new_brk)
+{
+    return do_obreak(new_brk);
+}
+
 /* 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>. */
@@ -340,6 +303,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_FREEBSD_NR_getloginclass: /* getloginclass(2) */
         ret = do_freebsd_getloginclass(arg1, arg2);
         break;
+
 #if 0
     case TARGET_FREEBSD_NR_pdwait4: /* pdwait4(2) */
         ret = do_freebsd_pdwait4(arg1, arg2, arg3, arg4);
@@ -417,6 +381,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_FREEBSD_NR_auditctl: /* auditctl(2) */
         ret = do_freebsd_auditctl(arg1);
         break;
+
     case TARGET_FREEBSD_NR_utrace: /* utrace(2) */
         ret = do_bsd_utrace(arg1, arg2);
         break;
@@ -434,6 +399,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
 
+
         /*
          * File system calls.
          */
@@ -807,20 +773,95 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
 
+        /*
+         * Memory management system calls.
+         */
+    case TARGET_FREEBSD_NR_mmap: /* mmap(2) */
+        ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+           arg8);
+        break;
+
+    case TARGET_FREEBSD_NR_munmap: /* munmap(2) */
+        ret = do_bsd_munmap(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mprotect: /* mprotect(2) */
+        ret = do_bsd_mprotect(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_msync: /* msync(2) */
+        ret = do_bsd_msync(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mlock: /* mlock(2) */
+        ret = do_bsd_mlock(arg1, arg2);
+        break;
 
-    case TARGET_FREEBSD_NR_mmap:
-        ret = get_errno(target_mmap(arg1, arg2, arg3,
-                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
-                                    arg5,
-                                    arg6));
+    case TARGET_FREEBSD_NR_munlock: /* munlock(2) */
+        ret = do_bsd_munlock(arg1, arg2);
         break;
-    case TARGET_FREEBSD_NR_mprotect:
-        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+
+    case TARGET_FREEBSD_NR_mlockall: /* mlockall(2) */
+        ret = do_bsd_mlockall(arg1);
         break;
-    case TARGET_FREEBSD_NR_break:
-        ret = do_obreak(arg1);
+
+    case TARGET_FREEBSD_NR_munlockall: /* munlockall(2) */
+        ret = do_bsd_munlockall();
+        break;
+
+    case TARGET_FREEBSD_NR_madvise: /* madvise(2) */
+        ret = do_bsd_madvise(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_minherit: /* minherit(2) */
+        ret = do_bsd_minherit(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mincore: /* mincore(2) */
+        ret = do_bsd_mincore(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_shm_open: /* shm_open(2) */
+        ret = do_bsd_shm_open(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_shm_unlink: /* shm_unlink(2) */
+        ret = do_bsd_shm_unlink(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_shmget: /* shmget(2) */
+        ret = do_bsd_shmget(arg1, arg2, arg3);
         break;
 
+    case TARGET_FREEBSD_NR_shmctl: /* shmctl(2) */
+        ret = do_bsd_shmctl(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_shmat: /* shmat(2) */
+        ret = do_bsd_shmat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_shmdt: /* shmdt(2) */
+        ret = do_bsd_shmdt(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_vadvise:
+        ret = do_bsd_vadvise();
+        break;
+
+    case TARGET_FREEBSD_NR_sbrk:
+        ret = do_bsd_sbrk();
+        break;
+
+    case TARGET_FREEBSD_NR_sstk:
+        ret = do_bsd_sstk();
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_mmap: /* undocumented */
+        ret = do_bsd_freebsd6_mmap(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+        break;
+
+
         /*
          * time related system calls.
          */
@@ -997,6 +1038,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                     arg8));
         break;
     }
+
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
@@ -1033,13 +1075,10 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_NETBSD_NR_mmap:
-        ret = get_errno(target_mmap(arg1, arg2, arg3,
-                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
-                                    arg5,
-                                    arg6));
+        ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
         break;
     case TARGET_NETBSD_NR_mprotect:
-        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+        ret = do_bsd_mprotect(arg1, arg2, arg3);
         break;
 
     case TARGET_NETBSD_NR_syscall:
@@ -1086,13 +1125,10 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_OPENBSD_NR_mmap:
-        ret = get_errno(target_mmap(arg1, arg2, arg3,
-                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
-                                    arg5,
-                                    arg6));
+        ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
         break;
     case TARGET_OPENBSD_NR_mprotect:
-        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+        ret = do_bsd_mprotect(arg1, arg2, arg3);
         break;
 
     case TARGET_OPENBSD_NR_syscall:
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 13/18] bsd-user: add support for socket related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (11 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 12/18] bsd-user: add support for memory management " Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 14/18] bsd-user: add support for thread " Stacey Son
                   ` (26 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for socket related system calls including
accept(2), bind(2), connect(2), getpeername(2), getsockname(2), getsockopt(2),
setsockopt(2), listen(2), recvfrom(2), recvmsg(2), sendmsg(2), sendto(2),
socket(2), socketpair(2), shutdown(2), setfib(2), sctp_peeloff(2),
sctp_generic_sendmsg(2), sctp_generic_recvmsg(2), sendfile(2), and
freebsd4_sendfile(2).

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs       |    4 +-
 bsd-user/bsd-socket.c        |  108 +++++++++
 bsd-user/bsd-socket.h        |  266 ++++++++++++++++++++
 bsd-user/freebsd/os-socket.c |  149 ++++++++++++
 bsd-user/freebsd/os-socket.h |  548 ++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h   |    6 +
 bsd-user/netbsd/os-socket.c  |    1 +
 bsd-user/netbsd/os-socket.h  |   98 ++++++++
 bsd-user/openbsd/os-socket.c |    1 +
 bsd-user/openbsd/os-socket.h |   98 ++++++++
 bsd-user/qemu-bsd.h          |    8 +
 bsd-user/syscall.c           |   93 +++++++
 12 files changed, 1378 insertions(+), 2 deletions(-)
 create mode 100644 bsd-user/bsd-socket.c
 create mode 100644 bsd-user/bsd-socket.h
 create mode 100644 bsd-user/freebsd/os-socket.c
 create mode 100644 bsd-user/freebsd/os-socket.h
 create mode 100644 bsd-user/netbsd/os-socket.c
 create mode 100644 bsd-user/netbsd/os-socket.h
 create mode 100644 bsd-user/openbsd/os-socket.c
 create mode 100644 bsd-user/openbsd/os-socket.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 1a33a6d..9869837 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,6 +1,6 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-mem.o bsd-proc.o \
+	        uaccess.o bsd-mem.o bsd-proc.o bsd-socket.o \
 			$(HOST_ABI_DIR)/os-proc.o \
-			$(HOST_ABI_DIR)/os-stat.o \
+			$(HOST_ABI_DIR)/os-socket.o $(HOST_ABI_DIR)/os-stat.o \
 			$(HOST_ABI_DIR)/os-sys.o \
 			$(HOST_ABI_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/bsd-socket.c b/bsd-user/bsd-socket.c
new file mode 100644
index 0000000..c1a3b49
--- /dev/null
+++ b/bsd-user/bsd-socket.c
@@ -0,0 +1,108 @@
+/*
+ *  BSD socket system call related helpers
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+/*
+ * socket conversion
+ */
+abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr,
+        socklen_t len)
+{
+    const socklen_t unix_maxlen = sizeof(struct sockaddr_un);
+    sa_family_t sa_family;
+    struct target_sockaddr *target_saddr;
+
+    target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
+    if (target_saddr == 0) {
+        return -TARGET_EFAULT;
+    }
+
+    sa_family = 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 will
+     * fix that here if needed.
+     */
+    if (target_saddr->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;
+        }
+    }
+
+    memcpy(addr, target_saddr, len);
+    addr->sa_family = sa_family;        /* type uint8_t */
+    addr->sa_len = target_saddr->sa_len;    /* type uint8_t */
+    unlock_user(target_saddr, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
+        socklen_t len)
+{
+    struct target_sockaddr *target_saddr;
+
+    target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
+    if (target_saddr == 0) {
+        return -TARGET_EFAULT;
+    }
+    memcpy(target_saddr, addr, len);
+    target_saddr->sa_family = addr->sa_family;  /* type uint8_t */
+    target_saddr->sa_len = addr->sa_len;        /* type uint8_t */
+    unlock_user(target_saddr, target_addr, len);
+
+    return 0;
+}
+
+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 == 0) {
+        return -TARGET_EFAULT;
+    }
+    mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
+    mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
+    if (len == sizeof(struct target_ip_mreqn)) {
+        mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
+    }
+    unlock_user(target_smreqn, target_addr, 0);
+
+    return 0;
+}
+
diff --git a/bsd-user/bsd-socket.h b/bsd-user/bsd-socket.h
new file mode 100644
index 0000000..f5d1ac8
--- /dev/null
+++ b/bsd-user/bsd-socket.h
@@ -0,0 +1,266 @@
+/*
+ *  socket related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __BSD_SOCKET_H_
+#define __BSD_SOCKET_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu-bsd.h"
+
+/* bind(2) */
+static inline abi_long do_bsd_bind(int sockfd, abi_ulong target_addr,
+        socklen_t addrlen)
+{
+    abi_long ret;
+    void *addr;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+
+    addr = alloca(addrlen + 1);
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(bind(sockfd, addr, addrlen));
+}
+
+/* connect(2) */
+static inline abi_long do_bsd_connect(int sockfd, abi_ulong target_addr,
+        socklen_t addrlen)
+{
+    abi_long ret;
+    void *addr;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    addr = alloca(addrlen);
+
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(connect(sockfd, addr, addrlen));
+}
+
+/* accept(2) */
+static inline abi_long do_bsd_accept(int fd, abi_ulong target_addr,
+        abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (target_addr == 0) {
+        return get_errno(accept(fd, NULL, NULL));
+    }
+    /* return EINVAL if addrlen pointer is invalid */
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EINVAL;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EINVAL;
+    }
+    addr = alloca(addrlen);
+
+    ret = get_errno(accept(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getpeername(2) */
+static inline abi_long do_bsd_getpeername(int fd, abi_ulong target_addr,
+        abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EFAULT;
+    }
+    addr = alloca(addrlen);
+    ret = get_errno(getpeername(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getsockname(2) */
+static inline abi_long do_bsd_getsockname(int fd, abi_ulong target_addr,
+        abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EFAULT;
+    }
+    addr = alloca(addrlen);
+
+    ret = get_errno(getsockname(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* socketpair(2) */
+static inline abi_long do_bsd_socketpair(int domain, int type, int protocol,
+        abi_ulong target_tab_addr)
+{
+    int tab[2];
+    abi_long ret;
+
+    ret = get_errno(socketpair(domain, type, protocol, tab));
+    if (!is_error(ret)) {
+        if (put_user_s32(tab[0], target_tab_addr) ||
+                put_user_s32(tab[1], target_tab_addr + sizeof(tab[0]))) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* sendto(2) */
+static inline abi_long do_bsd_sendto(int fd, abi_ulong msg, size_t len,
+        int flags, abi_ulong target_addr, socklen_t addrlen)
+{
+    struct sockaddr *saddr;
+    void *host_msg;
+    abi_long ret;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    host_msg = lock_user(VERIFY_READ, msg, len, 1);
+    if (!host_msg) {
+        return -TARGET_EFAULT;
+    }
+    if (target_addr) {
+        saddr = alloca(addrlen);
+        ret = target_to_host_sockaddr(saddr, target_addr, addrlen);
+        if (is_error(ret)) {
+            unlock_user(host_msg, msg, 0);
+            return ret;
+        }
+        ret = get_errno(sendto(fd, host_msg, len, flags, saddr, addrlen));
+    } else {
+        ret = get_errno(send(fd, host_msg, len, flags));
+    }
+    unlock_user(host_msg, msg, 0);
+    return ret;
+}
+
+/* recvfrom(2) */
+static inline abi_long do_bsd_recvfrom(int fd, abi_ulong msg, size_t len,
+        int flags, abi_ulong target_addr, abi_ulong target_addrlen)
+{
+    socklen_t addrlen;
+    struct sockaddr *saddr;
+    void *host_msg;
+    abi_long ret;
+
+    host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
+    if (!host_msg) {
+        return -TARGET_EFAULT;
+    }
+    if (target_addr) {
+        if (get_user_u32(addrlen, target_addrlen)) {
+            ret = -TARGET_EFAULT;
+            goto fail;
+        }
+        if ((int)addrlen < 0) {
+            ret = -TARGET_EINVAL;
+            goto fail;
+        }
+        saddr = alloca(addrlen);
+        ret = get_errno(recvfrom(fd, host_msg, len, flags, saddr, &addrlen));
+    } else {
+        saddr = NULL; /* To keep compiler quiet.  */
+        ret = get_errno(qemu_recv(fd, host_msg, len, flags));
+    }
+    if (!is_error(ret)) {
+        if (target_addr) {
+            host_to_target_sockaddr(target_addr, saddr, addrlen);
+            if (put_user_u32(addrlen, target_addrlen)) {
+                ret = -TARGET_EFAULT;
+                goto fail;
+            }
+        }
+        unlock_user(host_msg, msg, len);
+    } else {
+fail:
+        unlock_user(host_msg, msg, 0);
+    }
+    return ret;
+}
+
+/* socket(2) */
+static inline abi_long do_bsd_socket(abi_long domain, abi_long type,
+        abi_long protocol)
+{
+
+    return get_errno(socket(domain, type, protocol));
+}
+
+/* shutdown(2) */
+static inline abi_long do_bsd_shutdown(abi_long s, abi_long how)
+{
+
+    return get_errno(shutdown(s, how));
+}
+
+#endif /* !__BSD_SOCKET_H_ */
diff --git a/bsd-user/freebsd/os-socket.c b/bsd-user/freebsd/os-socket.c
new file mode 100644
index 0000000..949af28
--- /dev/null
+++ b/bsd-user/freebsd/os-socket.c
@@ -0,0 +1,149 @@
+/*
+ *  FreeBSD socket related system call helpers
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+abi_long t2h_freebsd_cmsg(struct msghdr *msgh,
+        struct target_msghdr *target_msgh)
+{
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
+    abi_long msg_controllen;
+    abi_ulong target_cmsg_addr;
+    struct target_cmsghdr *target_cmsg;
+    socklen_t space = 0;
+
+
+    msg_controllen = tswapal(target_msgh->msg_controllen);
+    if (msg_controllen < sizeof(struct target_cmsghdr)) {
+        goto the_end;
+    }
+    target_cmsg_addr = tswapal(target_msgh->msg_control);
+    target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
+    if (target_cmsg == 0) {
+        return -TARGET_EFAULT;
+    }
+    while (cmsg && target_cmsg) {
+        void *data = CMSG_DATA(cmsg);
+        void *target_data = TARGET_CMSG_DATA(target_cmsg);
+        int len = tswapal(target_cmsg->cmsg_len) -
+            TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr));
+        space += CMSG_SPACE(len);
+        if (space > msgh->msg_controllen) {
+            space -= CMSG_SPACE(len);
+            gemu_log("Host cmsg overflow\n");
+            break;
+        }
+        cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
+        cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
+        cmsg->cmsg_len = CMSG_LEN(len);
+
+        if (cmsg->cmsg_level != TARGET_SOL_SOCKET ||
+            cmsg->cmsg_type != SCM_RIGHTS) {
+            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);
+    }
+    unlock_user(target_cmsg, target_cmsg_addr, 0);
+
+the_end:
+    msgh->msg_controllen = space;
+    return 0;
+}
+
+abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh,
+        struct msghdr *msgh)
+{
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
+    abi_long msg_controllen;
+    abi_ulong target_cmsg_addr;
+    struct target_cmsghdr *target_cmsg;
+    socklen_t space = 0;
+
+    msg_controllen = tswapal(target_msgh->msg_controllen);
+    if (msg_controllen < sizeof(struct target_cmsghdr)) {
+        goto the_end;
+    }
+    target_cmsg_addr = tswapal(target_msgh->msg_control);
+    target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr,
+        msg_controllen, 0);
+    if (target_cmsg == 0) {
+        return -TARGET_EFAULT;
+    }
+    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);
+        if (space > msg_controllen) {
+            space -= TARGET_CMSG_SPACE(len);
+            gemu_log("Target cmsg overflow\n");
+            break;
+        }
+        target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
+        target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
+        target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
+        if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
+            (cmsg->cmsg_type == SCM_RIGHTS)) {
+            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]);
+            }
+        } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
+            (cmsg->cmsg_type == SO_TIMESTAMP) &&
+            (len == sizeof(struct timeval))) {
+            /* copy struct timeval to target */
+            struct timeval *tv = (struct timeval *)data;
+            struct target_freebsd_timeval *target_tv =
+                (struct target_freebsd_timeval *)target_data;
+            __put_user(tv->tv_sec, &target_tv->tv_sec);
+            __put_user(tv->tv_usec, &target_tv->tv_usec);
+        } else {
+            gemu_log("Unsupported ancillary data: %d/%d\n",
+                cmsg->cmsg_level, cmsg->cmsg_type);
+            memcpy(target_data, data, len);
+        }
+        cmsg = CMSG_NXTHDR(msgh, cmsg);
+        target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
+    }
+    unlock_user(target_cmsg, target_cmsg_addr, space);
+
+the_end:
+    target_msgh->msg_controllen = tswapal(space);
+    return 0;
+}
+
diff --git a/bsd-user/freebsd/os-socket.h b/bsd-user/freebsd/os-socket.h
new file mode 100644
index 0000000..9339ffb
--- /dev/null
+++ b/bsd-user/freebsd/os-socket.h
@@ -0,0 +1,548 @@
+/*
+ *  FreeBSD socket related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __FREEBSD_SOCKET_H_
+#define __FREEBSD_SOCKET_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu-os.h"
+
+/* sendmsg(2) */
+static inline abi_long do_freebsd_sendmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+    abi_long ret;
+    struct target_msghdr *msgp;
+    struct msghdr msg;
+    int count;
+    struct iovec *vec;
+    abi_ulong target_vec;
+
+    if (!lock_user_struct(VERIFY_READ, msgp, target_msg, 1)) {
+        return -TARGET_EFAULT;
+    }
+    if (msgp->msg_name) {
+        msg.msg_namelen = tswap32(msgp->msg_namelen);
+        msg.msg_name = alloca(msg.msg_namelen);
+        ret = target_to_host_sockaddr(msg.msg_name,
+            tswapal(msgp->msg_name), msg.msg_namelen);
+
+        if (is_error(ret)) {
+            unlock_user_struct(msgp, target_msg, 0);
+            return ret;
+        }
+    } else {
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+    }
+    msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
+    msg.msg_control = alloca(msg.msg_controllen);
+    msg.msg_flags = tswap32(msgp->msg_flags);
+
+    count = tswapal(msgp->msg_iovlen);
+    vec = alloca(count * sizeof(struct iovec));
+    target_vec = tswapal(msgp->msg_iov);
+    lock_iovec(VERIFY_READ, vec, target_vec, count, 1);
+    msg.msg_iovlen = count;
+    msg.msg_iov = vec;
+
+    ret = t2h_freebsd_cmsg(&msg, msgp);
+    if (!is_error(ret)) {
+        ret = get_errno(sendmsg(fd, &msg, flags));
+    }
+    unlock_iovec(vec, target_vec, count, 0);
+    unlock_user_struct(msgp, target_msg, 0);
+    return ret;
+}
+
+/* recvmsg(2) */
+static inline abi_long do_freebsd_recvmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+    abi_long ret, len;
+    struct target_msghdr *msgp;
+    struct msghdr msg;
+    int count;
+    struct iovec *vec;
+    abi_ulong target_vec;
+
+    if (!lock_user_struct(VERIFY_WRITE, msgp, target_msg, 0)) {
+        return -TARGET_EFAULT;
+    }
+    if (msgp->msg_name) {
+        msg.msg_namelen = tswap32(msgp->msg_namelen);
+        msg.msg_name = alloca(msg.msg_namelen);
+        ret = target_to_host_sockaddr(msg.msg_name,
+            tswapal(msgp->msg_name), msg.msg_namelen);
+
+        if (is_error(ret)) {
+            unlock_user_struct(msgp, target_msg, 1);
+            return ret;
+        }
+    } else {
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+    }
+    msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
+    msg.msg_control = alloca(msg.msg_controllen);
+    msg.msg_flags = tswap32(msgp->msg_flags);
+
+    count = tswapal(msgp->msg_iovlen);
+    vec = alloca(count * sizeof(struct iovec));
+    target_vec = tswapal(msgp->msg_iov);
+    lock_iovec(VERIFY_WRITE, vec, target_vec, count, 0);
+    msg.msg_iovlen = count;
+    msg.msg_iov = vec;
+
+    ret = get_errno(recvmsg(fd, &msg, flags));
+    if (!is_error(ret)) {
+        len = ret;
+        ret = h2t_freebsd_cmsg(msgp, &msg);
+        if (!is_error(ret)) {
+            msgp->msg_namelen = tswap32(msg.msg_namelen);
+            if (msg.msg_name != NULL) {
+                ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
+                        msg.msg_name, msg.msg_namelen);
+                if (is_error(ret)) {
+                    goto out;
+                }
+            }
+        }
+        ret = len;
+    }
+out:
+    unlock_iovec(vec, target_vec, count, 1);
+    unlock_user_struct(msgp, target_msg, 1);
+    return ret;
+}
+
+/* setsockopt(2) */
+static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, socklen_t optlen)
+{
+    abi_long ret;
+    int val;
+    struct ip_mreqn *ip_mreq;
+
+    switch (level) {
+    case IPPROTO_TCP:
+        /* TCP options all take an 'int' value. */
+        if (optlen < sizeof(uint32_t)) {
+            return -TARGET_EINVAL;
+        }
+        if (get_user_u32(val, optval_addr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
+        break;
+
+    case IPPROTO_IP:
+        switch (optname) {
+        case IP_HDRINCL:/* int; header is included with data */
+        case IP_TOS:    /* int; IP type of service and preced. */
+        case IP_TTL:    /* int; IP time to live */
+        case IP_RECVOPTS: /* bool; receive all IP opts w/dgram */
+        case IP_RECVRETOPTS: /* bool; receive IP opts for response */
+        case IP_RECVDSTADDR: /* bool; receive IP dst addr w/dgram */
+        case IP_MULTICAST_IF:/* u_char; set/get IP multicast i/f  */
+        case IP_MULTICAST_TTL:/* u_char; set/get IP multicast ttl */
+        case IP_MULTICAST_LOOP:/*u_char;set/get IP multicast loopback */
+        case IP_PORTRANGE: /* int; range to choose for unspec port */
+        case IP_RECVIF: /* bool; receive reception if w/dgram */
+        case IP_IPSEC_POLICY:   /* int; set/get security policy */
+        case IP_FAITH:  /* bool; accept FAITH'ed connections */
+        case IP_RECVTTL: /* bool; receive reception TTL w/dgram */
+            val = 0;
+            if (optlen >= sizeof(uint32_t)) {
+                if (get_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            } else if (optlen >= 1) {
+                if (get_user_u8(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            }
+            ret = get_errno(setsockopt(sockfd, level, optname, &val,
+                        sizeof(val)));
+            break;
+
+        case IP_ADD_MEMBERSHIP: /*ip_mreq; add an IP group membership */
+        case IP_DROP_MEMBERSHIP:/*ip_mreq; drop an IP group 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;
+
+        default:
+            goto unimplemented;
+        }
+        break;
+
+    case TARGET_SOL_SOCKET:
+        switch (optname) {
+        /* Options with 'int' argument.  */
+        case TARGET_SO_DEBUG:
+            optname = SO_DEBUG;
+            break;
+
+        case TARGET_SO_REUSEADDR:
+            optname = SO_REUSEADDR;
+            break;
+
+        case TARGET_SO_REUSEPORT:
+            optname = SO_REUSEADDR;
+            break;
+
+        case TARGET_SO_KEEPALIVE:
+            optname = SO_KEEPALIVE;
+            break;
+
+        case TARGET_SO_DONTROUTE:
+            optname = SO_DONTROUTE;
+            break;
+
+        case TARGET_SO_LINGER:
+            optname = SO_LINGER;
+            break;
+
+        case TARGET_SO_BROADCAST:
+            optname = SO_BROADCAST;
+            break;
+
+        case TARGET_SO_OOBINLINE:
+            optname = SO_OOBINLINE;
+            break;
+
+        case TARGET_SO_SNDBUF:
+            optname = SO_SNDBUF;
+            break;
+
+        case TARGET_SO_RCVBUF:
+            optname = SO_RCVBUF;
+            break;
+
+        case TARGET_SO_SNDLOWAT:
+            optname = SO_RCVLOWAT;
+            break;
+
+        case TARGET_SO_RCVLOWAT:
+            optname = SO_RCVLOWAT;
+            break;
+
+        case TARGET_SO_SNDTIMEO:
+            optname = SO_SNDTIMEO;
+            break;
+
+        case TARGET_SO_RCVTIMEO:
+            optname = SO_RCVTIMEO;
+            break;
+
+        case TARGET_SO_ACCEPTFILTER:
+            goto unimplemented;
+
+        case TARGET_SO_NOSIGPIPE:
+            optname = SO_NOSIGPIPE;
+            break;
+
+        case TARGET_SO_TIMESTAMP:
+            optname = SO_TIMESTAMP;
+            break;
+
+        case TARGET_SO_BINTIME:
+            optname = SO_BINTIME;
+            break;
+
+        case TARGET_SO_ERROR:
+            optname = SO_ERROR;
+            break;
+
+        case TARGET_SO_SETFIB:
+            optname = SO_ERROR;
+            break;
+
+#ifdef SO_USER_COOKIE
+        case TARGET_SO_USER_COOKIE:
+            optname = SO_USER_COOKIE;
+            break;
+#endif
+        default:
+            goto unimplemented;
+        }
+        if (optlen < sizeof(uint32_t)) {
+            return -TARGET_EINVAL;
+        }
+        if (get_user_u32(val, optval_addr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val,
+                    sizeof(val)));
+        break;
+    default:
+unimplemented:
+    gemu_log("Unsupported setsockopt level=%d optname=%d\n",
+        level, optname);
+    ret = -TARGET_ENOPROTOOPT;
+    }
+
+    return ret;
+}
+
+/* getsockopt(2) */
+static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, abi_ulong optlen)
+{
+    abi_long ret;
+    int len, val;
+    socklen_t lv;
+
+    switch (level) {
+    case TARGET_SOL_SOCKET:
+        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_ACCEPTFILTER:
+            goto unimplemented;
+
+        /* 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_REUSEPORT:
+            optname = SO_REUSEPORT;
+            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_TIMESTAMP:
+            optname = SO_TIMESTAMP;
+            goto int_case;
+
+        case TARGET_SO_RCVLOWAT:
+            optname = SO_RCVLOWAT;
+            goto int_case;
+
+        case TARGET_SO_LISTENINCQLEN:
+            optname = SO_LISTENINCQLEN;
+            goto int_case;
+
+        default:
+int_case:
+            if (get_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            if (len < 0) {
+                return -TARGET_EINVAL;
+            }
+            lv = sizeof(lv);
+            ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len > lv) {
+                len = lv;
+            }
+            if (len == 4) {
+                if (put_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            } else {
+                if (put_user_u8(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            }
+            if (put_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            break;
+
+        }
+        break;
+
+    case IPPROTO_TCP:
+        /* TCP options all take an 'int' value. */
+        goto int_case;
+
+    case IPPROTO_IP:
+        switch (optname) {
+        case IP_HDRINCL:
+        case IP_TOS:
+        case IP_TTL:
+        case IP_RECVOPTS:
+        case IP_RECVRETOPTS:
+        case IP_RECVDSTADDR:
+
+        case IP_RETOPTS:
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 && defined(IP_RECVTOS)
+        case IP_RECVTOS:
+#endif
+        case IP_MULTICAST_TTL:
+        case IP_MULTICAST_LOOP:
+        case IP_PORTRANGE:
+        case IP_IPSEC_POLICY:
+        case IP_FAITH:
+        case IP_ONESBCAST:
+        case IP_BINDANY:
+            if (get_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            if (len < 0) {
+                return -TARGET_EINVAL;
+            }
+            lv = sizeof(lv);
+            ret = get_errno(getsockopt(sockfd, level, optname,
+                &val, &lv));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len < sizeof(int) && len > 0 && val >= 0 &&
+                val < 255) {
+                len = 1;
+                if (put_user_u32(len, optlen) ||
+                        put_user_u8(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            } else {
+                if (len > sizeof(int)) {
+                    len = sizeof(int);
+                }
+                if (put_user_u32(len, optlen) ||
+                        put_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            }
+            break;
+
+        default:
+            goto unimplemented;
+        }
+        break;
+
+    default:
+unimplemented:
+        gemu_log("getsockopt level=%d optname=%d not yet supported\n",
+            level, optname);
+        ret = -TARGET_EOPNOTSUPP;
+        break;
+    }
+    return ret;
+}
+
+/* setfib(2) */
+static inline abi_long do_freebsd_setfib(abi_long fib)
+{
+
+    return get_errno(setfib(fib));
+}
+
+/* sctp_peeloff(2) */
+static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_peeloff()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_sendmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s,
+        abi_ulong target_msg, abi_long msglen, abi_ulong target_to,
+        abi_ulong len, abi_ulong target_sinfo, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_recvmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s,
+        abi_ulong target_iov, abi_long iovlen, abi_ulong target_from,
+        abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* freebsd4_sendfile(2) */
+static inline abi_long do_freebsd_freebsd4_sendfile(abi_long fd, abi_long s,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong nbytes, abi_ulong target_hdtr,
+        abi_ulong target_sbytes, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd4_sendfile()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sendfile(2) */
+static inline abi_long do_freebsd_sendfile(abi_long fd, abi_long s,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong nbytes, abi_ulong target_hdtr,
+        abi_ulong target_sbytes, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sendfile()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__FREEBSD_SOCKET_H_ */
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index e915246..90d8eb4 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -50,6 +50,12 @@ abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
 abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds,
         int n);
 
+/* os-socket.c */
+abi_long t2h_freebsd_cmsg(struct msghdr *msgh,
+                struct target_msghdr *target_msgh);
+abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh,
+                struct msghdr *msgh);
+
 /* os-stat.c */
 abi_long h2t_freebsd_stat(abi_ulong target_addr, struct stat *host_st);
 abi_long h2t_freebsd_nstat(abi_ulong target_addr, struct stat *host_st);
diff --git a/bsd-user/netbsd/os-socket.c b/bsd-user/netbsd/os-socket.c
new file mode 100644
index 0000000..d983c34
--- /dev/null
+++ b/bsd-user/netbsd/os-socket.c
@@ -0,0 +1 @@
+/* XXX NetBSD socket related helpers */
diff --git a/bsd-user/netbsd/os-socket.h b/bsd-user/netbsd/os-socket.h
new file mode 100644
index 0000000..a49c41d
--- /dev/null
+++ b/bsd-user/netbsd/os-socket.h
@@ -0,0 +1,98 @@
+/*
+ *  NetBSD socket related system call shims
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __NETBSD_SOCKET_H_
+#define __NETBSD_SOCKET_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* sendmsg(2) */
+static inline abi_long do_freebsd_sendmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* recvmsg(2) */
+static inline abi_long do_freebsd_recvmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setsockopt(2) */
+static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, socklen_t optlen)
+{
+
+    qemu_log("qemu: Unsupported syscall setsockopt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getsockopt(2) */
+static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, abi_ulong optlen)
+{
+
+    qemu_log("qemu: Unsupported syscall getsockopt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setfib(2) */
+static inline abi_long do_freebsd_setfib(abi_long fib)
+{
+
+    qemu_log("qemu: Unsupported syscall setfib()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_peeloff(2) */
+static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_peeloff()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_sendmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s,
+        abi_ulong target_msg, abi_long msglen, abi_ulong target_to,
+        abi_ulong len, abi_ulong target_sinfo, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_recvmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s,
+        abi_ulong target_iov, abi_long iovlen, abi_ulong target_from,
+        abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__NETBSD_SOCKET_H_ */
diff --git a/bsd-user/openbsd/os-socket.c b/bsd-user/openbsd/os-socket.c
new file mode 100644
index 0000000..183002d
--- /dev/null
+++ b/bsd-user/openbsd/os-socket.c
@@ -0,0 +1 @@
+/* XXX OpenBSD socket related helpers */
diff --git a/bsd-user/openbsd/os-socket.h b/bsd-user/openbsd/os-socket.h
new file mode 100644
index 0000000..b8b1e99
--- /dev/null
+++ b/bsd-user/openbsd/os-socket.h
@@ -0,0 +1,98 @@
+/*
+ *  OpenBSD socket related system call shims
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __OPENBSD_SOCKET_H_
+#define __OPENBSD_SOCKET_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* sendmsg(2) */
+static inline abi_long do_freebsd_sendmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* recvmsg(2) */
+static inline abi_long do_freebsd_recvmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setsockopt(2) */
+static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, socklen_t optlen)
+{
+
+    qemu_log("qemu: Unsupported syscall setsockopt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getsockopt(2) */
+static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, abi_ulong optlen)
+{
+
+    qemu_log("qemu: Unsupported syscall getsockopt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setfib(2) */
+static inline abi_long do_freebsd_setfib(abi_long fib)
+{
+
+    qemu_log("qemu: Unsupported syscall setfib()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_peeloff(2) */
+static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_peeloff()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_sendmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s,
+        abi_ulong target_msg, abi_long msglen, abi_ulong target_to,
+        abi_ulong len, abi_ulong target_sinfo, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_recvmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s,
+        abi_ulong target_iov, abi_long iovlen, abi_ulong target_from,
+        abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__OPENBSD_SOCKET_H_ */
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
index f562aad..09b99ef 100644
--- a/bsd-user/qemu-bsd.h
+++ b/bsd-user/qemu-bsd.h
@@ -50,4 +50,12 @@ abi_long host_to_target_rusage(abi_ulong target_addr,
         const struct rusage *rusage);
 int host_to_target_waitstatus(int status);
 
+/* bsd-socket.c */
+abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr,
+        socklen_t len);
+abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
+        socklen_t len);
+abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr,
+        socklen_t len);
+
 #endif /* !_QEMU_BSD_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index e3967fa..286c71e 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -39,11 +39,13 @@ static int host_to_target_errno(int err);
 #include "bsd-mem.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
+#include "bsd-socket.h"
 
 /* *BSD dependent syscall shims */
 #include "os-time.h"
 #include "os-proc.h"
 #include "os-signal.h"
+#include "os-socket.h"
 #include "os-stat.h"
 
 /* #define DEBUG */
@@ -1017,6 +1019,97 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * socket related system calls
+         */
+    case TARGET_FREEBSD_NR_accept: /* accept(2) */
+        ret = do_bsd_accept(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_bind: /* bind(2) */
+        ret = do_bsd_bind(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_connect: /* connect(2) */
+        ret = do_bsd_connect(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getpeername: /* getpeername(2) */
+        ret = do_bsd_getpeername(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getsockname: /* getsockname(2) */
+        ret = do_bsd_getsockname(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getsockopt: /* getsockopt(2) */
+        ret = do_bsd_getsockopt(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_setsockopt: /* setsockopt(2) */
+        ret = do_bsd_setsockopt(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_listen: /* listen(2) */
+        ret = get_errno(listen(arg1, arg2));
+        break;
+
+    case TARGET_FREEBSD_NR_recvfrom: /* recvfrom(2) */
+        ret = do_bsd_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_recvmsg: /* recvmsg(2) */
+        ret = do_freebsd_recvmsg(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sendmsg: /* sendmsg(2) */
+        ret = do_freebsd_sendmsg(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sendto: /* sendto(2) */
+        ret = do_bsd_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_socket: /* socket(2) */
+        ret = do_bsd_socket(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_socketpair: /* socketpair(2) */
+        ret = do_bsd_socketpair(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_shutdown: /* shutdown(2) */
+        ret = do_bsd_shutdown(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setfib: /* setfib(2) */
+        ret = do_freebsd_setfib(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sctp_peeloff: /* sctp_peeloff(2) */
+        ret = do_freebsd_sctp_peeloff(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sctp_generic_sendmsg: /* sctp_generic_sendmsg(2) */
+        ret = do_freebsd_sctp_generic_sendmsg(arg1, arg2, arg2, arg4, arg5,
+                arg6, arg7);
+        break;
+
+    case TARGET_FREEBSD_NR_sctp_generic_recvmsg: /* sctp_generic_recvmsg(2) */
+        ret = do_freebsd_sctp_generic_recvmsg(arg1, arg2, arg2, arg4, arg5,
+                arg6, arg7);
+        break;
+
+    case TARGET_FREEBSD_NR_sendfile: /* sendfile(2) */
+        ret = do_freebsd_sendfile(arg1, arg2, arg2, arg4, arg5, arg6, arg7,
+                arg8);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd4_sendfile: /* freebsd4_sendfile(2) */
+        ret = do_freebsd_freebsd4_sendfile(arg1, arg2, arg2, arg4, arg5,
+                arg6, arg7, arg8);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 14/18] bsd-user: add support for thread related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (12 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 13/18] bsd-user: add support for socket " Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 15/18] bsd-user: add support for the ioctl system call Stacey Son
                   ` (25 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for thread related system calls including
thr_create(), thr_new(), thr_set_name(), thr_self(), thr_suspend(),
thr_wake(), thr_kill(), thr_kill2(), rtprio_thread(2), getcontext(2),
setcontext(2), swapcontext(2), _umtx_lock(), _umtx_unlock(), and
_umtx_op().

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs       |    2 +-
 bsd-user/freebsd/os-thread.c |  936 ++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-thread.h |  510 +++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h   |    6 +
 bsd-user/main.c              |   94 ++++-
 bsd-user/mmap.c              |   26 ++-
 bsd-user/netbsd/os-thread.c  |    1 +
 bsd-user/netbsd/os-thread.h  |  133 ++++++
 bsd-user/openbsd/os-thread.c |    1 +
 bsd-user/openbsd/os-thread.h |  133 ++++++
 bsd-user/qemu.h              |   59 +++-
 bsd-user/syscall.c           |   71 +++-
 12 files changed, 1954 insertions(+), 18 deletions(-)
 create mode 100644 bsd-user/freebsd/os-thread.c
 create mode 100644 bsd-user/freebsd/os-thread.h
 create mode 100644 bsd-user/netbsd/os-thread.c
 create mode 100644 bsd-user/netbsd/os-thread.h
 create mode 100644 bsd-user/openbsd/os-thread.c
 create mode 100644 bsd-user/openbsd/os-thread.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 9869837..b691ffc 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -2,5 +2,5 @@ obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
 	        uaccess.o bsd-mem.o bsd-proc.o bsd-socket.o \
 			$(HOST_ABI_DIR)/os-proc.o \
 			$(HOST_ABI_DIR)/os-socket.o $(HOST_ABI_DIR)/os-stat.o \
-			$(HOST_ABI_DIR)/os-sys.o \
+			$(HOST_ABI_DIR)/os-sys.o $(HOST_ABI_DIR)/os-thread.o \
 			$(HOST_ABI_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/freebsd/os-thread.c b/bsd-user/freebsd/os-thread.c
new file mode 100644
index 0000000..c6f4a82
--- /dev/null
+++ b/bsd-user/freebsd/os-thread.c
@@ -0,0 +1,936 @@
+/*
+ *  FreeBSD thr emulation support code
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/mman.h>
+#include <sys/thr.h>
+#include <sys/umtx.h>
+#include <sys/rtprio.h>
+
+#include <machine/atomic.h>
+
+#include <time.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+#include "target_arch_cpu.h"
+#include "target_arch_thread.h"
+
+#define NEW_STACK_SIZE  0x40000
+
+/* sys/_umtx.h */
+struct target_umtx {
+    abi_ulong   u_owner;    /* Owner of the mutex. */
+};
+
+struct target_umutex {
+    uint32_t    m_owner;    /* Owner of the mutex */
+    uint32_t    m_flags;    /* Flags of the mutex */
+    uint32_t    m_ceiling[2];   /* Priority protect ceiling */
+    uint32_t    m_spare[4];
+};
+
+struct target_ucond {
+    uint32_t    c_has_waiters;  /* Has waiters in kernel */
+    uint32_t    c_flags;    /* Flags of the condition variable */
+    uint32_t    c_clockid;  /* Clock id */
+    uint32_t    c_spare[1];
+};
+
+struct target_urwlock {
+    uint32_t    rw_state;
+    uint32_t    rw_flags;
+    uint32_t    rw_blocked_readers;
+    uint32_t    rw_blocked_writers;
+    uint32_t    rw_spare[4];
+};
+
+struct target__usem {
+    uint32_t    _has_waiters;
+    uint32_t    _count;
+    uint32_t    _flags;
+};
+
+static pthread_mutex_t new_thread_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t *new_freebsd_thread_lock_ptr = &new_thread_lock;
+
+static void rtp_to_schedparam(const struct rtprio *rtp, int *policy,
+        struct sched_param *param)
+{
+
+    switch (rtp->type) {
+    case RTP_PRIO_REALTIME:
+        *policy = SCHED_RR;
+        param->sched_priority = RTP_PRIO_MAX - rtp->prio;
+        break;
+
+    case RTP_PRIO_FIFO:
+        *policy = SCHED_FIFO;
+        param->sched_priority = RTP_PRIO_MAX - rtp->prio;
+        break;
+
+    default:
+        *policy = SCHED_OTHER;
+        param->sched_priority = 0;
+        break;
+    }
+}
+
+void *new_freebsd_thread_start(void *arg)
+{
+    new_freebsd_thread_info_t *info = arg;
+    CPUArchState *env;
+    CPUState *cpu;
+    TaskState *ts;
+    long tid;
+
+    env = info->env;
+    cpu = ENV_GET_CPU(env);
+    thread_cpu = cpu;
+
+    ts = (TaskState *)env->opaque;
+    (void)thr_self(&tid);
+
+    /* copy out the TID info */
+    if (info->param.child_tid) {
+        put_user(tid, info->param.child_tid, abi_long);
+    }
+    if (info->param.parent_tid) {
+        put_user(info->parent_tid, info->param.parent_tid, abi_long);
+    }
+
+    /* Set arch dependent registers to start thread. */
+    target_thread_set_upcall(env, info->param.start_func, info->param.arg,
+        info->param.stack_base, info->param.stack_size);
+
+    /* 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 finished initializing the TLS state. */
+    pthread_mutex_lock(new_freebsd_thread_lock_ptr);
+    pthread_mutex_unlock(new_freebsd_thread_lock_ptr);
+
+    cpu_loop(env);
+    /* never exits */
+
+    return NULL;
+}
+
+/*
+ * FreeBSD user mutex (_umtx) emulation
+ */
+static int tcmpset_al(abi_ulong *addr, abi_ulong a, abi_ulong b)
+{
+    abi_ulong current = tswapal(a);
+    abi_ulong new = tswapal(b);
+
+#ifdef TARGET_ABI32
+    return atomic_cmpset_acq_32(addr, current, new);
+#else
+    return atomic_cmpset_acq_64(addr, current, new);
+#endif
+}
+
+static int tcmpset_32(uint32_t *addr, uint32_t a, uint32_t b)
+{
+    uint32_t current = tswap32(a);
+    uint32_t new = tswap32(b);
+
+    return atomic_cmpset_acq_32(addr, current, new);
+}
+
+abi_long freebsd_umtx_wait_uint(abi_ulong obj, uint32_t val,
+        struct timespec *timeout)
+{
+
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_WAIT_UINT, val, NULL, timeout));
+}
+
+abi_long freebsd_umtx_wait_uint_private(abi_ulong obj, uint32_t val,
+        struct timespec *timeout)
+{
+
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_WAIT_UINT_PRIVATE, val, NULL,
+                timeout));
+}
+
+abi_long freebsd_umtx_wake_private(abi_ulong obj, uint32_t val)
+{
+
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_WAKE_PRIVATE, val, NULL, NULL));
+}
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#if defined(UMTX_OP_NWAKE_PRIVATE)
+abi_long freebsd_umtx_nwake_private(abi_ulong obj, uint32_t val)
+{
+
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_NWAKE_PRIVATE, val, NULL,
+                NULL));
+}
+#endif
+
+#if defined(UMTX_OP_MUTEX_WAKE2)
+abi_long freebsd_umtx_mutex_wake2(abi_ulong obj, uint32_t val)
+{
+    if (!access_ok(VERIFY_WRITE, obj, sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_MUTEX_WAKE2, val, NULL, NULL));
+}
+#endif
+
+abi_long freebsd_umtx_sem_wait(abi_ulong obj, struct timespec *timeout)
+{
+
+    /* XXX Assumes struct _usem is opauque to the user */
+    if (!access_ok(VERIFY_WRITE, obj, sizeof(struct target__usem))) {
+        return -TARGET_EFAULT;
+    }
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_SEM_WAIT, 0, NULL, timeout));
+}
+
+abi_long freebsd_umtx_sem_wake(abi_ulong obj, uint32_t val)
+{
+
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_SEM_WAKE, val, NULL, NULL));
+}
+#endif
+
+abi_long t2h_freebsd_rtprio(struct rtprio *host_rtp, abi_ulong target_addr)
+{
+    struct target_freebsd_rtprio *target_rtp;
+
+    if (!lock_user_struct(VERIFY_READ, target_rtp, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_rtp->type, &target_rtp->type);
+    __get_user(host_rtp->prio, &target_rtp->prio);
+    unlock_user_struct(target_rtp, target_addr, 0);
+    return 0;
+}
+
+abi_long h2t_freebsd_rtprio(abi_ulong target_addr, struct rtprio *host_rtp)
+{
+    struct target_freebsd_rtprio *target_rtp;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_rtp, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_rtp->type, &target_rtp->type);
+    __put_user(host_rtp->prio, &target_rtp->prio);
+    unlock_user_struct(target_rtp, target_addr, 1);
+    return 0;
+}
+
+abi_long freebsd_lock_umtx(abi_ulong target_addr, abi_long id,
+        struct timespec *timeout)
+{
+    abi_long ret;
+    abi_long owner;
+
+    /*
+     * XXX Note that memory at umtx_addr can change and so we need to be
+     * careful and check for faults.
+     */
+    for (;;) {
+        struct target_umtx *target_umtx;
+
+        if (!lock_user_struct(VERIFY_WRITE, target_umtx, target_addr, 0)) {
+            return -TARGET_EFAULT;
+        }
+        /* Check the simple uncontested case. */
+        if (tcmpset_al(&target_umtx->u_owner,
+                TARGET_UMTX_UNOWNED, id)) {
+            unlock_user_struct(target_umtx, target_addr, 1);
+            return 0;
+        }
+        /* Check to see if the lock is contested but free. */
+        __get_user(owner, &target_umtx->u_owner);
+
+        if (TARGET_UMTX_CONTESTED == owner) {
+            if (tcmpset_al(&target_umtx->u_owner, TARGET_UMTX_CONTESTED,
+                        id | TARGET_UMTX_CONTESTED)) {
+                unlock_user_struct(target_umtx, target_addr, 1);
+                return 0;
+            }
+            /* We failed because it changed on us, restart. */
+            unlock_user_struct(target_umtx, target_addr, 1);
+            continue;
+        }
+
+        /* Set the contested bit and sleep. */
+        do {
+            __get_user(owner, &target_umtx->u_owner);
+            if (owner & TARGET_UMTX_CONTESTED) {
+                break;
+            }
+        } while (!tcmpset_al(&target_umtx->u_owner, owner,
+                    owner | TARGET_UMTX_CONTESTED));
+
+        __get_user(owner, &target_umtx->u_owner);
+        unlock_user_struct(target_umtx, target_addr, 1);
+
+        /* Byte swap, if needed, to match what is stored in user mem. */
+        owner = tswapal(owner);
+#ifdef TARGET_ABI32
+        ret = get_errno(_umtx_op(target_umtx, UMTX_OP_WAIT_UINT, owner,
+            NULL, timeout));
+#else
+        ret = get_errno(_umtx_op(target_umtx, UMTX_OP_WAIT, owner,
+            NULL, timeout));
+#endif
+        if (is_error(ret)) {
+            return ret;
+        }
+    }
+}
+
+abi_long freebsd_unlock_umtx(abi_ulong target_addr, abi_long id)
+{
+    abi_ulong owner;
+    struct target_umtx *target_umtx;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_umtx, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(owner, &target_umtx->u_owner);
+    if ((owner & ~TARGET_UMTX_CONTESTED) != id) {
+        unlock_user_struct(target_umtx, target_addr, 1);
+        return -TARGET_EPERM;
+    }
+    /* Check the simple uncontested case. */
+    if ((owner & ~TARGET_UMTX_CONTESTED) == 0) {
+        if (tcmpset_al(&target_umtx->u_owner, owner,
+            TARGET_UMTX_UNOWNED)) {
+            unlock_user_struct(target_umtx, target_addr, 1);
+            return 0;
+        }
+    }
+    /* This is a contested lock. Unlock it. */
+    __put_user(TARGET_UMTX_UNOWNED, &target_umtx->u_owner);
+    unlock_user_struct(target_umtx, target_addr, 1);
+
+    /* Wake up all those contesting it. */
+    _umtx_op(target_umtx, UMTX_OP_WAKE, 0, 0, 0);
+
+    return 0;
+}
+
+abi_long freebsd_umtx_wait(abi_ulong targ_addr, abi_ulong id,
+        struct timespec *ts)
+{
+
+    /* We want to check the user memory but not lock it.  We might sleep. */
+    if (!access_ok(VERIFY_READ, targ_addr, sizeof(abi_ulong))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* id has already been byte swapped to match what may be in user mem. */
+#ifdef TARGET_ABI32
+    return get_errno(_umtx_op(g2h(targ_addr), UMTX_OP_WAIT_UINT, id, NULL, ts));
+#else
+    return get_errno(_umtx_op(g2h(targ_addr), UMTX_OP_WAIT, id, NULL, ts));
+#endif
+}
+
+abi_long freebsd_umtx_wake(abi_ulong target_addr, uint32_t n_wake)
+{
+
+    return get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAKE, n_wake, NULL, 0));
+}
+
+abi_long freebsd_umtx_mutex_wake(abi_ulong obj, abi_long val)
+{
+
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_MUTEX_WAKE, val, NULL, NULL));
+}
+
+abi_long freebsd_lock_umutex(abi_ulong target_addr, uint32_t id,
+        struct timespec *ts, int mode)
+{
+    uint32_t owner, flags;
+    int ret = 0;
+
+    for (;;) {
+        struct target_umutex *target_umutex;
+
+        if (!lock_user_struct(VERIFY_WRITE, target_umutex, target_addr, 0)) {
+            return -TARGET_EFAULT;
+        }
+
+        __get_user(owner, &target_umutex->m_owner);
+
+        if (TARGET_UMUTEX_WAIT == mode) {
+            if (TARGET_UMUTEX_UNOWNED == owner ||
+                    TARGET_UMUTEX_CONTESTED == owner) {
+                unlock_user_struct(target_umutex, target_addr, 1);
+                return 0;
+            }
+        } else {
+            if (tcmpset_32(&target_umutex->m_owner, TARGET_UMUTEX_UNOWNED,
+                        id)) {
+                /* The acquired succeeded. */
+                unlock_user_struct(target_umutex, target_addr, 1);
+                return 0;
+            }
+
+            /* If no one owns it but it is contested try to acquire it. */
+            if (TARGET_UMUTEX_CONTESTED == owner) {
+                if (tcmpset_32(&target_umutex->m_owner, TARGET_UMUTEX_CONTESTED,
+                            id | TARGET_UMUTEX_CONTESTED)) {
+                    unlock_user_struct(target_umutex, target_addr, 1);
+                    return 0;
+                }
+                /* The lock changed so restart. */
+                unlock_user_struct(target_umutex, target_addr, 1);
+                continue;
+            }
+        }
+
+        __get_user(flags, &target_umutex->m_flags);
+        if ((flags & TARGET_UMUTEX_ERROR_CHECK) != 0 &&
+                (owner & ~TARGET_UMUTEX_CONTESTED) == id) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            return -TARGET_EDEADLK;
+        }
+
+        if (TARGET_UMUTEX_TRY == mode) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            return -TARGET_EBUSY;
+        }
+
+        /*
+         * If we caught a signal, we have retried and now
+         * exit immediately.
+         */
+        if (is_error(ret)) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            return ret;
+        }
+
+        /* Set the contested bit and sleep. */
+        if (!tcmpset_32(&target_umutex->m_owner, owner,
+                    owner | TARGET_UMUTEX_CONTESTED)) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            continue;
+        }
+
+        owner = owner | TARGET_UMUTEX_CONTESTED;
+        unlock_user_struct(target_umutex, target_addr, 1);
+
+        /* Byte swap, if needed, to match what is stored in user mem. */
+        owner = tswap32(owner);
+        ret = get_errno(_umtx_op(target_umutex, UMTX_OP_WAIT_UINT, owner, NULL,
+                    ts));
+    }
+
+    if (ts == NULL) {
+        /*
+         * In the case of no timeout do a restart on this syscall,
+         * if interrupted.
+         */
+        if (ret == -TARGET_EINTR) {
+            ret = -TARGET_ERESTART;
+        }
+    }
+    return ret;
+}
+
+abi_long freebsd_unlock_umutex(abi_ulong target_addr, uint32_t id)
+{
+    struct target_umutex *target_umutex;
+    uint32_t owner;
+
+
+    if (!lock_user_struct(VERIFY_WRITE, target_umutex, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    /* Make sure we own this mutex. */
+    __get_user(owner, &target_umutex->m_owner);
+    if ((owner & ~TARGET_UMUTEX_CONTESTED) != id) {
+        unlock_user_struct(target_umutex, target_addr, 1);
+        return -TARGET_EPERM;
+    }
+    if ((owner & TARGET_UMUTEX_CONTESTED) == 0) {
+        if (tcmpset_32(&target_umutex->m_owner, owner, TARGET_UMTX_UNOWNED)) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            return 0;
+        }
+    }
+    /* This is a contested lock. Unlock it. */
+    __put_user(TARGET_UMUTEX_UNOWNED, &target_umutex->m_owner);
+    unlock_user_struct(target_umutex, target_addr, 1);
+
+    /* And wake up all those contesting it. */
+    return get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAKE, 0, 0, 0));
+}
+
+/*
+ * _cv_mutex is keeps other threads from doing a signal or broadcast until
+ * the thread is actually asleep and ready.  This is a global mutex for all
+ * condition vars so I am sure performance may be a problem if there are lots
+ * of CVs.
+ */
+static struct umutex _cv_mutex = { 0, 0, { 0, 0 }, { 0, 0, 0, 0 } };
+
+
+/*
+ * wflags CVWAIT_CHECK_UNPARKING, CVWAIT_ABSTIME, CVWAIT_CLOCKID
+ */
+abi_long freebsd_cv_wait(abi_ulong target_ucond_addr,
+        abi_ulong target_umtx_addr, struct timespec *ts, int wflags)
+{
+    abi_long ret;
+    long tid;
+
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+                sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* Check the clock ID if needed. */
+    if ((wflags & TARGET_CVWAIT_CLOCKID) != 0) {
+        struct target_ucond *target_ucond;
+        uint32_t clockid;
+
+        if (!lock_user_struct(VERIFY_WRITE, target_ucond, target_ucond_addr,
+                    0)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(clockid, &target_ucond->c_clockid);
+        unlock_user_struct(target_ucond, target_ucond_addr, 1);
+        if (clockid < CLOCK_REALTIME || clockid >= CLOCK_THREAD_CPUTIME_ID) {
+            /* Only HW clock id will work. */
+            return -TARGET_EINVAL;
+        }
+    }
+
+    thr_self(&tid);
+
+    /* Lock the _cv_mutex so we can safely unlock the user mutex */
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
+
+    /* unlock the user mutex */
+    ret = freebsd_unlock_umutex(target_umtx_addr, tid);
+    if (is_error(ret)) {
+        _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+        return ret;
+    }
+
+    /* UMTX_OP_CV_WAIT unlocks _cv_mutex */
+    ret = get_errno(_umtx_op(g2h(target_ucond_addr), UMTX_OP_CV_WAIT, wflags,
+                &_cv_mutex, ts));
+
+    return ret;
+}
+
+abi_long freebsd_cv_signal(abi_ulong target_ucond_addr)
+{
+    abi_long ret;
+
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+                sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* Lock the _cv_mutex to prevent a race in do_cv_wait(). */
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
+    ret = get_errno(_umtx_op(g2h(target_ucond_addr), UMTX_OP_CV_SIGNAL, 0,
+        NULL, NULL));
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+
+    return ret;
+}
+
+abi_long freebsd_cv_broadcast(abi_ulong target_ucond_addr)
+{
+    int ret;
+
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+                sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* Lock the _cv_mutex to prevent a race in do_cv_wait(). */
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
+    ret = get_errno(_umtx_op(g2h(target_ucond_addr), UMTX_OP_CV_BROADCAST, 0,
+                NULL, NULL));
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+
+    return ret;
+}
+
+abi_long freebsd_rw_rdlock(abi_ulong target_addr, long fflag,
+        struct timespec *ts)
+{
+    struct target_urwlock *target_urwlock;
+    uint32_t flags, wrflags;
+    uint32_t state;
+    uint32_t blocked_readers;
+    abi_long ret;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    __get_user(flags, &target_urwlock->rw_flags);
+    wrflags = TARGET_URWLOCK_WRITE_OWNER;
+    if (!(fflag & TARGET_URWLOCK_PREFER_READER) &&
+            !(flags & TARGET_URWLOCK_PREFER_READER)) {
+        wrflags |= TARGET_URWLOCK_WRITE_WAITERS;
+    }
+    for (;;) {
+        __get_user(state, &target_urwlock->rw_state);
+        /* try to lock it */
+        while (!(state & wrflags)) {
+            if (TARGET_URWLOCK_READER_COUNT(state) ==
+                TARGET_URWLOCK_MAX_READERS) {
+                unlock_user_struct(target_urwlock,
+                    target_addr, 1);
+                return -TARGET_EAGAIN;
+            }
+            if (tcmpset_32(&target_urwlock->rw_state, state,
+                (state + 1))) {
+                /* The acquired succeeded. */
+                unlock_user_struct(target_urwlock,
+                    target_addr, 1);
+                return 0;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+        /* set read contention bit */
+        if (!tcmpset_32(&target_urwlock->rw_state, state,
+            state | TARGET_URWLOCK_READ_WAITERS)) {
+            /* The state has changed.  Start over. */
+            continue;
+        }
+
+        /* contention bit is set, increase read waiter count */
+        __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_readers,
+                    blocked_readers, blocked_readers + 1)) {
+            __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        }
+
+        while (state & wrflags) {
+            /* sleep/wait */
+            unlock_user_struct(target_urwlock, target_addr, 1);
+            ret = get_errno(_umtx_op(&target_urwlock->rw_blocked_readers,
+                        UMTX_OP_WAIT_UINT, blocked_readers, NULL, ts));
+            if (is_error(ret)) {
+                return ret;
+            }
+            if (!lock_user_struct(VERIFY_WRITE, target_urwlock,
+                        target_addr, 0)) {
+                return -TARGET_EFAULT;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        /* decrease read waiter count */
+        __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_readers,
+                    blocked_readers, (blocked_readers - 1))) {
+            __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        }
+        if (blocked_readers == 1) {
+            /* clear read contention bit */
+            __get_user(state, &target_urwlock->rw_state);
+            while (!tcmpset_32(&target_urwlock->rw_state, state,
+                state & ~TARGET_URWLOCK_READ_WAITERS)) {
+                __get_user(state, &target_urwlock->rw_state);
+            }
+        }
+    }
+}
+
+abi_long freebsd_rw_wrlock(abi_ulong target_addr, long fflag,
+        struct timespec *ts)
+{
+    struct target_urwlock *target_urwlock;
+    uint32_t blocked_readers, blocked_writers;
+    uint32_t state;
+    abi_long ret;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    blocked_readers = 0;
+    for (;;) {
+        __get_user(state, &target_urwlock->rw_state);
+        while (!(state & TARGET_URWLOCK_WRITE_OWNER) &&
+            TARGET_URWLOCK_READER_COUNT(state) == 0) {
+            if (tcmpset_32(&target_urwlock->rw_state, state,
+                        state | TARGET_URWLOCK_WRITE_OWNER)) {
+                unlock_user_struct(target_urwlock, target_addr, 1);
+                return 0;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        if (!(state & (TARGET_URWLOCK_WRITE_OWNER |
+                        TARGET_URWLOCK_WRITE_WAITERS)) &&
+                blocked_readers != 0) {
+            ret = get_errno(_umtx_op(&target_urwlock->rw_blocked_readers,
+                UMTX_OP_WAKE, INT_MAX, NULL, NULL));
+            return ret;
+        }
+        /* re-read the state */
+        __get_user(state, &target_urwlock->rw_state);
+
+        /* and set TARGET_URWLOCK_WRITE_WAITERS */
+        while (((state & TARGET_URWLOCK_WRITE_OWNER) ||
+                    TARGET_URWLOCK_READER_COUNT(state) != 0) &&
+                (state & TARGET_URWLOCK_WRITE_WAITERS) == 0) {
+            if (tcmpset_32(&target_urwlock->rw_state, state,
+                        state | TARGET_URWLOCK_WRITE_WAITERS)) {
+                break;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        /* contention bit is set, increase write waiter count */
+        __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_writers,
+                    blocked_writers, blocked_writers + 1)) {
+            __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        }
+
+        /* sleep */
+        while ((state & TARGET_URWLOCK_WRITE_OWNER) ||
+                (TARGET_URWLOCK_READER_COUNT(state) != 0)) {
+            unlock_user_struct(target_urwlock, target_addr, 1);
+            ret = get_errno(_umtx_op(&target_urwlock->rw_blocked_writers,
+                        UMTX_OP_WAIT_UINT, blocked_writers, NULL, ts));
+            if (is_error(ret)) {
+                return ret;
+            }
+            if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr,
+                        0)) {
+                return -TARGET_EFAULT;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        /* decrease the write waiter count */
+        __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_writers,
+                    blocked_writers, (blocked_writers - 1))) {
+            __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        }
+        if (blocked_writers == 1) {
+            /* clear write contention bit */
+            __get_user(state, &target_urwlock->rw_state);
+            while (!tcmpset_32(&target_urwlock->rw_state, state,
+                        state & ~TARGET_URWLOCK_WRITE_WAITERS)) {
+                __get_user(state, &target_urwlock->rw_state);
+            }
+            __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        } else {
+            blocked_readers = 0;
+        }
+    }
+}
+
+abi_long freebsd_rw_unlock(abi_ulong target_addr)
+{
+    struct target_urwlock *target_urwlock;
+    uint32_t flags, state, count;
+    void *q = NULL;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    __get_user(flags, &target_urwlock->rw_flags);
+    __get_user(state, &target_urwlock->rw_state);
+
+    if (state & TARGET_URWLOCK_WRITE_OWNER) {
+        for (;;) {
+            if (!tcmpset_32(&target_urwlock->rw_state, state,
+                state & ~TARGET_URWLOCK_WRITE_OWNER)) {
+                __get_user(state, &target_urwlock->rw_state);
+                if (!(state & TARGET_URWLOCK_WRITE_OWNER)) {
+                    unlock_user_struct(target_urwlock,
+                        target_addr, 1);
+                    return -TARGET_EPERM;
+                }
+            } else {
+                break;
+            }
+        }
+    } else if (TARGET_URWLOCK_READER_COUNT(state) != 0) {
+        /* decrement reader count */
+        for (;;) {
+            if (!tcmpset_32(&target_urwlock->rw_state, state, (state  - 1))) {
+                if (TARGET_URWLOCK_READER_COUNT(state) == 0) {
+                    unlock_user_struct(target_urwlock,
+                        target_addr, 1);
+                        return -TARGET_EPERM;
+                 }
+            } else {
+                break;
+            }
+        }
+    } else {
+        unlock_user_struct(target_urwlock, target_addr, 1);
+        return -TARGET_EPERM;
+    }
+
+    count = 0;
+
+    if (!(flags & TARGET_URWLOCK_PREFER_READER)) {
+        if (state & TARGET_URWLOCK_WRITE_WAITERS) {
+            count = 1;
+            q = &target_urwlock->rw_blocked_writers;
+        } else if (state & TARGET_URWLOCK_READ_WAITERS) {
+            count = INT_MAX;
+            q = &target_urwlock->rw_blocked_readers;
+        }
+    } else {
+        if (state & TARGET_URWLOCK_READ_WAITERS) {
+            count = INT_MAX;
+            q = &target_urwlock->rw_blocked_readers;
+        } else if (state & TARGET_URWLOCK_WRITE_WAITERS) {
+            count = 1;
+            q = &target_urwlock->rw_blocked_writers;
+        }
+    }
+
+    unlock_user_struct(target_urwlock, target_addr, 1);
+    if (q != NULL) {
+        return get_errno(_umtx_op(q, UMTX_OP_WAKE, count, NULL, NULL));
+    } else {
+        return 0;
+    }
+}
+
+abi_long do_freebsd_thr_new(CPUArchState *env,
+        abi_ulong target_param_addr, int32_t param_size)
+{
+    new_freebsd_thread_info_t info;
+    pthread_attr_t attr;
+    TaskState *ts;
+    CPUArchState *new_env;
+    struct target_freebsd_thr_param *target_param;
+    abi_ulong target_rtp_addr;
+    struct target_freebsd_rtprio *target_rtp;
+    struct rtprio *rtp_ptr, rtp;
+    TaskState *parent_ts = (TaskState *)env->opaque;
+    sigset_t sigmask;
+    struct sched_param sched_param;
+    int sched_policy;
+    int ret = 0;
+
+    memset(&info, 0, sizeof(info));
+
+    if (!lock_user_struct(VERIFY_READ, target_param, target_param_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    info.param.start_func = tswapal(target_param->start_func);
+    info.param.arg = tswapal(target_param->arg);
+    info.param.stack_base = tswapal(target_param->stack_base);
+    info.param.stack_size = tswapal(target_param->stack_size);
+    info.param.tls_base = tswapal(target_param->tls_base);
+    info.param.tls_size = tswapal(target_param->tls_size);
+    info.param.child_tid = tswapal(target_param->child_tid);
+    info.param.parent_tid = tswapal(target_param->parent_tid);
+    info.param.flags = tswap32(target_param->flags);
+    target_rtp_addr = info.param.rtp = tswapal(target_param->rtp);
+    unlock_user(target_param, target_param_addr, 0);
+
+    thr_self(&info.parent_tid);
+
+    if (target_rtp_addr) {
+        if (!lock_user_struct(VERIFY_READ, target_rtp, target_rtp_addr, 1)) {
+            return -TARGET_EFAULT;
+        }
+        rtp.type = tswap16(target_rtp->type);
+        rtp.prio = tswap16(target_rtp->prio);
+        unlock_user(target_rtp, target_rtp_addr, 0);
+        rtp_ptr = &rtp;
+    } else {
+        rtp_ptr = NULL;
+    }
+
+    /* Create a new CPU instance. */
+    ts = g_malloc0(sizeof(TaskState));
+    init_task_state(ts);
+    new_env = cpu_copy(env);
+    target_cpu_reset(new_env);
+
+    /* init regs that differ from the parent thread. */
+    target_cpu_clone_regs(new_env, info.param.stack_base);
+    new_env->opaque = ts;
+    ts->bprm = parent_ts->bprm;
+    ts->info = parent_ts->info;
+
+    target_cpu_set_tls(env, info.param.tls_base);
+
+    /* Grab a mutex so that thread setup appears atomic. */
+    pthread_mutex_lock(new_freebsd_thread_lock_ptr);
+
+    pthread_mutex_init(&info.mutex, NULL);
+    pthread_mutex_lock(&info.mutex);
+    pthread_cond_init(&info.cond, NULL);
+    info.env = new_env;
+
+    /* XXX check return values... */
+    pthread_attr_init(&attr);
+    pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    if (rtp_ptr) {
+        rtp_to_schedparam(&rtp, &sched_policy, &sched_param);
+        pthread_attr_setschedpolicy(&attr, sched_policy);
+        pthread_attr_setschedparam(&attr, &sched_param);
+    }
+
+    /*
+     * 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, new_freebsd_thread_start, &info);
+    /* XXX Free new CPU state if thread creation fails. */
+
+    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);
+    } else {
+        /* Creation of new thread failed. */
+        ret = -host_to_target_errno(errno);
+    }
+
+    pthread_mutex_unlock(&info.mutex);
+    pthread_cond_destroy(&info.cond);
+    pthread_mutex_destroy(&info.mutex);
+    pthread_mutex_unlock(new_freebsd_thread_lock_ptr);
+
+    return ret;
+}
diff --git a/bsd-user/freebsd/os-thread.h b/bsd-user/freebsd/os-thread.h
new file mode 100644
index 0000000..9f30471
--- /dev/null
+++ b/bsd-user/freebsd/os-thread.h
@@ -0,0 +1,510 @@
+/*
+ *  FreeBSD thread and user mutex related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __FREEBSD_OS_THREAD_H_
+#define __FREEBSD_OS_THREAD_H_
+
+#include <sys/thr.h>
+#include <sys/rtprio.h>
+
+#include "qemu-os.h"
+
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong target_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_self(abi_ulong target_id)
+{
+    abi_long ret;
+    long tid;
+
+    ret = get_errno(thr_self(&tid));
+    if (!is_error(ret)) {
+        if (put_user_sal(tid, target_id)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+static abi_long do_freebsd_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr)
+{
+    CPUState *cpu = ENV_GET_CPU(cpu_env);
+    TaskState *ts;
+
+    /*
+     * XXX This probably breaks if a signal arrives.
+     * We should disable signals.
+     */
+    cpu_list_lock();
+    /* Remove the CPU from the list. */
+    QTAILQ_REMOVE(&cpus, cpu, node);
+    cpu_list_unlock();
+    if (tid_addr) {
+        /* Signal target userland that it can free the stack. */
+        if (!put_user_sal(1, tid_addr)) {
+            freebsd_umtx_wake(tid_addr, INT_MAX);
+        }
+    }
+    thread_cpu = NULL;
+    object_unref(OBJECT(ENV_GET_CPU(cpu_env)));
+    ts = ((CPUArchState *)cpu_env)->opaque;
+    g_free(ts);
+    pthread_exit(NULL);
+    /* Doesn't return */
+    return 0;
+}
+
+static abi_long do_freebsd_thr_kill(long id, int sig)
+{
+
+    return get_errno(thr_kill(id, sig));
+}
+
+static abi_long do_freebsd_thr_kill2(pid_t pid, long id, int sig)
+{
+
+    return get_errno(thr_kill2(pid, id, sig));
+}
+
+static abi_long do_freebsd_thr_suspend(abi_ulong target_ts)
+{
+    abi_long ret;
+    struct timespec ts;
+
+    if (target_ts != 0) {
+        if (t2h_freebsd_timespec(&ts, target_ts)) {
+            return -TARGET_EFAULT;
+        }
+        ret = thr_suspend(&ts);
+    } else {
+        ret = thr_suspend(NULL);
+    }
+    return ret;
+}
+
+static abi_long do_freebsd_thr_wake(long tid)
+{
+
+    return get_errno(thr_wake(tid));
+}
+
+static abi_long do_freebsd_thr_set_name(long tid, abi_ulong target_name)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(target_name);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = thr_set_name(tid, p);
+    unlock_user(p, target_name, 0);
+
+    return ret;
+}
+
+static abi_long do_freebsd_rtprio_thread(int function, lwpid_t lwpid,
+        abi_ulong target_addr)
+{
+    int ret;
+    struct rtprio rtp;
+
+    ret = t2h_freebsd_rtprio(&rtp, target_addr);
+    if (!is_error(ret)) {
+        ret = get_errno(rtprio_thread(function, lwpid, &rtp));
+    }
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_rtprio(target_addr, &rtp);
+    }
+    return ret;
+}
+
+static abi_long do_freebsd_getcontext(void *cpu_env, abi_ulong arg1)
+{
+    abi_long ret;
+    target_ucontext_t *ucp;
+    sigset_t sigmask;
+
+    if (arg1 == 0) {
+        return -TARGET_EINVAL;
+    }
+    ret = get_errno(sigprocmask(0, NULL, &sigmask));
+    if (!is_error(ret)) {
+        ucp = lock_user(VERIFY_WRITE, arg1, sizeof(target_ucontext_t), 0);
+        if (ucp == 0) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_mcontext(cpu_env, &ucp->uc_mcontext, TARGET_MC_GET_CLEAR_RET);
+        host_to_target_sigset(&ucp->uc_sigmask, &sigmask);
+        memset(ucp->__spare__, 0, sizeof(ucp->__spare__));
+        unlock_user(ucp, arg1, sizeof(target_ucontext_t));
+    }
+    return ret;
+}
+
+static abi_long do_freebsd_setcontext(void *cpu_env, abi_ulong arg1)
+{
+    abi_long ret;
+    target_ucontext_t *ucp;
+    sigset_t sigmask;
+    if (arg1 == 0) {
+        return -TARGET_EINVAL;
+    }
+    ucp = lock_user(VERIFY_READ, arg1, sizeof(target_ucontext_t), 1);
+    if (ucp == 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = set_mcontext(cpu_env, &ucp->uc_mcontext, 0);
+    target_to_host_sigset(&sigmask, &ucp->uc_sigmask);
+    unlock_user(ucp, arg1, sizeof(target_ucontext_t));
+    if (!is_error(ret)) {
+        (void)sigprocmask(SIG_SETMASK, &sigmask, NULL);
+    }
+    return ret;
+}
+
+/* swapcontext(2) */
+static abi_long do_freebsd_swapcontext(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+    abi_long ret;
+    target_ucontext_t *ucp;
+    sigset_t sigmask;
+
+    if (arg1 == 0 || arg2 == 0) {
+        return -TARGET_EINVAL;
+    }
+    /* Save current context in arg1. */
+    ret = get_errno(sigprocmask(0, NULL,  &sigmask));
+    if (!is_error(ret)) {
+        ucp = lock_user(VERIFY_WRITE, arg1, sizeof(target_ucontext_t), 0);
+        if (ucp == 0) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_mcontext(cpu_env, &ucp->uc_mcontext, TARGET_MC_GET_CLEAR_RET);
+        host_to_target_sigset(&ucp->uc_sigmask, &sigmask);
+        memset(ucp->__spare__, 0, sizeof(ucp->__spare__));
+        unlock_user(ucp, arg1, sizeof(target_ucontext_t));
+    }
+    if (is_error(ret)) {
+            return ret;
+    }
+
+    /* Restore the context in arg2 to the current context. */
+    ucp = lock_user(VERIFY_READ, arg2, sizeof(target_ucontext_t), 1);
+    if (ucp == 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = set_mcontext(cpu_env, &ucp->uc_mcontext, 0);
+    target_to_host_sigset(&sigmask, &ucp->uc_sigmask);
+    unlock_user(ucp, arg2, sizeof(target_ucontext_t));
+    if (!is_error(ret)) {
+        (void)sigprocmask(SIG_SETMASK, &sigmask, NULL);
+    }
+    return ret;
+}
+
+
+/* undocumented _umtx_lock() */
+static inline abi_long do_freebsd__umtx_lock(abi_ulong target_addr)
+{
+    abi_long ret;
+    long tid;
+
+    ret = get_errno(thr_self(&tid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return freebsd_lock_umtx(target_addr, tid, NULL);
+}
+
+/* undocumented _umtx_unlock() */
+static inline abi_long do_freebsd__umtx_unlock(abi_ulong target_addr)
+{
+    abi_long ret;
+    long tid;
+
+    ret = get_errno(thr_self(&tid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return freebsd_unlock_umtx(target_addr, tid);
+}
+
+/* undocumented _umtx_op(void *obj, int op, u_long val, void *uaddr,
+                           void *target_ts); */
+static inline abi_long do_freebsd__umtx_op(abi_ulong obj, int op, abi_ulong val,
+        abi_ulong uaddr, abi_ulong target_ts)
+{
+    abi_long ret;
+    struct timespec ts;
+    long tid;
+
+    switch (op) {
+    case TARGET_UMTX_OP_LOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_lock_umtx(obj, tid, &ts);
+        } else {
+            ret = freebsd_lock_umtx(obj, tid, NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_UNLOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = freebsd_unlock_umtx(obj, tid);
+        break;
+
+    case TARGET_UMTX_OP_WAIT:
+        /* args: obj *, val, ts * */
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_wait(obj, tswapal(val), &ts);
+        } else {
+            ret = freebsd_umtx_wait(obj, tswapal(val), NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_WAKE:
+        /* args: obj *, nr_wakeup */
+        ret = freebsd_umtx_wake(obj, val);
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_LOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        if (target_ts) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_lock_umutex(obj, tid, &ts, 0);
+        } else {
+            ret = freebsd_lock_umutex(obj, tid, NULL, 0);
+        }
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_UNLOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = freebsd_unlock_umutex(obj, tid);
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_TRYLOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = freebsd_lock_umutex(obj, tid, NULL, TARGET_UMUTEX_TRY);
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_WAIT:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_lock_umutex(obj, tid, &ts, TARGET_UMUTEX_WAIT);
+        } else {
+            ret = freebsd_lock_umutex(obj, tid, NULL, TARGET_UMUTEX_WAIT);
+        }
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_WAKE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_mutex_wake(obj, val);
+        break;
+
+    case TARGET_UMTX_OP_SET_CEILING:
+        ret = 0; /* XXX quietly ignore these things for now */
+        break;
+
+    case TARGET_UMTX_OP_CV_WAIT:
+        /*
+         * Initialization of the struct conv is done by
+         * bzero'ing everything in userland.
+         */
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_cv_wait(obj, uaddr, &ts, val);
+        } else {
+            ret = freebsd_cv_wait(obj, uaddr, NULL, val);
+        }
+        break;
+
+    case TARGET_UMTX_OP_CV_SIGNAL:
+        /*
+         * XXX
+         * User code may check if c_has_waiters is zero.  Other
+         * than that it is assume that user code doesn't do
+         * much with the struct conv fields and is pretty
+         * much opauque to userland.
+         */
+        ret = freebsd_cv_signal(obj);
+        break;
+
+    case TARGET_UMTX_OP_CV_BROADCAST:
+        /*
+         * XXX
+         * User code may check if c_has_waiters is zero.  Other
+         * than that it is assume that user code doesn't do
+         * much with the struct conv fields and is pretty
+         * much opauque to userland.
+         */
+        ret = freebsd_cv_broadcast(obj);
+        break;
+
+    case TARGET_UMTX_OP_WAIT_UINT:
+        if (!access_ok(VERIFY_READ, obj, sizeof(abi_ulong))) {
+            return -TARGET_EFAULT;
+        }
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_wait_uint(obj, tswap32((uint32_t)val), &ts);
+        } else {
+            ret = freebsd_umtx_wait_uint(obj, tswap32((uint32_t)val), NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_WAIT_UINT_PRIVATE:
+        if (!access_ok(VERIFY_READ, obj, sizeof(abi_ulong))) {
+            return -TARGET_EFAULT;
+        }
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_wait_uint_private(obj, tswap32((uint32_t)val),
+                    &ts);
+        } else {
+            ret = freebsd_umtx_wait_uint_private(obj, tswap32((uint32_t)val),
+                    NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_WAKE_PRIVATE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_wake_private(obj, val);
+        break;
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 && defined(TARGET_UMTX_OP_NWAKE_PRIVATE)
+    case TARGET_UMTX_OP_NWAKE_PRIVATE:
+        {
+            int i;
+            abi_ulong *uaddr;
+            uint32_t imax = tswap32(INT_MAX);
+
+            if (!access_ok(VERIFY_READ, obj, val * sizeof(uint32_t))) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_nwake_private(obj, val);
+
+            uaddr = (abi_ulong *)g2h(obj);
+            ret = 0;
+            for (i = 0; i < (int32_t)val; i++) {
+                ret = freebsd_umtx_wake_private(tswapal(uaddr[i]), imax);
+                if (is_error(ret)) {
+                    break;
+                }
+            }
+        }
+        break;
+#endif
+
+    case TARGET_UMTX_OP_RW_RDLOCK:
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_rw_rdlock(obj, val, &ts);
+        } else {
+            ret = freebsd_rw_rdlock(obj, val, NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_RW_WRLOCK:
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_rw_wrlock(obj, val, &ts);
+        } else {
+            ret = freebsd_rw_wrlock(obj, val, NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_RW_UNLOCK:
+        ret = freebsd_rw_unlock(obj);
+        break;
+
+#ifdef UMTX_OP_MUTEX_WAKE2
+    case TARGET_UMTX_OP_MUTEX_WAKE2:
+        ret = freebsd_umtx_mutex_wake2(obj, val);
+        break;
+#endif
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+    case TARGET_UMTX_OP_SEM_WAIT:
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_sem_wait(obj, &ts);
+        } else {
+            ret = freebsd_umtx_sem_wait(obj, NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_SEM_WAKE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_sem_wake(obj, val);
+        break;
+#endif
+    default:
+        return -TARGET_EINVAL;
+    }
+    return ret;
+}
+
+#endif /* !__FREEBSD_OS_THREAD_H_ */
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index 90d8eb4..b5510dc 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -64,4 +64,10 @@ abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh);
 abi_long h2t_freebsd_statfs(abi_ulong target_addr, struct statfs *host_statfs);
 abi_long target_to_host_fcntl_cmd(int cmd);
 
+/* os-thread.c */
+abi_long t2h_freebsd_rtprio(struct rtprio *host_rtp, abi_ulong target_addr);
+abi_long h2t_freebsd_rtprio(abi_ulong target_addr, struct rtprio *host_rtp);
+abi_long do_freebsd_thr_new(CPUArchState *env, abi_ulong target_param_addr,
+        int32_t param_size);
+
 #endif /* !_QEMU_OS_H_ */
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 03053b0..47675cd 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -60,45 +60,127 @@ unsigned long target_sgrowsiz = TARGET_SGROWSIZ; /* amount to grow stack */
 
 char qemu_proc_pathname[PATH_MAX];  /* full path to exeutable */
 
-/* These are no-ops because we are not threadsafe.  */
+/* Helper routines for implementing atomic operations. */
+
+/*
+ * To implement exclusive operations we force all cpus to synchronize.
+ * We don't require a full sync, only that no cpus are executing guest code.
+ * The alternative is to map target atomic ops onto host eqivalents,
+ * which requires quite a lot of per host/target work.
+ */
+static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
+static int pending_cpus;
+
+/* Make sure everything is in a consistent state for calling fork(). */
 void fork_start(void)
 {
+    pthread_mutex_lock(&tcg_ctx.tb_ctx.tb_lock);
+    pthread_mutex_lock(&exclusive_lock);
+    mmap_fork_start();
 }
 
 void fork_end(int child)
 {
+    mmap_fork_end(child);
     if (child) {
+        CPUState *cpu, *next_cpu;
+        /*
+         * Child processes created by fork() only have a single thread.
+         * Discard information about the parent threads.
+         */
+        CPU_FOREACH_SAFE(cpu, next_cpu) {
+            if (cpu != thread_cpu) {
+                QTAILQ_REMOVE(&cpus, thread_cpu, node);
+            }
+        }
+        pending_cpus = 0;
+        pthread_mutex_init(&exclusive_lock, NULL);
+        pthread_mutex_init(&cpu_list_mutex, NULL);
+        pthread_cond_init(&exclusive_cond, NULL);
+        pthread_cond_init(&exclusive_resume, NULL);
+        pthread_mutex_init(&tcg_ctx.tb_ctx.tb_lock, NULL);
         gdbserver_fork((CPUArchState *)thread_cpu->env_ptr);
+    } else {
+        pthread_mutex_unlock(&exclusive_lock);
+        pthread_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
     }
 }
 
+/*
+ * Wait for pending exclusive operations to complete.  The exclusive lock
+ * must be held.
+ */
 static inline void exclusive_idle(void)
 {
+    while (pending_cpus) {
+        pthread_cond_wait(&exclusive_resume, &exclusive_lock);
+    }
 }
 
-static inline void start_exclusive(void)
+/* Start an exclusive operation.  Must only be called outside of cpu_exec. */
+void start_exclusive(void)
 {
+    CPUState *other_cpu;
+
+    pthread_mutex_lock(&exclusive_lock);
+    exclusive_idle();
+
+    pending_cpus = 1;
+    /* Make all other cpus stop executing. */
+    CPU_FOREACH(other_cpu) {
+        if (other_cpu->running) {
+            pending_cpus++;
+            cpu_exit(other_cpu);
+        }
+    }
+    if (pending_cpus > 1) {
+        pthread_cond_wait(&exclusive_cond, &exclusive_lock);
+    }
 }
 
-static inline void end_exclusive(void)
+/* Finish an exclusive operation. */
+void end_exclusive(void)
 {
+    pending_cpus = 0;
+    pthread_cond_broadcast(&exclusive_resume);
+    pthread_mutex_unlock(&exclusive_lock);
 }
 
-static inline void cpu_exec_start(CPUState *env)
+/* Wait for exclusive ops to finish, and begin cpu execution. */
+void cpu_exec_start(CPUState *cpu)
 {
+    pthread_mutex_lock(&exclusive_lock);
+    exclusive_idle();
+    cpu->running = true;
+    pthread_mutex_unlock(&exclusive_lock);
 }
 
-
-static inline void cpu_exec_end(CPUState *env)
+/* Mark cpu as not excuting, and release pending exclusive ops. */
+void cpu_exec_end(CPUState *cpu)
 {
+    pthread_mutex_lock(&exclusive_lock);
+    cpu->running = false;
+    if (pending_cpus > 1) {
+        pending_cpus--;
+        if (pending_cpus == 1) {
+            pthread_cond_signal(&exclusive_cond);
+        }
+    }
+    exclusive_idle();
+    pthread_mutex_unlock(&exclusive_lock);
 }
 
 void cpu_list_lock(void)
 {
+    pthread_mutex_lock(&cpu_list_mutex);
 }
 
 void cpu_list_unlock(void)
 {
+    pthread_mutex_unlock(&cpu_list_mutex);
 }
 
 void cpu_loop(CPUArchState *env)
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index f8ef423..849624f 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -29,13 +29,37 @@
 
 // #define DEBUG_MMAP
 
-/* We aren't threadsafe to start with, so no need to worry about locking.  */
+pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
+static __thread int mmap_lock_count;
+
 void mmap_lock(void)
 {
+    if (mmap_lock_count++ == 0) {
+        pthread_mutex_lock(&mmap_mutex);
+    }
 }
 
 void mmap_unlock(void)
 {
+    if (--mmap_lock_count == 0) {
+        pthread_mutex_unlock(&mmap_mutex);
+    }
+}
+
+/* Grab lock to make sure things are in a consistent state after fork().  */
+void mmap_fork_start(void)
+{
+    if (mmap_lock_count)
+        abort();
+    pthread_mutex_lock(&mmap_mutex);
+}
+
+void mmap_fork_end(int child)
+{
+    if (child)
+        pthread_mutex_init(&mmap_mutex, NULL);
+    else
+        pthread_mutex_unlock(&mmap_mutex);
 }
 
 /* NOTE: all the constants are the HOST ones, but addresses are target. */
diff --git a/bsd-user/netbsd/os-thread.c b/bsd-user/netbsd/os-thread.c
new file mode 100644
index 0000000..a4af765
--- /dev/null
+++ b/bsd-user/netbsd/os-thread.c
@@ -0,0 +1 @@
+/* XXX NetBSD thread related helpers */
diff --git a/bsd-user/netbsd/os-thread.h b/bsd-user/netbsd/os-thread.h
new file mode 100644
index 0000000..073b0a0
--- /dev/null
+++ b/bsd-user/netbsd/os-thread.h
@@ -0,0 +1,133 @@
+#ifndef __NETBSD_OS_THREAD_H_
+#define __NETBSD_OS_THREAD_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need to
+ * be emulated.
+ */
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong target_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong thread_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_new(CPUArchState *env,
+        abi_ulong target_param_addr, int32_t param_size)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_self(abi_ulong target_id)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_self()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_exit()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_kill(long id, int sig)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_kill()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_kill2(pid_t pid, long id, int sig)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_kill2()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_suspend(abi_ulong target_ts)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_suspend()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_wake(long tid)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_wake()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_set_name(long tid, abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_set_name()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_rtprio_thread(int function, lwpid_t lwpid,
+        abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall rtprio_thread()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_getcontext(void *cpu_env, abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_setcontext(void *cpu_env, abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_swapcontext(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall swapcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_lock(abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_lock()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_unlock(abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_unlock()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_op(abi_ulong obj, int op, abi_ulong val,
+        abi_ulong uaddr, abi_ulong target_ts)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_op()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __NETBSD_OS_THREAD_H_ */
diff --git a/bsd-user/openbsd/os-thread.c b/bsd-user/openbsd/os-thread.c
new file mode 100644
index 0000000..d125281
--- /dev/null
+++ b/bsd-user/openbsd/os-thread.c
@@ -0,0 +1 @@
+/* XXX OpenBSD thread related helpers */
diff --git a/bsd-user/openbsd/os-thread.h b/bsd-user/openbsd/os-thread.h
new file mode 100644
index 0000000..962a769
--- /dev/null
+++ b/bsd-user/openbsd/os-thread.h
@@ -0,0 +1,133 @@
+#ifndef __OPENBSD_OS_THREAD_H_
+#define __OPENBSD_OS_THREAD_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need to
+ * be emulated.
+ */
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong target_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong thread_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_new(CPUArchState *env,
+        abi_ulong target_param_addr, int32_t param_size)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_self(abi_ulong target_id)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_self()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_exit()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_kill(long id, int sig)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_kill()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_kill2(pid_t pid, long id, int sig)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_kill2()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_suspend(abi_ulong target_ts)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_suspend()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_wake(long tid)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_wake()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_set_name(long tid, abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_set_name()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_rtprio_thread(int function, lwpid_t lwpid,
+        abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall rtprio_thread()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_getcontext(void *cpu_env, abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_setcontext(void *cpu_env, abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_swapcontext(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall swapcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_lock(abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_lock()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_unlock(abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_unlock()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_op(abi_ulong obj, int op, abi_ulong val,
+        abi_ulong uaddr, abi_ulong target_ts)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_op()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_OS_THREAD_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 613a89e..4b2add2 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -42,11 +42,7 @@ extern enum BSDType bsd_type;
 #include "target_os_signal.h"
 #include "exec/gdbstub.h"
 
-#if defined(CONFIG_USE_NPTL)
 #define THREAD __thread
-#else
-#define THREAD
-#endif
 
 /* This struct is used to hold certain information about the image.
  * Basically, it replicates in user space what would be certain
@@ -67,6 +63,8 @@ struct image_info {
     abi_ulong entry;
     abi_ulong code_offset;
     abi_ulong data_offset;
+    abi_ulong arg_start;
+    abi_ulong arg_end;
     int       personality;
 };
 
@@ -89,6 +87,15 @@ struct emulated_sigtable {
 typedef struct TaskState {
     struct TaskState *next;
     int used; /* non zero if used */
+#ifdef TARGET_ARM
+    int swi_errno;
+#endif
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
+    /* Extra fields for semihosted binaries. */
+    uint32_t heap_base;
+    uint32_t heap_limit;
+    uint32_t stack_base;
+#endif
     struct image_info *info;
     struct bsd_binprm *bprm;
 
@@ -231,10 +238,8 @@ void mmap_unlock(void);
 abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
 void cpu_list_lock(void);
 void cpu_list_unlock(void);
-#if defined(CONFIG_USE_NPTL)
 void mmap_fork_start(void);
 void mmap_fork_end(int child);
-#endif
 
 /* main.c */
 extern unsigned long target_maxtsiz;
@@ -244,10 +249,15 @@ extern unsigned long target_dflssiz;
 extern unsigned long target_maxssiz;
 extern unsigned long target_sgrowsiz;
 extern char qemu_proc_pathname[];
+void start_exclusive(void);
+void end_exclusive(void);
+void cpu_exec_start(CPUState *cpu);
+void cpu_exec_end(CPUState *cpu);
 
 /* syscall.c */
 abi_long get_errno(abi_long ret);
 int is_error(abi_long ret);
+int host_to_target_errno(int err);
 
 /* os-proc.c */
 abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
@@ -258,6 +268,41 @@ abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
         abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen);
 abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2);
 
+/* os-thread.c */
+extern pthread_mutex_t *new_freebsd_thread_lock_ptr;
+void *new_freebsd_thread_start(void *arg);
+abi_long freebsd_lock_umtx(abi_ulong target_addr, abi_long tid,
+        struct timespec *timeout);
+abi_long freebsd_unlock_umtx(abi_ulong target_addr, abi_long id);
+abi_long freebsd_umtx_wait(abi_ulong targ_addr, abi_ulong id,
+        struct timespec *ts);
+abi_long freebsd_umtx_wake(abi_ulong target_addr, uint32_t n_wake);
+abi_long freebsd_umtx_mutex_wake(abi_ulong target_addr, abi_long val);
+abi_long freebsd_umtx_wait_uint(abi_ulong obj, uint32_t val,
+                struct timespec *timeout);
+abi_long freebsd_umtx_wait_uint_private(abi_ulong obj, uint32_t val,
+                struct timespec *timeout);
+abi_long freebsd_umtx_wake_private(abi_ulong obj, uint32_t val);
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+abi_long freebsd_umtx_nwake_private(abi_ulong obj, uint32_t val);
+abi_long freebsd_umtx_mutex_wake2(abi_ulong obj, uint32_t val);
+abi_long freebsd_umtx_sem_wait(abi_ulong obj, struct timespec *timeout);
+abi_long freebsd_umtx_sem_wake(abi_ulong obj, uint32_t val);
+#endif
+abi_long freebsd_lock_umutex(abi_ulong target_addr, uint32_t id,
+        struct timespec *ts, int mode);
+abi_long freebsd_unlock_umutex(abi_ulong target_addr, uint32_t id);
+abi_long freebsd_cv_wait(abi_ulong target_ucond_addr,
+                abi_ulong target_umtx_addr, struct timespec *ts, int wflags);
+abi_long freebsd_cv_signal(abi_ulong target_ucond_addr);
+abi_long freebsd_cv_broadcast(abi_ulong target_ucond_addr);
+abi_long freebsd_rw_rdlock(abi_ulong target_addr, long fflag,
+        struct timespec *ts);
+abi_long freebsd_rw_wrlock(abi_ulong target_addr, long fflag,
+        struct timespec *ts);
+abi_long freebsd_rw_unlock(abi_ulong target_addr);
+
+
 /* user access */
 
 #define VERIFY_READ 0
@@ -483,8 +528,6 @@ static inline int regpairs_aligned(void *cpu_env)
 }
 #endif
 
-#if defined(CONFIG_USE_NPTL)
 #include <pthread.h>
-#endif
 
 #endif /* QEMU_H */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 286c71e..0a851fe 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -32,7 +32,6 @@
 #include "qemu-common.h"
 
 #define target_to_host_bitmask(x, tbl) (x)
-static int host_to_target_errno(int err);
 
 /* BSD independent syscall shims */
 #include "bsd-file.h"
@@ -47,6 +46,7 @@ static int host_to_target_errno(int err);
 #include "os-signal.h"
 #include "os-socket.h"
 #include "os-stat.h"
+#include "os-thread.h"
 
 /* #define DEBUG */
 
@@ -64,7 +64,7 @@ abi_long get_errno(abi_long ret)
     }
 }
 
-static int host_to_target_errno(int err)
+int host_to_target_errno(int err)
 {
     /* XXX need to translate host errnos here */
     return err;
@@ -1110,6 +1110,73 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * thread system calls
+         */
+    case TARGET_FREEBSD_NR_thr_create: /* thr_create(2) */
+        ret = do_freebsd_thr_create(cpu_env, arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_new: /* thr_new(2) */
+        ret = do_freebsd_thr_new(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_set_name: /* thr_set_name(2) */
+        ret = do_freebsd_thr_set_name(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_self: /* thr_self(2) */
+        ret = do_freebsd_thr_self(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_suspend: /* thr_suspend(2) */
+        ret = do_freebsd_thr_suspend(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_wake: /* thr_wake(2) */
+        ret = do_freebsd_thr_wake(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_kill: /* thr_kill(2) */
+        ret = do_freebsd_thr_kill(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_kill2: /* thr_kill2(2) */
+        ret = do_freebsd_thr_kill2(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_exit: /* thr_exit(2) */
+        ret = do_freebsd_thr_exit(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_rtprio_thread: /* rtprio_thread(2) */
+        ret = do_freebsd_rtprio_thread(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getcontext: /* getcontext(2) */
+        ret = do_freebsd_getcontext(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setcontext: /* setcontext(2) */
+        ret = do_freebsd_setcontext(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_swapcontext: /* swapcontext(2) */
+        ret = do_freebsd_swapcontext(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR__umtx_lock: /* undocumented */
+        ret = do_freebsd__umtx_lock(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR__umtx_unlock: /* undocumented */
+        ret = do_freebsd__umtx_unlock(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR__umtx_op: /* undocumented */
+        ret = do_freebsd__umtx_op(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 15/18] bsd-user: add support for the ioctl system call
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (13 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 14/18] bsd-user: add support for thread " Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 16/18] bsd-user: add support for extended attribute and ACL related syscalls Stacey Son
                   ` (24 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support for the ioctl system call.  This uses the
generic thunking code to convert data between the host and target CPU.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 Makefile.target                    |    2 +-
 bsd-user/Makefile.objs             |    2 +-
 bsd-user/bsd-ioctl.c               |  448 ++++++++++++++++++++++++++++++++++++
 bsd-user/bsd-ioctl.h               |   27 +++
 bsd-user/freebsd/os-ioctl-cmds.h   |   47 ++++
 bsd-user/freebsd/os-ioctl-filio.h  |   45 ++++
 bsd-user/freebsd/os-ioctl-ioccom.h |   54 +++++
 bsd-user/freebsd/os-ioctl-ttycom.h |  257 +++++++++++++++++++++
 bsd-user/freebsd/os-ioctl-types.h  |    7 +
 bsd-user/netbsd/os-ioctl-cmds.h    |   48 ++++
 bsd-user/netbsd/os-ioctl-filio.h   |   29 +++
 bsd-user/netbsd/os-ioctl-ioccom.h  |   38 +++
 bsd-user/netbsd/os-ioctl-ttycom.h  |  240 +++++++++++++++++++
 bsd-user/netbsd/os-ioctl-types.h   |    7 +
 bsd-user/openbsd/os-ioctl-cmds.h   |   48 ++++
 bsd-user/openbsd/os-ioctl-filio.h  |   29 +++
 bsd-user/openbsd/os-ioctl-ioccom.h |   38 +++
 bsd-user/openbsd/os-ioctl-ttycom.h |  240 +++++++++++++++++++
 bsd-user/openbsd/os-ioctl-types.h  |    7 +
 bsd-user/qemu.h                    |    1 +
 bsd-user/syscall.c                 |   27 ++-
 21 files changed, 1632 insertions(+), 9 deletions(-)
 create mode 100644 bsd-user/bsd-ioctl.c
 create mode 100644 bsd-user/bsd-ioctl.h
 create mode 100644 bsd-user/freebsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/freebsd/os-ioctl-filio.h
 create mode 100644 bsd-user/freebsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/freebsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/freebsd/os-ioctl-types.h
 create mode 100644 bsd-user/netbsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/netbsd/os-ioctl-filio.h
 create mode 100644 bsd-user/netbsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/netbsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/netbsd/os-ioctl-types.h
 create mode 100644 bsd-user/openbsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/openbsd/os-ioctl-filio.h
 create mode 100644 bsd-user/openbsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/openbsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/openbsd/os-ioctl-types.h

diff --git a/Makefile.target b/Makefile.target
index 7da81dc..ef52ee4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -107,7 +107,7 @@ QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR) \
 			 -I$(SRC_PATH)/bsd-user/$(HOST_ABI_DIR)
 
 obj-y += bsd-user/
-obj-y += gdbstub.o user-exec.o
+obj-y += gdbstub.o thunk.o user-exec.o
 
 endif #CONFIG_BSD_USER
 
diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index b691ffc..242e6f4 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,5 +1,5 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-mem.o bsd-proc.o bsd-socket.o \
+	        uaccess.o bsd-ioctl.o bsd-mem.o bsd-proc.o bsd-socket.o \
 			$(HOST_ABI_DIR)/os-proc.o \
 			$(HOST_ABI_DIR)/os-socket.o $(HOST_ABI_DIR)/os-stat.o \
 			$(HOST_ABI_DIR)/os-sys.o $(HOST_ABI_DIR)/os-thread.o \
diff --git a/bsd-user/bsd-ioctl.c b/bsd-user/bsd-ioctl.c
new file mode 100644
index 0000000..95505a4
--- /dev/null
+++ b/bsd-user/bsd-ioctl.c
@@ -0,0 +1,448 @@
+/*
+ *  BSD ioctl(2) emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#include <sys/_termios.h>
+#else
+#include <sys/termios.h>
+#endif
+#include <sys/ttycom.h>
+#include <sys/filio.h>
+
+#include "qemu.h"
+#include "qemu-common.h"
+
+#include "bsd-ioctl.h"
+#include "os-ioctl-filio.h"
+#include "os-ioctl-ttycom.h"
+
+static const bitmask_transtbl iflag_tbl[] = {
+    { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
+    { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
+    { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
+    { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
+    { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
+    { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
+    { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
+    { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
+    { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
+    { TARGET_IXON, TARGET_IXON, IXON, IXON },
+    { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
+#ifdef IXANY
+    { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
+#endif
+#ifdef IMAXBEL
+    { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
+#endif
+    { 0, 0, 0, 0 }
+};
+
+static const bitmask_transtbl oflag_tbl[] = {
+    { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
+#ifdef ONLCR
+    { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
+#endif
+#ifdef TABDLY
+    { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
+    { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
+#endif
+#ifdef ONOEOT
+    { TARGET_ONOEOT, TARGET_ONOEOT, ONOEOT, ONOEOT },
+#endif
+#ifdef OCRNL
+    { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
+#endif
+#ifdef ONOCR
+    { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
+#endif
+#ifdef ONLRET
+    { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
+#endif
+    { 0, 0, 0, 0 }
+};
+
+static const bitmask_transtbl cflag_tbl[] = {
+#ifdef CIGNORE
+    { TARGET_CIGNORE, TARGET_CIGNORE, CIGNORE, CIGNORE },
+#endif
+    { 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 },
+#ifdef CCTS_OFLOW
+    { TARGET_CCTS_OFLOW, TARGET_CCTS_OFLOW, CCTS_OFLOW, CCTS_OFLOW },
+#endif
+#ifdef CRTSCTS
+    { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
+#endif
+#ifdef CRTS_IFLOW
+    { TARGET_CRTS_IFLOW, TARGET_CRTS_IFLOW, CRTS_IFLOW, CRTS_IFLOW },
+#endif
+#ifdef CDTS_IFLOW
+    { TARGET_CDTR_IFLOW, TARGET_CDTR_IFLOW, CDTR_IFLOW, CDTR_IFLOW },
+#endif
+#ifdef CDSR_OFLOW
+    { TARGET_CDSR_OFLOW, TARGET_CDSR_OFLOW, CDSR_OFLOW, CDSR_OFLOW },
+#endif
+#ifdef CCAR_OFLOW
+    { TARGET_CCAR_OFLOW, TARGET_CCAR_OFLOW, CCAR_OFLOW, CCAR_OFLOW },
+#endif
+    { 0, 0, 0, 0 }
+};
+
+static const bitmask_transtbl lflag_tbl[] = {
+#ifdef ECHOKE
+    { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
+#endif
+    { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
+    { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
+    { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
+    { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
+#ifdef ECHOPRT
+    { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
+#endif
+#ifdef ECHOCTL
+    { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
+#endif
+    { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
+    { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
+#ifdef ALTWERASE
+    { TARGET_ALTWERASE, TARGET_ALTWERASE, ALTWERASE, ALTWERASE },
+#endif
+    { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
+    { TARGET_EXTPROC, TARGET_EXTPROC, EXTPROC, EXTPROC },
+    { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
+#ifdef FLUSHO
+    { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
+#endif
+#ifdef NOKERNINFO
+    { TARGET_NOKERNINFO, TARGET_NOKERNINFO, NOKERNINFO, NOKERNINFO },
+#endif
+#ifdef PENDIN
+    { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
+#endif
+    { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
+    { 0, 0, 0, 0 }
+};
+
+static void target_to_host_termios(void *dst, const void *src)
+{
+    struct termios *host = dst;
+    const struct target_termios *target = src;
+
+    host->c_iflag = target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
+    host->c_oflag = target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
+    host->c_cflag = target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
+    host->c_lflag = target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
+
+    memset(host->c_cc, 0, sizeof(host->c_cc));
+    host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
+    host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
+#ifdef VEOL2
+    host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
+#endif
+    host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
+#ifdef VWERASE
+    host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
+#endif
+    host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
+#ifdef VREPRINT
+    host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
+#endif
+#ifdef VERASE2
+    host->c_cc[VERASE2] = target->c_cc[TARGET_VERASE2];
+#endif
+    host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
+    host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
+    host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
+#ifdef VDSUSP
+    host->c_cc[VDSUSP] = target->c_cc[TARGET_VDSUSP];
+#endif
+    host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
+    host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
+#ifdef VLNEXT
+    host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
+#endif
+#ifdef VDISCARD
+    host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
+#endif
+    host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
+    host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
+#ifdef VSTATUS
+    host->c_cc[VSTATUS] = target->c_cc[TARGET_VSTATUS];
+#endif
+
+    host->c_ispeed = tswap32(target->c_ispeed);
+    host->c_ospeed = tswap32(target->c_ospeed);
+}
+
+static void host_to_target_termios(void *dst, const void *src)
+{
+    struct target_termios *target = dst;
+    const struct termios *host = src;
+
+    target->c_iflag = tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
+    target->c_oflag = tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
+    target->c_cflag = tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
+    target->c_lflag = tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
+
+    memset(target->c_cc, 0, sizeof(target->c_cc));
+    target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
+    target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
+#ifdef VEOL2
+    target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
+#endif
+    target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
+#ifdef VWERASE
+    target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
+#endif
+    target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
+#ifdef VREPRINT
+    target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
+#endif
+#ifdef VERASE2
+    target->c_cc[TARGET_VERASE2] = host->c_cc[VERASE2];
+#endif
+    target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
+    target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
+    target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
+#ifdef VDSUSP
+    target->c_cc[TARGET_VDSUSP] = host->c_cc[VDSUSP];
+#endif
+    target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
+    target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
+#ifdef VLNEXT
+    target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
+#endif
+#ifdef VDISCARD
+    target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
+#endif
+    target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
+    target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
+#ifdef VSTATUS
+    target->c_cc[TARGET_VSTATUS] = host->c_cc[VSTATUS];
+#endif
+
+    target->c_ispeed = tswap32(host->c_ispeed);
+    target->c_ospeed = tswap32(host->c_ospeed);
+}
+
+static const StructEntry struct_termios_def = {
+    .convert = { host_to_target_termios, target_to_host_termios },
+    .size = { sizeof(struct target_termios), sizeof(struct termios) },
+    .align = { __alignof__(struct target_termios),
+        __alignof__(struct termios) },
+};
+
+
+/* ioctl structure type definitions */
+#define STRUCT(name, ...) STRUCT_ ## name,
+#define STRUCT_SPECIAL(name) STRUCT_ ## name,
+enum {
+#include "os-ioctl-types.h"
+};
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+#define STRUCT(name, ...) \
+    static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
+#define STRUCT_SPECIAL(name)
+#include "os-ioctl-types.h"
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+
+struct IOCTLEntry;
+
+typedef abi_long do_ioctl_fn(const struct IOCTLEntry *ie, uint8_t *buf_temp,
+                int fd, abi_long cmd, abi_long arg);
+
+struct IOCTLEntry {
+    unsigned int target_cmd;
+    unsigned int host_cmd;
+    const char *name;
+    int access;
+    do_ioctl_fn *do_ioctl;
+    const argtype arg_type[5];
+};
+typedef struct IOCTLEntry IOCTLEntry;
+
+#define MAX_STRUCT_SIZE 4096
+
+static IOCTLEntry ioctl_entries[] = {
+#define IOC_    0x0000
+#define IOC_R   0x0001
+#define IOC_W   0x0002
+#define IOC_RW  (IOC_R | IOC_W)
+#define IOCTL(cmd, access, ...) \
+    { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
+#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
+    { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
+#include "os-ioctl-cmds.h"
+    { 0, 0 },
+};
+
+abi_long do_bsd_ioctl(int fd, abi_long cmd, abi_long arg)
+{
+    const IOCTLEntry *ie;
+    const argtype *arg_type;
+    abi_long ret;
+    uint8_t buf_temp[MAX_STRUCT_SIZE];
+    int target_size;
+    void *argptr;
+
+    ie = ioctl_entries;
+    for (;;) {
+        if (ie->target_cmd == 0) {
+            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
+            return -TARGET_ENOSYS;
+        }
+        if (ie->target_cmd == cmd) {
+            break;
+        }
+        ie++;
+    }
+    arg_type = ie->arg_type;
+#if defined(DEBUG)
+    gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
+#endif
+    if (ie->do_ioctl) {
+        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
+    }
+
+    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 argument */
+        ret = get_errno(ioctl(fd, ie->host_cmd, arg));
+        break;
+
+    case TYPE_PTR:
+        arg_type++;
+        target_size = thunk_type_size(arg_type, 0);
+        switch (ie->access) {
+        case IOC_R:
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            if (!is_error(ret)) {
+                argptr = lock_user(VERIFY_WRITE, arg,
+                    target_size, 0);
+                if (!argptr) {
+                    return -TARGET_EFAULT;
+                }
+                thunk_convert(argptr, buf_temp, arg_type,
+                    THUNK_TARGET);
+                unlock_user(argptr, arg, target_size);
+            }
+            break;
+
+        case IOC_W:
+            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);
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            break;
+
+        case IOC_RW:
+            /* fallthrough */
+        default:
+            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);
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            if (!is_error(ret)) {
+                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+                if (!argptr) {
+                    return -TARGET_EFAULT;
+                }
+                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+                unlock_user(argptr, arg, target_size);
+            }
+            break;
+        }
+        break;
+
+    default:
+        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
+            (long)cmd, arg_type[0]);
+        ret = -TARGET_ENOSYS;
+        break;
+    }
+    return ret;
+}
+
+void init_bsd_ioctl(void)
+{
+    IOCTLEntry *ie;
+    const argtype *arg_type;
+    int size;
+
+#define STRUCT(name, ...) \
+ thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
+#define STRUCT_SPECIAL(name) \
+ thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
+#include "os-ioctl-types.h"
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+    /*
+     * Patch the ioctl size if necessary using the fact that no
+     * ioctl has all the bits at '1' in the size field
+     * (IOCPARM_MAX - 1).
+     */
+    ie = ioctl_entries;
+    while (ie->target_cmd != 0) {
+        if (((ie->target_cmd >> TARGET_IOCPARM_SHIFT) &
+                    TARGET_IOCPARM_MASK) == TARGET_IOCPARM_MASK) {
+            arg_type = ie->arg_type;
+            if (arg_type[0] != TYPE_PTR) {
+                fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
+                        ie->target_cmd);
+                exit(1);
+            }
+            arg_type++;
+            size = thunk_type_size(arg_type, 0);
+            ie->target_cmd = (ie->target_cmd &
+                    ~(TARGET_IOCPARM_MASK << TARGET_IOCPARM_SHIFT)) |
+                (size << TARGET_IOCPARM_SHIFT);
+        }
+        ie++;
+    }
+
+}
+
diff --git a/bsd-user/bsd-ioctl.h b/bsd-user/bsd-ioctl.h
new file mode 100644
index 0000000..b593c88
--- /dev/null
+++ b/bsd-user/bsd-ioctl.h
@@ -0,0 +1,27 @@
+/*
+ *  ioctl system call definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_IOCTL_H_
+#define __BSD_IOCTL_H_
+
+abi_long do_bsd_ioctl(int fd, abi_long cmd, abi_long arg);
+void init_bsd_ioctl(void);
+
+#endif /* !__BSD_IOCTL_H_ */
+
diff --git a/bsd-user/freebsd/os-ioctl-cmds.h b/bsd-user/freebsd/os-ioctl-cmds.h
new file mode 100644
index 0000000..85d3c41
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-cmds.h
@@ -0,0 +1,47 @@
+
+/* sys/ttycom.h tty(4) */
+IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCCBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCSDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCCDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR))
+IOCTL(TIOCNOTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCSTOP, IOC_, TYPE_NULL)
+IOCTL(TIOCSTART, IOC_, TYPE_NULL)
+IOCTL(TIOCSCTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCDRAIN, IOC_, TYPE_NULL)
+IOCTL(TIOCEXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCNXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
+
+/* sys/filio.h */
+IOCTL(FIOCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODTYPE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOGETLBA, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODGNAME, IOC_R, MK_PTR(STRUCT_fiodgname_arg))
+IOCTL(FIONWRITE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONSPACE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOSEEKDATA, IOC_RW, MK_PTR(TYPE_ULONG))
+IOCTL(FIOSEEKHOLE, IOC_RW, MK_PTR(TYPE_ULONG))
diff --git a/bsd-user/freebsd/os-ioctl-filio.h b/bsd-user/freebsd/os-ioctl-filio.h
new file mode 100644
index 0000000..7e1aae9
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-filio.h
@@ -0,0 +1,45 @@
+/*
+ *  FreeBSD filio definitions for ioctl(2) emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _IOCTL_FILIO_H_
+#define _IOCTL_FILIO_H_
+
+/* see sys/filio.h */
+#define TARGET_FIOCLEX      TARGET_IO('f', 1)
+#define TARGET_FIONCLEX     TARGET_IO('f', 2)
+#define TARGET_FIONREAD     TARGET_IOR('f', 127, int)
+#define TARGET_FIONBIO      TARGET_IOW('f', 126, int)
+#define TARGET_FIOASYNC     TARGET_IOW('f', 125, int)
+#define TARGET_FIOSETOWN    TARGET_IOW('f', 124, int)
+#define TARGET_FIOGETOWN    TARGET_IOR('f', 123, int)
+#define TARGET_FIODTYPE     TARGET_IOR('f', 122, int)
+#define TARGET_FIOGETLBA    TARGET_IOR('f', 121, int)
+
+struct target_fiodgname_arg {
+    int32_t     len;
+    abi_ulong   buf;
+};
+
+#define TARGET_FIODGNAME    TARGET_IOW('f', 120,    \
+                struct target_fiodgname_arg)
+#define TARGET_FIONWRITE    TARGET_IOR('f', 119, int)
+#define TARGET_FIONSPACE    TARGET_IOR('f', 118, int)
+#define TARGET_FIOSEEKDATA  TARGET_IOWR('f', 97, off_t)
+#define TARGET_FIOSEEKHOLE  TARGET_IOWR('f', 98, off_t)
+
+#endif /* !_IOCTL_FILIO_H_ */
diff --git a/bsd-user/freebsd/os-ioctl-ioccom.h b/bsd-user/freebsd/os-ioctl-ioccom.h
new file mode 100644
index 0000000..fb9456f
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-ioccom.h
@@ -0,0 +1,54 @@
+/*
+ *  FreeBSD ioccom definitions for ioctl(2) emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _IOCTL_IOCCOM_H_
+#define _IOCTL_IOCCOM_H_
+/*
+ * Ioctl's have the command encoded in the lower word, and the size of
+ * any in or out parameters in the upper word.  The high 3 bits of the
+ * upper word are used to encode the in/out status of the parameter.
+ */
+/* number of bits for ioctl size */
+#define TARGET_IOCPARM_SHIFT    13
+
+/* parameter length mask */
+#define TARGET_IOCPARM_MASK ((1 << TARGET_IOCPARM_SHIFT) - 1)
+
+#define TARGET_IOCPARM_LEN(x)   (((x) >> 16) & TARGET_IOCPARM_MASK)
+#define TARGET_IOCBASECMD(x)    ((x) & ~(TARGET_IOCPARM_MASK << 16))
+#define TARGET_IOCGROUP(x)  (((x) >> 8) & 0xff)
+
+#define TARGET_IOCPARM_MAX  (1 << TARGET_IOCPARM_SHIFT) /* max size of ioctl */
+#define TARGET_IOC_VOID     0x20000000  /* no parameters */
+#define TARGET_IOC_OUT      0x40000000  /* copy out parameters */
+#define TARGET_IOC_IN       0x80000000  /* copy in parameters */
+#define TARGET_IOC_INOUT    (TARGET_IOC_IN|TARGET_IOC_OUT)
+#define TARGET_IOC_DIRMASK  (TARGET_IOC_VOID|TARGET_IOC_OUT|TARGET_IOC_IN)
+
+#define TARGET_IOC(inout, group, num, len) ((abi_ulong) \
+    ((inout) | (((len) & TARGET_IOCPARM_MASK) << 16) | ((group) << 8) \
+     | (num)))
+#define TARGET_IO(g, n)       TARGET_IOC(IOC_VOID,    (g), (n), 0)
+#define TARGET_IOWINT(g, n)   TARGET_IOC(IOC_VOID,    (g), (n), sizeof(int))
+#define TARGET_IOR(g, n, t)   TARGET_IOC(IOC_OUT, (g), (n), sizeof(t))
+#define TARGET_IOW(g, n, t)   TARGET_IOC(IOC_IN,  (g), (n), sizeof(t))
+/* this should be _IORW, but stdio got there first */
+#define TARGET_IOWR(g, n, t)  TARGET_IOC(IOC_INOUT,   (g), (n), sizeof(t))
+
+#endif /* !_IOCTL_IOCCOM_H_ */
diff --git a/bsd-user/freebsd/os-ioctl-ttycom.h b/bsd-user/freebsd/os-ioctl-ttycom.h
new file mode 100644
index 0000000..b60db25
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-ttycom.h
@@ -0,0 +1,257 @@
+/*
+ *  FreeBSD ttycom definitions for ioctl(2) emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _IOCTL_TTYCOM_H_
+#define _IOCTL_TTYCOM_H_
+
+#include "os-ioctl-ioccom.h"
+
+/* From sys/ttycom.h and sys/_termios.h */
+
+#define TARGET_VEOF     0   /* ICANON */
+#define TARGET_VEOL     1   /* ICANON */
+#define TARGET_VEOL2    2   /* ICANON together with IEXTEN */
+#define TARGET_VERASE   3   /* ICANON */
+#define TARGET_VWERASE  4   /* ICANON together with IEXTEN */
+#define TARGET_VKILL    5   /* ICANON */
+#define TARGET_VREPRINT 6   /* ICANON together with IEXTEN */
+#define TARGET_VERASE2  7   /* ICANON */
+#define TARGET_VINTR    8   /* ISIG */
+#define TARGET_VQUIT    9   /* ISIG */
+#define TARGET_VSUSP    10  /* ISIG */
+#define TARGET_VDSUSP   11  /* ISIG together with IEXTEN */
+#define TARGET_VSTART   12  /* IXON, IXOFF */
+#define TARGET_VSTOP    13  /* IXON, IXOFF */
+#define TARGET_VLNEXT   14  /* IEXTEN */
+#define TARGET_VDISCARD 15  /* IEXTEN */
+#define TARGET_VMIN     16  /* !ICANON */
+#define TARGET_VTIME    17  /* !ICANON */
+#define TARGET_VSTATUS  18  /* ICANON together with IEXTEN */
+/*                      19         spare 2 */
+#define TARGET_NCCS     20
+
+/*
+ * Input flags - software input processing
+ */
+#define TARGET_IGNBRK   0x00000001  /* ignore BREAK condition */
+#define TARGET_BRKINT   0x00000002  /* map BREAK to SIGINTR */
+#define TARGET_IGNPAR   0x00000004  /* ignore (discard) parity errors */
+#define TARGET_PARMRK   0x00000008  /* mark parity and framing errors */
+#define TARGET_INPCK    0x00000010  /* enable checking of parity errors */
+#define TARGET_ISTRIP   0x00000020  /* strip 8th bit off chars */
+#define TARGET_INLCR    0x00000040  /* map NL into CR */
+#define TARGET_IGNCR    0x00000080  /* ignore CR */
+#define TARGET_ICRNL    0x00000100  /* map CR to NL (ala CRMOD) */
+#define TARGET_IXON     0x00000200  /* enable output flow control */
+#define TARGET_IXOFF    0x00000400  /* enable input flow control */
+#define TARGET_IXANY    0x00000800  /* any char will restart after stop */
+#define TARGET_IMAXBEL  0x00002000  /* ring bell on input queue full */
+
+/*
+ * Output flags - software output processing
+ */
+#define TARGET_OPOST    0x00000001  /* enable following output processing */
+#define TARGET_ONLCR    0x00000002  /* map NL to CR-NL (ala CRMOD) */
+#define TARGET_TABDLY   0x00000004  /* tab delay mask */
+#define TARGET_TAB0     0x00000000  /* no tab delay and expansion */
+#define TARGET_TAB3     0x00000004  /* expand tabs to spaces */
+#define TARGET_ONOEOT   0x00000008  /* discard EOT's (^D) on output) */
+#define TARGET_OCRNL    0x00000010  /* map CR to NL on output */
+#define TARGET_ONOCR    0x00000020  /* no CR output at column 0 */
+#define TARGET_ONLRET   0x00000040  /* NL performs CR function */
+
+/*
+ * Control flags - hardware control of terminal
+ */
+#define TARGET_CIGNORE      0x00000001  /* ignore control flags */
+#define TARGET_CSIZE        0x00000300  /* character size mask */
+#define     TARGET_CS5      0x00000000  /* 5 bits (pseudo) */
+#define     TARGET_CS6      0x00000100  /* 6 bits */
+#define     TARGET_CS7      0x00000200  /* 7 bits */
+#define     TARGET_CS8      0x00000300  /* 8 bits */
+#define TARGET_CSTOPB       0x00000400  /* send 2 stop bits */
+#define TARGET_CREAD        0x00000800  /* enable receiver */
+#define TARGET_PARENB       0x00001000  /* parity enable */
+#define TARGET_PARODD       0x00002000  /* odd parity, else even */
+#define TARGET_HUPCL        0x00004000  /* hang up on last close */
+#define TARGET_CLOCAL       0x00008000  /* ignore modem status lines */
+#define TARGET_CCTS_OFLOW   0x00010000  /* CTS flow control of output */
+#define TARGET_CRTSCTS      (TARGET_CCTS_OFLOW | TARGET_CRTS_IFLOW)
+#define TARGET_CRTS_IFLOW   0x00020000  /* RTS flow control of input */
+#define TARGET_CDTR_IFLOW   0x00040000  /* DTR flow control of input */
+#define TARGET_CDSR_OFLOW   0x00080000  /* DSR flow control of output */
+#define TARGET_CCAR_OFLOW   0x00100000  /* DCD flow control of output */
+
+/*
+ * "Local" flags - dumping ground for other state
+ */
+#define TARGET_ECHOKE   0x00000001  /* visual erase for line kill */
+#define TARGET_ECHOE    0x00000002  /* visually erase chars */
+#define TARGET_ECHOK    0x00000004  /* echo NL after line kill */
+#define TARGET_ECHO 0x00000008  /* enable echoing */
+#define TARGET_ECHONL   0x00000010  /* echo NL even if ECHO is off */
+#define TARGET_ECHOPRT  0x00000020  /* visual erase mode for hardcopy */
+#define TARGET_ECHOCTL  0x00000040  /* echo control chars as ^(Char) */
+#define TARGET_ISIG 0x00000080  /* enable signals INTR, QUIT, [D]SUSP */
+#define TARGET_ICANON   0x00000100  /* canonicalize input lines */
+#define TARGET_ALTWERASE 0x00000200 /* use alternate WERASE algorithm */
+#define TARGET_IEXTEN   0x00000400  /* enable DISCARD and LNEXT */
+#define TARGET_EXTPROC  0x00000800  /* external processing */
+#define TARGET_TOSTOP   0x00400000  /* stop background jobs from output */
+#define TARGET_FLUSHO   0x00800000  /* output being flushed (state) */
+#define TARGET_NOKERNINFO 0x02000000    /* no kernel output from VSTATUS */
+#define TARGET_PENDIN   0x20000000  /* XXX retype pending input (state) */
+#define TARGET_NOFLSH   0x80000000  /* don't flush after interrupt */
+
+struct target_termios {
+    uint32_t c_iflag;   /* input flags */
+    uint32_t c_oflag;   /* output flags */
+    uint32_t c_cflag;   /* control flags */
+    uint32_t c_lflag;   /* local flags */
+    uint8_t  c_cc[TARGET_NCCS]; /* control chars */
+    uint32_t c_ispeed;  /* input speed */
+    uint32_t c_ospeed;  /* output speed */
+};
+
+
+struct target_winsize {
+    uint16_t ws_row;    /* rows, in characters */
+    uint16_t ws_col;    /* columns, in characters */
+    uint16_t ws_xpixel; /* horizontal size, pixels */
+    uint16_t ws_ypixel; /* vertical size, pixels */
+};
+
+                        /* 0-2 compat */
+                        /* 3-7 unused */
+                        /* 8-10 compat */
+                        /* 11-12 unused */
+#define TARGET_TIOCEXCL  TARGET_IO('t', 13) /* set exclusive use of tty */
+#define TARGET_TIOCNXCL  TARGET_IO('t', 14) /* reset exclusive use of tty */
+#define TARGET_TIOCGPTN  TARGET_IOR('t', 15, int) /* Get pts number. */
+#define TARGET_TIOCFLUSH TARGET_IOW('t', 16, int) /* flush buffers */
+                    /* 17-18 compat */
+/* get termios struct */
+#define TARGET_TIOCGETA TARGET_IOR('t', 19, struct target_termios)
+/* set termios struct */
+#define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios)
+/* drain output, set */
+#define TARGET_TIOCSETAW    TARGET_IOW('t', 21, struct target_termios)
+/* drn out, fls in, set */
+#define TARGET_TIOCSETAF    TARGET_IOW('t', 22, struct target_termios)
+                        /* 23-25 unused */
+#define TARGET_TIOCGETD TARGET_IOR('t', 26, int) /* get line discipline */
+#define TARGET_TIOCSETD TARGET_IOW('t', 27, int) /* set line discipline */
+#define TARGET_TIOCPTMASTER  TARGET_IO('t', 28) /* pts master validation */
+                    /* 29-85 unused */
+/* get ttywait timeout */
+#define TARGET_TIOCGDRAINWAIT   TARGET_IOR('t', 86, int)
+/* set ttywait timeout */
+#define TARGET_TIOCSDRAINWAIT   TARGET_IOW('t', 87, int)
+                    /* 88 unused */
+                    /* 89-91 conflicts: tun and tap */
+/* enable/get timestamp of last input event */
+#define TARGET_TIOCTIMESTAMP    TARGET_IOR('t', 89, struct target_timeval)
+/* modem: get wait on close */
+#define TARGET_TIOCMGDTRWAIT    TARGET_IOR('t', 90, int)
+/* modem: set wait on close */
+#define TARGET_TIOCMSDTRWAIT    TARGET_IOW('t', 91, int)
+                    /* 92-93 tun and tap */
+                    /* 94-97 conflicts: tun and tap */
+/* wait till output drained */
+#define TARGET_TIOCDRAIN     TARGET_IO('t', 94)
+ /* pty: generate signal */
+#define TARGET_TIOCSIG      TARGET_IOWINT('t', 95)
+/* pty: external processing */
+#define TARGET_TIOCEXT      TARGET_IOW('t', 96, int)
+/* become controlling tty */
+#define TARGET_TIOCSCTTY     TARGET_IO('t', 97)
+/* become virtual console */
+#define TARGET_TIOCCONS TARGET_IOW('t', 98, int)
+/* get session id */
+#define TARGET_TIOCGSID TARGET_IOR('t', 99, int)
+                        /* 100 unused */
+/* simulate ^T status message */
+#define TARGET_TIOCSTAT  TARGET_IO('t', 101)
+ /* pty: set/clr usr cntl mode */
+#define TARGET_TIOCUCNTL    TARGET_IOW('t', 102, int)
+/* usr cntl op "n" */
+#define TARGET_TIOCCMD(n)   TARGET_IO('u', n)
+/* set window size */
+#define TARGET_TIOCSWINSZ   TARGET_IOW('t', 103, struct target_winsize)
+/* get window size */
+#define TARGET_TIOCGWINSZ   TARGET_IOR('t', 104, struct target_winsize)
+                        /* 105 unused */
+/* get all modem bits */
+#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
+#define     TARGET_TIOCM_LE 0001        /* line enable */
+#define     TARGET_TIOCM_DTR    0002    /* data terminal ready */
+#define     TARGET_TIOCM_RTS    0004    /* request to send */
+#define     TARGET_TIOCM_ST 0010        /* secondary transmit */
+#define     TARGET_TIOCM_SR 0020        /* secondary receive */
+#define     TARGET_TIOCM_CTS    0040    /* clear to send */
+#define     TARGET_TIOCM_DCD    0100    /* data carrier detect */
+#define     TARGET_TIOCM_RI     0200    /* ring indicate */
+#define     TARGET_TIOCM_DSR    0400    /* data set ready */
+#define     TARGET_TIOCM_CD TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_CAR    TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_RNG    TARGET_TIOCM_RI
+#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) /* bic modem bits */
+#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) /* bis modem bits */
+#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) /* set all modem bits */
+/* start output, like ^Q */
+#define TARGET_TIOCSTART     TARGET_IO('t', 110)
+/* stop output, like ^S */
+#define TARGET_TIOCSTOP  TARGET_IO('t', 111)
+/* pty: set/clear packet mode */
+#define TARGET_TIOCPKT      TARGET_IOW('t', 112, int)
+#define     TARGET_TIOCPKT_DATA     0x00    /* data packet */
+#define     TARGET_TIOCPKT_FLUSHREAD    0x01    /* flush packet */
+#define     TARGET_TIOCPKT_FLUSHWRITE   0x02    /* flush packet */
+#define     TARGET_TIOCPKT_STOP     0x04    /* stop output */
+#define     TARGET_TIOCPKT_START        0x08    /* start output */
+#define     TARGET_TIOCPKT_NOSTOP       0x10    /* no more ^S, ^Q */
+#define     TARGET_TIOCPKT_DOSTOP       0x20    /* now do ^S ^Q */
+#define     TARGET_TIOCPKT_IOCTL        0x40    /* state change of pty
+                               driver */
+#define TARGET_TIOCNOTTY     TARGET_IO('t', 113)    /* void tty
+                               association */
+#define TARGET_TIOCSTI      TARGET_IOW('t', 114, char)  /* simulate
+                            terminal input */
+#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)   /* output queue size */
+                        /* 116-117 compat */
+#define TARGET_TIOCSPGRP    TARGET_IOW('t', 118, int) /* set pgrp of tty */
+#define TARGET_TIOCGPGRP    TARGET_IOR('t', 119, int) /* get pgrp of tty */
+#define TARGET_TIOCCDTR  TARGET_IO('t', 120)        /* clear data terminal
+                               ready */
+#define TARGET_TIOCSDTR  TARGET_IO('t', 121)        /* set data terminal
+                               ready */
+#define TARGET_TIOCCBRK  TARGET_IO('t', 122)        /* clear break bit */
+#define TARGET_TIOCSBRK  TARGET_IO('t', 123)        /* set break bit */
+                        /* 124-127 compat */
+
+#define TARGET_TTYDISC      0       /* termios tty line
+                           discipline */
+#define TARGET_SLIPDISC     4       /* serial IP discipline */
+#define TARGET_PPPDISC      5       /* PPP discipline */
+#define TARGET_NETGRAPHDISC 6       /* Netgraph tty node
+                           discipline */
+#define TARGET_H4DISC       7       /* Netgraph Bluetooth H4
+                           discipline */
+
+#endif /*! _IOCTL_TTYCOM_H_ */
diff --git a/bsd-user/freebsd/os-ioctl-types.h b/bsd-user/freebsd/os-ioctl-types.h
new file mode 100644
index 0000000..60b9288
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-types.h
@@ -0,0 +1,7 @@
+
+STRUCT_SPECIAL(termios)
+
+STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
+
+STRUCT(fiodgname_arg, TYPE_INT, TYPE_PTRVOID)
+
diff --git a/bsd-user/netbsd/os-ioctl-cmds.h b/bsd-user/netbsd/os-ioctl-cmds.h
new file mode 100644
index 0000000..12af33c
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-cmds.h
@@ -0,0 +1,48 @@
+/* XXX should be fixed for NetBSD ioctl cmds */
+
+/* sys/ttycom.h tty(4) */
+IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCCBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCSDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCCDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR))
+IOCTL(TIOCNOTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCSTOP, IOC_, TYPE_NULL)
+IOCTL(TIOCSTART, IOC_, TYPE_NULL)
+IOCTL(TIOCSCTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCDRAIN, IOC_, TYPE_NULL)
+IOCTL(TIOCEXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCNXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
+
+/* sys/filio.h */
+IOCTL(FIOCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODTYPE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOGETLBA, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODGNAME, IOC_R, MK_PTR(STRUCT_fiodgname_arg))
+IOCTL(FIONWRITE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONSPACE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOSEEKDATA, IOC_RW, MK_PTR(TYPE_ULONG))
+IOCTL(FIOSEEKHOLE, IOC_RW, MK_PTR(TYPE_ULONG))
diff --git a/bsd-user/netbsd/os-ioctl-filio.h b/bsd-user/netbsd/os-ioctl-filio.h
new file mode 100644
index 0000000..24b63ae
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-filio.h
@@ -0,0 +1,29 @@
+#ifndef _IOCTL_FILIO_H_
+#define _IOCTL_FILIO_H_
+
+/* XXX needs to be fixed for NetBSD dependencies */
+
+/* see sys/filio.h */
+#define TARGET_FIOCLEX      TARGET_IO('f', 1)
+#define TARGET_FIONCLEX     TARGET_IO('f', 2)
+#define TARGET_FIONREAD     TARGET_IOR('f', 127, int)
+#define TARGET_FIONBIO      TARGET_IOW('f', 126, int)
+#define TARGET_FIOASYNC     TARGET_IOW('f', 125, int)
+#define TARGET_FIOSETOWN    TARGET_IOW('f', 124, int)
+#define TARGET_FIOGETOWN    TARGET_IOR('f', 123, int)
+#define TARGET_FIODTYPE     TARGET_IOR('f', 122, int)
+#define TARGET_FIOGETLBA    TARGET_IOR('f', 121, int)
+
+struct target_fiodgname_arg {
+    int32_t     len;
+    abi_ulong   buf;
+};
+
+#define TARGET_FIODGNAME    TARGET_IOW('f', 120,    \
+                struct target_fiodgname_arg)
+#define TARGET_FIONWRITE    TARGET_IOR('f', 119, int)
+#define TARGET_FIONSPACE    TARGET_IOR('f', 118, int)
+#define TARGET_FIOSEEKDATA  TARGET_IOWR('f', 97, off_t)
+#define TARGET_FIOSEEKHOLE  TARGET_IOWR('f', 98, off_t)
+
+#endif /* !_IOCTL_FILIO_H_ */
diff --git a/bsd-user/netbsd/os-ioctl-ioccom.h b/bsd-user/netbsd/os-ioctl-ioccom.h
new file mode 100644
index 0000000..e193a16
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-ioccom.h
@@ -0,0 +1,38 @@
+#ifndef _IOCTL_IOCCOM_H_
+#define _IOCTL_IOCCOM_H_
+
+/* XXX needs to be fixed for NetBSD dependencies */
+
+/*
+ * Ioctl's have the command encoded in the lower word, and the size of
+ * any in or out parameters in the upper word.  The high 3 bits of the
+ * upper word are used to encode the in/out status of the parameter.
+ */
+/* number of bits for ioctl size */
+#define TARGET_IOCPARM_SHIFT    13
+
+/* parameter length mask */
+#define TARGET_IOCPARM_MASK ((1 << TARGET_IOCPARM_SHIFT) - 1)
+
+#define TARGET_IOCPARM_LEN(x)   (((x) >> 16) & TARGET_IOCPARM_MASK)
+#define TARGET_IOCBASECMD(x)    ((x) & ~(TARGET_IOCPARM_MASK << 16))
+#define TARGET_IOCGROUP(x)  (((x) >> 8) & 0xff)
+
+#define TARGET_IOCPARM_MAX  (1 << TARGET_IOCPARM_SHIFT) /* max size of ioctl */
+#define TARGET_IOC_VOID     0x20000000  /* no parameters */
+#define TARGET_IOC_OUT      0x40000000  /* copy out parameters */
+#define TARGET_IOC_IN       0x80000000  /* copy in parameters */
+#define TARGET_IOC_INOUT    (TARGET_IOC_IN|TARGET_IOC_OUT)
+#define TARGET_IOC_DIRMASK  (TARGET_IOC_VOID|TARGET_IOC_OUT|TARGET_IOC_IN)
+
+#define TARGET_IOC(inout, group, num, len) ((abi_ulong) \
+    ((inout) | (((len) & TARGET_IOCPARM_MASK) << 16) | ((group) << 8) \
+     | (num)))
+#define TARGET_IO(g, n)      TARGET_IOC(IOC_VOID,    (g), (n), 0)
+#define TARGET_IOWINT(g, n)  TARGET_IOC(IOC_VOID,    (g), (n), sizeof(int))
+#define TARGET_IOR(g, n, t)   TARGET_IOC(IOC_OUT, (g), (n), sizeof(t))
+#define TARGET_IOW(g, n, t)   TARGET_IOC(IOC_IN,  (g), (n), sizeof(t))
+/* this should be _IORW, but stdio got there first */
+#define TARGET_IOWR(g, n, t)  TARGET_IOC(IOC_INOUT,   (g), (n), sizeof(t))
+
+#endif /* !_IOCTL_IOCCOM_H_ */
diff --git a/bsd-user/netbsd/os-ioctl-ttycom.h b/bsd-user/netbsd/os-ioctl-ttycom.h
new file mode 100644
index 0000000..9086635
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-ttycom.h
@@ -0,0 +1,240 @@
+#ifndef _IOCTL_TTYCOM_H_
+#define _IOCTL_TTYCOM_H_
+
+/* XXX Needs to be fixed for NetBSD dependencies */
+
+#include "os-ioctl-ioccom.h"
+
+/* From sys/ttycom.h and sys/_termios.h */
+
+#define TARGET_VEOF     0   /* ICANON */
+#define TARGET_VEOL     1   /* ICANON */
+#define TARGET_VEOL2    2   /* ICANON together with IEXTEN */
+#define TARGET_VERASE   3   /* ICANON */
+#define TARGET_VWERASE  4   /* ICANON together with IEXTEN */
+#define TARGET_VKILL    5   /* ICANON */
+#define TARGET_VREPRINT 6   /* ICANON together with IEXTEN */
+#define TARGET_VERASE2  7   /* ICANON */
+#define TARGET_VINTR    8   /* ISIG */
+#define TARGET_VQUIT    9   /* ISIG */
+#define TARGET_VSUSP    10  /* ISIG */
+#define TARGET_VDSUSP   11  /* ISIG together with IEXTEN */
+#define TARGET_VSTART   12  /* IXON, IXOFF */
+#define TARGET_VSTOP    13  /* IXON, IXOFF */
+#define TARGET_VLNEXT   14  /* IEXTEN */
+#define TARGET_VDISCARD 15  /* IEXTEN */
+#define TARGET_VMIN     16  /* !ICANON */
+#define TARGET_VTIME    17  /* !ICANON */
+#define TARGET_VSTATUS  18  /* ICANON together with IEXTEN */
+/*                      19         spare 2 */
+#define TARGET_NCCS     20
+
+/*
+ * Input flags - software input processing
+ */
+#define TARGET_IGNBRK   0x00000001  /* ignore BREAK condition */
+#define TARGET_BRKINT   0x00000002  /* map BREAK to SIGINTR */
+#define TARGET_IGNPAR   0x00000004  /* ignore (discard) parity errors */
+#define TARGET_PARMRK   0x00000008  /* mark parity and framing errors */
+#define TARGET_INPCK    0x00000010  /* enable checking of parity errors */
+#define TARGET_ISTRIP   0x00000020  /* strip 8th bit off chars */
+#define TARGET_INLCR    0x00000040  /* map NL into CR */
+#define TARGET_IGNCR    0x00000080  /* ignore CR */
+#define TARGET_ICRNL    0x00000100  /* map CR to NL (ala CRMOD) */
+#define TARGET_IXON     0x00000200  /* enable output flow control */
+#define TARGET_IXOFF    0x00000400  /* enable input flow control */
+#define TARGET_IXANY    0x00000800  /* any char will restart after stop */
+#define TARGET_IMAXBEL  0x00002000  /* ring bell on input queue full */
+
+/*
+ * Output flags - software output processing
+ */
+#define TARGET_OPOST    0x00000001  /* enable following output processing */
+#define TARGET_ONLCR    0x00000002  /* map NL to CR-NL (ala CRMOD) */
+#define TARGET_TABDLY   0x00000004  /* tab delay mask */
+#define TARGET_TAB0     0x00000000  /* no tab delay and expansion */
+#define TARGET_TAB3     0x00000004  /* expand tabs to spaces */
+#define TARGET_ONOEOT   0x00000008  /* discard EOT's (^D) on output) */
+#define TARGET_OCRNL    0x00000010  /* map CR to NL on output */
+#define TARGET_ONOCR    0x00000020  /* no CR output at column 0 */
+#define TARGET_ONLRET   0x00000040  /* NL performs CR function */
+
+/*
+ * Control flags - hardware control of terminal
+ */
+#define TARGET_CIGNORE      0x00000001  /* ignore control flags */
+#define TARGET_CSIZE        0x00000300  /* character size mask */
+#define     TARGET_CS5      0x00000000  /* 5 bits (pseudo) */
+#define     TARGET_CS6      0x00000100  /* 6 bits */
+#define     TARGET_CS7      0x00000200  /* 7 bits */
+#define     TARGET_CS8      0x00000300  /* 8 bits */
+#define TARGET_CSTOPB       0x00000400  /* send 2 stop bits */
+#define TARGET_CREAD        0x00000800  /* enable receiver */
+#define TARGET_PARENB       0x00001000  /* parity enable */
+#define TARGET_PARODD       0x00002000  /* odd parity, else even */
+#define TARGET_HUPCL        0x00004000  /* hang up on last close */
+#define TARGET_CLOCAL       0x00008000  /* ignore modem status lines */
+#define TARGET_CCTS_OFLOW   0x00010000  /* CTS flow control of output */
+#define TARGET_CRTSCTS      (TARGET_CCTS_OFLOW | TARGET_CRTS_IFLOW)
+#define TARGET_CRTS_IFLOW   0x00020000  /* RTS flow control of input */
+#define TARGET_CDTR_IFLOW   0x00040000  /* DTR flow control of input */
+#define TARGET_CDSR_OFLOW   0x00080000  /* DSR flow control of output */
+#define TARGET_CCAR_OFLOW   0x00100000  /* DCD flow control of output */
+
+/*
+ * "Local" flags - dumping ground for other state
+ */
+#define TARGET_ECHOKE   0x00000001  /* visual erase for line kill */
+#define TARGET_ECHOE    0x00000002  /* visually erase chars */
+#define TARGET_ECHOK    0x00000004  /* echo NL after line kill */
+#define TARGET_ECHO 0x00000008  /* enable echoing */
+#define TARGET_ECHONL   0x00000010  /* echo NL even if ECHO is off */
+#define TARGET_ECHOPRT  0x00000020  /* visual erase mode for hardcopy */
+#define TARGET_ECHOCTL  0x00000040  /* echo control chars as ^(Char) */
+#define TARGET_ISIG 0x00000080  /* enable signals INTR, QUIT, [D]SUSP */
+#define TARGET_ICANON   0x00000100  /* canonicalize input lines */
+#define TARGET_ALTWERASE 0x00000200 /* use alternate WERASE algorithm */
+#define TARGET_IEXTEN   0x00000400  /* enable DISCARD and LNEXT */
+#define TARGET_EXTPROC  0x00000800  /* external processing */
+#define TARGET_TOSTOP   0x00400000  /* stop background jobs from output */
+#define TARGET_FLUSHO   0x00800000  /* output being flushed (state) */
+#define TARGET_NOKERNINFO 0x02000000    /* no kernel output from VSTATUS */
+#define TARGET_PENDIN   0x20000000  /* XXX retype pending input (state) */
+#define TARGET_NOFLSH   0x80000000  /* don't flush after interrupt */
+
+struct target_termios {
+    uint32_t c_iflag;   /* input flags */
+    uint32_t c_oflag;   /* output flags */
+    uint32_t c_cflag;   /* control flags */
+    uint32_t c_lflag;   /* local flags */
+    uint8_t  c_cc[TARGET_NCCS]; /* control chars */
+    uint32_t c_ispeed;  /* input speed */
+    uint32_t c_ospeed;  /* output speed */
+};
+
+
+struct target_winsize {
+    uint16_t ws_row;    /* rows, in characters */
+    uint16_t ws_col;    /* columns, in characters */
+    uint16_t ws_xpixel; /* horizontal size, pixels */
+    uint16_t ws_ypixel; /* vertical size, pixels */
+};
+
+                        /* 0-2 compat */
+                        /* 3-7 unused */
+                        /* 8-10 compat */
+                        /* 11-12 unused */
+#define TARGET_TIOCEXCL  TARGET_IO('t', 13) /* set exclusive use of tty */
+#define TARGET_TIOCNXCL  TARGET_IO('t', 14) /* reset exclusive use of tty */
+#define TARGET_TIOCGPTN  TARGET_IOR('t', 15, int) /* Get pts number. */
+#define TARGET_TIOCFLUSH TARGET_IOW('t', 16, int) /* flush buffers */
+                    /* 17-18 compat */
+/* get termios struct */
+#define TARGET_TIOCGETA TARGET_IOR('t', 19, struct target_termios)
+/* set termios struct */
+#define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios)
+/* drain output, set */
+#define TARGET_TIOCSETAW    TARGET_IOW('t', 21, struct target_termios)
+/* drn out, fls in, set */
+#define TARGET_TIOCSETAF    TARGET_IOW('t', 22, struct target_termios)
+                        /* 23-25 unused */
+#define TARGET_TIOCGETD TARGET_IOR('t', 26, int) /* get line discipline */
+#define TARGET_TIOCSETD TARGET_IOW('t', 27, int) /* set line discipline */
+#define TARGET_TIOCPTMASTER  TARGET_IO('t', 28) /* pts master validation */
+                    /* 29-85 unused */
+/* get ttywait timeout */
+#define TARGET_TIOCGDRAINWAIT   TARGET_IOR('t', 86, int)
+/* set ttywait timeout */
+#define TARGET_TIOCSDRAINWAIT   TARGET_IOW('t', 87, int)
+                    /* 88 unused */
+                    /* 89-91 conflicts: tun and tap */
+/* enable/get timestamp of last input event */
+#define TARGET_TIOCTIMESTAMP    TARGET_IOR('t', 89, struct target_timeval)
+/* modem: get wait on close */
+#define TARGET_TIOCMGDTRWAIT    TARGET_IOR('t', 90, int)
+/* modem: set wait on close */
+#define TARGET_TIOCMSDTRWAIT    TARGET_IOW('t', 91, int)
+                    /* 92-93 tun and tap */
+                    /* 94-97 conflicts: tun and tap */
+/* wait till output drained */
+#define TARGET_TIOCDRAIN     TARGET_IO('t', 94)
+ /* pty: generate signal */
+#define TARGET_TIOCSIG      TARGET_IOWINT('t', 95)
+/* pty: external processing */
+#define TARGET_TIOCEXT      TARGET_IOW('t', 96, int)
+/* become controlling tty */
+#define TARGET_TIOCSCTTY     TARGET_IO('t', 97)
+/* become virtual console */
+#define TARGET_TIOCCONS TARGET_IOW('t', 98, int)
+/* get session id */
+#define TARGET_TIOCGSID TARGET_IOR('t', 99, int)
+                        /* 100 unused */
+/* simulate ^T status message */
+#define TARGET_TIOCSTAT  TARGET_IO('t', 101)
+ /* pty: set/clr usr cntl mode */
+#define TARGET_TIOCUCNTL    TARGET_IOW('t', 102, int)
+/* usr cntl op "n" */
+#define TARGET_TIOCCMD(n)   TARGET_IO('u', n)
+/* set window size */
+#define TARGET_TIOCSWINSZ   TARGET_IOW('t', 103, struct target_winsize)
+/* get window size */
+#define TARGET_TIOCGWINSZ   TARGET_IOR('t', 104, struct target_winsize)
+                        /* 105 unused */
+/* get all modem bits */
+#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
+#define     TARGET_TIOCM_LE 0001        /* line enable */
+#define     TARGET_TIOCM_DTR    0002    /* data terminal ready */
+#define     TARGET_TIOCM_RTS    0004    /* request to send */
+#define     TARGET_TIOCM_ST 0010        /* secondary transmit */
+#define     TARGET_TIOCM_SR 0020        /* secondary receive */
+#define     TARGET_TIOCM_CTS    0040    /* clear to send */
+#define     TARGET_TIOCM_DCD    0100    /* data carrier detect */
+#define     TARGET_TIOCM_RI     0200    /* ring indicate */
+#define     TARGET_TIOCM_DSR    0400    /* data set ready */
+#define     TARGET_TIOCM_CD TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_CAR    TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_RNG    TARGET_TIOCM_RI
+#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) /* bic modem bits */
+#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) /* bis modem bits */
+#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) /* set all modem bits */
+/* start output, like ^Q */
+#define TARGET_TIOCSTART     TARGET_IO('t', 110)
+/* stop output, like ^S */
+#define TARGET_TIOCSTOP  TARGET_IO('t', 111)
+/* pty: set/clear packet mode */
+#define TARGET_TIOCPKT      TARGET_IOW('t', 112, int)
+#define     TARGET_TIOCPKT_DATA     0x00    /* data packet */
+#define     TARGET_TIOCPKT_FLUSHREAD    0x01    /* flush packet */
+#define     TARGET_TIOCPKT_FLUSHWRITE   0x02    /* flush packet */
+#define     TARGET_TIOCPKT_STOP     0x04    /* stop output */
+#define     TARGET_TIOCPKT_START        0x08    /* start output */
+#define     TARGET_TIOCPKT_NOSTOP       0x10    /* no more ^S, ^Q */
+#define     TARGET_TIOCPKT_DOSTOP       0x20    /* now do ^S ^Q */
+#define     TARGET_TIOCPKT_IOCTL        0x40    /* state change of pty
+                               driver */
+#define TARGET_TIOCNOTTY     TARGET_IO('t', 113)    /* void tty
+                               association */
+#define TARGET_TIOCSTI      TARGET_IOW('t', 114, char)  /* simulate
+                            terminal input */
+#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)   /* output queue size */
+                        /* 116-117 compat */
+#define TARGET_TIOCSPGRP    TARGET_IOW('t', 118, int) /* set pgrp of tty */
+#define TARGET_TIOCGPGRP    TARGET_IOR('t', 119, int) /* get pgrp of tty */
+#define TARGET_TIOCCDTR  TARGET_IO('t', 120)        /* clear data terminal
+                               ready */
+#define TARGET_TIOCSDTR  TARGET_IO('t', 121)        /* set data terminal
+                               ready */
+#define TARGET_TIOCCBRK  TARGET_IO('t', 122)        /* clear break bit */
+#define TARGET_TIOCSBRK  TARGET_IO('t', 123)        /* set break bit */
+                        /* 124-127 compat */
+
+#define TARGET_TTYDISC      0       /* termios tty line
+                           discipline */
+#define TARGET_SLIPDISC     4       /* serial IP discipline */
+#define TARGET_PPPDISC      5       /* PPP discipline */
+#define TARGET_NETGRAPHDISC 6       /* Netgraph tty node
+                           discipline */
+#define TARGET_H4DISC       7       /* Netgraph Bluetooth H4
+                           discipline */
+
+#endif /*! _IOCTL_TTYCOM_H_ */
diff --git a/bsd-user/netbsd/os-ioctl-types.h b/bsd-user/netbsd/os-ioctl-types.h
new file mode 100644
index 0000000..e761c20
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-types.h
@@ -0,0 +1,7 @@
+/* XXX should be fixed for NetBSD types and structs */
+STRUCT_SPECIAL(termios)
+
+STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
+
+STRUCT(fiodgname_arg, TYPE_INT, TYPE_PTRVOID)
+
diff --git a/bsd-user/openbsd/os-ioctl-cmds.h b/bsd-user/openbsd/os-ioctl-cmds.h
new file mode 100644
index 0000000..a15f056
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-cmds.h
@@ -0,0 +1,48 @@
+/* XXX should be fixed for OpenBSD ioctl cmds */
+
+/* sys/ttycom.h tty(4) */
+IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCCBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCSDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCCDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR))
+IOCTL(TIOCNOTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCSTOP, IOC_, TYPE_NULL)
+IOCTL(TIOCSTART, IOC_, TYPE_NULL)
+IOCTL(TIOCSCTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCDRAIN, IOC_, TYPE_NULL)
+IOCTL(TIOCEXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCNXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
+
+/* sys/filio.h */
+IOCTL(FIOCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODTYPE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOGETLBA, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODGNAME, IOC_R, MK_PTR(STRUCT_fiodgname_arg))
+IOCTL(FIONWRITE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONSPACE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOSEEKDATA, IOC_RW, MK_PTR(TYPE_ULONG))
+IOCTL(FIOSEEKHOLE, IOC_RW, MK_PTR(TYPE_ULONG))
diff --git a/bsd-user/openbsd/os-ioctl-filio.h b/bsd-user/openbsd/os-ioctl-filio.h
new file mode 100644
index 0000000..e3f7474
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-filio.h
@@ -0,0 +1,29 @@
+#ifndef _IOCTL_FILIO_H_
+#define _IOCTL_FILIO_H_
+
+/* XXX needs to be fixed for OpenBSD dependencies */
+
+/* see sys/filio.h */
+#define TARGET_FIOCLEX      TARGET_IO('f', 1)
+#define TARGET_FIONCLEX     TARGET_IO('f', 2)
+#define TARGET_FIONREAD     TARGET_IOR('f', 127, int)
+#define TARGET_FIONBIO      TARGET_IOW('f', 126, int)
+#define TARGET_FIOASYNC     TARGET_IOW('f', 125, int)
+#define TARGET_FIOSETOWN    TARGET_IOW('f', 124, int)
+#define TARGET_FIOGETOWN    TARGET_IOR('f', 123, int)
+#define TARGET_FIODTYPE     TARGET_IOR('f', 122, int)
+#define TARGET_FIOGETLBA    TARGET_IOR('f', 121, int)
+
+struct target_fiodgname_arg {
+    int32_t     len;
+    abi_ulong   buf;
+};
+
+#define TARGET_FIODGNAME    TARGET_IOW('f', 120,    \
+                struct target_fiodgname_arg)
+#define TARGET_FIONWRITE    TARGET_IOR('f', 119, int)
+#define TARGET_FIONSPACE    TARGET_IOR('f', 118, int)
+#define TARGET_FIOSEEKDATA  TARGET_IOWR('f', 97, off_t)
+#define TARGET_FIOSEEKHOLE  TARGET_IOWR('f', 98, off_t)
+
+#endif /* !_IOCTL_FILIO_H_ */
diff --git a/bsd-user/openbsd/os-ioctl-ioccom.h b/bsd-user/openbsd/os-ioctl-ioccom.h
new file mode 100644
index 0000000..fa1c6b4
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-ioccom.h
@@ -0,0 +1,38 @@
+#ifndef _IOCTL_IOCCOM_H_
+#define _IOCTL_IOCCOM_H_
+
+/* XXX needs to be fixed for OpenBSD dependencies */
+
+/*
+ * Ioctl's have the command encoded in the lower word, and the size of
+ * any in or out parameters in the upper word.  The high 3 bits of the
+ * upper word are used to encode the in/out status of the parameter.
+ */
+/* number of bits for ioctl size */
+#define TARGET_IOCPARM_SHIFT    13
+
+/* parameter length mask */
+#define TARGET_IOCPARM_MASK ((1 << TARGET_IOCPARM_SHIFT) - 1)
+
+#define TARGET_IOCPARM_LEN(x)   (((x) >> 16) & TARGET_IOCPARM_MASK)
+#define TARGET_IOCBASECMD(x)    ((x) & ~(TARGET_IOCPARM_MASK << 16))
+#define TARGET_IOCGROUP(x)  (((x) >> 8) & 0xff)
+
+#define TARGET_IOCPARM_MAX  (1 << TARGET_IOCPARM_SHIFT) /* max size of ioctl */
+#define TARGET_IOC_VOID     0x20000000  /* no parameters */
+#define TARGET_IOC_OUT      0x40000000  /* copy out parameters */
+#define TARGET_IOC_IN       0x80000000  /* copy in parameters */
+#define TARGET_IOC_INOUT    (TARGET_IOC_IN|TARGET_IOC_OUT)
+#define TARGET_IOC_DIRMASK  (TARGET_IOC_VOID|TARGET_IOC_OUT|TARGET_IOC_IN)
+
+#define TARGET_IOC(inout, group, num, len) ((abi_ulong) \
+    ((inout) | (((len) & TARGET_IOCPARM_MASK) << 16) | ((group) << 8) \
+     | (num)))
+#define TARGET_IO(g, n)       TARGET_IOC(IOC_VOID,    (g), (n), 0)
+#define TARGET_IOWINT(g, n)   TARGET_IOC(IOC_VOID,    (g), (n), sizeof(int))
+#define TARGET_IOR(g, n, t)   TARGET_IOC(IOC_OUT, (g), (n), sizeof(t))
+#define TARGET_IOW(g, n, t)   TARGET_IOC(IOC_IN,  (g), (n), sizeof(t))
+/* this should be _IORW, but stdio got there first */
+#define TARGET_IOWR(g, n, t)  TARGET_IOC(IOC_INOUT,   (g), (n), sizeof(t))
+
+#endif /* !_IOCTL_IOCCOM_H_ */
diff --git a/bsd-user/openbsd/os-ioctl-ttycom.h b/bsd-user/openbsd/os-ioctl-ttycom.h
new file mode 100644
index 0000000..745d702
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-ttycom.h
@@ -0,0 +1,240 @@
+#ifndef _IOCTL_TTYCOM_H_
+#define _IOCTL_TTYCOM_H_
+
+/* XXX Needs to be fixed for OpenBSD dependencies */
+
+#include "os-ioctl-ioccom.h"
+
+/* From sys/ttycom.h and sys/_termios.h */
+
+#define TARGET_VEOF     0   /* ICANON */
+#define TARGET_VEOL     1   /* ICANON */
+#define TARGET_VEOL2    2   /* ICANON together with IEXTEN */
+#define TARGET_VERASE   3   /* ICANON */
+#define TARGET_VWERASE  4   /* ICANON together with IEXTEN */
+#define TARGET_VKILL    5   /* ICANON */
+#define TARGET_VREPRINT 6   /* ICANON together with IEXTEN */
+#define TARGET_VERASE2  7   /* ICANON */
+#define TARGET_VINTR    8   /* ISIG */
+#define TARGET_VQUIT    9   /* ISIG */
+#define TARGET_VSUSP    10  /* ISIG */
+#define TARGET_VDSUSP   11  /* ISIG together with IEXTEN */
+#define TARGET_VSTART   12  /* IXON, IXOFF */
+#define TARGET_VSTOP    13  /* IXON, IXOFF */
+#define TARGET_VLNEXT   14  /* IEXTEN */
+#define TARGET_VDISCARD 15  /* IEXTEN */
+#define TARGET_VMIN     16  /* !ICANON */
+#define TARGET_VTIME    17  /* !ICANON */
+#define TARGET_VSTATUS  18  /* ICANON together with IEXTEN */
+/*                      19         spare 2 */
+#define TARGET_NCCS     20
+
+/*
+ * Input flags - software input processing
+ */
+#define TARGET_IGNBRK   0x00000001  /* ignore BREAK condition */
+#define TARGET_BRKINT   0x00000002  /* map BREAK to SIGINTR */
+#define TARGET_IGNPAR   0x00000004  /* ignore (discard) parity errors */
+#define TARGET_PARMRK   0x00000008  /* mark parity and framing errors */
+#define TARGET_INPCK    0x00000010  /* enable checking of parity errors */
+#define TARGET_ISTRIP   0x00000020  /* strip 8th bit off chars */
+#define TARGET_INLCR    0x00000040  /* map NL into CR */
+#define TARGET_IGNCR    0x00000080  /* ignore CR */
+#define TARGET_ICRNL    0x00000100  /* map CR to NL (ala CRMOD) */
+#define TARGET_IXON     0x00000200  /* enable output flow control */
+#define TARGET_IXOFF    0x00000400  /* enable input flow control */
+#define TARGET_IXANY    0x00000800  /* any char will restart after stop */
+#define TARGET_IMAXBEL  0x00002000  /* ring bell on input queue full */
+
+/*
+ * Output flags - software output processing
+ */
+#define TARGET_OPOST    0x00000001  /* enable following output processing */
+#define TARGET_ONLCR    0x00000002  /* map NL to CR-NL (ala CRMOD) */
+#define TARGET_TABDLY   0x00000004  /* tab delay mask */
+#define TARGET_TAB0     0x00000000  /* no tab delay and expansion */
+#define TARGET_TAB3     0x00000004  /* expand tabs to spaces */
+#define TARGET_ONOEOT   0x00000008  /* discard EOT's (^D) on output) */
+#define TARGET_OCRNL    0x00000010  /* map CR to NL on output */
+#define TARGET_ONOCR    0x00000020  /* no CR output at column 0 */
+#define TARGET_ONLRET   0x00000040  /* NL performs CR function */
+
+/*
+ * Control flags - hardware control of terminal
+ */
+#define TARGET_CIGNORE      0x00000001  /* ignore control flags */
+#define TARGET_CSIZE        0x00000300  /* character size mask */
+#define     TARGET_CS5      0x00000000  /* 5 bits (pseudo) */
+#define     TARGET_CS6      0x00000100  /* 6 bits */
+#define     TARGET_CS7      0x00000200  /* 7 bits */
+#define     TARGET_CS8      0x00000300  /* 8 bits */
+#define TARGET_CSTOPB       0x00000400  /* send 2 stop bits */
+#define TARGET_CREAD        0x00000800  /* enable receiver */
+#define TARGET_PARENB       0x00001000  /* parity enable */
+#define TARGET_PARODD       0x00002000  /* odd parity, else even */
+#define TARGET_HUPCL        0x00004000  /* hang up on last close */
+#define TARGET_CLOCAL       0x00008000  /* ignore modem status lines */
+#define TARGET_CCTS_OFLOW   0x00010000  /* CTS flow control of output */
+#define TARGET_CRTSCTS      (TARGET_CCTS_OFLOW | TARGET_CRTS_IFLOW)
+#define TARGET_CRTS_IFLOW   0x00020000  /* RTS flow control of input */
+#define TARGET_CDTR_IFLOW   0x00040000  /* DTR flow control of input */
+#define TARGET_CDSR_OFLOW   0x00080000  /* DSR flow control of output */
+#define TARGET_CCAR_OFLOW   0x00100000  /* DCD flow control of output */
+
+/*
+ * "Local" flags - dumping ground for other state
+ */
+#define TARGET_ECHOKE   0x00000001  /* visual erase for line kill */
+#define TARGET_ECHOE    0x00000002  /* visually erase chars */
+#define TARGET_ECHOK    0x00000004  /* echo NL after line kill */
+#define TARGET_ECHO 0x00000008  /* enable echoing */
+#define TARGET_ECHONL   0x00000010  /* echo NL even if ECHO is off */
+#define TARGET_ECHOPRT  0x00000020  /* visual erase mode for hardcopy */
+#define TARGET_ECHOCTL  0x00000040  /* echo control chars as ^(Char) */
+#define TARGET_ISIG 0x00000080  /* enable signals INTR, QUIT, [D]SUSP */
+#define TARGET_ICANON   0x00000100  /* canonicalize input lines */
+#define TARGET_ALTWERASE 0x00000200 /* use alternate WERASE algorithm */
+#define TARGET_IEXTEN   0x00000400  /* enable DISCARD and LNEXT */
+#define TARGET_EXTPROC  0x00000800  /* external processing */
+#define TARGET_TOSTOP   0x00400000  /* stop background jobs from output */
+#define TARGET_FLUSHO   0x00800000  /* output being flushed (state) */
+#define TARGET_NOKERNINFO 0x02000000    /* no kernel output from VSTATUS */
+#define TARGET_PENDIN   0x20000000  /* XXX retype pending input (state) */
+#define TARGET_NOFLSH   0x80000000  /* don't flush after interrupt */
+
+struct target_termios {
+    uint32_t c_iflag;   /* input flags */
+    uint32_t c_oflag;   /* output flags */
+    uint32_t c_cflag;   /* control flags */
+    uint32_t c_lflag;   /* local flags */
+    uint8_t  c_cc[TARGET_NCCS]; /* control chars */
+    uint32_t c_ispeed;  /* input speed */
+    uint32_t c_ospeed;  /* output speed */
+};
+
+
+struct target_winsize {
+    uint16_t ws_row;    /* rows, in characters */
+    uint16_t ws_col;    /* columns, in characters */
+    uint16_t ws_xpixel; /* horizontal size, pixels */
+    uint16_t ws_ypixel; /* vertical size, pixels */
+};
+
+                        /* 0-2 compat */
+                        /* 3-7 unused */
+                        /* 8-10 compat */
+                        /* 11-12 unused */
+#define TARGET_TIOCEXCL  TARGET_IO('t', 13) /* set exclusive use of tty */
+#define TARGET_TIOCNXCL  TARGET_IO('t', 14) /* reset exclusive use of tty */
+#define TARGET_TIOCGPTN  TARGET_IOR('t', 15, int) /* Get pts number. */
+#define TARGET_TIOCFLUSH TARGET_IOW('t', 16, int) /* flush buffers */
+                    /* 17-18 compat */
+/* get termios struct */
+#define TARGET_TIOCGETA TARGET_IOR('t', 19, struct target_termios)
+/* set termios struct */
+#define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios)
+/* drain output, set */
+#define TARGET_TIOCSETAW    TARGET_IOW('t', 21, struct target_termios)
+/* drn out, fls in, set */
+#define TARGET_TIOCSETAF    TARGET_IOW('t', 22, struct target_termios)
+                        /* 23-25 unused */
+#define TARGET_TIOCGETD TARGET_IOR('t', 26, int) /* get line discipline */
+#define TARGET_TIOCSETD TARGET_IOW('t', 27, int) /* set line discipline */
+#define TARGET_TIOCPTMASTER  TARGET_IO('t', 28) /* pts master validation */
+                    /* 29-85 unused */
+/* get ttywait timeout */
+#define TARGET_TIOCGDRAINWAIT   TARGET_IOR('t', 86, int)
+/* set ttywait timeout */
+#define TARGET_TIOCSDRAINWAIT   TARGET_IOW('t', 87, int)
+                    /* 88 unused */
+                    /* 89-91 conflicts: tun and tap */
+/* enable/get timestamp of last input event */
+#define TARGET_TIOCTIMESTAMP    TARGET_IOR('t', 89, struct target_timeval)
+/* modem: get wait on close */
+#define TARGET_TIOCMGDTRWAIT    TARGET_IOR('t', 90, int)
+/* modem: set wait on close */
+#define TARGET_TIOCMSDTRWAIT    TARGET_IOW('t', 91, int)
+                    /* 92-93 tun and tap */
+                    /* 94-97 conflicts: tun and tap */
+/* wait till output drained */
+#define TARGET_TIOCDRAIN     TARGET_IO('t', 94)
+ /* pty: generate signal */
+#define TARGET_TIOCSIG      TARGET_IOWINT('t', 95)
+/* pty: external processing */
+#define TARGET_TIOCEXT      TARGET_IOW('t', 96, int)
+/* become controlling tty */
+#define TARGET_TIOCSCTTY     TARGET_IO('t', 97)
+/* become virtual console */
+#define TARGET_TIOCCONS TARGET_IOW('t', 98, int)
+/* get session id */
+#define TARGET_TIOCGSID TARGET_IOR('t', 99, int)
+                        /* 100 unused */
+/* simulate ^T status message */
+#define TARGET_TIOCSTAT  TARGET_IO('t', 101)
+ /* pty: set/clr usr cntl mode */
+#define TARGET_TIOCUCNTL    TARGET_IOW('t', 102, int)
+/* usr cntl op "n" */
+#define TARGET_TIOCCMD(n)   TARGET_IO('u', n)
+/* set window size */
+#define TARGET_TIOCSWINSZ   TARGET_IOW('t', 103, struct target_winsize)
+/* get window size */
+#define TARGET_TIOCGWINSZ   TARGET_IOR('t', 104, struct target_winsize)
+                        /* 105 unused */
+/* get all modem bits */
+#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
+#define     TARGET_TIOCM_LE 0001        /* line enable */
+#define     TARGET_TIOCM_DTR    0002    /* data terminal ready */
+#define     TARGET_TIOCM_RTS    0004    /* request to send */
+#define     TARGET_TIOCM_ST 0010        /* secondary transmit */
+#define     TARGET_TIOCM_SR 0020        /* secondary receive */
+#define     TARGET_TIOCM_CTS    0040    /* clear to send */
+#define     TARGET_TIOCM_DCD    0100    /* data carrier detect */
+#define     TARGET_TIOCM_RI     0200    /* ring indicate */
+#define     TARGET_TIOCM_DSR    0400    /* data set ready */
+#define     TARGET_TIOCM_CD TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_CAR    TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_RNG    TARGET_TIOCM_RI
+#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) /* bic modem bits */
+#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) /* bis modem bits */
+#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) /* set all modem bits */
+/* start output, like ^Q */
+#define TARGET_TIOCSTART     TARGET_IO('t', 110)
+/* stop output, like ^S */
+#define TARGET_TIOCSTOP  TARGET_IO('t', 111)
+/* pty: set/clear packet mode */
+#define TARGET_TIOCPKT      TARGET_IOW('t', 112, int)
+#define     TARGET_TIOCPKT_DATA     0x00    /* data packet */
+#define     TARGET_TIOCPKT_FLUSHREAD    0x01    /* flush packet */
+#define     TARGET_TIOCPKT_FLUSHWRITE   0x02    /* flush packet */
+#define     TARGET_TIOCPKT_STOP     0x04    /* stop output */
+#define     TARGET_TIOCPKT_START        0x08    /* start output */
+#define     TARGET_TIOCPKT_NOSTOP       0x10    /* no more ^S, ^Q */
+#define     TARGET_TIOCPKT_DOSTOP       0x20    /* now do ^S ^Q */
+#define     TARGET_TIOCPKT_IOCTL        0x40    /* state change of pty
+                               driver */
+#define TARGET_TIOCNOTTY     TARGET_IO('t', 113)    /* void tty
+                               association */
+#define TARGET_TIOCSTI      TARGET_IOW('t', 114, char)  /* simulate
+                            terminal input */
+#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)   /* output queue size */
+                        /* 116-117 compat */
+#define TARGET_TIOCSPGRP    TARGET_IOW('t', 118, int) /* set pgrp of tty */
+#define TARGET_TIOCGPGRP    TARGET_IOR('t', 119, int) /* get pgrp of tty */
+#define TARGET_TIOCCDTR  TARGET_IO('t', 120)        /* clear data terminal
+                               ready */
+#define TARGET_TIOCSDTR  TARGET_IO('t', 121)        /* set data terminal
+                               ready */
+#define TARGET_TIOCCBRK  TARGET_IO('t', 122)        /* clear break bit */
+#define TARGET_TIOCSBRK  TARGET_IO('t', 123)        /* set break bit */
+                        /* 124-127 compat */
+
+#define TARGET_TTYDISC      0       /* termios tty line
+                           discipline */
+#define TARGET_SLIPDISC     4       /* serial IP discipline */
+#define TARGET_PPPDISC      5       /* PPP discipline */
+#define TARGET_NETGRAPHDISC 6       /* Netgraph tty node
+                           discipline */
+#define TARGET_H4DISC       7       /* Netgraph Bluetooth H4
+                           discipline */
+
+#endif /*! _IOCTL_TTYCOM_H_ */
diff --git a/bsd-user/openbsd/os-ioctl-types.h b/bsd-user/openbsd/os-ioctl-types.h
new file mode 100644
index 0000000..6f8b97b
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-types.h
@@ -0,0 +1,7 @@
+/* XXX should be fixed for OpenBSD types and structs */
+STRUCT_SPECIAL(termios)
+
+STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
+
+STRUCT(fiodgname_arg, TYPE_INT, TYPE_PTRVOID)
+
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 4b2add2..10d0fc4 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -36,6 +36,7 @@ enum BSDType {
 };
 extern enum BSDType bsd_type;
 
+#include "exec/user/thunk.h"
 #include "syscall_defs.h"
 #include "syscall.h"
 #include "target_os_vmparam.h"
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 0a851fe..6cd7dbd 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -35,6 +35,7 @@
 
 /* BSD independent syscall shims */
 #include "bsd-file.h"
+#include "bsd-ioctl.h"
 #include "bsd-mem.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
@@ -81,16 +82,18 @@ int is_error(abi_long ret)
  * 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)
+        int count, int copy)
 {
     struct target_iovec *target_vec;
     abi_ulong base;
     int i;
 
-    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
-    if (!target_vec)
+    target_vec = lock_user(VERIFY_READ, target_addr,
+            count * sizeof(struct target_iovec), 1);
+    if (!target_vec) {
         return -TARGET_EFAULT;
-    for(i = 0;i < count; i++) {
+    }
+    for (i = 0; i < count; i++) {
         base = tswapl(target_vec[i].iov_base);
         vec[i].iov_len = tswapl(target_vec[i].iov_len);
         if (vec[i].iov_len != 0) {
@@ -107,16 +110,17 @@ static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
 }
 
 static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
-                             int count, int copy)
+        int count, int copy)
 {
     struct target_iovec *target_vec;
     abi_ulong base;
     int i;
 
-    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
+    target_vec = lock_user(VERIFY_READ, target_addr,
+            count * sizeof(struct target_iovec), 1);
     if (!target_vec)
         return -TARGET_EFAULT;
-    for(i = 0;i < count; i++) {
+    for (i = 0; i < count; i++) {
         if (target_vec[i].iov_base) {
             base = tswapl(target_vec[i].iov_base);
             unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
@@ -1177,6 +1181,13 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * ioctl(2)
+         */
+    case TARGET_FREEBSD_NR_ioctl: /* ioctl(2) */
+        ret = do_bsd_ioctl(arg1, arg2, arg3);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
@@ -1309,4 +1320,6 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
 
 void syscall_init(void)
 {
+
+    init_bsd_ioctl();
 }
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 16/18] bsd-user: add support for extended attribute and ACL related syscalls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (14 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 15/18] bsd-user: add support for the ioctl system call Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2014-01-27 20:11   ` Peter Maydell
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 17/18] bsd-user: add support for miscellaneous system calls Stacey Son
                   ` (23 subsequent siblings)
  39 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change add support for extended attribute and Access Control List
(ACL) related system calls including extattrctl(), extattr_set_file(2),
extattr_delete_file(2), extattr_set_fd(2), extattr_get_fd(2),
extattr_delete_fd(2), extattr_get_link(2), extattr_set_link(2),
extattr_delete_link(2), extattr_list_fd(2), extattr_list_file(2),
extattr_list_link(2), __acl_aclcheck_fd(), __acl_aclcheck_file(),
__acl_aclcheck_link(), __acl_delete_fd(), __acl_delete_file(),
__acl_delete_link(), __acl_get_fd(), __acl_get_file(), __acl_get_link(),
__acl_get_fd(), __acl_set_file(), and __acl_set_link().

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs        |    2 +-
 bsd-user/freebsd/os-extattr.c |  119 ++++++++
 bsd-user/freebsd/os-extattr.h |  644 +++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h    |    6 +
 bsd-user/netbsd/os-extattr.h  |  247 ++++++++++++++++
 bsd-user/openbsd/os-extattr.h |  247 ++++++++++++++++
 bsd-user/syscall.c            |  104 +++++++
 7 files changed, 1368 insertions(+), 1 deletions(-)
 create mode 100644 bsd-user/freebsd/os-extattr.c
 create mode 100644 bsd-user/freebsd/os-extattr.h
 create mode 100644 bsd-user/netbsd/os-extattr.h
 create mode 100644 bsd-user/openbsd/os-extattr.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 242e6f4..b9eaf2d 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,6 +1,6 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
 	        uaccess.o bsd-ioctl.o bsd-mem.o bsd-proc.o bsd-socket.o \
-			$(HOST_ABI_DIR)/os-proc.o \
+			$(HOST_ABI_DIR)/os-extattr.o $(HOST_ABI_DIR)/os-proc.o \
 			$(HOST_ABI_DIR)/os-socket.o $(HOST_ABI_DIR)/os-stat.o \
 			$(HOST_ABI_DIR)/os-sys.o $(HOST_ABI_DIR)/os-thread.o \
 			$(HOST_ABI_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/freebsd/os-extattr.c b/bsd-user/freebsd/os-extattr.c
new file mode 100644
index 0000000..7a10047
--- /dev/null
+++ b/bsd-user/freebsd/os-extattr.c
@@ -0,0 +1,119 @@
+/*
+ *  FreeBSD extend attributes and ACL conversions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#ifndef _ACL_PRIVATE
+#define _ACL_PRIVATE
+#endif
+#include <sys/acl.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+/*
+ * FreeBSD ACL conversion.
+ */
+abi_long t2h_freebsd_acl(struct acl *host_acl, abi_ulong target_addr)
+{
+    uint32_t i;
+    struct target_freebsd_acl *target_acl;
+
+    if (!lock_user_struct(VERIFY_READ, target_acl, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt);
+    __get_user(host_acl->acl_cnt, &target_acl->acl_cnt);
+
+    for (i = 0; i < host_acl->acl_maxcnt; i++) {
+        __get_user(host_acl->acl_entry[i].ae_tag,
+            &target_acl->acl_entry[i].ae_tag);
+        __get_user(host_acl->acl_entry[i].ae_id,
+            &target_acl->acl_entry[i].ae_id);
+        __get_user(host_acl->acl_entry[i].ae_perm,
+            &target_acl->acl_entry[i].ae_perm);
+        __get_user(host_acl->acl_entry[i].ae_entry_type,
+            &target_acl->acl_entry[i].ae_entry_type);
+        __get_user(host_acl->acl_entry[i].ae_flags,
+            &target_acl->acl_entry[i].ae_flags);
+    }
+
+    unlock_user_struct(target_acl, target_addr, 0);
+    return 0;
+}
+
+abi_long h2t_freebsd_acl(abi_ulong target_addr, struct acl *host_acl)
+{
+    uint32_t i;
+    struct target_freebsd_acl *target_acl;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_acl, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    __put_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt);
+    __put_user(host_acl->acl_cnt, &target_acl->acl_cnt);
+
+    for (i = 0; i < host_acl->acl_maxcnt; i++) {
+        __put_user(host_acl->acl_entry[i].ae_tag,
+            &target_acl->acl_entry[i].ae_tag);
+        __put_user(host_acl->acl_entry[i].ae_id,
+            &target_acl->acl_entry[i].ae_id);
+        __put_user(host_acl->acl_entry[i].ae_perm,
+            &target_acl->acl_entry[i].ae_perm);
+        __get_user(host_acl->acl_entry[i].ae_entry_type,
+            &target_acl->acl_entry[i].ae_entry_type);
+        __get_user(host_acl->acl_entry[i].ae_flags,
+            &target_acl->acl_entry[i].ae_flags);
+    }
+
+    unlock_user_struct(target_acl, target_addr, 1);
+    return 0;
+}
+
+abi_long t2h_freebsd_acl_type(acl_type_t *host_type, abi_long target_type)
+{
+    acl_type_t type = tswap32(target_type);
+
+    switch (type) {
+    case TARGET_FREEBSD_ACL_TYPE_ACCESS_OLD:
+        *host_type = ACL_TYPE_ACCESS_OLD;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_DEFAULT_OLD:
+        *host_type = ACL_TYPE_DEFAULT_OLD;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_ACCESS:
+        *host_type = ACL_TYPE_ACCESS;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_DEFAULT:
+        *host_type = ACL_TYPE_ACCESS;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_NFS4:
+        *host_type = ACL_TYPE_NFS4;
+        break;
+
+    default:
+        return -TARGET_EINVAL;
+    }
+    return 0;
+}
+
diff --git a/bsd-user/freebsd/os-extattr.h b/bsd-user/freebsd/os-extattr.h
new file mode 100644
index 0000000..0cae8b0
--- /dev/null
+++ b/bsd-user/freebsd/os-extattr.h
@@ -0,0 +1,644 @@
+/*
+ *  FreeBSD extended attributes and ACL system call support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/extattr.h>
+#ifndef _ACL_PRIVATE
+#define _ACL_PRIVATE
+#endif
+#include <sys/acl.h>
+
+#include "qemu-os.h"
+
+/* extattrctl() */
+static inline abi_long do_freebsd_extattrctl(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *p, *a, *f;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    f = lock_user_string(arg3);
+    if (f == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg5);
+    if (a == NULL) {
+        unlock_user(f, arg3, 0);
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattrctl(path(p), arg2, f, arg4, a));
+    unlock_user(a, arg5, 0);
+    unlock_user(f, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_set_file(2) */
+static inline abi_long do_freebsd_extattr_set_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    d = lock_user(VERIFY_READ, arg4, arg5, 1);
+    if (d == NULL) {
+        unlock_user(a, arg3, 0);
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_set_file(path(p), arg2, a, d, arg5));
+    unlock_user(d, arg4, arg5);
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_get_file(2) */
+static inline abi_long do_freebsd_extattr_get_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    if (arg4 && arg5 > 0) {
+        d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
+        if (d == NULL) {
+            unlock_user(a, arg3, 0);
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_get_file(path(p), arg2, a, d, arg5));
+        unlock_user(d, arg4, arg5);
+    } else {
+        ret = get_errno(extattr_get_file(path(p), arg2, a, NULL, arg5));
+    }
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_delete_file(2) */
+static inline abi_long do_freebsd_extattr_delete_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *p, *a;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_delete_file(path(p), arg2, a));
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_set_fd(2) */
+static inline abi_long do_freebsd_extattr_set_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *a, *d;
+
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+    d = lock_user(VERIFY_READ, arg4, arg5, 1);
+    if (d == NULL) {
+        unlock_user(a, arg3, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_set_fd(arg1, arg2, a, d, arg5));
+    unlock_user(d, arg4, arg5);
+    unlock_user(a, arg3, 0);
+
+    return ret;
+}
+
+/* extattr_get_fd(2) */
+static inline abi_long do_freebsd_extattr_get_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *a, *d;
+
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+
+    if (arg4 && arg5 > 0) {
+        d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
+        if (d == NULL) {
+            unlock_user(a, arg3, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_get_fd(arg1, arg2, a, d, arg5));
+        unlock_user(d, arg4, arg5);
+    } else {
+        ret = get_errno(extattr_get_fd(arg1, arg2, a, NULL, arg5));
+    }
+    unlock_user(a, arg3, 0);
+
+    return ret;
+}
+
+/* extattr_delete_fd(2) */
+static inline abi_long do_freebsd_extattr_delete_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *a;
+
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_delete_fd(arg1, arg2, a));
+    unlock_user(a, arg3, 0);
+
+    return ret;
+}
+
+/* extattr_get_link(2) */
+static inline abi_long do_freebsd_extattr_get_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void  *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    if (arg4 && arg5 > 0) {
+        d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
+        if (d == NULL) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_get_link(path(p), arg2, a, d, arg5));
+        unlock_user(d, arg4, arg5);
+    } else {
+        ret = get_errno(extattr_get_link(path(p), arg2, a, NULL, arg5));
+    }
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_set_link(2) */
+static inline abi_long do_freebsd_extattr_set_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void  *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    d = lock_user(VERIFY_READ, arg4, arg5, 1);
+    if (d == NULL) {
+        unlock_user(a, arg3, 0);
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_set_link(path(p), arg2, a, d, arg5));
+    unlock_user(d, arg4, arg5);
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_delete_link(2) */
+static inline abi_long do_freebsd_extattr_delete_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *p, *a;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_delete_link(path(p), arg2, a));
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_list_fd(2) */
+static inline abi_long do_freebsd_extattr_list_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3, abi_ulong arg4)
+{
+    abi_long ret;
+    void *d;
+
+    if (arg3 && arg4 > 0) {
+        d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+        if (d == NULL) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_list_fd(arg1, arg2, d, arg4));
+        unlock_user(d, arg3, arg4);
+    } else {
+        ret = get_errno(extattr_list_fd(arg1, arg2, NULL, arg4));
+    }
+    return ret;
+}
+
+/* extattr_list_file(2) */
+static inline abi_long do_freebsd_extattr_list_file(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+    abi_long ret;
+    void *p, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (arg3 && arg4 > 0) {
+        d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+        if (d == NULL) {
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_list_file(path(p), arg2, d, arg4));
+        unlock_user(d, arg3, arg4);
+    } else {
+        ret = get_errno(extattr_list_file(path(p), arg2, NULL, arg4));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_list_link(2) */
+static inline abi_long do_freebsd_extattr_list_link(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+    abi_long ret;
+    void *p, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (arg3 && arg4 > 0) {
+        d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+        if (d == NULL) {
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_list_link(path(p), arg2, d, arg4));
+        unlock_user(d, arg3, arg4);
+    } else {
+        ret = get_errno(extattr_list_link(path(p), arg2, NULL, arg4));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/*
+ *  Access Control Lists
+ */
+
+/* __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_fd(abi_long arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    struct acl host_acl;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_aclcheck_fd(arg1, type, &host_acl));
+    }
+
+    return ret;
+}
+
+/* __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    struct acl host_acl;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_aclcheck_file(path(p) , arg2, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    struct acl host_acl;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_aclcheck_link(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_delete_fd(int filedes, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_fd(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    return get_errno(__acl_delete_fd(arg1, type));
+}
+
+/* int __acl_delete_file(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_file(abi_ulong arg1,
+        abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_delete_file(path(p), type));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_delete_link(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_link(abi_ulong arg1,
+        abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_delete_link(path(p), type));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = get_errno(__acl_get_fd(arg1, type, &host_acl));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_acl(arg3, &host_acl);
+    }
+    return ret;
+}
+
+/* __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_get_file(path(p), type, &host_acl));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_acl(arg3, &host_acl);
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_get_link(path(p), type, &host_acl));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_acl(arg3, &host_acl);
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_set_fd(arg1, type, &host_acl));
+    }
+
+    return ret;
+}
+
+/* int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_set_file(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_set_link(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index b5510dc..7d79e52 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -70,4 +70,10 @@ abi_long h2t_freebsd_rtprio(abi_ulong target_addr, struct rtprio *host_rtp);
 abi_long do_freebsd_thr_new(CPUArchState *env, abi_ulong target_param_addr,
         int32_t param_size);
 
+/* os-extattr.c */
+struct acl;
+abi_long t2h_freebsd_acl(struct acl *host_acl, abi_ulong target_addr);
+abi_long h2t_freebsd_acl(abi_ulong target_addr, struct acl *host_acl);
+abi_long t2h_freebsd_acl_type(acl_type_t *host_type, abi_long target_type);
+
 #endif /* !_QEMU_OS_H_ */
diff --git a/bsd-user/netbsd/os-extattr.h b/bsd-user/netbsd/os-extattr.h
new file mode 100644
index 0000000..c2f42ac
--- /dev/null
+++ b/bsd-user/netbsd/os-extattr.h
@@ -0,0 +1,247 @@
+/*
+ *  NetBSD extended attributes and ACL system call support
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* XXX To support FreeBSD targets the following will need to be added. */
+
+/* extattrctl() */
+static inline abi_long do_freebsd_extattrctl(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattrctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_file(2) */
+static inline abi_long do_freebsd_extattr_set_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_file(2) */
+static inline abi_long do_freebsd_extattr_get_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_file(2) */
+static inline abi_long do_freebsd_extattr_delete_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_fd(2) */
+static inline abi_long do_freebsd_extattr_set_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_fd(2) */
+static inline abi_long do_freebsd_extattr_get_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_fd(2) */
+static inline abi_long do_freebsd_extattr_delete_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_link(2) */
+static inline abi_long do_freebsd_extattr_get_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_link(2) */
+static inline abi_long do_freebsd_extattr_set_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_link(2) */
+static inline abi_long do_freebsd_extattr_delete_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_fd(2) */
+static inline abi_long do_freebsd_extattr_list_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall exattr_list_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_file(2) */
+static inline abi_long do_freebsd_extattr_list_file(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_list_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_link(2) */
+static inline abi_long do_freebsd_extattr_list_link(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_list_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ *  Access Control Lists
+ */
+
+/* __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_fd(abi_long arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_fd(int filedes, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_fd(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_file(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_file(abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_fil()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_link(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_link(abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall _acl_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
diff --git a/bsd-user/openbsd/os-extattr.h b/bsd-user/openbsd/os-extattr.h
new file mode 100644
index 0000000..5c23af3
--- /dev/null
+++ b/bsd-user/openbsd/os-extattr.h
@@ -0,0 +1,247 @@
+/*
+ *  OpenBSD extended attributes and ACL system call support
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* XXX To support FreeBSD targets the following will need to be added. */
+
+/* extattrctl() */
+static inline abi_long do_freebsd_extattrctl(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattrctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_file(2) */
+static inline abi_long do_freebsd_extattr_set_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_file(2) */
+static inline abi_long do_freebsd_extattr_get_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_file(2) */
+static inline abi_long do_freebsd_extattr_delete_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_fd(2) */
+static inline abi_long do_freebsd_extattr_set_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_fd(2) */
+static inline abi_long do_freebsd_extattr_get_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_fd(2) */
+static inline abi_long do_freebsd_extattr_delete_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_link(2) */
+static inline abi_long do_freebsd_extattr_get_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_link(2) */
+static inline abi_long do_freebsd_extattr_set_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_link(2) */
+static inline abi_long do_freebsd_extattr_delete_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_fd(2) */
+static inline abi_long do_freebsd_extattr_list_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall exattr_list_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_file(2) */
+static inline abi_long do_freebsd_extattr_list_file(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_list_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_link(2) */
+static inline abi_long do_freebsd_extattr_list_link(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_list_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ *  Access Control Lists
+ */
+
+/* __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_fd(abi_long arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_fd(int filedes, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_fd(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_file(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_file(abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_fil()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_link(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_link(abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall _acl_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 6cd7dbd..ab17f3f 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -42,6 +42,7 @@
 #include "bsd-socket.h"
 
 /* *BSD dependent syscall shims */
+#include "os-extattr.h"
 #include "os-time.h"
 #include "os-proc.h"
 #include "os-signal.h"
@@ -1204,6 +1205,109 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                 arg5, arg6, arg7, arg8, 0);
         break;
 
+        /*
+         * extended attributes system calls
+         */
+    case TARGET_FREEBSD_NR_extattrctl: /* extattrctl() */
+        ret = do_freebsd_extattrctl(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_set_file: /* extattr_set_file(2) */
+        ret = do_freebsd_extattr_set_file(arg1, arg2, arg3, arg4, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_get_file: /* extattr_get_file(2) */
+        ret = do_freebsd_extattr_get_file(arg1, arg2, arg3, arg4, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_delete_file: /* extattr_delete_file(2) */
+        ret = do_freebsd_extattr_delete_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_set_fd: /* extattr_set_fd(2) */
+        ret = do_freebsd_extattr_set_fd(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_get_fd: /* extattr_get_fd(2) */
+        ret = do_freebsd_extattr_get_fd(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_delete_fd: /* extattr_delete_fd(2) */
+        ret = do_freebsd_extattr_delete_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_get_link: /* extattr_get_link(2) */
+        ret = do_freebsd_extattr_get_link(arg1, arg2, arg3, arg4, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_set_link: /* extattr_set_link(2) */
+        ret = do_freebsd_extattr_set_link(arg1, arg2, arg3, arg4, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_delete_link: /* extattr_delete_link(2) */
+        ret = do_freebsd_extattr_delete_link(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_list_fd: /* extattr_list_fd(2) */
+        ret = do_freebsd_extattr_list_fd(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_list_file: /* extattr_list_file(2) */
+        ret = do_freebsd_extattr_list_file(arg1, arg2, arg3,  arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_list_link: /* extattr_list_link(2) */
+        ret = do_freebsd_extattr_list_link(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_aclcheck_fd: /* __acl_aclcheck_fd() */
+        ret = do_freebsd__acl_aclcheck_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_aclcheck_file: /* __acl_aclcheck_file() */
+        ret = do_freebsd__acl_aclcheck_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_aclcheck_link: /* __acl_aclcheck_link() */
+        ret = do_freebsd__acl_aclcheck_link(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_delete_fd: /* __acl_delete_fd() */
+        ret = do_freebsd__acl_delete_fd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_delete_file: /* __acl_delete_file() */
+        ret = do_freebsd__acl_delete_file(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_delete_link: /* __acl_delete_link() */
+        ret = do_freebsd__acl_delete_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_get_fd: /* __acl_get_fd() */
+        ret =  do_freebsd__acl_get_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_get_file: /* __acl_get_file() */
+        ret = do_freebsd__acl_get_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_get_link: /* __acl_get_link() */
+        ret = do_freebsd__acl_get_link(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_set_fd: /* __acl_get_fd() */
+        ret = do_freebsd__acl_set_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_set_file: /* __acl_set_file() */
+        ret = do_freebsd__acl_set_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_set_link: /* __acl_set_link() */
+        ret = do_freebsd__acl_set_link(arg1, arg2, arg3);
+        break;
+
     default:
         ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
                     arg8));
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 17/18] bsd-user: add support for miscellaneous system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (15 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 16/18] bsd-user: add support for extended attribute and ACL related syscalls Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-list Stacey Son
                   ` (22 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for miscellaneous system calls including
extattr*() (extended attributes), __acl*() (access control lists),
sem*() (system V semaphores), msg*() (system V messages), sched_*()
(scheduler control), cpuset*() (CPU affinity set management),
mod*() and kld*() (kernel module), rctl_*() (resource controls),
__mac_*() (Mandatory Access Control), posix_*() (additional posix support),
and other miscellaneous system calls.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs     |    2 +-
 bsd-user/bsd-misc.c        |  209 +++++++++++++++++++++
 bsd-user/bsd-misc.h        |  339 +++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-misc.h |  442 ++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/netbsd/os-misc.h  |  375 +++++++++++++++++++++++++++++++++++++
 bsd-user/openbsd/os-misc.h |  375 +++++++++++++++++++++++++++++++++++++
 bsd-user/qemu-bsd.h        |   18 ++
 bsd-user/syscall.c         |  229 +++++++++++++++++++++++
 8 files changed, 1988 insertions(+), 1 deletions(-)
 create mode 100644 bsd-user/bsd-misc.c
 create mode 100644 bsd-user/bsd-misc.h
 create mode 100644 bsd-user/freebsd/os-misc.h
 create mode 100644 bsd-user/netbsd/os-misc.h
 create mode 100644 bsd-user/openbsd/os-misc.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index b9eaf2d..e6078ab 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,5 +1,5 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-ioctl.o bsd-mem.o bsd-proc.o bsd-socket.o \
+	        uaccess.o bsd-ioctl.o bsd-mem.o bsd-misc.o bsd-proc.o bsd-socket.o \
 			$(HOST_ABI_DIR)/os-extattr.o $(HOST_ABI_DIR)/os-proc.o \
 			$(HOST_ABI_DIR)/os-socket.o $(HOST_ABI_DIR)/os-stat.o \
 			$(HOST_ABI_DIR)/os-sys.o $(HOST_ABI_DIR)/os-thread.o \
diff --git a/bsd-user/bsd-misc.c b/bsd-user/bsd-misc.c
new file mode 100644
index 0000000..bc85473
--- /dev/null
+++ b/bsd-user/bsd-misc.c
@@ -0,0 +1,209 @@
+/*
+ *  BSD misc system call conversions routines
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/uuid.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+/*
+ * BSD uuidgen(2) struct uuid conversion
+ */
+abi_long host_to_target_uuid(abi_ulong target_addr, struct uuid *host_uuid)
+{
+    struct target_uuid *target_uuid;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_uuid, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_uuid->time_low, &target_uuid->time_low);
+    __put_user(host_uuid->time_mid, &target_uuid->time_mid);
+    __put_user(host_uuid->time_hi_and_version,
+        &target_uuid->time_hi_and_version);
+    host_uuid->clock_seq_hi_and_reserved =
+        target_uuid->clock_seq_hi_and_reserved;
+    host_uuid->clock_seq_low = target_uuid->clock_seq_low;
+    memcpy(host_uuid->node, target_uuid->node, TARGET_UUID_NODE_LEN);
+    unlock_user_struct(target_uuid, target_addr, 1);
+    return 0;
+}
+
+abi_long target_to_host_semarray(int semid, unsigned short **host_array,
+        abi_ulong target_addr)
+{
+    abi_long ret;
+    int nsems, i;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+
+    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 = (unsigned short *)malloc(nsems * sizeof(unsigned short));
+    array = lock_user(VERIFY_READ, target_addr,
+        nsems*sizeof(unsigned short), 1);
+    if (array == NULL) {
+        free(*host_array);
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsems; i++) {
+        (*host_array)[i] = array[i];
+    }
+    unlock_user(array, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+        unsigned short **host_array)
+{
+    abi_long ret;
+    int nsems, i;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1) {
+        free(*host_array);
+        return get_errno(ret);
+    }
+
+    nsems = semid_ds.sem_nsems;
+    array = (unsigned short *)lock_user(VERIFY_WRITE, target_addr,
+        nsems*sizeof(unsigned short), 0);
+    if (array == NULL) {
+        free(*host_array);
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsems; i++) {
+        array[i] = (*host_array)[i];
+    }
+    free(*host_array);
+    unlock_user(array, target_addr, 1);
+    return 0;
+}
+
+abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
+        abi_ulong target_addr)
+{
+    struct target_semid_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->sem_perm), (target_addr +
+                    offsetof(struct target_semid_ds, sem_perm)))) {
+        return -TARGET_EFAULT;
+    }
+    /* sem_base is not used by kernel for IPC_STAT/IPC_SET */
+    /* host_sd->sem_base  = g2h(target_sd->sem_base); */
+    host_sd->sem_nsems = tswap16(target_sd->sem_nsems);
+    host_sd->sem_otime = tswapal(target_sd->sem_otime);
+    host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+abi_long host_to_target_semid_ds(abi_ulong target_addr,
+        struct semid_ds *host_sd)
+{
+    struct target_semid_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 +
+                    offsetof(struct target_semid_ds, sem_perm)),
+                &(host_sd->sem_perm))) {
+        return -TARGET_EFAULT;
+    }
+    /* sem_base is not used by kernel for IPC_STAT/IPC_SET */
+    /* target_sd->sem_base = h2g((void *)host_sd->sem_base); */
+    target_sd->sem_nsems = tswap16(host_sd->sem_nsems);
+    target_sd->sem_otime = tswapal(host_sd->sem_otime);
+    target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 1);
+
+    return 0;
+}
+
+abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
+        abi_ulong target_addr)
+{
+    struct target_msqid_ds *target_md;
+
+    if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    if (target_to_host_ipc_perm(&(host_md->msg_perm), target_addr)) {
+        return -TARGET_EFAULT;
+    }
+
+    /* msg_first and msg_last are not used by IPC_SET/IPC_STAT in kernel. */
+    host_md->msg_first = host_md->msg_last = NULL;
+    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);
+    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);
+    unlock_user_struct(target_md, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_msqid_ds(abi_ulong target_addr,
+        struct msqid_ds *host_md)
+{
+    struct target_msqid_ds *target_md;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    if (host_to_target_ipc_perm(target_addr, &(host_md->msg_perm))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* msg_first and msg_last are not used by IPC_SET/IPC_STAT in kernel. */
+    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);
+    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);
+    unlock_user_struct(target_md, target_addr, 1);
+
+    return 0;
+}
+
diff --git a/bsd-user/bsd-misc.h b/bsd-user/bsd-misc.h
new file mode 100644
index 0000000..0c34089
--- /dev/null
+++ b/bsd-user/bsd-misc.h
@@ -0,0 +1,339 @@
+/*
+ *  miscellaneous BSD system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_MISC_H_
+#define __BSD_MISC_H_
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/uuid.h>
+
+#include "qemu-bsd.h"
+
+/* quotactl(2) */
+static inline abi_long do_bsd_quotactl(abi_ulong path, abi_long cmd,
+        abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall quotactl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* reboot(2) */
+static inline abi_long do_bsd_reboot(abi_long how)
+{
+
+    qemu_log("qemu: Unsupported syscall reboot()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* uuidgen(2) */
+static inline abi_long do_bsd_uuidgen(abi_ulong target_addr, int count)
+{
+    int i;
+    abi_long ret;
+    struct uuid *host_uuid;
+
+    if (count < 1 || count > 2048) {
+        return -TARGET_EINVAL;
+    }
+
+    host_uuid = (struct uuid *)g_malloc(count * sizeof(struct uuid));
+
+    if (host_uuid == NULL) {
+        return -TARGET_ENOMEM;
+    }
+
+    ret = get_errno(uuidgen(host_uuid, count));
+    if (is_error(ret)) {
+        goto out;
+    }
+    for (i = 0; i < count; i++) {
+        ret = host_to_target_uuid(target_addr +
+            (abi_ulong)(sizeof(struct target_uuid) * i), &host_uuid[i]);
+        if (is_error(ret)) {
+            goto out;
+        }
+    }
+
+out:
+    g_free(host_uuid);
+    return ret;
+}
+
+
+/*
+ * System V Semaphores
+ */
+
+/* semget(2) */
+static inline abi_long do_bsd_semget(abi_long key, int nsems,
+        int target_flags)
+{
+
+    return get_errno(semget(key, nsems,
+                target_to_host_bitmask(target_flags, ipc_flags_tbl)));
+}
+
+/* semop(2) */
+static inline abi_long do_bsd_semop(int semid, abi_long ptr, unsigned nsops)
+{
+    struct sembuf sops[nsops];
+    struct target_sembuf *target_sembuf;
+    int i;
+
+    target_sembuf = lock_user(VERIFY_READ, ptr,
+            nsops * sizeof(struct target_sembuf), 1);
+    if (target_sembuf == NULL) {
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsops; i++) {
+        __get_user(sops[i].sem_num, &target_sembuf[i].sem_num);
+        __get_user(sops[i].sem_op, &target_sembuf[i].sem_op);
+        __get_user(sops[i].sem_flg, &target_sembuf[i].sem_flg);
+    }
+    unlock_user(target_sembuf, ptr, 0);
+
+    return semop(semid, sops, nsops);
+}
+
+/* __semctl(2) */
+static inline abi_long do_bsd___semctl(int semid, int semnum, int target_cmd,
+        union target_semun target_su)
+{
+    union semun arg;
+    struct semid_ds dsarg;
+    unsigned short *array = NULL;
+    int host_cmd;
+    abi_long ret = 0;
+    abi_long err;
+    abi_ulong target_addr;
+
+    switch (target_cmd) {
+    case TARGET_GETVAL:
+        host_cmd = GETVAL;
+        break;
+
+    case TARGET_SETVAL:
+        host_cmd = SETVAL;
+        break;
+
+    case TARGET_GETALL:
+        host_cmd = GETALL;
+        break;
+
+    case TARGET_SETALL:
+        host_cmd = SETALL;
+        break;
+
+    case TARGET_IPC_STAT:
+        host_cmd = IPC_STAT;
+        break;
+
+    case TARGET_IPC_SET:
+        host_cmd = IPC_SET;
+        break;
+
+    case TARGET_IPC_RMID:
+        host_cmd = IPC_RMID;
+        break;
+
+    case TARGET_GETPID:
+        host_cmd = GETPID;
+        break;
+
+    case TARGET_GETNCNT:
+        host_cmd = GETNCNT;
+        break;
+
+    case TARGET_GETZCNT:
+        host_cmd = GETZCNT;
+        break;
+
+    default:
+        return -TARGET_EINVAL;
+    }
+
+    switch (host_cmd) {
+    case GETVAL:
+    case SETVAL:
+        arg.val = tswap32(target_su.val);
+        ret = get_errno(semctl(semid, semnum, host_cmd, arg));
+        target_su.val = tswap32(arg.val);
+        break;
+
+    case GETALL:
+    case SETALL:
+        if (get_user_ual(target_addr, (abi_ulong)target_su.array)) {
+            return -TARGET_EFAULT;
+        }
+        err = target_to_host_semarray(semid, &array, target_addr);
+        if (is_error(err)) {
+            return err;
+        }
+        arg.array = array;
+        ret = get_errno(semctl(semid, semnum, host_cmd, arg));
+        err = host_to_target_semarray(semid, target_addr, &array);
+        if (is_error(err)) {
+            return err;
+        }
+        break;
+
+    case IPC_STAT:
+    case IPC_SET:
+        if (get_user_ual(target_addr, (abi_ulong)target_su.buf)) {
+            return -TARGET_EFAULT;
+        }
+        err = target_to_host_semid_ds(&dsarg, target_addr);
+        if (is_error(err)) {
+            return err;
+        }
+        arg.buf = &dsarg;
+        ret = get_errno(semctl(semid, semnum, host_cmd, arg));
+        err = host_to_target_semid_ds(target_addr, &dsarg);
+        if (is_error(err)) {
+            return err;
+        }
+        break;
+
+    case IPC_RMID:
+    case GETPID:
+    case GETNCNT:
+    case GETZCNT:
+        ret = get_errno(semctl(semid, semnum, host_cmd, NULL));
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+/* msgctl(2) */
+static inline abi_long do_bsd_msgctl(int msgid, int target_cmd, abi_long ptr)
+{
+    struct msqid_ds dsarg;
+    abi_long ret = -TARGET_EINVAL;
+    int host_cmd;
+
+    switch (target_cmd) {
+    case TARGET_IPC_STAT:
+        host_cmd = IPC_STAT;
+        break;
+
+    case TARGET_IPC_SET:
+        host_cmd = IPC_SET;
+        break;
+
+    case TARGET_IPC_RMID:
+        host_cmd = IPC_RMID;
+        break;
+
+    default:
+        return -TARGET_EINVAL;
+    }
+
+    switch (host_cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+        if (target_to_host_msqid_ds(&dsarg, ptr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(msgctl(msgid, host_cmd, &dsarg));
+        if (host_to_target_msqid_ds(ptr, &dsarg)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    case IPC_RMID:
+        ret = get_errno(msgctl(msgid, host_cmd, NULL));
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+/* msgsnd(2) */
+static inline abi_long do_bsd_msgsnd(int msqid, abi_long msgp,
+        unsigned int msgsz, int msgflg)
+{
+    struct target_msgbuf *target_mb;
+    struct mymsg *host_mb;
+    abi_long ret;
+
+    if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) {
+        return -TARGET_EFAULT;
+    }
+    host_mb = g_malloc(msgsz+sizeof(long));
+    host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
+    memcpy(host_mb->mtext, target_mb->mtext, msgsz);
+    ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
+    g_free(host_mb);
+    unlock_user_struct(target_mb, msgp, 0);
+
+    return ret;
+}
+
+/* msgrcv(2) */
+static inline abi_long do_bsd_msgrcv(int msqid, abi_long msgp,
+        unsigned int msgsz, abi_long msgtyp, int msgflg)
+{
+    struct target_msgbuf *target_mb = NULL;
+    char *target_mtext;
+    struct mymsg *host_mb;
+    abi_long ret = 0;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) {
+        return -TARGET_EFAULT;
+    }
+    host_mb = g_malloc(msgsz+sizeof(long));
+    ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
+    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 == NULL) {
+            ret = -TARGET_EFAULT;
+            goto end;
+        }
+        memcpy(target_mb->mtext, host_mb->mtext, ret);
+        unlock_user(target_mtext, target_mtext_addr, ret);
+    }
+    target_mb->mtype = tswapal(host_mb->mtype);
+end:
+    if (target_mb != NULL) {
+        unlock_user_struct(target_mb, msgp, 1);
+    }
+    g_free(host_mb);
+    return ret;
+}
+
+/* getdtablesize(2) */
+static inline abi_long do_bsd_getdtablesize(void)
+{
+
+    return get_errno(getdtablesize());
+}
+
+#endif /* ! __BSD_MISC_H_ */
diff --git a/bsd-user/freebsd/os-misc.h b/bsd-user/freebsd/os-misc.h
new file mode 100644
index 0000000..07e60fe
--- /dev/null
+++ b/bsd-user/freebsd/os-misc.h
@@ -0,0 +1,442 @@
+/*
+ *  miscellaneous FreeBSD system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __OS_MISC_H_
+#define __OS_MISC_H_
+
+#include <sys/cpuset.h>
+#include <sched.h>
+
+/* sched_setparam(2) */
+static inline abi_long do_freebsd_sched_setparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+    abi_long ret;
+    struct sched_param host_sp;
+
+    ret = get_user_s32(host_sp.sched_priority, target_sp_addr);
+    if (!is_error(ret)) {
+        ret = get_errno(sched_setparam(pid, &host_sp));
+    }
+    return ret;
+}
+
+/* sched_get_param(2) */
+static inline abi_long do_freebsd_sched_getparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+    abi_long ret;
+    struct sched_param host_sp;
+
+    ret = get_errno(sched_getparam(pid, &host_sp));
+    if (!is_error(ret)) {
+        ret = put_user_s32(host_sp.sched_priority, target_sp_addr);
+    }
+    return ret;
+}
+
+/* sched_setscheduler(2) */
+static inline abi_long do_freebsd_sched_setscheduler(pid_t pid, int policy,
+        abi_ulong target_sp_addr)
+{
+    abi_long ret;
+    struct sched_param host_sp;
+
+    ret = get_user_s32(host_sp.sched_priority, target_sp_addr);
+    if (!is_error(ret)) {
+        ret = get_errno(sched_setscheduler(pid, policy, &host_sp));
+    }
+    return ret;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_getscheduler(pid_t pid)
+{
+
+    return get_errno(sched_getscheduler(pid));
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_rr_get_interval(pid_t pid,
+        abi_ulong target_ts_addr)
+{
+    abi_long ret;
+    struct timespec host_ts;
+
+    ret = get_errno(sched_rr_get_interval(pid, &host_ts));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_timespec(target_ts_addr, &host_ts);
+    }
+    return ret;
+}
+
+/* cpuset(2) */
+static inline abi_long do_freebsd_cpuset(abi_ulong target_cpuid)
+{
+    abi_long ret;
+    cpusetid_t setid;
+
+    ret = get_errno(cpuset(&setid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return put_user_s32(setid, target_cpuid);
+}
+
+#define target_to_host_cpuset_which(hp, t) { \
+    (*hp) = t;                               \
+} while (0)
+
+#define target_to_host_cpuset_level(hp, t) { \
+    (*hp) = t;                               \
+} while (0)
+
+/* cpuset_setid(2) */
+static inline abi_long do_freebsd_cpuset_setid(void *cpu_env, abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    id_t id;    /* 64-bit value */
+    cpusetid_t setid;
+    cpuwhich_t which;
+
+    target_to_host_cpuset_which(&which, arg1);
+#if TARGET_ABI_BITS == 32
+    /* See if we need to align the register pairs */
+    if (regpairs_aligned(cpu_env)) {
+        id = target_offset64(arg3, arg4);
+        setid = arg5;
+    } else {
+        id = target_offset64(arg2, arg3);
+        setid = arg4;
+    }
+#else
+    id = arg2;
+    setid = arg3;
+#endif
+    return get_errno(cpuset_setid(which, id, setid));
+}
+
+/* cpuset_getid(2) */
+static inline abi_long do_freebsd_cpuset_getid(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    id_t id;    /* 64-bit value */
+    cpusetid_t setid;
+    cpuwhich_t which;
+    cpulevel_t level;
+    abi_ulong target_setid;
+
+    target_to_host_cpuset_which(&which, arg1);
+    target_to_host_cpuset_level(&level, arg2);
+#if TARGET_ABI_BITS == 32
+    id = target_offset64(arg3, arg4);
+    target_setid = arg5;
+#else
+    id = arg3;
+    target_setid = arg4;
+#endif
+    ret = get_errno(cpuset_getid(level, which, id, &setid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return put_user_s32(setid, target_setid);
+}
+
+/* cpuset_getaffinity(2) */
+static inline abi_long do_freebsd_cpuset_getaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setaffinity(2) */
+static inline abi_long do_freebsd_cpuset_setaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* modfnext(2) */
+static inline abi_long do_freebsd_modfnext(abi_long modid)
+{
+
+    qemu_log("qemu: Unsupported syscall modfnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* modfind(2) */
+static inline abi_long do_freebsd_modfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall modfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldload(2) */
+static inline abi_long do_freebsd_kldload(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunload(2) */
+static inline abi_long do_freebsd_kldunload(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunloadf(2) */
+static inline abi_long do_freebsd_kldunloadf(abi_long fileid, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunloadf()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfind(2) */
+static inline abi_long do_freebsd_kldfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldnext(2) */
+static inline abi_long do_freebsd_kldnext(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* kldstat(2) */
+static inline abi_long do_freebsd_kldstat(abi_long fileid,
+        abi_ulong target_stat)
+{
+
+    qemu_log("qemu: Unsupported syscall kldstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfirstmod(2) */
+static inline abi_long do_freebsd_kldfirstmod(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfirstmod()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldsym(2) */
+static inline abi_long do_freebsd_kldsym(abi_long fileid, abi_long cmd,
+        abi_ulong target_data)
+{
+
+    qemu_log("qemu: Unsupported syscall kldsym()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Resource limits (undocumented except for rctl(8) and rctl.conf(5) )
+ */
+/* rctl_get_racct() */
+static inline abi_long do_freebsd_rctl_get_racct(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_racct()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_rules() */
+static inline abi_long do_freebsd_rctl_get_rules(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_rules()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_add_rule() */
+static inline abi_long do_freebsd_rctl_add_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_add_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_remove_rule() */
+static inline abi_long do_freebsd_rctl_remove_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_remove_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_limits() */
+static inline abi_long do_freebsd_rctl_get_limits(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_limits()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Kernel environment
+ */
+
+/* kenv(2) */
+static inline abi_long do_freebsd_kenv(abi_long what, abi_ulong target_name,
+        abi_ulong target_value, abi_long len)
+{
+
+    qemu_log("qemu: Unsupported syscall kenv()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ *  Mandatory Access Control
+ */
+
+/* __mac_get_proc */
+static inline abi_long do_freebsd___mac_get_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_proc */
+static inline abi_long do_freebsd___mac_set_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* __mac_get_fd */
+static inline abi_long do_freebsd___mac_get_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_fd */
+static inline abi_long do_freebsd___mac_set_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_file */
+static inline abi_long do_freebsd___mac_get_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_file */
+static inline abi_long do_freebsd___mac_set_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_link */
+static inline abi_long do_freebsd___mac_get_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_link */
+static inline abi_long do_freebsd___mac_set_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* mac_syscall */
+static inline abi_long do_freebsd_mac_syscall(abi_ulong target_policy,
+        abi_long call, abi_ulong target_arg)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_syscall()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ * New posix calls
+ */
+/* posix_fallocate(2) */
+static inline abi_long do_freebsd_posix_fallocate(abi_long fd, abi_ulong offset,
+        abi_ulong len)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fallocate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_openpt(2) */
+static inline abi_long do_freebsd_posix_openpt(abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_openpt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_fadvise(2) */
+static inline abi_long do_freebsd_posix_fadvise(abi_long fd, abi_ulong offset,
+        abi_ulong len, abi_long advise)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fadvise()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+#endif /* ! __OS_MISC_H_ */
diff --git a/bsd-user/netbsd/os-misc.h b/bsd-user/netbsd/os-misc.h
new file mode 100644
index 0000000..8be3662
--- /dev/null
+++ b/bsd-user/netbsd/os-misc.h
@@ -0,0 +1,375 @@
+/*
+ *  miscellaneous NetBSD system call shims
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __OS_MISC_H_
+#define __OS_MISC_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* sched_setparam(2) */
+static inline abi_long do_freebsd_sched_setparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_setparam()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_get_param(2) */
+static inline abi_long do_freebsd_sched_getparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_getparam()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_setscheduler(2) */
+static inline abi_long do_freebsd_sched_setscheduler(pid_t pid, int policy,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_setscheduler()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_getscheduler(pid_t pid)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_getscheduler()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_rr_get_interval(pid_t pid,
+        abi_ulong target_ts_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_rr_get_interval()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset(2) */
+static inline abi_long do_freebsd_cpuset(abi_ulong target_cpuid)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setid(2) */
+static inline abi_long do_freebsd_cpuset_setid(void *cpu_env, abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_getid(2) */
+static inline abi_long do_freebsd_cpuset_getid(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_getaffinity(2) */
+static inline abi_long do_freebsd_cpuset_getaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setaffinity(2) */
+static inline abi_long do_freebsd_cpuset_setaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* modfnext(2) */
+static inline abi_long do_freebsd_modfnext(abi_long modid)
+{
+
+    qemu_log("qemu: Unsupported syscall modfnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* modfind(2) */
+static inline abi_long do_freebsd_modfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall modfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldload(2) */
+static inline abi_long do_freebsd_kldload(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunload(2) */
+static inline abi_long do_freebsd_kldunload(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunloadf(2) */
+static inline abi_long do_freebsd_kldunloadf(abi_long fileid, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunloadf()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfind(2) */
+static inline abi_long do_freebsd_kldfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldnext(2) */
+static inline abi_long do_freebsd_kldnext(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* kldstat(2) */
+static inline abi_long do_freebsd_kldstat(abi_long fileid,
+        abi_ulong target_stat)
+{
+
+    qemu_log("qemu: Unsupported syscall kldstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfirstmod(2) */
+static inline abi_long do_freebsd_kldfirstmod(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfirstmod()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldsym(2) */
+static inline abi_long do_freebsd_kldsym(abi_long fileid, abi_long cmd,
+        abi_ulong target_data)
+{
+
+    qemu_log("qemu: Unsupported syscall kldsym()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Resource limits (undocumented except for rctl(8) and rctl.conf(5) )
+ */
+/* rctl_get_racct() */
+static inline abi_long do_freebsd_rctl_get_racct(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_racct()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_rules() */
+static inline abi_long do_freebsd_rctl_get_rules(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_rules()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_add_rule() */
+static inline abi_long do_freebsd_rctl_add_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_add_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_remove_rule() */
+static inline abi_long do_freebsd_rctl_remove_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_remove_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_limits() */
+static inline abi_long do_freebsd_rctl_get_limits(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_limits()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Kernel environment
+ */
+
+/* kenv(2) */
+static inline abi_long do_freebsd_kenv(abi_long what, abi_ulong target_name,
+        abi_ulong target_value, abi_long len)
+{
+
+    qemu_log("qemu: Unsupported syscall kenv()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ *  Mandatory Access Control
+ */
+
+/* __mac_get_proc */
+static inline abi_long do_freebsd___mac_get_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_proc */
+static inline abi_long do_freebsd___mac_set_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* __mac_get_fd */
+static inline abi_long do_freebsd___mac_get_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_fd */
+static inline abi_long do_freebsd___mac_set_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_file */
+static inline abi_long do_freebsd___mac_get_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_file */
+static inline abi_long do_freebsd___mac_set_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_link */
+static inline abi_long do_freebsd___mac_get_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_link */
+static inline abi_long do_freebsd___mac_set_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* mac_syscall */
+static inline abi_long do_freebsd_mac_syscall(abi_ulong target_policy,
+        abi_long call, abi_ulong target_arg)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_syscall()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ * New posix calls
+ */
+/* posix_fallocate(2) */
+static inline abi_long do_freebsd_posix_fallocate(abi_long fd, abi_ulong offset,
+        abi_ulong len)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fallocate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_openpt(2) */
+static inline abi_long do_freebsd_posix_openpt(abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_openpt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_fadvise(2) */
+static inline abi_long do_freebsd_posix_fadvise(abi_long fd, abi_ulong offset,
+        abi_ulong len, abi_long advise)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fadvise()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OS_MISC_H_ */
diff --git a/bsd-user/openbsd/os-misc.h b/bsd-user/openbsd/os-misc.h
new file mode 100644
index 0000000..5a17ac9
--- /dev/null
+++ b/bsd-user/openbsd/os-misc.h
@@ -0,0 +1,375 @@
+/*
+ *  miscellaneous OpenBSD system call shims
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __OS_MISC_H_
+#define __OS_MISC_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* sched_setparam(2) */
+static inline abi_long do_freebsd_sched_setparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_setparam()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_get_param(2) */
+static inline abi_long do_freebsd_sched_getparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_getparam()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_setscheduler(2) */
+static inline abi_long do_freebsd_sched_setscheduler(pid_t pid, int policy,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_setscheduler()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_getscheduler(pid_t pid)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_getscheduler()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_rr_get_interval(pid_t pid,
+        abi_ulong target_ts_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_rr_get_interval()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset(2) */
+static inline abi_long do_freebsd_cpuset(abi_ulong target_cpuid)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setid(2) */
+static inline abi_long do_freebsd_cpuset_setid(void *cpu_env, abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_getid(2) */
+static inline abi_long do_freebsd_cpuset_getid(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_getaffinity(2) */
+static inline abi_long do_freebsd_cpuset_getaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setaffinity(2) */
+static inline abi_long do_freebsd_cpuset_setaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* modfnext(2) */
+static inline abi_long do_freebsd_modfnext(abi_long modid)
+{
+
+    qemu_log("qemu: Unsupported syscall modfnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* modfind(2) */
+static inline abi_long do_freebsd_modfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall modfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldload(2) */
+static inline abi_long do_freebsd_kldload(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunload(2) */
+static inline abi_long do_freebsd_kldunload(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunloadf(2) */
+static inline abi_long do_freebsd_kldunloadf(abi_long fileid, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunloadf()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfind(2) */
+static inline abi_long do_freebsd_kldfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldnext(2) */
+static inline abi_long do_freebsd_kldnext(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* kldstat(2) */
+static inline abi_long do_freebsd_kldstat(abi_long fileid,
+        abi_ulong target_stat)
+{
+
+    qemu_log("qemu: Unsupported syscall kldstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfirstmod(2) */
+static inline abi_long do_freebsd_kldfirstmod(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfirstmod()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldsym(2) */
+static inline abi_long do_freebsd_kldsym(abi_long fileid, abi_long cmd,
+        abi_ulong target_data)
+{
+
+    qemu_log("qemu: Unsupported syscall kldsym()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Resource limits (undocumented except for rctl(8) and rctl.conf(5) )
+ */
+/* rctl_get_racct() */
+static inline abi_long do_freebsd_rctl_get_racct(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_racct()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_rules() */
+static inline abi_long do_freebsd_rctl_get_rules(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_rules()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_add_rule() */
+static inline abi_long do_freebsd_rctl_add_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_add_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_remove_rule() */
+static inline abi_long do_freebsd_rctl_remove_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_remove_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_limits() */
+static inline abi_long do_freebsd_rctl_get_limits(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_limits()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Kernel environment
+ */
+
+/* kenv(2) */
+static inline abi_long do_freebsd_kenv(abi_long what, abi_ulong target_name,
+        abi_ulong target_value, abi_long len)
+{
+
+    qemu_log("qemu: Unsupported syscall kenv()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ *  Mandatory Access Control
+ */
+
+/* __mac_get_proc */
+static inline abi_long do_freebsd___mac_get_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_proc */
+static inline abi_long do_freebsd___mac_set_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* __mac_get_fd */
+static inline abi_long do_freebsd___mac_get_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_fd */
+static inline abi_long do_freebsd___mac_set_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_file */
+static inline abi_long do_freebsd___mac_get_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_file */
+static inline abi_long do_freebsd___mac_set_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_link */
+static inline abi_long do_freebsd___mac_get_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_link */
+static inline abi_long do_freebsd___mac_set_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* mac_syscall */
+static inline abi_long do_freebsd_mac_syscall(abi_ulong target_policy,
+        abi_long call, abi_ulong target_arg)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_syscall()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ * New posix calls
+ */
+/* posix_fallocate(2) */
+static inline abi_long do_freebsd_posix_fallocate(abi_long fd, abi_ulong offset,
+        abi_ulong len)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fallocate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_openpt(2) */
+static inline abi_long do_freebsd_posix_openpt(abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_openpt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_fadvise(2) */
+static inline abi_long do_freebsd_posix_fadvise(abi_long fd, abi_ulong offset,
+        abi_ulong len, abi_long advise)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fadvise()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OS_MISC_H_ */
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
index 09b99ef..771245d 100644
--- a/bsd-user/qemu-bsd.h
+++ b/bsd-user/qemu-bsd.h
@@ -58,4 +58,22 @@ abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
 abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr,
         socklen_t len);
 
+/* bsd-misc.c */
+abi_long host_to_target_uuid(abi_ulong target_addr, struct uuid *host_uuid);
+
+abi_long target_to_host_semarray(int semid, unsigned short **host_array,
+        abi_ulong target_addr);
+abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+        unsigned short **host_array);
+
+abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
+        abi_ulong target_addr);
+abi_long host_to_target_semid_ds(abi_ulong target_addr,
+        struct semid_ds *host_sd);
+
+abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
+        abi_ulong target_addr);
+abi_long host_to_target_msqid_ds(abi_ulong target_addr,
+        struct msqid_ds *host_md);
+
 #endif /* !_QEMU_BSD_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index ab17f3f..35bf394 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -37,6 +37,7 @@
 #include "bsd-file.h"
 #include "bsd-ioctl.h"
 #include "bsd-mem.h"
+#include "bsd-misc.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
 #include "bsd-socket.h"
@@ -44,6 +45,7 @@
 /* *BSD dependent syscall shims */
 #include "os-extattr.h"
 #include "os-time.h"
+#include "os-misc.h"
 #include "os-proc.h"
 #include "os-signal.h"
 #include "os-socket.h"
@@ -1308,6 +1310,233 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = do_freebsd__acl_set_link(arg1, arg2, arg3);
         break;
 
+        /*
+         * SysV Semaphores
+         */
+    case TARGET_FREEBSD_NR_semget: /* semget(2) */
+        ret = do_bsd_semget(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_semop: /* semop(2) */
+        ret = do_bsd_semop(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___semctl: /* __semctl() undocumented */
+        ret = do_bsd___semctl(arg1, arg2, arg3,
+                (union target_semun)(abi_ulong)arg4);
+        break;
+
+        /*
+         * SysV Messages
+         */
+    case TARGET_FREEBSD_NR_msgctl: /* msgctl(2) */
+        ret = do_bsd_msgctl(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_msgsnd: /* msgsnd(2) */
+        ret = do_bsd_msgsnd(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_msgrcv: /* msgrcv(2) */
+        ret = do_bsd_msgrcv(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+        /*
+         * FreeBSD scheduler control
+         */
+    case TARGET_FREEBSD_NR_sched_setparam: /* sched_setparam(2) */
+        ret = do_freebsd_sched_setparam(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_getparam: /* sched_getparam(2) */
+        ret = do_freebsd_sched_getparam(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_setscheduler: /* sched_setscheduler(2) */
+        ret = do_freebsd_sched_setscheduler(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_getscheduler: /* sched_getscheduler(2) */
+        ret = do_freebsd_sched_getscheduler(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_rr_get_interval: /* sched_rr_get_interval(2) */
+        ret = do_freebsd_sched_rr_get_interval(arg1, arg2);
+        break;
+
+        /*
+         * FreeBSD CPU affinity sets management
+         */
+    case TARGET_FREEBSD_NR_cpuset: /* cpuset(2) */
+        ret = do_freebsd_cpuset(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_setid: /* cpuset_setid(2) */
+        ret = do_freebsd_cpuset_setid(cpu_env, arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_getid: /* cpuset_getid(2) */
+        ret = do_freebsd_cpuset_getid(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_getaffinity: /* cpuset_getaffinity(2) */
+        ret = do_freebsd_cpuset_getaffinity(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_setaffinity: /* cpuset_setaffinity(2) */
+        ret = do_freebsd_cpuset_setaffinity(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+
+        /*
+         * FreeBSD kernel module
+         */
+    case TARGET_FREEBSD_NR_modfnext: /* modfnext(2) */
+        ret = do_freebsd_modfnext(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_modfind: /* modfind(2) */
+        ret = do_freebsd_modfind(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldload: /* kldload(2) */
+        ret = do_freebsd_kldload(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldunload: /* kldunload(2) */
+        ret = do_freebsd_kldunload(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldunloadf: /* kldunloadf(2) */
+        ret = do_freebsd_kldunloadf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kldfind: /* kldfind(2) */
+        ret = do_freebsd_kldfind(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldnext: /* kldnext(2) */
+        ret = do_freebsd_kldnext(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldstat: /* kldstat(2) */
+        ret = do_freebsd_kldstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kldfirstmod: /* kldfirstmod(2) */
+        ret = do_freebsd_kldfirstmod(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldsym: /* kldsym(2) */
+        ret = do_freebsd_kldsym(arg1, arg2, arg3);
+        break;
+
+        /*
+         * FreeBSD resource controls (undocumented except for rctl(8)
+         * and rctl.conf(5) )
+         */
+    case TARGET_FREEBSD_NR_rctl_get_racct: /* rctl_get_racct() */
+        ret = do_freebsd_rctl_get_racct(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_rctl_get_rules: /* rctl_get_rules() */
+        ret = do_freebsd_rctl_get_rules(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_rctl_add_rule: /* rctl_add_rule() */
+        ret = do_freebsd_rctl_add_rule(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_rctl_remove_rule: /* rctl_remove_rule() */
+        ret = do_freebsd_rctl_remove_rule(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_rctl_get_limits: /* rctl_get_limits() */
+        ret = do_freebsd_rctl_get_limits(arg1, arg2, arg3, arg4);
+        break;
+
+        /*
+         * FreeBSD Mandatory Access Control
+         */
+    case TARGET_FREEBSD_NR___mac_get_proc: /* __mac_get_proc() */
+        ret = do_freebsd___mac_get_proc(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_set_proc: /* __mac_set_proc() */
+        ret = do_freebsd___mac_set_proc(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_get_fd: /* __mac_get_fd() */
+        ret = do_freebsd___mac_get_fd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_set_fd: /* __mac_set_fd() */
+        ret = do_freebsd___mac_set_fd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_get_file: /* __mac_get_file() */
+        ret = do_freebsd___mac_get_proc(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_set_file: /* __mac_set_file() */
+        ret = do_freebsd___mac_set_file(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_get_link: /* __mac_get_link() */
+        ret = do_freebsd___mac_get_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_set_link: /* __mac_set_link() */
+        ret = do_freebsd___mac_set_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mac_syscall: /* mac_syscall() */
+        ret = do_freebsd_mac_syscall(arg1, arg2, arg3);
+        break;
+
+        /*
+         * FreeBSD additional posix support
+         */
+    case TARGET_FREEBSD_NR_posix_fallocate: /* posix_fallocate(2) */
+        ret = do_freebsd_posix_fallocate(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_posix_openpt: /* posix_fallocate(2) */
+        ret = do_freebsd_posix_openpt(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_posix_fadvise: /* posix_fadvise(2) */
+        ret = do_freebsd_posix_fadvise(arg1, arg2, arg3, arg4);
+        break;
+
+        /*
+         * Misc
+         */
+    case TARGET_FREEBSD_NR_quotactl: /* quotactl(2) */
+        ret = do_bsd_quotactl(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_reboot: /* reboot(2) */
+        ret = do_bsd_reboot(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_uuidgen: /* uuidgen(2) */
+        ret = do_bsd_uuidgen(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getdtablesize: /* getdtablesize(2) */
+        ret = do_bsd_getdtablesize();
+        break;
+
+    case TARGET_FREEBSD_NR_kenv: /* kenv(2) */
+        ret = do_freebsd_kenv(arg1, arg2, arg2, arg4);
+        break;
+
+
+    case TARGET_FREEBSD_NR_break:
+        ret = do_obreak(arg1);
+        break;
+
     default:
         ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
                     arg8));
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-list
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (16 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 17/18] bsd-user: add support for miscellaneous system calls Stacey Son
@ 2013-10-16 14:37 ` Stacey Son
  2013-10-16 15:22   ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-listt Alex Bennée
  2013-10-16 16:26   ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-list Peter Maydell
  2013-10-16 15:27 ` [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/armsupport Alex Bennée
                   ` (21 subsequent siblings)
  39 siblings, 2 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 14:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds arm-bsd-user, mips-bsd-user, mips64-bsd-user,
mips64el-bsd-user, and mipsel-bsd-user as --target-list options to configure.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 default-configs/arm-bsd-user.mak      |    3 +++
 default-configs/mips-bsd-user.mak     |    1 +
 default-configs/mips64-bsd-user.mak   |    1 +
 default-configs/mips64el-bsd-user.mak |    1 +
 default-configs/mipsel-bsd-user.mak   |    1 +
 5 files changed, 7 insertions(+), 0 deletions(-)
 create mode 100644 default-configs/arm-bsd-user.mak
 create mode 100644 default-configs/mips-bsd-user.mak
 create mode 100644 default-configs/mips64-bsd-user.mak
 create mode 100644 default-configs/mips64el-bsd-user.mak
 create mode 100644 default-configs/mipsel-bsd-user.mak

diff --git a/default-configs/arm-bsd-user.mak b/default-configs/arm-bsd-user.mak
new file mode 100644
index 0000000..46d4aa2
--- /dev/null
+++ b/default-configs/arm-bsd-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for arm-linux-user
+
+CONFIG_GDBSTUB_XML=y
diff --git a/default-configs/mips-bsd-user.mak b/default-configs/mips-bsd-user.mak
new file mode 100644
index 0000000..3fb129a
--- /dev/null
+++ b/default-configs/mips-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips-bsd-user
diff --git a/default-configs/mips64-bsd-user.mak b/default-configs/mips64-bsd-user.mak
new file mode 100644
index 0000000..d4e72a6
--- /dev/null
+++ b/default-configs/mips64-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips64-bsd-user
diff --git a/default-configs/mips64el-bsd-user.mak b/default-configs/mips64el-bsd-user.mak
new file mode 100644
index 0000000..b879228
--- /dev/null
+++ b/default-configs/mips64el-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips64el-bsd-user
diff --git a/default-configs/mipsel-bsd-user.mak b/default-configs/mipsel-bsd-user.mak
new file mode 100644
index 0000000..312b9d5
--- /dev/null
+++ b/default-configs/mipsel-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for mipsel-bsd-user
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-listt
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-list Stacey Son
@ 2013-10-16 15:22   ` Alex Bennée
  2013-10-16 16:12     ` Stacey Son
  2013-10-16 16:31     ` Peter Maydell
  2013-10-16 16:26   ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-list Peter Maydell
  1 sibling, 2 replies; 95+ messages in thread
From: Alex Bennée @ 2013-10-16 15:22 UTC (permalink / raw)
  To: Stacey Son; +Cc: qemu-devel


sson@FreeBSD.org writes:

> This change adds arm-bsd-user, mips-bsd-user, mips64-bsd-user,
> mips64el-bsd-user, and mipsel-bsd-user as --target-list options to configure.
>
> Signed-off-by: Stacey Son <sson@FreeBSD.org>
> ---
<snip>
> new file mode 100644
> index 0000000..46d4aa2
> --- /dev/null
> +++ b/default-configs/arm-bsd-user.mak
> @@ -0,0 +1,3 @@
> +# Default configuration for arm-linux-user
Comment wrong
> +
> +CONFIG_GDBSTUB_XML=y
<snip>

Given how little is typically in the -user .mak fragments I wonder what
the point of them is. Should the build fall-back to a generic .mak
fragment if there is no special config for a given build target?

-- 
Alex Bennée

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/armsupport..
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (17 preceding siblings ...)
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-list Stacey Son
@ 2013-10-16 15:27 ` Alex Bennée
  2013-10-16 15:40   ` Stacey Son
  2013-10-16 16:29 ` [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Peter Maydell
                   ` (20 subsequent siblings)
  39 siblings, 1 reply; 95+ messages in thread
From: Alex Bennée @ 2013-10-16 15:27 UTC (permalink / raw)
  To: Stacey Son; +Cc: qemu-devel


sson@FreeBSD.org writes:

> This patch series adds a significant number of system calls and mips/arm
> support for bsd-user.  In its current state it can emulate most
> FreeBSD mips/mips64 and arm target binaries on a x86 host in a simple
> chroot environment. (see https://wiki.freebsd.org/QemuUserModeHowTo for
> the details.)
>
> Besides adding a lot of shims and other support code this change
> restructures the code significantly to reduce the amount of C
> preprocessor conditionals for the various target and host arch/OS's.
> In general, the target cpu depedent code has been moved into into
> the various arch directories and the host OS dependent code (ie.
> FreeBSD, NetBSD, OpenBSD) has been moved into the OS directories as
> much as possible.
<snip>

What has been the approach to test and verification of the shims? Is
there a BSD equivalent to the LTP or some other POSIX test suite to
exercise all these shim calls?

-- 
Alex Bennée

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 04/18] bsd-user: move target arch and host OSdependent code out of main.cc
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 04/18] bsd-user: move target arch and host OS dependent code out of main.c Stacey Son
@ 2013-10-16 15:38   ` Alex Bennée
  2013-10-16 15:46     ` Stacey Son
  0 siblings, 1 reply; 95+ messages in thread
From: Alex Bennée @ 2013-10-16 15:38 UTC (permalink / raw)
  To: Stacey Son; +Cc: qemu-devel


sson@FreeBSD.org writes:

> This change moves the cpu initialization and main loop code from
> main.c to the OS and arch dependent directories. This eliminates
> many of the #ifdef's in main.c. The cpu initialization and loop
> code is now located in the arch directory along with target arch
> support code.
>
> Signed-off-by: Stacey Son <sson@FreeBSD.org>
<snip>
> +#if 0
> +                TaskState *ts = env->opaque;
> +                uint32_t opcode;
> +                int rc;
> +
> +                /* we handle the FPU emulation here, as Linux */
> +                /* we get the opcode */
> +                /* FIXME - what to do if get_user() fails? */
> +                get_user_u32(opcode, env->regs[15]);
> +
> +                rc = EmulateAll(opcode, &ts->fpa, env);
> +                if (rc == 0) { /* illegal instruction */
> +                    info.si_signo = SIGILL;
> +                    info.si_errno = 0;
> +                    info.si_code = TARGET_ILL_ILLOPN;
> +                    info._sifields._sigfault._addr = env->regs[15];
> +                    queue_signal(env, info.si_signo, &info);
> +
> +                } else if (rc < 0) { /* FP exception */
> +                    int arm_fpe = 0;
> +
> +                    /* translate softfloat flags to FPSR flags */
> +                    if (-rc & float_flag_invalid) {
> +                        arm_fpe |= BIT_IOC;
> +                    }
> +                    if (-rc & float_flag_divbyzero) {
> +                        arm_fpe |= BIT_DZC;
> +                    }
> +                    if (-rc & float_flag_overflow) {
> +                        arm_fpe |= BIT_OFC;
> +                    }
> +                    if (-rc & float_flag_underflow) {
> +                        arm_fpe |= BIT_UFC;
> +                    }
> +                    if (-rc & float_flag_inexact) {
> +                        arm_fpe |= BIT_IXC;
> +                    }
> +
> +                    FPSR fpsr = ts->fpa.fpsr;
> +                    /* printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe); */
> +
> +                    if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
> +                        info.si_signo = SIGFPE;
> +                        info.si_errno = 0;
> +
> +                        /* ordered by priority, least first */
> +                        if (arm_fpe & BIT_IXC) {
> +                            info.si_code = TARGET_FPE_FLTRES;
> +                        }
> +                        if (arm_fpe & BIT_UFC) {
> +                            info.si_code = TARGET_FPE_FLTUND;
> +                        }
> +                        if (arm_fpe & BIT_OFC) {
> +                            info.si_code = TARGET_FPE_FLTOVF;
> +                        }
> +                        if (arm_fpe & BIT_DZC) {
> +                            info.si_code = TARGET_FPE_FLTDIV;
> +                        }
> +                        if (arm_fpe & BIT_IOC) {
> +                            info.si_code = TARGET_FPE_FLTINV;
> +                        }
> +                        info._sifields._sigfault._addr = env->regs[15];
> +                        queue_signal(env, info.si_signo, &info);
> +                    } else {
> +                        env->regs[15] += 4;
> +                    }
> +
> +                    /* accumulate unenabled exceptions */
> +                    if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) {
> +                        fpsr |= BIT_IXC;
> +                    }
> +                    if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) {
> +                        fpsr |= BIT_UFC;
> +                    }
> +                    if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) {
> +                        fpsr |= BIT_OFC;
> +                    }
> +                    if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) {
> +                        fpsr |= BIT_DZC;
> +                    }
> +                    if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) {
> +                        fpsr |= BIT_IOC;
> +                    }
> +                    ts->fpa.fpsr = fpsr;
> +                } else { /* everything OK */
> +                    /* increment PC */
> +                    env->regs[15] += 4;
> +                }
> +            }
> +#endif

I'm fairly sure that should either be deleted or re-instated. We have
SCMs for a reason ;-)

> +            break;
> +        case EXCP_SWI:
> +        case EXCP_BKPT:
> +            {
> +                env->eabi = 1;
> +                /* system call */
> +                if (trapnr == EXCP_BKPT) {
> +                    if (env->thumb) {
> +                        /* FIXME - what to do if get_user() fails? */
> +#ifdef FREEBSD_ARM_OABI
> +                        get_user_u16(insn, env->regs[15]);
> +                        n = insn & 0xff;
> +#else
> +                        n = env->regs[7];
> +#endif
> +                        env->regs[15] += 2;
> +                    } else {
> +                        /* FIXME - what to do if get_user() fails? */
> +#ifdef FREEBSD_ARM_OABI
> +                        get_user_u32(insn, env->regs[15]);
> +                        n = (insn & 0xf) | ((insn >> 4) & 0xff0);
> +#else
> +                        n = env->regs[7];
> +#endif
> +                        env->regs[15] += 4;
> +                    }
> +                } else {
> +                    if (env->thumb) {
> +#ifdef FREEBSD_ARM_OABI
> +                        /* FIXME - what to do if get_user() fails? */
> +                        get_user_u16(insn, env->regs[15] - 2);
> +                        n = insn & 0xff;
> +#else
> +                        n = env->regs[7];
> +#endif
> +                    } else {
> +#ifdef FREEBSD_ARM_OABI
> +                        /* FIXME - what to do if get_user() fails? */
> +                        get_user_u32(insn, env->regs[15] - 4);
> +                        n = insn & 0xffffff;
> +#else
> +                        n = env->regs[7];
> +#endif
> +                    }
> +                }
> +
> +#ifdef DEBUG_ARM
> +        printf("AVANT CALL %d\n", n);
> +#endif

I think debug statements (rather than user visible logging) should
generally be wrapped up in a macro.

> +                if (bsd_type == target_freebsd) {
> +                    int ret;
> +                    abi_ulong params = get_sp_from_cpustate(env);
> +                    int32_t syscall_nr = n;
> +                    int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
> +

Another #if 0, there are several more in the patch.

> +#if 0 /* XXX FIXME */
<snip>
> +static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
> +{
> +    return state->regs[13]; /* sp */
> +}
> +
> +static inline void set_second_rval(CPUARMState *state, abi_ulong retval2)
> +{
> +    state->regs[1] = retval2;
> +}

It's a shame ARM hasn't got some un-ambigious #define's for registers

<snip>

More #if 0's

> +#if 0
> +        case EXCP0B_NOSEG:
> +        case EXCP0C_STACK:
<snip>


-- 
Alex Bennée

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/armsupport..
  2013-10-16 15:27 ` [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/armsupport Alex Bennée
@ 2013-10-16 15:40   ` Stacey Son
  0 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 15:40 UTC (permalink / raw)
  To: Alex Bennée; +Cc: qemu-devel


On Oct 16, 2013, at 10:27 AM, Alex Bennée <alex.bennee@linaro.org> wrote:

> 
> sson@FreeBSD.org writes:
> 
>> This patch series adds a significant number of system calls and mips/arm
>> support for bsd-user.  In its current state it can emulate most
>> FreeBSD mips/mips64 and arm target binaries on a x86 host in a simple
>> chroot environment. (see https://wiki.freebsd.org/QemuUserModeHowTo for
>> the details.)
>> 
>> Besides adding a lot of shims and other support code this change
>> restructures the code significantly to reduce the amount of C
>> preprocessor conditionals for the various target and host arch/OS's.
>> In general, the target cpu depedent code has been moved into into
>> the various arch directories and the host OS dependent code (ie.
>> FreeBSD, NetBSD, OpenBSD) has been moved into the OS directories as
>> much as possible.
> <snip>
> 
> What has been the approach to test and verification of the shims? Is
> there a BSD equivalent to the LTP or some other POSIX test suite to
> exercise all these shim calls?

I did write a lot unit tests which I didn't submit (yet) but my main test was cross building things like perl 5.14 and running its rather large test suite.   I also cross built over 8,000 packages for FreeBSD/MIPS64 using Poudrière and qemu-mips64 (see http://people.freebsd.org/~bapt/pres/modern-package-management.pdf for more information).

Regards,

-stacey.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 04/18] bsd-user: move target arch and host OSdependent code out of main.cc
  2013-10-16 15:38   ` [Qemu-devel] [PATCH 04/18] bsd-user: move target arch and host OSdependent code out of main.cc Alex Bennée
@ 2013-10-16 15:46     ` Stacey Son
  2013-10-16 16:32       ` Peter Maydell
  0 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-10-16 15:46 UTC (permalink / raw)
  To: Alex Bennée; +Cc: qemu-devel


The arm code came from another source as noted in the cover letter.  It could use a lot more work.

-stacey.


On Oct 16, 2013, at 10:38 AM, Alex Bennée <alex.bennee@linaro.org> wrote:

> 
> sson@FreeBSD.org writes:
> 
>> This change moves the cpu initialization and main loop code from
>> main.c to the OS and arch dependent directories. This eliminates
>> many of the #ifdef's in main.c. The cpu initialization and loop
>> code is now located in the arch directory along with target arch
>> support code.
>> 
>> Signed-off-by: Stacey Son <sson@FreeBSD.org>
> <snip>
>> +#if 0
>> +                TaskState *ts = env->opaque;
>> +                uint32_t opcode;
>> +                int rc;
>> +
>> +                /* we handle the FPU emulation here, as Linux */
>> +                /* we get the opcode */
>> +                /* FIXME - what to do if get_user() fails? */
>> +                get_user_u32(opcode, env->regs[15]);
>> +
>> +                rc = EmulateAll(opcode, &ts->fpa, env);
>> +                if (rc == 0) { /* illegal instruction */
>> +                    info.si_signo = SIGILL;
>> +                    info.si_errno = 0;
>> +                    info.si_code = TARGET_ILL_ILLOPN;
>> +                    info._sifields._sigfault._addr = env->regs[15];
>> +                    queue_signal(env, info.si_signo, &info);
>> +
>> +                } else if (rc < 0) { /* FP exception */
>> +                    int arm_fpe = 0;
>> +
>> +                    /* translate softfloat flags to FPSR flags */
>> +                    if (-rc & float_flag_invalid) {
>> +                        arm_fpe |= BIT_IOC;
>> +                    }
>> +                    if (-rc & float_flag_divbyzero) {
>> +                        arm_fpe |= BIT_DZC;
>> +                    }
>> +                    if (-rc & float_flag_overflow) {
>> +                        arm_fpe |= BIT_OFC;
>> +                    }
>> +                    if (-rc & float_flag_underflow) {
>> +                        arm_fpe |= BIT_UFC;
>> +                    }
>> +                    if (-rc & float_flag_inexact) {
>> +                        arm_fpe |= BIT_IXC;
>> +                    }
>> +
>> +                    FPSR fpsr = ts->fpa.fpsr;
>> +                    /* printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe); */
>> +
>> +                    if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
>> +                        info.si_signo = SIGFPE;
>> +                        info.si_errno = 0;
>> +
>> +                        /* ordered by priority, least first */
>> +                        if (arm_fpe & BIT_IXC) {
>> +                            info.si_code = TARGET_FPE_FLTRES;
>> +                        }
>> +                        if (arm_fpe & BIT_UFC) {
>> +                            info.si_code = TARGET_FPE_FLTUND;
>> +                        }
>> +                        if (arm_fpe & BIT_OFC) {
>> +                            info.si_code = TARGET_FPE_FLTOVF;
>> +                        }
>> +                        if (arm_fpe & BIT_DZC) {
>> +                            info.si_code = TARGET_FPE_FLTDIV;
>> +                        }
>> +                        if (arm_fpe & BIT_IOC) {
>> +                            info.si_code = TARGET_FPE_FLTINV;
>> +                        }
>> +                        info._sifields._sigfault._addr = env->regs[15];
>> +                        queue_signal(env, info.si_signo, &info);
>> +                    } else {
>> +                        env->regs[15] += 4;
>> +                    }
>> +
>> +                    /* accumulate unenabled exceptions */
>> +                    if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) {
>> +                        fpsr |= BIT_IXC;
>> +                    }
>> +                    if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) {
>> +                        fpsr |= BIT_UFC;
>> +                    }
>> +                    if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) {
>> +                        fpsr |= BIT_OFC;
>> +                    }
>> +                    if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) {
>> +                        fpsr |= BIT_DZC;
>> +                    }
>> +                    if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) {
>> +                        fpsr |= BIT_IOC;
>> +                    }
>> +                    ts->fpa.fpsr = fpsr;
>> +                } else { /* everything OK */
>> +                    /* increment PC */
>> +                    env->regs[15] += 4;
>> +                }
>> +            }
>> +#endif
> 
> I'm fairly sure that should either be deleted or re-instated. We have
> SCMs for a reason ;-)
> 
>> +            break;
>> +        case EXCP_SWI:
>> +        case EXCP_BKPT:
>> +            {
>> +                env->eabi = 1;
>> +                /* system call */
>> +                if (trapnr == EXCP_BKPT) {
>> +                    if (env->thumb) {
>> +                        /* FIXME - what to do if get_user() fails? */
>> +#ifdef FREEBSD_ARM_OABI
>> +                        get_user_u16(insn, env->regs[15]);
>> +                        n = insn & 0xff;
>> +#else
>> +                        n = env->regs[7];
>> +#endif
>> +                        env->regs[15] += 2;
>> +                    } else {
>> +                        /* FIXME - what to do if get_user() fails? */
>> +#ifdef FREEBSD_ARM_OABI
>> +                        get_user_u32(insn, env->regs[15]);
>> +                        n = (insn & 0xf) | ((insn >> 4) & 0xff0);
>> +#else
>> +                        n = env->regs[7];
>> +#endif
>> +                        env->regs[15] += 4;
>> +                    }
>> +                } else {
>> +                    if (env->thumb) {
>> +#ifdef FREEBSD_ARM_OABI
>> +                        /* FIXME - what to do if get_user() fails? */
>> +                        get_user_u16(insn, env->regs[15] - 2);
>> +                        n = insn & 0xff;
>> +#else
>> +                        n = env->regs[7];
>> +#endif
>> +                    } else {
>> +#ifdef FREEBSD_ARM_OABI
>> +                        /* FIXME - what to do if get_user() fails? */
>> +                        get_user_u32(insn, env->regs[15] - 4);
>> +                        n = insn & 0xffffff;
>> +#else
>> +                        n = env->regs[7];
>> +#endif
>> +                    }
>> +                }
>> +
>> +#ifdef DEBUG_ARM
>> +        printf("AVANT CALL %d\n", n);
>> +#endif
> 
> I think debug statements (rather than user visible logging) should
> generally be wrapped up in a macro.
> 
>> +                if (bsd_type == target_freebsd) {
>> +                    int ret;
>> +                    abi_ulong params = get_sp_from_cpustate(env);
>> +                    int32_t syscall_nr = n;
>> +                    int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
>> +
> 
> Another #if 0, there are several more in the patch.
> 
>> +#if 0 /* XXX FIXME */
> <snip>
>> +static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
>> +{
>> +    return state->regs[13]; /* sp */
>> +}
>> +
>> +static inline void set_second_rval(CPUARMState *state, abi_ulong retval2)
>> +{
>> +    state->regs[1] = retval2;
>> +}
> 
> It's a shame ARM hasn't got some un-ambigious #define's for registers
> 
> <snip>
> 
> More #if 0's
> 
>> +#if 0
>> +        case EXCP0B_NOSEG:
>> +        case EXCP0C_STACK:
> <snip>
> 
> 
> -- 
> Alex Bennée

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-listt
  2013-10-16 15:22   ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-listt Alex Bennée
@ 2013-10-16 16:12     ` Stacey Son
  2013-10-16 16:31     ` Peter Maydell
  1 sibling, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-16 16:12 UTC (permalink / raw)
  To: Alex Bennée; +Cc: qemu-devel


On Oct 16, 2013, at 10:22 AM, Alex Bennée <alex.bennee@linaro.org> wrote:

> 
> sson@FreeBSD.org writes:
> 
>> This change adds arm-bsd-user, mips-bsd-user, mips64-bsd-user,
>> mips64el-bsd-user, and mipsel-bsd-user as --target-list options to configure.
>> 
>> Signed-off-by: Stacey Son <sson@FreeBSD.org>
>> ---
> <snip>
>> new file mode 100644
>> index 0000000..46d4aa2
>> --- /dev/null
>> +++ b/default-configs/arm-bsd-user.mak
>> @@ -0,0 +1,3 @@
>> +# Default configuration for arm-linux-user
> Comment wrong

Yes, indeed.  Now we know the source of this file.  I fixed that in the patch set at http://people.freebsd.org/~sson/qemu/qemu-1.6.1/

<snip>

-stacey.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-list
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-list Stacey Son
  2013-10-16 15:22   ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-listt Alex Bennée
@ 2013-10-16 16:26   ` Peter Maydell
  1 sibling, 0 replies; 95+ messages in thread
From: Peter Maydell @ 2013-10-16 16:26 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers

On 16 October 2013 15:37, Stacey Son <sson@freebsd.org> wrote:
> This change adds arm-bsd-user, mips-bsd-user, mips64-bsd-user,
> mips64el-bsd-user, and mipsel-bsd-user as --target-list options to configure.

> diff --git a/default-configs/arm-bsd-user.mak b/default-configs/arm-bsd-user.mak
> new file mode 100644
> index 0000000..46d4aa2
> --- /dev/null
> +++ b/default-configs/arm-bsd-user.mak
> @@ -0,0 +1,3 @@
> +# Default configuration for arm-linux-user

Comment doesn't match filename...

-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support.
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (18 preceding siblings ...)
  2013-10-16 15:27 ` [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/armsupport Alex Bennée
@ 2013-10-16 16:29 ` Peter Maydell
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                   ` (19 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Peter Maydell @ 2013-10-16 16:29 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers

On 16 October 2013 15:36, Stacey Son <sson@freebsd.org> wrote:
> This patch series adds a significant number of system calls and mips/arm
> support for bsd-user.  In its current state it can emulate most
> FreeBSD mips/mips64 and arm target binaries on a x86 host in a simple
> chroot environment. (see https://wiki.freebsd.org/QemuUserModeHowTo for
> the details.)
>
> Besides adding a lot of shims and other support code this change
> restructures the code significantly to reduce the amount of C
> preprocessor conditionals for the various target and host arch/OS's.
> In general, the target cpu depedent code has been moved into into
> the various arch directories and the host OS dependent code (ie.
> FreeBSD, NetBSD, OpenBSD) has been moved into the OS directories as
> much as possible.

Thanks -- this series definitely looks in much better shape than
the previous one. I've looked at the (fairly minor) changes to
code outside bsd-user/ and I think they're OK.

-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-listt
  2013-10-16 15:22   ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-listt Alex Bennée
  2013-10-16 16:12     ` Stacey Son
@ 2013-10-16 16:31     ` Peter Maydell
  1 sibling, 0 replies; 95+ messages in thread
From: Peter Maydell @ 2013-10-16 16:31 UTC (permalink / raw)
  To: Alex Bennée; +Cc: Stacey Son, QEMU Developers

On 16 October 2013 16:22, Alex Bennée <alex.bennee@linaro.org> wrote:
> Given how little is typically in the -user .mak fragments I wonder what
> the point of them is. Should the build fall-back to a generic .mak
> fragment if there is no special config for a given build target?

At the moment our list of "targets that you can build" is exactly
"list of targets with a .mak file", so in order to have a generic .mak
you'd need to have a list of supported targets somewhere else.
Personally I'm not sure that's worth doing (possibly the "move to
Kconfig" work will obsolete these files anyway.)

-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 04/18] bsd-user: move target arch and host OSdependent code out of main.cc
  2013-10-16 15:46     ` Stacey Son
@ 2013-10-16 16:32       ` Peter Maydell
  2013-10-17 19:07         ` Stacey Son
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Maydell @ 2013-10-16 16:32 UTC (permalink / raw)
  To: Stacey Son; +Cc: Alex Bennée, QEMU Developers

On 16 October 2013 16:46, Stacey Son <sson@freebsd.org> wrote:
> The arm code came from another source as noted in the cover letter.  It could use a lot more work.

Possibly better to leave it out of this initial patch set and submit
it separately
later then?

-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 04/18] bsd-user: move target arch and host OSdependent code out of main.cc
  2013-10-16 16:32       ` Peter Maydell
@ 2013-10-17 19:07         ` Stacey Son
  0 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-10-17 19:07 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Alex Bennée, QEMU Developers


On Oct 16, 2013, at 11:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:

> On 16 October 2013 16:46, Stacey Son <sson@freebsd.org> wrote:
>> The arm code came from another source as noted in the cover letter.  It could use a lot more work.
> 
> Possibly better to leave it out of this initial patch set and submit
> it separately
> later then?

I cleaned up the arm cpu_loop() a bit.  You can view the replacement patch it at:

http://people.freebsd.org/~sson/qemu/qemu-1.6.1/0004-bsd-user-move-target-arch-and-host-OS-dependent-code.patch

Of course, it is still missing support for things like handling undefined instruction (co-proc) exceptions via "EmulateAll()" but I am hoping someone will pick that up.  It is current state, however, it can be used to cross build a good amount of FreeBSD/arm ports.  I am hoping one of the BSD/arm guys will find it useful and start contributing.  :)

-stacey.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 01/18] bsd-user: refresh freebsd system call numbers
  2013-10-16 14:36 ` [Qemu-devel] [PATCH 01/18] bsd-user: refresh freebsd system call numbers Stacey Son
@ 2013-10-24  1:22   ` Ed Maste
  0 siblings, 0 replies; 95+ messages in thread
From: Ed Maste @ 2013-10-24  1:22 UTC (permalink / raw)
  To: qemu-devel

On 16 October 2013 10:36, Stacey Son <sson@freebsd.org> wrote:
> Update FreeBSD system call numbers in freebsd/syscall_nr.h.
>
> Signed-off-by: Stacey Son <sson@FreeBSD.org>

Reviewed-by: Ed Maste <emaste@freebsd.org>

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 00/19] bsd-user: Add system call and mips/arm support.
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (19 preceding siblings ...)
  2013-10-16 16:29 ` [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Peter Maydell
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-26 21:01   ` Ed Maste
                     ` (20 more replies)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 01/19] bsd-user: refresh freebsd system call numbers Stacey Son
                   ` (18 subsequent siblings)
  39 siblings, 21 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

[v2]

- Rebases to 1.7.0-rc0. (Requires, however, Andreas Tobler's patch to
  build: see
  http://lists.nongnu.org/archive/html/qemu-devel/2013-11/msg00000.html)
- Fixes deadlock in the _umtx_op() system call handler.
- Fixes race condition in mmap() system call handler.
- Makes qemu-mips (o32) usable.
- A small code clean up to the ARM cpu_loop().
- Fixes comment in arm-bsd-user.mak to match filename.
- Fixes symbol conflicts with FreeBSD's libcrypto for static link.

[v1]

This patch series adds a significant number of system calls and mips/arm
support for bsd-user.  In its current state it can emulate most
FreeBSD mips/mips64 and arm target binaries on a x86 host in a simple
chroot environment. (see https://wiki.freebsd.org/QemuUserModeHowTo for
the details.)

Besides adding a lot of shims and other support code this change
restructures the code significantly to reduce the amount of C
preprocessor conditionals for the various target and host arch/OS's.
In general, the target cpu depedent code has been moved into into
the various arch directories and the host OS dependent code (ie.
FreeBSD, NetBSD, OpenBSD) has been moved into the OS directories as
much as possible.

I would like to recognize Olivier Houchard for a lot of the arm
dependent code and Juergen Lock, the maintainer of the FreeBSD
Qemu port, for their contributions.

Best Regards,

Stacey D. Son
---

Stacey Son (19):
  bsd-user: refresh freebsd system call numbers
  bsd-user: add HOST_ABI_DIR for the various *BSD dependent code.
  bsd-user: move OS/arch dependent code for strace into separate
    directories
  bsd-user: move target arch and host OS dependent code out of main.c
  bsd-user: move target arch and host OS dependent code out of
    syscall.c
  bsd-user: add support for freebsd time related system calls
  bsd-user: add support for freebsd signal related system calls
  bsd-user: move target arch and host OS dependent code out of
    elfload.c
  bsd-user: add support for freebsd process related system calls
  bsd-user: add support for file system related system calls
  bsd-user: add support for stat, directory, and file control related
    system calls
  bsd-user: add support for memory management related system calls
  bsd-user: add support for socket related system calls
  bsd-user: add support for thread related system calls
  bsd-user: add support for the ioctl system call
  bsd-user: add support for extended attribute and ACL related syscalls
  bsd-user: add support for miscellaneous system calls
  bsd-user: add arm, mips and mips64 options to configure target-list
  bsd-user: fix linking conflicts with FreeBSD libcrypto

 Makefile.target                         |    5 +-
 bsd-user/Makefile.objs                  |    6 +-
 bsd-user/arm/syscall.h                  |   36 +
 bsd-user/arm/target_arch.h              |   10 +
 bsd-user/arm/target_arch_cpu.c          |   27 +
 bsd-user/arm/target_arch_cpu.h          |  375 ++++++
 bsd-user/arm/target_arch_elf.h          |   54 +
 bsd-user/arm/target_arch_signal.h       |  257 +++++
 bsd-user/arm/target_arch_sigtramp.h     |   33 +
 bsd-user/arm/target_arch_sysarch.h      |   78 ++
 bsd-user/arm/target_arch_thread.h       |   67 ++
 bsd-user/arm/target_arch_vmparam.h      |   51 +
 bsd-user/bsd-file.h                     | 1111 ++++++++++++++++++
 bsd-user/bsd-ioctl.c                    |  448 ++++++++
 bsd-user/bsd-ioctl.h                    |   27 +
 bsd-user/bsd-mem.c                      |  122 ++
 bsd-user/bsd-mem.h                      |  393 +++++++
 bsd-user/bsd-misc.c                     |  209 ++++
 bsd-user/bsd-misc.h                     |  339 ++++++
 bsd-user/bsd-proc.c                     |  160 +++
 bsd-user/bsd-proc.h                     |  434 +++++++
 bsd-user/bsd-signal.h                   |  232 ++++
 bsd-user/bsd-socket.c                   |  108 ++
 bsd-user/bsd-socket.h                   |  266 +++++
 bsd-user/bsdload.c                      |  170 ++-
 bsd-user/elfload.c                      |  956 ++++-------------
 bsd-user/errno_defs.h                   |   13 +-
 bsd-user/freebsd/host_os.h              |   46 +
 bsd-user/freebsd/os-extattr.c           |  119 ++
 bsd-user/freebsd/os-extattr.h           |  644 +++++++++++
 bsd-user/freebsd/os-ioctl-cmds.h        |   47 +
 bsd-user/freebsd/os-ioctl-filio.h       |   45 +
 bsd-user/freebsd/os-ioctl-ioccom.h      |   54 +
 bsd-user/freebsd/os-ioctl-ttycom.h      |  257 +++++
 bsd-user/freebsd/os-ioctl-types.h       |    7 +
 bsd-user/freebsd/os-misc.h              |  442 ++++++++
 bsd-user/freebsd/os-proc.c              |  234 ++++
 bsd-user/freebsd/os-proc.h              |  428 +++++++
 bsd-user/freebsd/os-signal.h            |   43 +
 bsd-user/freebsd/os-socket.c            |  149 +++
 bsd-user/freebsd/os-socket.h            |  548 +++++++++
 bsd-user/freebsd/os-stat.c              |  234 ++++
 bsd-user/freebsd/os-stat.h              |  437 +++++++
 bsd-user/freebsd/os-strace.h            |   29 +
 bsd-user/freebsd/os-sys.c               |  268 +++++
 bsd-user/freebsd/os-thread.c            | 1001 ++++++++++++++++
 bsd-user/freebsd/os-thread.h            |  511 +++++++++
 bsd-user/freebsd/os-time.c              |  205 ++++
 bsd-user/freebsd/os-time.h              |  643 +++++++++++
 bsd-user/freebsd/qemu-os.h              |   79 ++
 bsd-user/freebsd/strace.list            |   76 ++-
 bsd-user/freebsd/syscall_nr.h           |  813 ++++++++------
 bsd-user/freebsd/target_os_elf.h        |  145 +++
 bsd-user/freebsd/target_os_siginfo.h    |  110 ++
 bsd-user/freebsd/target_os_signal.h     |   79 ++
 bsd-user/freebsd/target_os_stack.h      |  157 +++
 bsd-user/freebsd/target_os_thread.h     |    6 +
 bsd-user/freebsd/target_os_vmparam.h    |   23 +
 bsd-user/i386/syscall.h                 |   23 +
 bsd-user/i386/target_arch.h             |   13 +
 bsd-user/i386/target_arch_cpu.c         |   79 ++
 bsd-user/i386/target_arch_cpu.h         |  302 +++++
 bsd-user/i386/target_arch_elf.h         |   62 +
 bsd-user/i386/target_arch_signal.h      |   94 ++
 bsd-user/i386/target_arch_sigtramp.h    |   11 +
 bsd-user/i386/target_arch_sysarch.h     |   78 ++
 bsd-user/i386/target_arch_thread.h      |   45 +
 bsd-user/i386/target_arch_vmparam.h     |   28 +
 bsd-user/i386/target_signal.h           |    6 -
 bsd-user/main.c                         |  926 +++------------
 bsd-user/mips/syscall.h                 |   52 +
 bsd-user/mips/target_arch.h             |   10 +
 bsd-user/mips/target_arch_cpu.c         |   27 +
 bsd-user/mips/target_arch_cpu.h         |  257 +++++
 bsd-user/mips/target_arch_elf.h         |   36 +
 bsd-user/mips/target_arch_signal.h      |  237 ++++
 bsd-user/mips/target_arch_sigtramp.h    |   23 +
 bsd-user/mips/target_arch_sysarch.h     |   69 ++
 bsd-user/mips/target_arch_thread.h      |   54 +
 bsd-user/mips/target_arch_vmparam.h     |   50 +
 bsd-user/mips64/syscall.h               |   53 +
 bsd-user/mips64/target_arch.h           |   10 +
 bsd-user/mips64/target_arch_cpu.c       |   27 +
 bsd-user/mips64/target_arch_cpu.h       |  243 ++++
 bsd-user/mips64/target_arch_elf.h       |   36 +
 bsd-user/mips64/target_arch_signal.h    |  236 ++++
 bsd-user/mips64/target_arch_sigtramp.h  |   23 +
 bsd-user/mips64/target_arch_sysarch.h   |   69 ++
 bsd-user/mips64/target_arch_thread.h    |   54 +
 bsd-user/mips64/target_arch_vmparam.h   |   47 +
 bsd-user/mmap.c                         |  473 +++++---
 bsd-user/netbsd/host_os.h               |   31 +
 bsd-user/netbsd/os-extattr.h            |  247 ++++
 bsd-user/netbsd/os-ioctl-cmds.h         |   48 +
 bsd-user/netbsd/os-ioctl-filio.h        |   29 +
 bsd-user/netbsd/os-ioctl-ioccom.h       |   38 +
 bsd-user/netbsd/os-ioctl-ttycom.h       |  240 ++++
 bsd-user/netbsd/os-ioctl-types.h        |    7 +
 bsd-user/netbsd/os-misc.h               |  375 ++++++
 bsd-user/netbsd/os-proc.c               |   11 +
 bsd-user/netbsd/os-proc.h               |  243 ++++
 bsd-user/netbsd/os-socket.c             |    1 +
 bsd-user/netbsd/os-socket.h             |   98 ++
 bsd-user/netbsd/os-stat.c               |    1 +
 bsd-user/netbsd/os-stat.h               |    1 +
 bsd-user/netbsd/os-strace.h             |    1 +
 bsd-user/netbsd/os-sys.c                |   46 +
 bsd-user/netbsd/os-thread.c             |    1 +
 bsd-user/netbsd/os-thread.h             |  133 +++
 bsd-user/netbsd/os-time.c               |    1 +
 bsd-user/netbsd/os-time.h               |  179 +++
 bsd-user/netbsd/qemu-os.h               |    1 +
 bsd-user/netbsd/target_os_elf.h         |  226 ++++
 bsd-user/netbsd/target_os_siginfo.h     |   82 ++
 bsd-user/netbsd/target_os_signal.h      |   70 ++
 bsd-user/netbsd/target_os_stack.h       |   33 +
 bsd-user/netbsd/target_os_thread.h      |    6 +
 bsd-user/openbsd/host_os.h              |   31 +
 bsd-user/openbsd/os-extattr.h           |  247 ++++
 bsd-user/openbsd/os-ioctl-cmds.h        |   48 +
 bsd-user/openbsd/os-ioctl-filio.h       |   29 +
 bsd-user/openbsd/os-ioctl-ioccom.h      |   38 +
 bsd-user/openbsd/os-ioctl-ttycom.h      |  240 ++++
 bsd-user/openbsd/os-ioctl-types.h       |    7 +
 bsd-user/openbsd/os-misc.h              |  375 ++++++
 bsd-user/openbsd/os-proc.c              |   11 +
 bsd-user/openbsd/os-proc.h              |  243 ++++
 bsd-user/openbsd/os-socket.c            |    1 +
 bsd-user/openbsd/os-socket.h            |   98 ++
 bsd-user/openbsd/os-stat.c              |    1 +
 bsd-user/openbsd/os-stat.h              |  176 +++
 bsd-user/openbsd/os-strace.h            |    1 +
 bsd-user/openbsd/os-sys.c               |   46 +
 bsd-user/openbsd/os-thread.c            |    1 +
 bsd-user/openbsd/os-thread.h            |  133 +++
 bsd-user/openbsd/os-time.c              |    1 +
 bsd-user/openbsd/os-time.h              |  179 +++
 bsd-user/openbsd/qemu-os.h              |    1 +
 bsd-user/openbsd/target_os_elf.h        |  226 ++++
 bsd-user/openbsd/target_os_siginfo.h    |   82 ++
 bsd-user/openbsd/target_os_signal.h     |   70 ++
 bsd-user/openbsd/target_os_stack.h      |   33 +
 bsd-user/openbsd/target_os_thread.h     |    6 +
 bsd-user/qemu-bsd.h                     |   79 ++
 bsd-user/qemu.h                         |  202 +++-
 bsd-user/signal.c                       |  907 +++++++++++++++-
 bsd-user/sparc/syscall.h                |   29 +-
 bsd-user/sparc/target_arch.h            |   11 +
 bsd-user/sparc/target_arch_cpu.c        |  113 ++
 bsd-user/sparc/target_arch_cpu.h        |  158 +++
 bsd-user/sparc/target_arch_elf.h        |   30 +
 bsd-user/sparc/target_arch_signal.h     |   77 ++
 bsd-user/sparc/target_arch_sigtramp.h   |   11 +
 bsd-user/sparc/target_arch_sysarch.h    |   52 +
 bsd-user/sparc/target_arch_thread.h     |   39 +
 bsd-user/sparc/target_arch_vmparam.h    |   37 +
 bsd-user/sparc/target_signal.h          |    5 -
 bsd-user/sparc64/syscall.h              |   28 +-
 bsd-user/sparc64/target_arch.h          |   11 +
 bsd-user/sparc64/target_arch_cpu.c      |  118 ++
 bsd-user/sparc64/target_arch_cpu.h      |  191 ++++
 bsd-user/sparc64/target_arch_elf.h      |   34 +
 bsd-user/sparc64/target_arch_signal.h   |   94 ++
 bsd-user/sparc64/target_arch_sigtramp.h |   11 +
 bsd-user/sparc64/target_arch_sysarch.h  |   52 +
 bsd-user/sparc64/target_arch_thread.h   |   55 +
 bsd-user/sparc64/target_arch_vmparam.h  |   37 +
 bsd-user/sparc64/target_signal.h        |    5 -
 bsd-user/strace.c                       |  175 ++-
 bsd-user/syscall.c                      | 1884 ++++++++++++++++++++++++-------
 bsd-user/syscall_defs.h                 |  860 +++++++++++++--
 bsd-user/x86_64/syscall.h               |   26 +-
 bsd-user/x86_64/target_arch.h           |   13 +
 bsd-user/x86_64/target_arch_cpu.c       |   79 ++
 bsd-user/x86_64/target_arch_cpu.h       |  324 ++++++
 bsd-user/x86_64/target_arch_elf.h       |   55 +
 bsd-user/x86_64/target_arch_signal.h    |   94 ++
 bsd-user/x86_64/target_arch_sigtramp.h  |   11 +
 bsd-user/x86_64/target_arch_sysarch.h   |   76 ++
 bsd-user/x86_64/target_arch_thread.h    |   40 +
 bsd-user/x86_64/target_arch_vmparam.h   |   28 +
 bsd-user/x86_64/target_signal.h         |    5 -
 configure                               |   11 +
 default-configs/arm-bsd-user.mak        |    3 +
 default-configs/mips-bsd-user.mak       |    1 +
 default-configs/mips64-bsd-user.mak     |    1 +
 default-configs/mips64el-bsd-user.mak   |    1 +
 default-configs/mipsel-bsd-user.mak     |    1 +
 include/qemu/aes.h                      |    9 +
 include/qemu/tls.h                      |    2 +-
 190 files changed, 25475 insertions(+), 2702 deletions(-)
 create mode 100644 bsd-user/arm/syscall.h
 create mode 100644 bsd-user/arm/target_arch.h
 create mode 100644 bsd-user/arm/target_arch_cpu.c
 create mode 100644 bsd-user/arm/target_arch_cpu.h
 create mode 100644 bsd-user/arm/target_arch_elf.h
 create mode 100644 bsd-user/arm/target_arch_signal.h
 create mode 100644 bsd-user/arm/target_arch_sigtramp.h
 create mode 100644 bsd-user/arm/target_arch_sysarch.h
 create mode 100644 bsd-user/arm/target_arch_thread.h
 create mode 100644 bsd-user/arm/target_arch_vmparam.h
 create mode 100644 bsd-user/bsd-file.h
 create mode 100644 bsd-user/bsd-ioctl.c
 create mode 100644 bsd-user/bsd-ioctl.h
 create mode 100644 bsd-user/bsd-mem.c
 create mode 100644 bsd-user/bsd-mem.h
 create mode 100644 bsd-user/bsd-misc.c
 create mode 100644 bsd-user/bsd-misc.h
 create mode 100644 bsd-user/bsd-proc.c
 create mode 100644 bsd-user/bsd-proc.h
 create mode 100644 bsd-user/bsd-signal.h
 create mode 100644 bsd-user/bsd-socket.c
 create mode 100644 bsd-user/bsd-socket.h
 create mode 100644 bsd-user/freebsd/host_os.h
 create mode 100644 bsd-user/freebsd/os-extattr.c
 create mode 100644 bsd-user/freebsd/os-extattr.h
 create mode 100644 bsd-user/freebsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/freebsd/os-ioctl-filio.h
 create mode 100644 bsd-user/freebsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/freebsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/freebsd/os-ioctl-types.h
 create mode 100644 bsd-user/freebsd/os-misc.h
 create mode 100644 bsd-user/freebsd/os-proc.c
 create mode 100644 bsd-user/freebsd/os-proc.h
 create mode 100644 bsd-user/freebsd/os-signal.h
 create mode 100644 bsd-user/freebsd/os-socket.c
 create mode 100644 bsd-user/freebsd/os-socket.h
 create mode 100644 bsd-user/freebsd/os-stat.c
 create mode 100644 bsd-user/freebsd/os-stat.h
 create mode 100644 bsd-user/freebsd/os-strace.h
 create mode 100644 bsd-user/freebsd/os-sys.c
 create mode 100644 bsd-user/freebsd/os-thread.c
 create mode 100644 bsd-user/freebsd/os-thread.h
 create mode 100644 bsd-user/freebsd/os-time.c
 create mode 100644 bsd-user/freebsd/os-time.h
 create mode 100644 bsd-user/freebsd/qemu-os.h
 create mode 100644 bsd-user/freebsd/target_os_elf.h
 create mode 100644 bsd-user/freebsd/target_os_siginfo.h
 create mode 100644 bsd-user/freebsd/target_os_signal.h
 create mode 100644 bsd-user/freebsd/target_os_stack.h
 create mode 100644 bsd-user/freebsd/target_os_thread.h
 create mode 100644 bsd-user/freebsd/target_os_vmparam.h
 create mode 100644 bsd-user/i386/target_arch.h
 create mode 100644 bsd-user/i386/target_arch_cpu.c
 create mode 100644 bsd-user/i386/target_arch_cpu.h
 create mode 100644 bsd-user/i386/target_arch_elf.h
 create mode 100644 bsd-user/i386/target_arch_signal.h
 create mode 100644 bsd-user/i386/target_arch_sigtramp.h
 create mode 100644 bsd-user/i386/target_arch_sysarch.h
 create mode 100644 bsd-user/i386/target_arch_thread.h
 create mode 100644 bsd-user/i386/target_arch_vmparam.h
 create mode 100644 bsd-user/mips/syscall.h
 create mode 100644 bsd-user/mips/target_arch.h
 create mode 100644 bsd-user/mips/target_arch_cpu.c
 create mode 100644 bsd-user/mips/target_arch_cpu.h
 create mode 100644 bsd-user/mips/target_arch_elf.h
 create mode 100644 bsd-user/mips/target_arch_signal.h
 create mode 100644 bsd-user/mips/target_arch_sigtramp.h
 create mode 100644 bsd-user/mips/target_arch_sysarch.h
 create mode 100644 bsd-user/mips/target_arch_thread.h
 create mode 100644 bsd-user/mips/target_arch_vmparam.h
 create mode 100644 bsd-user/mips64/syscall.h
 create mode 100644 bsd-user/mips64/target_arch.h
 create mode 100644 bsd-user/mips64/target_arch_cpu.c
 create mode 100644 bsd-user/mips64/target_arch_cpu.h
 create mode 100644 bsd-user/mips64/target_arch_elf.h
 create mode 100644 bsd-user/mips64/target_arch_signal.h
 create mode 100644 bsd-user/mips64/target_arch_sigtramp.h
 create mode 100644 bsd-user/mips64/target_arch_sysarch.h
 create mode 100644 bsd-user/mips64/target_arch_thread.h
 create mode 100644 bsd-user/mips64/target_arch_vmparam.h
 create mode 100644 bsd-user/netbsd/host_os.h
 create mode 100644 bsd-user/netbsd/os-extattr.h
 create mode 100644 bsd-user/netbsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/netbsd/os-ioctl-filio.h
 create mode 100644 bsd-user/netbsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/netbsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/netbsd/os-ioctl-types.h
 create mode 100644 bsd-user/netbsd/os-misc.h
 create mode 100644 bsd-user/netbsd/os-proc.c
 create mode 100644 bsd-user/netbsd/os-proc.h
 create mode 100644 bsd-user/netbsd/os-socket.c
 create mode 100644 bsd-user/netbsd/os-socket.h
 create mode 100644 bsd-user/netbsd/os-stat.c
 create mode 100644 bsd-user/netbsd/os-stat.h
 create mode 100644 bsd-user/netbsd/os-strace.h
 create mode 100644 bsd-user/netbsd/os-sys.c
 create mode 100644 bsd-user/netbsd/os-thread.c
 create mode 100644 bsd-user/netbsd/os-thread.h
 create mode 100644 bsd-user/netbsd/os-time.c
 create mode 100644 bsd-user/netbsd/os-time.h
 create mode 100644 bsd-user/netbsd/qemu-os.h
 create mode 100644 bsd-user/netbsd/target_os_elf.h
 create mode 100644 bsd-user/netbsd/target_os_siginfo.h
 create mode 100644 bsd-user/netbsd/target_os_signal.h
 create mode 100644 bsd-user/netbsd/target_os_stack.h
 create mode 100644 bsd-user/netbsd/target_os_thread.h
 create mode 100644 bsd-user/openbsd/host_os.h
 create mode 100644 bsd-user/openbsd/os-extattr.h
 create mode 100644 bsd-user/openbsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/openbsd/os-ioctl-filio.h
 create mode 100644 bsd-user/openbsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/openbsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/openbsd/os-ioctl-types.h
 create mode 100644 bsd-user/openbsd/os-misc.h
 create mode 100644 bsd-user/openbsd/os-proc.c
 create mode 100644 bsd-user/openbsd/os-proc.h
 create mode 100644 bsd-user/openbsd/os-socket.c
 create mode 100644 bsd-user/openbsd/os-socket.h
 create mode 100644 bsd-user/openbsd/os-stat.c
 create mode 100644 bsd-user/openbsd/os-stat.h
 create mode 100644 bsd-user/openbsd/os-strace.h
 create mode 100644 bsd-user/openbsd/os-sys.c
 create mode 100644 bsd-user/openbsd/os-thread.c
 create mode 100644 bsd-user/openbsd/os-thread.h
 create mode 100644 bsd-user/openbsd/os-time.c
 create mode 100644 bsd-user/openbsd/os-time.h
 create mode 100644 bsd-user/openbsd/qemu-os.h
 create mode 100644 bsd-user/openbsd/target_os_elf.h
 create mode 100644 bsd-user/openbsd/target_os_siginfo.h
 create mode 100644 bsd-user/openbsd/target_os_signal.h
 create mode 100644 bsd-user/openbsd/target_os_stack.h
 create mode 100644 bsd-user/openbsd/target_os_thread.h
 create mode 100644 bsd-user/qemu-bsd.h
 create mode 100644 bsd-user/sparc/target_arch.h
 create mode 100644 bsd-user/sparc/target_arch_cpu.c
 create mode 100644 bsd-user/sparc/target_arch_cpu.h
 create mode 100644 bsd-user/sparc/target_arch_elf.h
 create mode 100644 bsd-user/sparc/target_arch_signal.h
 create mode 100644 bsd-user/sparc/target_arch_sigtramp.h
 create mode 100644 bsd-user/sparc/target_arch_sysarch.h
 create mode 100644 bsd-user/sparc/target_arch_thread.h
 create mode 100644 bsd-user/sparc/target_arch_vmparam.h
 create mode 100644 bsd-user/sparc64/target_arch.h
 create mode 100644 bsd-user/sparc64/target_arch_cpu.c
 create mode 100644 bsd-user/sparc64/target_arch_cpu.h
 create mode 100644 bsd-user/sparc64/target_arch_elf.h
 create mode 100644 bsd-user/sparc64/target_arch_signal.h
 create mode 100644 bsd-user/sparc64/target_arch_sigtramp.h
 create mode 100644 bsd-user/sparc64/target_arch_sysarch.h
 create mode 100644 bsd-user/sparc64/target_arch_thread.h
 create mode 100644 bsd-user/sparc64/target_arch_vmparam.h
 create mode 100644 bsd-user/x86_64/target_arch.h
 create mode 100644 bsd-user/x86_64/target_arch_cpu.c
 create mode 100644 bsd-user/x86_64/target_arch_cpu.h
 create mode 100644 bsd-user/x86_64/target_arch_elf.h
 create mode 100644 bsd-user/x86_64/target_arch_signal.h
 create mode 100644 bsd-user/x86_64/target_arch_sigtramp.h
 create mode 100644 bsd-user/x86_64/target_arch_sysarch.h
 create mode 100644 bsd-user/x86_64/target_arch_thread.h
 create mode 100644 bsd-user/x86_64/target_arch_vmparam.h
 create mode 100644 default-configs/arm-bsd-user.mak
 create mode 100644 default-configs/mips-bsd-user.mak
 create mode 100644 default-configs/mips64-bsd-user.mak
 create mode 100644 default-configs/mips64el-bsd-user.mak
 create mode 100644 default-configs/mipsel-bsd-user.mak

-- 
1.7.8

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 01/19] bsd-user: refresh freebsd system call numbers
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (20 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 02/19] bsd-user: add HOST_ABI_DIR for the various *BSD dependent code Stacey Son
                   ` (17 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

Update FreeBSD system call numbers in freebsd/syscall_nr.h.

Reviewed-by: Ed Maste <emaste@freebsd.org>
Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/freebsd/syscall_nr.h |  813 ++++++++++++++++++++++-------------------
 1 files changed, 445 insertions(+), 368 deletions(-)

diff --git a/bsd-user/freebsd/syscall_nr.h b/bsd-user/freebsd/syscall_nr.h
index 36336ab..d849024 100644
--- a/bsd-user/freebsd/syscall_nr.h
+++ b/bsd-user/freebsd/syscall_nr.h
@@ -1,373 +1,450 @@
 /*
  * System call numbers.
  *
- * $FreeBSD: src/sys/sys/syscall.h,v 1.224 2008/08/24 21:23:08 rwatson Exp $
- * created from FreeBSD: head/sys/kern/syscalls.master 182123 2008-08-24 21:20:35Z rwatson
+ * created from FreeBSD: releng/9.1/sys/kern/syscalls.master 229723
+ * 2012-01-06 19:29:16Z jhb
  */
 
-#define TARGET_FREEBSD_NR_syscall     0
-#define TARGET_FREEBSD_NR_exit        1
-#define TARGET_FREEBSD_NR_fork        2
-#define TARGET_FREEBSD_NR_read        3
-#define TARGET_FREEBSD_NR_write       4
-#define TARGET_FREEBSD_NR_open        5
-#define TARGET_FREEBSD_NR_close       6
-#define TARGET_FREEBSD_NR_wait4       7
-#define TARGET_FREEBSD_NR_link        9
-#define TARGET_FREEBSD_NR_unlink      10
-#define TARGET_FREEBSD_NR_chdir       12
-#define TARGET_FREEBSD_NR_fchdir      13
-#define TARGET_FREEBSD_NR_mknod       14
-#define TARGET_FREEBSD_NR_chmod       15
-#define TARGET_FREEBSD_NR_chown       16
-#define TARGET_FREEBSD_NR_break       17
-#define TARGET_FREEBSD_NR_freebsd4_getfsstat  18
-#define TARGET_FREEBSD_NR_getpid      20
-#define TARGET_FREEBSD_NR_mount       21
-#define TARGET_FREEBSD_NR_unmount     22
-#define TARGET_FREEBSD_NR_setuid      23
-#define TARGET_FREEBSD_NR_getuid      24
-#define TARGET_FREEBSD_NR_geteuid     25
-#define TARGET_FREEBSD_NR_ptrace      26
-#define TARGET_FREEBSD_NR_recvmsg     27
-#define TARGET_FREEBSD_NR_sendmsg     28
-#define TARGET_FREEBSD_NR_recvfrom    29
-#define TARGET_FREEBSD_NR_accept      30
-#define TARGET_FREEBSD_NR_getpeername 31
-#define TARGET_FREEBSD_NR_getsockname 32
-#define TARGET_FREEBSD_NR_access      33
-#define TARGET_FREEBSD_NR_chflags     34
-#define TARGET_FREEBSD_NR_fchflags    35
-#define TARGET_FREEBSD_NR_sync        36
-#define TARGET_FREEBSD_NR_kill        37
-#define TARGET_FREEBSD_NR_getppid     39
-#define TARGET_FREEBSD_NR_dup 41
-#define TARGET_FREEBSD_NR_pipe        42
-#define TARGET_FREEBSD_NR_getegid     43
-#define TARGET_FREEBSD_NR_profil      44
-#define TARGET_FREEBSD_NR_ktrace      45
-#define TARGET_FREEBSD_NR_getgid      47
-#define TARGET_FREEBSD_NR_getlogin    49
-#define TARGET_FREEBSD_NR_setlogin    50
-#define TARGET_FREEBSD_NR_acct        51
-#define TARGET_FREEBSD_NR_sigaltstack 53
-#define TARGET_FREEBSD_NR_ioctl       54
-#define TARGET_FREEBSD_NR_reboot      55
-#define TARGET_FREEBSD_NR_revoke      56
-#define TARGET_FREEBSD_NR_symlink     57
-#define TARGET_FREEBSD_NR_readlink    58
-#define TARGET_FREEBSD_NR_execve      59
-#define TARGET_FREEBSD_NR_umask       60
-#define TARGET_FREEBSD_NR_chroot      61
-#define TARGET_FREEBSD_NR_msync       65
-#define TARGET_FREEBSD_NR_vfork       66
-#define TARGET_FREEBSD_NR_sbrk        69
-#define TARGET_FREEBSD_NR_sstk        70
-#define TARGET_FREEBSD_NR_vadvise     72
-#define TARGET_FREEBSD_NR_munmap      73
-#define TARGET_FREEBSD_NR_mprotect    74
-#define TARGET_FREEBSD_NR_madvise     75
-#define TARGET_FREEBSD_NR_mincore     78
-#define TARGET_FREEBSD_NR_getgroups   79
-#define TARGET_FREEBSD_NR_setgroups   80
-#define TARGET_FREEBSD_NR_getpgrp     81
-#define TARGET_FREEBSD_NR_setpgid     82
-#define TARGET_FREEBSD_NR_setitimer   83
-#define TARGET_FREEBSD_NR_swapon      85
-#define TARGET_FREEBSD_NR_getitimer   86
-#define TARGET_FREEBSD_NR_getdtablesize       89
-#define TARGET_FREEBSD_NR_dup2        90
-#define TARGET_FREEBSD_NR_fcntl       92
-#define TARGET_FREEBSD_NR_select      93
-#define TARGET_FREEBSD_NR_fsync       95
-#define TARGET_FREEBSD_NR_setpriority 96
-#define TARGET_FREEBSD_NR_socket      97
-#define TARGET_FREEBSD_NR_connect     98
-#define TARGET_FREEBSD_NR_getpriority 100
-#define TARGET_FREEBSD_NR_bind        104
-#define TARGET_FREEBSD_NR_setsockopt  105
-#define TARGET_FREEBSD_NR_listen      106
-#define TARGET_FREEBSD_NR_gettimeofday        116
-#define TARGET_FREEBSD_NR_getrusage   117
-#define TARGET_FREEBSD_NR_getsockopt  118
-#define TARGET_FREEBSD_NR_readv       120
-#define TARGET_FREEBSD_NR_writev      121
-#define TARGET_FREEBSD_NR_settimeofday        122
-#define TARGET_FREEBSD_NR_fchown      123
-#define TARGET_FREEBSD_NR_fchmod      124
-#define TARGET_FREEBSD_NR_setreuid    126
-#define TARGET_FREEBSD_NR_setregid    127
-#define TARGET_FREEBSD_NR_rename      128
-#define TARGET_FREEBSD_NR_flock       131
-#define TARGET_FREEBSD_NR_mkfifo      132
-#define TARGET_FREEBSD_NR_sendto      133
-#define TARGET_FREEBSD_NR_shutdown    134
-#define TARGET_FREEBSD_NR_socketpair  135
-#define TARGET_FREEBSD_NR_mkdir       136
-#define TARGET_FREEBSD_NR_rmdir       137
-#define TARGET_FREEBSD_NR_utimes      138
-#define TARGET_FREEBSD_NR_adjtime     140
-#define TARGET_FREEBSD_NR_setsid      147
-#define TARGET_FREEBSD_NR_quotactl    148
-#define TARGET_FREEBSD_NR_nlm_syscall 154
-#define TARGET_FREEBSD_NR_nfssvc      155
-#define TARGET_FREEBSD_NR_freebsd4_statfs     157
-#define TARGET_FREEBSD_NR_freebsd4_fstatfs    158
-#define TARGET_FREEBSD_NR_lgetfh      160
-#define TARGET_FREEBSD_NR_getfh       161
-#define TARGET_FREEBSD_NR_getdomainname       162
-#define TARGET_FREEBSD_NR_setdomainname       163
-#define TARGET_FREEBSD_NR_uname       164
-#define TARGET_FREEBSD_NR_sysarch     165
-#define TARGET_FREEBSD_NR_rtprio      166
-#define TARGET_FREEBSD_NR_semsys      169
-#define TARGET_FREEBSD_NR_msgsys      170
-#define TARGET_FREEBSD_NR_shmsys      171
-#define TARGET_FREEBSD_NR_freebsd6_pread      173
-#define TARGET_FREEBSD_NR_freebsd6_pwrite     174
-#define TARGET_FREEBSD_NR_setfib      175
-#define TARGET_FREEBSD_NR_ntp_adjtime 176
-#define TARGET_FREEBSD_NR_setgid      181
-#define TARGET_FREEBSD_NR_setegid     182
-#define TARGET_FREEBSD_NR_seteuid     183
-#define TARGET_FREEBSD_NR_stat        188
-#define TARGET_FREEBSD_NR_fstat       189
-#define TARGET_FREEBSD_NR_lstat       190
-#define TARGET_FREEBSD_NR_pathconf    191
-#define TARGET_FREEBSD_NR_fpathconf   192
-#define TARGET_FREEBSD_NR_getrlimit   194
-#define TARGET_FREEBSD_NR_setrlimit   195
-#define TARGET_FREEBSD_NR_getdirentries       196
-#define TARGET_FREEBSD_NR_freebsd6_mmap       197
-#define TARGET_FREEBSD_NR___syscall   198
-#define TARGET_FREEBSD_NR_freebsd6_lseek      199
-#define TARGET_FREEBSD_NR_freebsd6_truncate   200
-#define TARGET_FREEBSD_NR_freebsd6_ftruncate  201
-#define TARGET_FREEBSD_NR___sysctl    202
-#define TARGET_FREEBSD_NR_mlock       203
-#define TARGET_FREEBSD_NR_munlock     204
-#define TARGET_FREEBSD_NR_undelete    205
-#define TARGET_FREEBSD_NR_futimes     206
-#define TARGET_FREEBSD_NR_getpgid     207
-#define TARGET_FREEBSD_NR_poll        209
-#define TARGET_FREEBSD_NR___semctl    220
-#define TARGET_FREEBSD_NR_semget      221
-#define TARGET_FREEBSD_NR_semop       222
-#define TARGET_FREEBSD_NR_msgctl      224
-#define TARGET_FREEBSD_NR_msgget      225
-#define TARGET_FREEBSD_NR_msgsnd      226
-#define TARGET_FREEBSD_NR_msgrcv      227
-#define TARGET_FREEBSD_NR_shmat       228
-#define TARGET_FREEBSD_NR_shmctl      229
-#define TARGET_FREEBSD_NR_shmdt       230
-#define TARGET_FREEBSD_NR_shmget      231
-#define TARGET_FREEBSD_NR_clock_gettime       232
-#define TARGET_FREEBSD_NR_clock_settime       233
-#define TARGET_FREEBSD_NR_clock_getres        234
-#define TARGET_FREEBSD_NR_ktimer_create       235
-#define TARGET_FREEBSD_NR_ktimer_delete       236
-#define TARGET_FREEBSD_NR_ktimer_settime      237
-#define TARGET_FREEBSD_NR_ktimer_gettime      238
-#define TARGET_FREEBSD_NR_ktimer_getoverrun   239
-#define TARGET_FREEBSD_NR_nanosleep   240
-#define TARGET_FREEBSD_NR_ntp_gettime 248
-#define TARGET_FREEBSD_NR_minherit    250
-#define TARGET_FREEBSD_NR_rfork       251
-#define TARGET_FREEBSD_NR_openbsd_poll        252
-#define TARGET_FREEBSD_NR_issetugid   253
-#define TARGET_FREEBSD_NR_lchown      254
-#define TARGET_FREEBSD_NR_aio_read    255
-#define TARGET_FREEBSD_NR_aio_write   256
-#define TARGET_FREEBSD_NR_lio_listio  257
-#define TARGET_FREEBSD_NR_getdents    272
-#define TARGET_FREEBSD_NR_lchmod      274
-#define TARGET_FREEBSD_NR_netbsd_lchown       275
-#define TARGET_FREEBSD_NR_lutimes     276
-#define TARGET_FREEBSD_NR_netbsd_msync        277
-#define TARGET_FREEBSD_NR_nstat       278
-#define TARGET_FREEBSD_NR_nfstat      279
-#define TARGET_FREEBSD_NR_nlstat      280
-#define TARGET_FREEBSD_NR_preadv      289
-#define TARGET_FREEBSD_NR_pwritev     290
-#define TARGET_FREEBSD_NR_freebsd4_fhstatfs   297
-#define TARGET_FREEBSD_NR_fhopen      298
-#define TARGET_FREEBSD_NR_fhstat      299
-#define TARGET_FREEBSD_NR_modnext     300
-#define TARGET_FREEBSD_NR_modstat     301
-#define TARGET_FREEBSD_NR_modfnext    302
-#define TARGET_FREEBSD_NR_modfind     303
-#define TARGET_FREEBSD_NR_kldload     304
-#define TARGET_FREEBSD_NR_kldunload   305
-#define TARGET_FREEBSD_NR_kldfind     306
-#define TARGET_FREEBSD_NR_kldnext     307
-#define TARGET_FREEBSD_NR_kldstat     308
-#define TARGET_FREEBSD_NR_kldfirstmod 309
-#define TARGET_FREEBSD_NR_getsid      310
-#define TARGET_FREEBSD_NR_setresuid   311
-#define TARGET_FREEBSD_NR_setresgid   312
-#define TARGET_FREEBSD_NR_aio_return  314
-#define TARGET_FREEBSD_NR_aio_suspend 315
-#define TARGET_FREEBSD_NR_aio_cancel  316
-#define TARGET_FREEBSD_NR_aio_error   317
-#define TARGET_FREEBSD_NR_oaio_read   318
-#define TARGET_FREEBSD_NR_oaio_write  319
-#define TARGET_FREEBSD_NR_olio_listio 320
-#define TARGET_FREEBSD_NR_yield       321
-#define TARGET_FREEBSD_NR_mlockall    324
-#define TARGET_FREEBSD_NR_munlockall  325
-#define TARGET_FREEBSD_NR___getcwd    326
-#define TARGET_FREEBSD_NR_sched_setparam      327
-#define TARGET_FREEBSD_NR_sched_getparam      328
-#define TARGET_FREEBSD_NR_sched_setscheduler  329
-#define TARGET_FREEBSD_NR_sched_getscheduler  330
-#define TARGET_FREEBSD_NR_sched_yield 331
-#define TARGET_FREEBSD_NR_sched_get_priority_max      332
-#define TARGET_FREEBSD_NR_sched_get_priority_min      333
-#define TARGET_FREEBSD_NR_sched_rr_get_interval       334
-#define TARGET_FREEBSD_NR_utrace      335
-#define TARGET_FREEBSD_NR_freebsd4_sendfile   336
-#define TARGET_FREEBSD_NR_kldsym      337
-#define TARGET_FREEBSD_NR_jail        338
-#define TARGET_FREEBSD_NR_sigprocmask 340
-#define TARGET_FREEBSD_NR_sigsuspend  341
-#define TARGET_FREEBSD_NR_freebsd4_sigaction  342
-#define TARGET_FREEBSD_NR_sigpending  343
-#define TARGET_FREEBSD_NR_freebsd4_sigreturn  344
-#define TARGET_FREEBSD_NR_sigtimedwait        345
-#define TARGET_FREEBSD_NR_sigwaitinfo 346
-#define TARGET_FREEBSD_NR___acl_get_file      347
-#define TARGET_FREEBSD_NR___acl_set_file      348
-#define TARGET_FREEBSD_NR___acl_get_fd        349
-#define TARGET_FREEBSD_NR___acl_set_fd        350
-#define TARGET_FREEBSD_NR___acl_delete_file   351
-#define TARGET_FREEBSD_NR___acl_delete_fd     352
-#define TARGET_FREEBSD_NR___acl_aclcheck_file 353
-#define TARGET_FREEBSD_NR___acl_aclcheck_fd   354
-#define TARGET_FREEBSD_NR_extattrctl  355
-#define TARGET_FREEBSD_NR_extattr_set_file    356
-#define TARGET_FREEBSD_NR_extattr_get_file    357
-#define TARGET_FREEBSD_NR_extattr_delete_file 358
-#define TARGET_FREEBSD_NR_aio_waitcomplete    359
-#define TARGET_FREEBSD_NR_getresuid   360
-#define TARGET_FREEBSD_NR_getresgid   361
-#define TARGET_FREEBSD_NR_kqueue      362
-#define TARGET_FREEBSD_NR_kevent      363
-#define TARGET_FREEBSD_NR_extattr_set_fd      371
-#define TARGET_FREEBSD_NR_extattr_get_fd      372
-#define TARGET_FREEBSD_NR_extattr_delete_fd   373
-#define TARGET_FREEBSD_NR___setugid   374
-#define TARGET_FREEBSD_NR_nfsclnt     375
-#define TARGET_FREEBSD_NR_eaccess     376
-#define TARGET_FREEBSD_NR_nmount      378
-#define TARGET_FREEBSD_NR___mac_get_proc      384
-#define TARGET_FREEBSD_NR___mac_set_proc      385
-#define TARGET_FREEBSD_NR___mac_get_fd        386
-#define TARGET_FREEBSD_NR___mac_get_file      387
-#define TARGET_FREEBSD_NR___mac_set_fd        388
-#define TARGET_FREEBSD_NR___mac_set_file      389
-#define TARGET_FREEBSD_NR_kenv        390
-#define TARGET_FREEBSD_NR_lchflags    391
-#define TARGET_FREEBSD_NR_uuidgen     392
-#define TARGET_FREEBSD_NR_sendfile    393
-#define TARGET_FREEBSD_NR_mac_syscall 394
-#define TARGET_FREEBSD_NR_getfsstat   395
-#define TARGET_FREEBSD_NR_statfs      396
-#define TARGET_FREEBSD_NR_fstatfs     397
-#define TARGET_FREEBSD_NR_fhstatfs    398
-#define TARGET_FREEBSD_NR_ksem_close  400
-#define TARGET_FREEBSD_NR_ksem_post   401
-#define TARGET_FREEBSD_NR_ksem_wait   402
-#define TARGET_FREEBSD_NR_ksem_trywait        403
-#define TARGET_FREEBSD_NR_ksem_init   404
-#define TARGET_FREEBSD_NR_ksem_open   405
-#define TARGET_FREEBSD_NR_ksem_unlink 406
-#define TARGET_FREEBSD_NR_ksem_getvalue       407
-#define TARGET_FREEBSD_NR_ksem_destroy        408
-#define TARGET_FREEBSD_NR___mac_get_pid       409
-#define TARGET_FREEBSD_NR___mac_get_link      410
-#define TARGET_FREEBSD_NR___mac_set_link      411
-#define TARGET_FREEBSD_NR_extattr_set_link    412
-#define TARGET_FREEBSD_NR_extattr_get_link    413
-#define TARGET_FREEBSD_NR_extattr_delete_link 414
-#define TARGET_FREEBSD_NR___mac_execve        415
-#define TARGET_FREEBSD_NR_sigaction   416
-#define TARGET_FREEBSD_NR_sigreturn   417
-#define TARGET_FREEBSD_NR_getcontext  421
-#define TARGET_FREEBSD_NR_setcontext  422
-#define TARGET_FREEBSD_NR_swapcontext 423
-#define TARGET_FREEBSD_NR_swapoff     424
-#define TARGET_FREEBSD_NR___acl_get_link      425
-#define TARGET_FREEBSD_NR___acl_set_link      426
-#define TARGET_FREEBSD_NR___acl_delete_link   427
-#define TARGET_FREEBSD_NR___acl_aclcheck_link 428
-#define TARGET_FREEBSD_NR_sigwait     429
-#define TARGET_FREEBSD_NR_thr_create  430
-#define TARGET_FREEBSD_NR_thr_exit    431
-#define TARGET_FREEBSD_NR_thr_self    432
-#define TARGET_FREEBSD_NR_thr_kill    433
-#define TARGET_FREEBSD_NR__umtx_lock  434
-#define TARGET_FREEBSD_NR__umtx_unlock        435
-#define TARGET_FREEBSD_NR_jail_attach 436
-#define TARGET_FREEBSD_NR_extattr_list_fd     437
-#define TARGET_FREEBSD_NR_extattr_list_file   438
-#define TARGET_FREEBSD_NR_extattr_list_link   439
-#define TARGET_FREEBSD_NR_ksem_timedwait      441
-#define TARGET_FREEBSD_NR_thr_suspend 442
-#define TARGET_FREEBSD_NR_thr_wake    443
-#define TARGET_FREEBSD_NR_kldunloadf  444
-#define TARGET_FREEBSD_NR_audit       445
-#define TARGET_FREEBSD_NR_auditon     446
-#define TARGET_FREEBSD_NR_getauid     447
-#define TARGET_FREEBSD_NR_setauid     448
-#define TARGET_FREEBSD_NR_getaudit    449
-#define TARGET_FREEBSD_NR_setaudit    450
-#define TARGET_FREEBSD_NR_getaudit_addr       451
-#define TARGET_FREEBSD_NR_setaudit_addr       452
-#define TARGET_FREEBSD_NR_auditctl    453
-#define TARGET_FREEBSD_NR__umtx_op    454
-#define TARGET_FREEBSD_NR_thr_new     455
-#define TARGET_FREEBSD_NR_sigqueue    456
-#define TARGET_FREEBSD_NR_kmq_open    457
-#define TARGET_FREEBSD_NR_kmq_setattr 458
-#define TARGET_FREEBSD_NR_kmq_timedreceive    459
-#define TARGET_FREEBSD_NR_kmq_timedsend       460
-#define TARGET_FREEBSD_NR_kmq_notify  461
-#define TARGET_FREEBSD_NR_kmq_unlink  462
-#define TARGET_FREEBSD_NR_abort2      463
-#define TARGET_FREEBSD_NR_thr_set_name        464
-#define TARGET_FREEBSD_NR_aio_fsync   465
-#define TARGET_FREEBSD_NR_rtprio_thread       466
-#define TARGET_FREEBSD_NR_sctp_peeloff        471
-#define TARGET_FREEBSD_NR_sctp_generic_sendmsg        472
-#define TARGET_FREEBSD_NR_sctp_generic_sendmsg_iov    473
-#define TARGET_FREEBSD_NR_sctp_generic_recvmsg        474
-#define TARGET_FREEBSD_NR_pread       475
-#define TARGET_FREEBSD_NR_pwrite      476
-#define TARGET_FREEBSD_NR_mmap        477
-#define TARGET_FREEBSD_NR_lseek       478
-#define TARGET_FREEBSD_NR_truncate    479
-#define TARGET_FREEBSD_NR_ftruncate   480
-#define TARGET_FREEBSD_NR_thr_kill2   481
-#define TARGET_FREEBSD_NR_shm_open    482
-#define TARGET_FREEBSD_NR_shm_unlink  483
-#define TARGET_FREEBSD_NR_cpuset      484
-#define TARGET_FREEBSD_NR_cpuset_setid        485
-#define TARGET_FREEBSD_NR_cpuset_getid        486
-#define TARGET_FREEBSD_NR_cpuset_getaffinity  487
-#define TARGET_FREEBSD_NR_cpuset_setaffinity  488
-#define TARGET_FREEBSD_NR_faccessat   489
-#define TARGET_FREEBSD_NR_fchmodat    490
-#define TARGET_FREEBSD_NR_fchownat    491
-#define TARGET_FREEBSD_NR_fexecve     492
-#define TARGET_FREEBSD_NR_fstatat     493
-#define TARGET_FREEBSD_NR_futimesat   494
-#define TARGET_FREEBSD_NR_linkat      495
-#define TARGET_FREEBSD_NR_mkdirat     496
-#define TARGET_FREEBSD_NR_mkfifoat    497
-#define TARGET_FREEBSD_NR_mknodat     498
-#define TARGET_FREEBSD_NR_openat      499
-#define TARGET_FREEBSD_NR_readlinkat  500
-#define TARGET_FREEBSD_NR_renameat    501
-#define TARGET_FREEBSD_NR_symlinkat   502
-#define TARGET_FREEBSD_NR_unlinkat    503
-#define TARGET_FREEBSD_NR_posix_openpt        504
+#define TARGET_FREEBSD_NR_syscall   0
+#define TARGET_FREEBSD_NR_exit  1
+#define TARGET_FREEBSD_NR_fork  2
+#define TARGET_FREEBSD_NR_read  3
+#define TARGET_FREEBSD_NR_write 4
+#define TARGET_FREEBSD_NR_open  5
+#define TARGET_FREEBSD_NR_close 6
+#define TARGET_FREEBSD_NR_wait4 7
+                /* 8 is old creat */
+#define TARGET_FREEBSD_NR_link  9
+#define TARGET_FREEBSD_NR_unlink    10
+                /* 11 is obsolete execv */
+#define TARGET_FREEBSD_NR_chdir 12
+#define TARGET_FREEBSD_NR_fchdir    13
+#define TARGET_FREEBSD_NR_mknod 14
+#define TARGET_FREEBSD_NR_chmod 15
+#define TARGET_FREEBSD_NR_chown 16
+#define TARGET_FREEBSD_NR_break 17
+#define TARGET_FREEBSD_NR_freebsd4_getfsstat    18
+                /* 19 is old lseek */
+#define TARGET_FREEBSD_NR_getpid    20
+#define TARGET_FREEBSD_NR_mount 21
+#define TARGET_FREEBSD_NR_unmount   22
+#define TARGET_FREEBSD_NR_setuid    23
+#define TARGET_FREEBSD_NR_getuid    24
+#define TARGET_FREEBSD_NR_geteuid   25
+#define TARGET_FREEBSD_NR_ptrace    26
+#define TARGET_FREEBSD_NR_recvmsg   27
+#define TARGET_FREEBSD_NR_sendmsg   28
+#define TARGET_FREEBSD_NR_recvfrom  29
+#define TARGET_FREEBSD_NR_accept    30
+#define TARGET_FREEBSD_NR_getpeername   31
+#define TARGET_FREEBSD_NR_getsockname   32
+#define TARGET_FREEBSD_NR_access    33
+#define TARGET_FREEBSD_NR_chflags   34
+#define TARGET_FREEBSD_NR_fchflags  35
+#define TARGET_FREEBSD_NR_sync  36
+#define TARGET_FREEBSD_NR_kill  37
+                /* 38 is old stat */
+#define TARGET_FREEBSD_NR_getppid   39
+                /* 40 is old lstat */
+#define TARGET_FREEBSD_NR_dup   41
+#define TARGET_FREEBSD_NR_pipe  42
+#define TARGET_FREEBSD_NR_getegid   43
+#define TARGET_FREEBSD_NR_profil    44
+#define TARGET_FREEBSD_NR_ktrace    45
+                /* 46 is old sigaction */
+#define TARGET_FREEBSD_NR_getgid    47
+                /* 48 is old sigprocmask */
+#define TARGET_FREEBSD_NR_getlogin  49
+#define TARGET_FREEBSD_NR_setlogin  50
+#define TARGET_FREEBSD_NR_acct  51
+                /* 52 is old sigpending */
+#define TARGET_FREEBSD_NR_sigaltstack   53
+#define TARGET_FREEBSD_NR_ioctl 54
+#define TARGET_FREEBSD_NR_reboot    55
+#define TARGET_FREEBSD_NR_revoke    56
+#define TARGET_FREEBSD_NR_symlink   57
+#define TARGET_FREEBSD_NR_readlink  58
+#define TARGET_FREEBSD_NR_execve    59
+#define TARGET_FREEBSD_NR_umask 60
+#define TARGET_FREEBSD_NR_chroot    61
+                /* 62 is old fstat */
+                /* 63 is old getkerninfo */
+                /* 64 is old getpagesize */
+#define TARGET_FREEBSD_NR_msync 65
+#define TARGET_FREEBSD_NR_vfork 66
+                /* 67 is obsolete vread */
+                /* 68 is obsolete vwrite */
+#define TARGET_FREEBSD_NR_sbrk  69
+#define TARGET_FREEBSD_NR_sstk  70
+                /* 71 is old mmap */
+#define TARGET_FREEBSD_NR_vadvise   72
+#define TARGET_FREEBSD_NR_munmap    73
+#define TARGET_FREEBSD_NR_mprotect  74
+#define TARGET_FREEBSD_NR_madvise   75
+                /* 76 is obsolete vhangup */
+                /* 77 is obsolete vlimit */
+#define TARGET_FREEBSD_NR_mincore   78
+#define TARGET_FREEBSD_NR_getgroups 79
+#define TARGET_FREEBSD_NR_setgroups 80
+#define TARGET_FREEBSD_NR_getpgrp   81
+#define TARGET_FREEBSD_NR_setpgid   82
+#define TARGET_FREEBSD_NR_setitimer 83
+                /* 84 is old wait */
+#define TARGET_FREEBSD_NR_swapon    85
+#define TARGET_FREEBSD_NR_getitimer 86
+                /* 87 is old gethostname */
+                /* 88 is old sethostname */
+#define TARGET_FREEBSD_NR_getdtablesize 89
+#define TARGET_FREEBSD_NR_dup2  90
+#define TARGET_FREEBSD_NR_fcntl 92
+#define TARGET_FREEBSD_NR_select    93
+#define TARGET_FREEBSD_NR_fsync 95
+#define TARGET_FREEBSD_NR_setpriority   96
+#define TARGET_FREEBSD_NR_socket    97
+#define TARGET_FREEBSD_NR_connect   98
+                /* 99 is old accept */
+#define TARGET_FREEBSD_NR_getpriority   100
+                /* 101 is old send */
+                /* 102 is old recv */
+                /* 103 is old sigreturn */
+#define TARGET_FREEBSD_NR_bind  104
+#define TARGET_FREEBSD_NR_setsockopt    105
+#define TARGET_FREEBSD_NR_listen    106
+                /* 107 is obsolete vtimes */
+                /* 108 is old sigvec */
+                /* 109 is old sigblock */
+                /* 110 is old sigsetmask */
+                /* 111 is old sigsuspend */
+                /* 112 is old sigstack */
+                /* 113 is old recvmsg */
+                /* 114 is old sendmsg */
+                /* 115 is obsolete vtrace */
+#define TARGET_FREEBSD_NR_gettimeofday  116
+#define TARGET_FREEBSD_NR_getrusage 117
+#define TARGET_FREEBSD_NR_getsockopt    118
+#define TARGET_FREEBSD_NR_readv 120
+#define TARGET_FREEBSD_NR_writev    121
+#define TARGET_FREEBSD_NR_settimeofday  122
+#define TARGET_FREEBSD_NR_fchown    123
+#define TARGET_FREEBSD_NR_fchmod    124
+                /* 125 is old recvfrom */
+#define TARGET_FREEBSD_NR_setreuid  126
+#define TARGET_FREEBSD_NR_setregid  127
+#define TARGET_FREEBSD_NR_rename    128
+                /* 129 is old truncate */
+                /* 130 is old ftruncate */
+#define TARGET_FREEBSD_NR_flock 131
+#define TARGET_FREEBSD_NR_mkfifo    132
+#define TARGET_FREEBSD_NR_sendto    133
+#define TARGET_FREEBSD_NR_shutdown  134
+#define TARGET_FREEBSD_NR_socketpair    135
+#define TARGET_FREEBSD_NR_mkdir 136
+#define TARGET_FREEBSD_NR_rmdir 137
+#define TARGET_FREEBSD_NR_utimes    138
+                /* 139 is obsolete 4.2 sigreturn */
+#define TARGET_FREEBSD_NR_adjtime   140
+                /* 141 is old getpeername */
+                /* 142 is old gethostid */
+                /* 143 is old sethostid */
+                /* 144 is old getrlimit */
+                /* 145 is old setrlimit */
+                /* 146 is old killpg */
+#define TARGET_FREEBSD_NR_killpg    146 /* COMPAT */
+#define TARGET_FREEBSD_NR_setsid    147
+#define TARGET_FREEBSD_NR_quotactl  148
+                /* 149 is old quota */
+                /* 150 is old getsockname */
+#define TARGET_FREEBSD_NR_nlm_syscall   154
+#define TARGET_FREEBSD_NR_nfssvc    155
+                /* 156 is old getdirentries */
+#define TARGET_FREEBSD_NR_freebsd4_statfs   157
+#define TARGET_FREEBSD_NR_freebsd4_fstatfs  158
+#define TARGET_FREEBSD_NR_lgetfh    160
+#define TARGET_FREEBSD_NR_getfh 161
+#define TARGET_FREEBSD_NR_freebsd4_getdomainname    162
+#define TARGET_FREEBSD_NR_freebsd4_setdomainname    163
+#define TARGET_FREEBSD_NR_freebsd4_uname    164
+#define TARGET_FREEBSD_NR_sysarch   165
+#define TARGET_FREEBSD_NR_rtprio    166
+#define TARGET_FREEBSD_NR_semsys    169
+#define TARGET_FREEBSD_NR_msgsys    170
+#define TARGET_FREEBSD_NR_shmsys    171
+#define TARGET_FREEBSD_NR_freebsd6_pread    173
+#define TARGET_FREEBSD_NR_freebsd6_pwrite   174
+#define TARGET_FREEBSD_NR_setfib    175
+#define TARGET_FREEBSD_NR_ntp_adjtime   176
+#define TARGET_FREEBSD_NR_setgid    181
+#define TARGET_FREEBSD_NR_setegid   182
+#define TARGET_FREEBSD_NR_seteuid   183
+#define TARGET_FREEBSD_NR_stat  188
+#define TARGET_FREEBSD_NR_fstat 189
+#define TARGET_FREEBSD_NR_lstat 190
+#define TARGET_FREEBSD_NR_pathconf  191
+#define TARGET_FREEBSD_NR_fpathconf 192
+#define TARGET_FREEBSD_NR_getrlimit 194
+#define TARGET_FREEBSD_NR_setrlimit 195
+#define TARGET_FREEBSD_NR_getdirentries 196
+#define TARGET_FREEBSD_NR_freebsd6_mmap 197
+#define TARGET_FREEBSD_NR___syscall 198
+#define TARGET_FREEBSD_NR_freebsd6_lseek    199
+#define TARGET_FREEBSD_NR_freebsd6_truncate 200
+#define TARGET_FREEBSD_NR_freebsd6_ftruncate    201
+#define TARGET_FREEBSD_NR___sysctl  202
+#define TARGET_FREEBSD_NR_mlock 203
+#define TARGET_FREEBSD_NR_munlock   204
+#define TARGET_FREEBSD_NR_undelete  205
+#define TARGET_FREEBSD_NR_futimes   206
+#define TARGET_FREEBSD_NR_getpgid   207
+#define TARGET_FREEBSD_NR_poll  209
+#define TARGET_FREEBSD_NR_freebsd7___semctl 220
+#define TARGET_FREEBSD_NR_semget    221
+#define TARGET_FREEBSD_NR_semop 222
+#define TARGET_FREEBSD_NR_freebsd7_msgctl   224
+#define TARGET_FREEBSD_NR_msgget    225
+#define TARGET_FREEBSD_NR_msgsnd    226
+#define TARGET_FREEBSD_NR_msgrcv    227
+#define TARGET_FREEBSD_NR_shmat 228
+#define TARGET_FREEBSD_NR_freebsd7_shmctl   229
+#define TARGET_FREEBSD_NR_shmdt 230
+#define TARGET_FREEBSD_NR_shmget    231
+#define TARGET_FREEBSD_NR_clock_gettime 232
+#define TARGET_FREEBSD_NR_clock_settime 233
+#define TARGET_FREEBSD_NR_clock_getres  234
+#define TARGET_FREEBSD_NR_ktimer_create 235
+#define TARGET_FREEBSD_NR_ktimer_delete 236
+#define TARGET_FREEBSD_NR_ktimer_settime    237
+#define TARGET_FREEBSD_NR_ktimer_gettime    238
+#define TARGET_FREEBSD_NR_ktimer_getoverrun 239
+#define TARGET_FREEBSD_NR_nanosleep 240
+#define TARGET_FREEBSD_NR_ntp_gettime   248
+#define TARGET_FREEBSD_NR_minherit  250
+#define TARGET_FREEBSD_NR_rfork 251
+#define TARGET_FREEBSD_NR_openbsd_poll  252
+#define TARGET_FREEBSD_NR_issetugid 253
+#define TARGET_FREEBSD_NR_lchown    254
+#define TARGET_FREEBSD_NR_aio_read  255
+#define TARGET_FREEBSD_NR_aio_write 256
+#define TARGET_FREEBSD_NR_lio_listio    257
+#define TARGET_FREEBSD_NR_getdents  272
+#define TARGET_FREEBSD_NR_lchmod    274
+#define TARGET_FREEBSD_NR_netbsd_lchown 275
+#define TARGET_FREEBSD_NR_lutimes   276
+#define TARGET_FREEBSD_NR_netbsd_msync  277
+#define TARGET_FREEBSD_NR_nstat 278
+#define TARGET_FREEBSD_NR_nfstat    279
+#define TARGET_FREEBSD_NR_nlstat    280
+#define TARGET_FREEBSD_NR_preadv    289
+#define TARGET_FREEBSD_NR_pwritev   290
+#define TARGET_FREEBSD_NR_freebsd4_fhstatfs 297
+#define TARGET_FREEBSD_NR_fhopen    298
+#define TARGET_FREEBSD_NR_fhstat    299
+#define TARGET_FREEBSD_NR_modnext   300
+#define TARGET_FREEBSD_NR_modstat   301
+#define TARGET_FREEBSD_NR_modfnext  302
+#define TARGET_FREEBSD_NR_modfind   303
+#define TARGET_FREEBSD_NR_kldload   304
+#define TARGET_FREEBSD_NR_kldunload 305
+#define TARGET_FREEBSD_NR_kldfind   306
+#define TARGET_FREEBSD_NR_kldnext   307
+#define TARGET_FREEBSD_NR_kldstat   308
+#define TARGET_FREEBSD_NR_kldfirstmod   309
+#define TARGET_FREEBSD_NR_getsid    310
+#define TARGET_FREEBSD_NR_setresuid 311
+#define TARGET_FREEBSD_NR_setresgid 312
+                /* 313 is obsolete signanosleep */
+#define TARGET_FREEBSD_NR_aio_return    314
+#define TARGET_FREEBSD_NR_aio_suspend   315
+#define TARGET_FREEBSD_NR_aio_cancel    316
+#define TARGET_FREEBSD_NR_aio_error 317
+#define TARGET_FREEBSD_NR_oaio_read 318
+#define TARGET_FREEBSD_NR_oaio_write    319
+#define TARGET_FREEBSD_NR_olio_listio   320
+#define TARGET_FREEBSD_NR_yield 321
+                /* 322 is obsolete thr_sleep */
+                /* 323 is obsolete thr_wakeup */
+#define TARGET_FREEBSD_NR_mlockall  324
+#define TARGET_FREEBSD_NR_munlockall    325
+#define TARGET_FREEBSD_NR___getcwd  326
+#define TARGET_FREEBSD_NR_sched_setparam    327
+#define TARGET_FREEBSD_NR_sched_getparam    328
+#define TARGET_FREEBSD_NR_sched_setscheduler    329
+#define TARGET_FREEBSD_NR_sched_getscheduler    330
+#define TARGET_FREEBSD_NR_sched_yield   331
+#define TARGET_FREEBSD_NR_sched_get_priority_max    332
+#define TARGET_FREEBSD_NR_sched_get_priority_min    333
+#define TARGET_FREEBSD_NR_sched_rr_get_interval 334
+#define TARGET_FREEBSD_NR_utrace    335
+#define TARGET_FREEBSD_NR_freebsd4_sendfile 336
+#define TARGET_FREEBSD_NR_kldsym    337
+#define TARGET_FREEBSD_NR_jail  338
+#define TARGET_FREEBSD_NR_nnpfs_syscall 339
+#define TARGET_FREEBSD_NR_sigprocmask   340
+#define TARGET_FREEBSD_NR_sigsuspend    341
+#define TARGET_FREEBSD_NR_freebsd4_sigaction    342
+#define TARGET_FREEBSD_NR_sigpending    343
+#define TARGET_FREEBSD_NR_freebsd4_sigreturn    344
+#define TARGET_FREEBSD_NR_sigtimedwait  345
+#define TARGET_FREEBSD_NR_sigwaitinfo   346
+#define TARGET_FREEBSD_NR___acl_get_file    347
+#define TARGET_FREEBSD_NR___acl_set_file    348
+#define TARGET_FREEBSD_NR___acl_get_fd  349
+#define TARGET_FREEBSD_NR___acl_set_fd  350
+#define TARGET_FREEBSD_NR___acl_delete_file 351
+#define TARGET_FREEBSD_NR___acl_delete_fd   352
+#define TARGET_FREEBSD_NR___acl_aclcheck_file   353
+#define TARGET_FREEBSD_NR___acl_aclcheck_fd 354
+#define TARGET_FREEBSD_NR_extattrctl    355
+#define TARGET_FREEBSD_NR_extattr_set_file  356
+#define TARGET_FREEBSD_NR_extattr_get_file  357
+#define TARGET_FREEBSD_NR_extattr_delete_file   358
+#define TARGET_FREEBSD_NR_aio_waitcomplete  359
+#define TARGET_FREEBSD_NR_getresuid 360
+#define TARGET_FREEBSD_NR_getresgid 361
+#define TARGET_FREEBSD_NR_kqueue    362
+#define TARGET_FREEBSD_NR_kevent    363
+#define TARGET_FREEBSD_NR_extattr_set_fd    371
+#define TARGET_FREEBSD_NR_extattr_get_fd    372
+#define TARGET_FREEBSD_NR_extattr_delete_fd 373
+#define TARGET_FREEBSD_NR___setugid 374
+#define TARGET_FREEBSD_NR_eaccess   376
+#define TARGET_FREEBSD_NR_afs3_syscall  377
+#define TARGET_FREEBSD_NR_nmount    378
+#define TARGET_FREEBSD_NR___mac_get_proc    384
+#define TARGET_FREEBSD_NR___mac_set_proc    385
+#define TARGET_FREEBSD_NR___mac_get_fd  386
+#define TARGET_FREEBSD_NR___mac_get_file    387
+#define TARGET_FREEBSD_NR___mac_set_fd  388
+#define TARGET_FREEBSD_NR___mac_set_file    389
+#define TARGET_FREEBSD_NR_kenv  390
+#define TARGET_FREEBSD_NR_lchflags  391
+#define TARGET_FREEBSD_NR_uuidgen   392
+#define TARGET_FREEBSD_NR_sendfile  393
+#define TARGET_FREEBSD_NR_mac_syscall   394
+#define TARGET_FREEBSD_NR_getfsstat 395
+#define TARGET_FREEBSD_NR_statfs    396
+#define TARGET_FREEBSD_NR_fstatfs   397
+#define TARGET_FREEBSD_NR_fhstatfs  398
+#define TARGET_FREEBSD_NR_ksem_close    400
+#define TARGET_FREEBSD_NR_ksem_post 401
+#define TARGET_FREEBSD_NR_ksem_wait 402
+#define TARGET_FREEBSD_NR_ksem_trywait  403
+#define TARGET_FREEBSD_NR_ksem_init 404
+#define TARGET_FREEBSD_NR_ksem_open 405
+#define TARGET_FREEBSD_NR_ksem_unlink   406
+#define TARGET_FREEBSD_NR_ksem_getvalue 407
+#define TARGET_FREEBSD_NR_ksem_destroy  408
+#define TARGET_FREEBSD_NR___mac_get_pid 409
+#define TARGET_FREEBSD_NR___mac_get_link    410
+#define TARGET_FREEBSD_NR___mac_set_link    411
+#define TARGET_FREEBSD_NR_extattr_set_link  412
+#define TARGET_FREEBSD_NR_extattr_get_link  413
+#define TARGET_FREEBSD_NR_extattr_delete_link   414
+#define TARGET_FREEBSD_NR___mac_execve  415
+#define TARGET_FREEBSD_NR_sigaction 416
+#define TARGET_FREEBSD_NR_sigreturn 417
+#define TARGET_FREEBSD_NR_getcontext    421
+#define TARGET_FREEBSD_NR_setcontext    422
+#define TARGET_FREEBSD_NR_swapcontext   423
+#define TARGET_FREEBSD_NR_swapoff   424
+#define TARGET_FREEBSD_NR___acl_get_link    425
+#define TARGET_FREEBSD_NR___acl_set_link    426
+#define TARGET_FREEBSD_NR___acl_delete_link 427
+#define TARGET_FREEBSD_NR___acl_aclcheck_link   428
+#define TARGET_FREEBSD_NR_sigwait   429
+#define TARGET_FREEBSD_NR_thr_create    430
+#define TARGET_FREEBSD_NR_thr_exit  431
+#define TARGET_FREEBSD_NR_thr_self  432
+#define TARGET_FREEBSD_NR_thr_kill  433
+#define TARGET_FREEBSD_NR__umtx_lock    434
+#define TARGET_FREEBSD_NR__umtx_unlock  435
+#define TARGET_FREEBSD_NR_jail_attach   436
+#define TARGET_FREEBSD_NR_extattr_list_fd   437
+#define TARGET_FREEBSD_NR_extattr_list_file 438
+#define TARGET_FREEBSD_NR_extattr_list_link 439
+#define TARGET_FREEBSD_NR_ksem_timedwait    441
+#define TARGET_FREEBSD_NR_thr_suspend   442
+#define TARGET_FREEBSD_NR_thr_wake  443
+#define TARGET_FREEBSD_NR_kldunloadf    444
+#define TARGET_FREEBSD_NR_audit 445
+#define TARGET_FREEBSD_NR_auditon   446
+#define TARGET_FREEBSD_NR_getauid   447
+#define TARGET_FREEBSD_NR_setauid   448
+#define TARGET_FREEBSD_NR_getaudit  449
+#define TARGET_FREEBSD_NR_setaudit  450
+#define TARGET_FREEBSD_NR_getaudit_addr 451
+#define TARGET_FREEBSD_NR_setaudit_addr 452
+#define TARGET_FREEBSD_NR_auditctl  453
+#define TARGET_FREEBSD_NR__umtx_op  454
+#define TARGET_FREEBSD_NR_thr_new   455
+#define TARGET_FREEBSD_NR_sigqueue  456
+#define TARGET_FREEBSD_NR_kmq_open  457
+#define TARGET_FREEBSD_NR_kmq_setattr   458
+#define TARGET_FREEBSD_NR_kmq_timedreceive  459
+#define TARGET_FREEBSD_NR_kmq_timedsend 460
+#define TARGET_FREEBSD_NR_kmq_notify    461
+#define TARGET_FREEBSD_NR_kmq_unlink    462
+#define TARGET_FREEBSD_NR_abort2    463
+#define TARGET_FREEBSD_NR_thr_set_name  464
+#define TARGET_FREEBSD_NR_aio_fsync 465
+#define TARGET_FREEBSD_NR_rtprio_thread 466
+#define TARGET_FREEBSD_NR_sctp_peeloff  471
+#define TARGET_FREEBSD_NR_sctp_generic_sendmsg  472
+#define TARGET_FREEBSD_NR_sctp_generic_sendmsg_iov  473
+#define TARGET_FREEBSD_NR_sctp_generic_recvmsg  474
+#define TARGET_FREEBSD_NR_pread 475
+#define TARGET_FREEBSD_NR_pwrite    476
+#define TARGET_FREEBSD_NR_mmap  477
+#define TARGET_FREEBSD_NR_lseek 478
+#define TARGET_FREEBSD_NR_truncate  479
+#define TARGET_FREEBSD_NR_ftruncate 480
+#define TARGET_FREEBSD_NR_thr_kill2 481
+#define TARGET_FREEBSD_NR_shm_open  482
+#define TARGET_FREEBSD_NR_shm_unlink    483
+#define TARGET_FREEBSD_NR_cpuset    484
+#define TARGET_FREEBSD_NR_cpuset_setid  485
+#define TARGET_FREEBSD_NR_cpuset_getid  486
+#define TARGET_FREEBSD_NR_cpuset_getaffinity    487
+#define TARGET_FREEBSD_NR_cpuset_setaffinity    488
+#define TARGET_FREEBSD_NR_faccessat 489
+#define TARGET_FREEBSD_NR_fchmodat  490
+#define TARGET_FREEBSD_NR_fchownat  491
+#define TARGET_FREEBSD_NR_fexecve   492
+#define TARGET_FREEBSD_NR_fstatat   493
+#define TARGET_FREEBSD_NR_futimesat 494
+#define TARGET_FREEBSD_NR_linkat    495
+#define TARGET_FREEBSD_NR_mkdirat   496
+#define TARGET_FREEBSD_NR_mkfifoat  497
+#define TARGET_FREEBSD_NR_mknodat   498
+#define TARGET_FREEBSD_NR_openat    499
+#define TARGET_FREEBSD_NR_readlinkat    500
+#define TARGET_FREEBSD_NR_renameat  501
+#define TARGET_FREEBSD_NR_symlinkat 502
+#define TARGET_FREEBSD_NR_unlinkat  503
+#define TARGET_FREEBSD_NR_posix_openpt  504
+#define TARGET_FREEBSD_NR_gssd_syscall  505
+#define TARGET_FREEBSD_NR_jail_get  506
+#define TARGET_FREEBSD_NR_jail_set  507
+#define TARGET_FREEBSD_NR_jail_remove   508
+#define TARGET_FREEBSD_NR_closefrom 509
+#define TARGET_FREEBSD_NR___semctl  510
+#define TARGET_FREEBSD_NR_msgctl    511
+#define TARGET_FREEBSD_NR_shmctl    512
+#define TARGET_FREEBSD_NR_lpathconf 513
+#define TARGET_FREEBSD_NR_cap_new   514
+#define TARGET_FREEBSD_NR_cap_getrights 515
+#define TARGET_FREEBSD_NR_cap_enter 516
+#define TARGET_FREEBSD_NR_cap_getmode   517
+#define TARGET_FREEBSD_NR_pdfork    518
+#define TARGET_FREEBSD_NR_pdkill    519
+#define TARGET_FREEBSD_NR_pdgetpid  520
+#define TARGET_FREEBSD_NR_pselect   522
+#define TARGET_FREEBSD_NR_getloginclass 523
+#define TARGET_FREEBSD_NR_setloginclass 524
+#define TARGET_FREEBSD_NR_rctl_get_racct    525
+#define TARGET_FREEBSD_NR_rctl_get_rules    526
+#define TARGET_FREEBSD_NR_rctl_get_limits   527
+#define TARGET_FREEBSD_NR_rctl_add_rule 528
+#define TARGET_FREEBSD_NR_rctl_remove_rule  529
+#define TARGET_FREEBSD_NR_posix_fallocate   530
+#define TARGET_FREEBSD_NR_posix_fadvise 531
+#define TARGET_FREEBSD_NR_MAXSYSCALL    532
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 02/19] bsd-user: add HOST_ABI_DIR for the various *BSD dependent code.
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (21 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 01/19] bsd-user: refresh freebsd system call numbers Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-27 11:27   ` Paolo Bonzini
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 03/19] bsd-user: move OS/arch dependent code for strace into separate directories Stacey Son
                   ` (16 subsequent siblings)
  39 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds HOST_ABI_DIR (similar to TARGET_ABI_DIR) so the various
BSD OS dependent code can be seperated into its own directories rather
than using #ifdef's.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 Makefile.target |    3 ++-
 configure       |   11 +++++++++++
 2 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/Makefile.target b/Makefile.target
index af6ac7e..82ae8cb 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -99,7 +99,8 @@ endif #CONFIG_LINUX_USER
 
 ifdef CONFIG_BSD_USER
 
-QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR)
+QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR) \
+			 -I$(SRC_PATH)/bsd-user/$(HOST_ABI_DIR)
 
 obj-y += bsd-user/
 obj-y += gdbstub.o user-exec.o
diff --git a/configure b/configure
index 91372f9..14571c6 100755
--- a/configure
+++ b/configure
@@ -449,6 +449,9 @@ fi
 
 # OS specific
 
+# host *BSD for user mode
+HOST_ABI_DIR=""
+
 case $targetos in
 CYGWIN*)
   mingw32="yes"
@@ -473,12 +476,14 @@ FreeBSD)
   audio_possible_drivers="oss sdl esd pa"
   # needed for kinfo_getvmmap(3) in libutil.h
   LIBS="-lutil $LIBS"
+  HOST_ABI_DIR="freebsd"
 ;;
 DragonFly)
   bsd="yes"
   make="${MAKE-gmake}"
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd pa"
+  HOST_ABI_DIR="dragonfly"
 ;;
 NetBSD)
   bsd="yes"
@@ -486,12 +491,14 @@ NetBSD)
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd"
   oss_lib="-lossaudio"
+  HOST_ABI_DIR="netbsd"
 ;;
 OpenBSD)
   bsd="yes"
   make="${MAKE-gmake}"
   audio_drv_list="sdl"
   audio_possible_drivers="sdl esd"
+  HOST_ABI_DIR="openbsd"
 ;;
 Darwin)
   bsd="yes"
@@ -510,6 +517,7 @@ Darwin)
   # Disable attempts to use ObjectiveC features in os/object.h since they
   # won't work when we're compiling with gcc as a C compiler.
   QEMU_CFLAGS="-DOS_OBJECT_USE_OBJC=0 $QEMU_CFLAGS"
+  HOST_ABI_DIR="darwin"
 ;;
 SunOS)
   solaris="yes"
@@ -4471,6 +4479,9 @@ if [ "$TARGET_ABI_DIR" = "" ]; then
   TARGET_ABI_DIR=$TARGET_ARCH
 fi
 echo "TARGET_ABI_DIR=$TARGET_ABI_DIR" >> $config_target_mak
+if [ "$HOST_ABI_DIR" != "" ]; then
+    echo "HOST_ABI_DIR=$HOST_ABI_DIR" >> $config_target_mak
+fi
 case "$target_name" in
   i386|x86_64)
     if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 03/19] bsd-user: move OS/arch dependent code for strace into separate directories
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (22 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 02/19] bsd-user: add HOST_ABI_DIR for the various *BSD dependent code Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 04/19] bsd-user: move target arch and host OS dependent code out of main.c Stacey Son
                   ` (15 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change moves host OS and arch dependent code for the sysarch system
call related to the -strace functionality into the appropriate HOST_ABI_DIR
and TARGET_ABI_DIR directories.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/arm/syscall.h                 |   36 +++++++
 bsd-user/arm/target_arch_sysarch.h     |   78 ++++++++++++++
 bsd-user/freebsd/os-strace.h           |   29 +++++
 bsd-user/freebsd/strace.list           |   76 +++++++++++++--
 bsd-user/i386/syscall.h                |   23 ++++
 bsd-user/i386/target_arch_sysarch.h    |   78 ++++++++++++++
 bsd-user/mips/syscall.h                |   52 ++++++++++
 bsd-user/mips/target_arch_sysarch.h    |   69 +++++++++++++
 bsd-user/mips64/syscall.h              |   53 ++++++++++
 bsd-user/mips64/target_arch_sysarch.h  |   69 +++++++++++++
 bsd-user/netbsd/os-strace.h            |    1 +
 bsd-user/openbsd/os-strace.h           |    1 +
 bsd-user/qemu.h                        |   26 +++++
 bsd-user/sparc/syscall.h               |   29 +++++-
 bsd-user/sparc/target_arch_sysarch.h   |   52 ++++++++++
 bsd-user/sparc64/syscall.h             |   28 +++++-
 bsd-user/sparc64/target_arch_sysarch.h |   52 ++++++++++
 bsd-user/strace.c                      |  175 +++++++++++++++++++++----------
 bsd-user/x86_64/syscall.h              |   26 +++++-
 bsd-user/x86_64/target_arch_sysarch.h  |   76 ++++++++++++++
 20 files changed, 962 insertions(+), 67 deletions(-)
 create mode 100644 bsd-user/arm/syscall.h
 create mode 100644 bsd-user/arm/target_arch_sysarch.h
 create mode 100644 bsd-user/freebsd/os-strace.h
 create mode 100644 bsd-user/i386/target_arch_sysarch.h
 create mode 100644 bsd-user/mips/syscall.h
 create mode 100644 bsd-user/mips/target_arch_sysarch.h
 create mode 100644 bsd-user/mips64/syscall.h
 create mode 100644 bsd-user/mips64/target_arch_sysarch.h
 create mode 100644 bsd-user/netbsd/os-strace.h
 create mode 100644 bsd-user/openbsd/os-strace.h
 create mode 100644 bsd-user/sparc/target_arch_sysarch.h
 create mode 100644 bsd-user/sparc64/target_arch_sysarch.h
 create mode 100644 bsd-user/x86_64/target_arch_sysarch.h

diff --git a/bsd-user/arm/syscall.h b/bsd-user/arm/syscall.h
new file mode 100644
index 0000000..bc3d6e6
--- /dev/null
+++ b/bsd-user/arm/syscall.h
@@ -0,0 +1,36 @@
+#ifndef __ARCH_SYSCALL_H_
+#define __ARCH_SYSCALL_H_
+
+struct target_pt_regs {
+    abi_long uregs[17];
+};
+
+#define ARM_cpsr    uregs[16]
+#define ARM_pc      uregs[15]
+#define ARM_lr      uregs[14]
+#define ARM_sp      uregs[13]
+#define ARM_ip      uregs[12]
+#define ARM_fp      uregs[11]
+#define ARM_r10     uregs[10]
+#define ARM_r9      uregs[9]
+#define ARM_r8      uregs[8]
+#define ARM_r7      uregs[7]
+#define ARM_r6      uregs[6]
+#define ARM_r5      uregs[5]
+#define ARM_r4      uregs[4]
+#define ARM_r3      uregs[3]
+#define ARM_r2      uregs[2]
+#define ARM_r1      uregs[1]
+#define ARM_r0      uregs[0]
+
+#define ARM_SYSCALL_BASE    0 /* XXX: FreeBSD only */
+
+#define TARGET_FREEBSD_ARM_SYNC_ICACHE      0
+#define TARGET_FREEBSD_ARM_DRAIN_WRITEBUF   1
+#define TARGET_FREEBSD_ARM_SET_TP       2
+#define TARGET_FREEBSD_ARM_GET_TP       3
+
+#define TARGET_HW_MACHINE       "arm"
+#define TARGET_HW_MACHINE_ARCH  "armv6"
+
+#endif /* !__ARCH_SYSCALL_H_ */
diff --git a/bsd-user/arm/target_arch_sysarch.h b/bsd-user/arm/target_arch_sysarch.h
new file mode 100644
index 0000000..96d617a
--- /dev/null
+++ b/bsd-user/arm/target_arch_sysarch.h
@@ -0,0 +1,78 @@
+/*
+ *  arm sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+#include "target_arch.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUARMState *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_FREEBSD_ARM_SYNC_ICACHE:
+    case TARGET_FREEBSD_ARM_DRAIN_WRITEBUF:
+        break;
+
+    case TARGET_FREEBSD_ARM_SET_TP:
+        target_cpu_set_tls(env, parms);
+        break;
+
+    case TARGET_FREEBSD_ARM_GET_TP:
+        ret = target_cpu_get_tls(env);
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    switch (arg1) {
+    case TARGET_FREEBSD_ARM_SYNC_ICACHE:
+        gemu_log("%s(ARM_SYNC_ICACHE, ...)", name->name);
+        break;
+
+    case TARGET_FREEBSD_ARM_DRAIN_WRITEBUF:
+        gemu_log("%s(ARM_DRAIN_WRITEBUF, ...)", name->name);
+        break;
+
+    case TARGET_FREEBSD_ARM_SET_TP:
+        gemu_log("%s(ARM_SET_TP, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    case TARGET_FREEBSD_ARM_GET_TP:
+        gemu_log("%s(ARM_GET_TP, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    default:
+        gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
+    }
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/freebsd/os-strace.h b/bsd-user/freebsd/os-strace.h
new file mode 100644
index 0000000..a222f09
--- /dev/null
+++ b/bsd-user/freebsd/os-strace.h
@@ -0,0 +1,29 @@
+/*
+ *  FreeBSD dependent strace print functions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "target_arch_sysarch.h"    /* architecture dependent functions */
+
+
+static inline void do_os_print_sysarch(const struct syscallname *name,
+        abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4,
+        abi_long arg5, abi_long arg6)
+{
+    /* This is arch dependent */
+    do_freebsd_arch_print_sysarch(name, arg1, arg2, arg3, arg4, arg5, arg6);
+}
diff --git a/bsd-user/freebsd/strace.list b/bsd-user/freebsd/strace.list
index 1edf412..ae2a4a3 100644
--- a/bsd-user/freebsd/strace.list
+++ b/bsd-user/freebsd/strace.list
@@ -1,7 +1,38 @@
+/*
+ *  FreeBSD strace list
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+{ TARGET_FREEBSD_NR___acl_aclcheck_fd, "__acl_get_fd", "%s(%d, %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_aclcheck_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_aclcheck_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_delete_fd, "__acl_delete_fd", "%s(%d, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_delete_file, "__acl_delete_file", "%s(\"%s\", %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_delete_link, "__acl_delete_link", "%s(\"%s\", %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_get_fd, "__acl_get_fd", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_get_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_get_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_set_fd, "__acl_get_fd", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_set_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_set_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL },
 { TARGET_FREEBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR___semctl, "__semctl", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR___syscall, "__syscall", NULL, NULL, NULL },
-{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, print_sysctl, NULL },
+{ TARGET_FREEBSD_NR__umtx_op, "_umtx_op", "%s(%#x, %d, %d, %#x, %#x)", NULL, NULL },
 { TARGET_FREEBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL },
 { TARGET_FREEBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL },
 { TARGET_FREEBSD_NR_acct, "acct", NULL, NULL, NULL },
@@ -20,24 +51,41 @@
 { TARGET_FREEBSD_NR_connect, "connect", "%s(%d,%#x,%d)", NULL, NULL },
 { TARGET_FREEBSD_NR_dup, "dup", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_dup2, "dup2", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_eaccess, "eaccess", "%s(%s,%#x)", NULL, NULL },
 { TARGET_FREEBSD_NR_execve, "execve", NULL, print_execve, NULL },
 { TARGET_FREEBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattrctl, "extattrctl", "%s(\"%s\", %d, \"%s\", %d, \"%s\"", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_delete_fd, "extattr_delete_fd", "%s(%d, %d, \"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_delete_file, "extattr_delete_file", "%s(\"%s\", %d, \"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_delete_link, "extattr_delete_link", "%s(\"%s\", %d, \"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_get_fd, "extattr_get_fd", "%s(%d, %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_get_file, "extattr_get_file", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_get_file, "extattr_get_link", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_list_fd, "extattr_list_fd", "%s(%d, %d, %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_list_file, "extattr_list_file", "%s(\"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_list_link, "extattr_list_link", "%s(\"%s\", %d, %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_set_fd, "extattr_set_fd", "%s(%d, %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_set_file, "extattr_set_file", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_set_link, "extattr_set_link", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL },
 { TARGET_FREEBSD_NR_fchdir, "fchdir", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fchflags, "fchflags", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL },
-{ TARGET_FREEBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fchown, "fchown", "%s(%d,%d,%d)", NULL, NULL },
 { TARGET_FREEBSD_NR_fcntl, "fcntl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_fexecve, "fexecve", NULL, print_execve, NULL },
 { TARGET_FREEBSD_NR_fhopen, "fhopen", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fhstat, "fhstat", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fhstatfs, "fhstatfs", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_flock, "flock", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fork, "fork", "%s()", NULL, NULL },
 { TARGET_FREEBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL },
-{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%p)", NULL, NULL },
-{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%p)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fstatat, "fstatat", "%s(%d,\"%s\", %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%#x)", NULL, NULL },
 { TARGET_FREEBSD_NR_fsync, "fsync", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getcontext, "getcontext", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_freebsd6_mmap, "freebsd6_mmap", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getegid, "getegid", "%s()", NULL, NULL },
@@ -63,7 +111,7 @@
 { TARGET_FREEBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getuid, "getuid", "%s()", NULL, NULL },
-{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, print_ioctl, NULL },
 { TARGET_FREEBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL },
 { TARGET_FREEBSD_NR_kevent, "kevent", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_kill, "kill", NULL, NULL, NULL },
@@ -72,6 +120,7 @@
 { TARGET_FREEBSD_NR_lchown, "lchown", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL },
 { TARGET_FREEBSD_NR_listen, "listen", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_lpathconf, "lpathconf", "%s(\"%s\", %d)", NULL, NULL },
 { TARGET_FREEBSD_NR_lseek, "lseek", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_lstat, "lstat", "%s(\"%s\",%p)", NULL, NULL },
 { TARGET_FREEBSD_NR_madvise, "madvise", NULL, NULL, NULL },
@@ -96,7 +145,9 @@
 { TARGET_FREEBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL },
+{ TARGET_FREEBSD_NR_openat, "openat", "%s(%d, \"%s\",%#x,%#o)", NULL, NULL },
 { TARGET_FREEBSD_NR_pathconf, "pathconf", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_pathconf, "pathconf", "%s(\"%s\", %d)", NULL, NULL },
 { TARGET_FREEBSD_NR_pipe, "pipe", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_poll, "poll", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_pread, "pread", NULL, NULL, NULL },
@@ -116,6 +167,7 @@
 { TARGET_FREEBSD_NR_revoke, "revoke", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_rfork, "rfork", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_rmdir, "rmdir", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_rtprio_thread, "rtprio_thread", "%s(%d, %d, %p)", NULL, NULL },
 { TARGET_FREEBSD_NR_sbrk, "sbrk", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_select, "select", NULL, NULL, NULL },
@@ -123,6 +175,7 @@
 { TARGET_FREEBSD_NR_semop, "semop", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sendto, "sendto", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setcontext, "setcontext", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_setegid, "setegid", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_seteuid, "seteuid", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_setgid, "setgid", NULL, NULL, NULL },
@@ -151,15 +204,24 @@
 { TARGET_FREEBSD_NR_sigprocmask, "sigprocmask", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sigreturn, "sigreturn", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sigsuspend, "sigsuspend", NULL, NULL, NULL },
-{ TARGET_FREEBSD_NR_socket, "socket", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_socket, "socket", "%s(%d,%d,%d)", NULL, NULL },
 { TARGET_FREEBSD_NR_socketpair, "socketpair", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sstk, "sstk", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_stat, "stat", "%s(\"%s\",%p)", NULL, NULL },
 { TARGET_FREEBSD_NR_statfs, "statfs", "%s(\"%s\",%p)", NULL, NULL },
 { TARGET_FREEBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL },
 { TARGET_FREEBSD_NR_sync, "sync", NULL, NULL, NULL },
-{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, print_sysarch, NULL },
 { TARGET_FREEBSD_NR_syscall, "syscall", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_create, "thr_create", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_exit, "thr_exit", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_kill, "thr_kill", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_kill2, "thr_kill2", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_new, "thr_new", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_self, "thr_self", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_set_name, "thr_set_name", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_suspend, "thr_suspend", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_wake, "thr_wake", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_truncate, "truncate", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL },
 { TARGET_FREEBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL },
diff --git a/bsd-user/i386/syscall.h b/bsd-user/i386/syscall.h
index 9b34c61..52de302 100644
--- a/bsd-user/i386/syscall.h
+++ b/bsd-user/i386/syscall.h
@@ -1,3 +1,23 @@
+/*
+ *  i386 system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _I386_SYSCALL_H_
+#define _I386_SYSCALL_H_
+
 /* default linux values for the selectors */
 #define __USER_CS	(0x23)
 #define __USER_DS	(0x2B)
@@ -158,4 +178,7 @@ struct target_vm86plus_struct {
 
 
 #define UNAME_MACHINE "i386"
+#define TARGET_HW_MACHINE UNAME_MACHINE
+#define TARGET_HW_MACHINE_ARCH UNAME_MACHINE
 
+#endif /* ! _I386_SYSCALL_H_ */
diff --git a/bsd-user/i386/target_arch_sysarch.h b/bsd-user/i386/target_arch_sysarch.h
new file mode 100644
index 0000000..4fa6698
--- /dev/null
+++ b/bsd-user/i386/target_arch_sysarch.h
@@ -0,0 +1,78 @@
+/*
+ *  i386 sysarch system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUX86State *env, int op,
+        abi_ulong parms)
+{
+    abi_long ret = 0;
+    abi_ulong val;
+    int idx;
+
+    switch (op) {
+    case TARGET_FREEBSD_I386_SET_GSBASE:
+    case TARGET_FREEBSD_I386_SET_FSBASE:
+        if (op == TARGET_FREEBSD_I386_SET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        if (get_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        cpu_x86_load_seg(env, idx, 0);
+        env->segs[idx].base = val;
+        break;
+
+    case TARGET_FREEBSD_I386_GET_GSBASE:
+    case TARGET_FREEBSD_I386_GET_FSBASE:
+        if (op == TARGET_FREEBSD_I386_GET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        val = env->segs[idx].base;
+        if (put_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    /* XXX handle the others... */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", "
+        TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4);
+}
+
+#endif /* !__ARCH_SYSARCH_H_ */
+
diff --git a/bsd-user/mips/syscall.h b/bsd-user/mips/syscall.h
new file mode 100644
index 0000000..aacc6dd
--- /dev/null
+++ b/bsd-user/mips/syscall.h
@@ -0,0 +1,52 @@
+/*
+ *  mips system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _MIPS_SYSCALL_H_
+#define _MIPS_SYSCALL_H_
+
+/*
+ * struct target_pt_regs defines the way the registers are stored on the stack
+ * during a system call.
+ */
+
+struct target_pt_regs {
+    /* Saved main processor registers. */
+    abi_ulong regs[32];
+
+    /* Saved special registers. */
+    abi_ulong cp0_status;
+    abi_ulong lo;
+    abi_ulong hi;
+    abi_ulong cp0_badvaddr;
+    abi_ulong cp0_cause;
+    abi_ulong cp0_epc;
+};
+
+#if defined(TARGET_WORDS_BIGENDIAN)
+#define UNAME_MACHINE "mips"
+#else
+#define UNAME_MACHINE "mipsel"
+#endif
+
+#define TARGET_HW_MACHINE       "mips"
+#define TARGET_HW_MACHINE_ARCH   UNAME_MACHINE
+
+/* sysarch() commands */
+#define TARGET_MIPS_SET_TLS     1
+#define TARGET_MIPS_GET_TLS     2
+
+#endif /* !_MIPS_SYSCALL_H_ */
diff --git a/bsd-user/mips/target_arch_sysarch.h b/bsd-user/mips/target_arch_sysarch.h
new file mode 100644
index 0000000..d333740
--- /dev/null
+++ b/bsd-user/mips/target_arch_sysarch.h
@@ -0,0 +1,69 @@
+/*
+ *  mips sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+#include "target_arch.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUMIPSState *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_MIPS_SET_TLS:
+        target_cpu_set_tls(env, parms);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        if (put_user(target_cpu_get_tls(env), parms, abi_ulong)) {
+            ret = -TARGET_EFAULT;
+        }
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    switch (arg1) {
+    case TARGET_MIPS_SET_TLS:
+        gemu_log("%s(SET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        gemu_log("%s(GET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    default:
+        gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
+    }
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/mips64/syscall.h b/bsd-user/mips64/syscall.h
new file mode 100644
index 0000000..bf4c598
--- /dev/null
+++ b/bsd-user/mips64/syscall.h
@@ -0,0 +1,53 @@
+/*
+ *  mips64 system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _MIPS64_SYSCALL_H_
+#define _MIPS64_SYSCALL_H_
+
+/*
+ * struct target_pt_regs defines the way the registers are stored on the stack
+ * during a system call.
+ */
+
+struct target_pt_regs {
+    /* Saved main processor registers. */
+    abi_ulong regs[32];
+
+    /* Saved special registers. */
+    abi_ulong cp0_status;
+    abi_ulong lo;
+    abi_ulong hi;
+    abi_ulong cp0_badvaddr;
+    abi_ulong cp0_cause;
+    abi_ulong cp0_epc;
+};
+
+
+#if defined(TARGET_WORDS_BIGENDIAN)
+#define UNAME_MACHINE "mips64"
+#else
+#define UNAME_MACHINE "mips64el"
+#endif
+
+#define TARGET_HW_MACHINE       "mips"
+#define TARGET_HW_MACHINE_ARCH  UNAME_MACHINE
+
+/* sysarch() commands */
+#define TARGET_MIPS_SET_TLS     1
+#define TARGET_MIPS_GET_TLS     2
+
+#endif /* !_MIPS64_SYSCALL_H_ */
diff --git a/bsd-user/mips64/target_arch_sysarch.h b/bsd-user/mips64/target_arch_sysarch.h
new file mode 100644
index 0000000..95b4e78
--- /dev/null
+++ b/bsd-user/mips64/target_arch_sysarch.h
@@ -0,0 +1,69 @@
+/*
+ *  mips64 sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+#include "target_arch.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUMIPSState *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_MIPS_SET_TLS:
+        target_cpu_set_tls(env, parms);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        if (put_user(target_cpu_get_tls(env), parms, abi_ulong)) {
+            ret = -TARGET_EFAULT;
+        }
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    switch (arg1) {
+    case TARGET_MIPS_SET_TLS:
+        gemu_log("%s(SET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        gemu_log("%s(GET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    default:
+        gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
+    }
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/netbsd/os-strace.h b/bsd-user/netbsd/os-strace.h
new file mode 100644
index 0000000..70cf51d
--- /dev/null
+++ b/bsd-user/netbsd/os-strace.h
@@ -0,0 +1 @@
+/* XXX NetBSD dependent strace print functions */
diff --git a/bsd-user/openbsd/os-strace.h b/bsd-user/openbsd/os-strace.h
new file mode 100644
index 0000000..9161390
--- /dev/null
+++ b/bsd-user/openbsd/os-strace.h
@@ -0,0 +1 @@
+/* XXX OpenBSD dependent strace print functions */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index ddc74ed..b8a34c7 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -1,3 +1,19 @@
+/*
+ *  qemu bsd user mode definition
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
 #ifndef QEMU_H
 #define QEMU_H
 
@@ -149,6 +165,16 @@ void fork_end(int child);
 #include "qemu/log.h"
 
 /* strace.c */
+struct syscallname {
+    int nr;
+    const char *name;
+    const char *format;
+    void (*call)(const struct syscallname *,
+                 abi_long, abi_long, abi_long,
+                 abi_long, abi_long, abi_long);
+    void (*result)(const struct syscallname *, abi_long);
+};
+
 void
 print_freebsd_syscall(int num,
                       abi_long arg1, abi_long arg2, abi_long arg3,
diff --git a/bsd-user/sparc/syscall.h b/bsd-user/sparc/syscall.h
index 5a9bb7e..3a5b1e2 100644
--- a/bsd-user/sparc/syscall.h
+++ b/bsd-user/sparc/syscall.h
@@ -1,3 +1,23 @@
+/*
+ *  sparc dependent system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _SPARC_SYSCALL_H_
+#define _SPARC_SYSCALL_H_
+
 struct target_pt_regs {
 	abi_ulong psr;
 	abi_ulong pc;
@@ -6,4 +26,11 @@ struct target_pt_regs {
 	abi_ulong u_regs[16];
 };
 
-#define UNAME_MACHINE "sun4"
+#define UNAME_MACHINE           "sun4"
+#define TARGET_HW_MACHINE       "sparc"
+#define TARGET_HW_MACHINE_ARCH  "sparc"
+
+#define TARGET_SPARC_UTRAP_INSTALL      1
+#define TARGET_SPARC_SIGTRAMP_INSTALL   2
+
+#endif /* ! _SPARC_SYSCALL_H_ */
diff --git a/bsd-user/sparc/target_arch_sysarch.h b/bsd-user/sparc/target_arch_sysarch.h
new file mode 100644
index 0000000..454c084
--- /dev/null
+++ b/bsd-user/sparc/target_arch_sysarch.h
@@ -0,0 +1,52 @@
+/*
+ *  SPARC sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(void *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_SPARC_SIGTRAMP_INSTALL:
+        /* XXX not currently handled */
+    case TARGET_SPARC_UTRAP_INSTALL:
+        /* XXX not currently handled */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", "
+        TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4);
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/sparc64/syscall.h b/bsd-user/sparc64/syscall.h
index 81a816d..58cc38d 100644
--- a/bsd-user/sparc64/syscall.h
+++ b/bsd-user/sparc64/syscall.h
@@ -1,3 +1,22 @@
+/*
+ *  sparc64 dependent system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _SPARC64_SYSCALL_H_
+#define _SPARC64_SYSCALL_H_
 struct target_pt_regs {
 	abi_ulong u_regs[16];
 	abi_ulong tstate;
@@ -7,4 +26,11 @@ struct target_pt_regs {
 	abi_ulong fprs;
 };
 
-#define UNAME_MACHINE "sun4u"
+#define UNAME_MACHINE           "sun4u"
+#define TARGET_HW_MACHINE       "sparc"
+#define TARGET_HW_MACHINE_ARCH  "sparc64"
+
+#define TARGET_SPARC_UTRAP_INSTALL      1
+#define TARGET_SPARC_SIGTRAMP_INSTALL   2
+
+#endif /* !_SPARC64_SYSCALL_H_ */
diff --git a/bsd-user/sparc64/target_arch_sysarch.h b/bsd-user/sparc64/target_arch_sysarch.h
new file mode 100644
index 0000000..84e1339
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_sysarch.h
@@ -0,0 +1,52 @@
+/*
+ *  SPARC64 sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(void *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_SPARC_SIGTRAMP_INSTALL:
+        /* XXX not currently handled */
+    case TARGET_SPARC_UTRAP_INSTALL:
+        /* XXX not currently handled */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", "
+        TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4);
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/strace.c b/bsd-user/strace.c
index d73bbca..60aabc3 100644
--- a/bsd-user/strace.c
+++ b/bsd-user/strace.c
@@ -1,37 +1,73 @@
+/*
+ *  System call tracing and debugging
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
 #include <stdio.h>
 #include <errno.h>
 #include <sys/select.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <sys/syscall.h>
+#include <sys/ioccom.h>
+#include <ctype.h>
+
 #include "qemu.h"
 
-int do_strace=0;
+#include "os-strace.h"  /* OS dependent strace print functions */
 
-struct syscallname {
-    int nr;
-    const char *name;
-    const char *format;
-    void (*call)(const struct syscallname *,
-                 abi_long, abi_long, abi_long,
-                 abi_long, abi_long, abi_long);
-    void (*result)(const struct syscallname *, abi_long);
-};
+int do_strace;
 
 /*
  * Utility functions
  */
 
-static void
-print_execve(const struct syscallname *name,
-             abi_long arg1, abi_long arg2, abi_long arg3,
-             abi_long arg4, abi_long arg5, abi_long arg6)
+static void print_sysctl(const struct syscallname *name, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
+        abi_long arg6)
+{
+    uint32_t i;
+    int32_t *namep;
+
+    gemu_log("%s({ ", name->name);
+    namep = lock_user(VERIFY_READ, arg1, sizeof(int32_t) * arg2, 1);
+    if (namep) {
+        int32_t *p = namep;
+
+        for (i = 0; i < (uint32_t)arg2; i++) {
+            gemu_log("%d ", tswap32(*p++));
+        }
+        unlock_user(namep, arg1, 0);
+    }
+    gemu_log("}, %u, 0x" TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ", 0x"
+        TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ")",
+        (uint32_t)arg2, arg3, arg4, arg5, arg6);
+}
+
+static void print_execve(const struct syscallname *name, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
+        abi_long arg6)
 {
     abi_ulong arg_ptr_addr;
     char *s;
 
-    if (!(s = lock_user_string(arg1)))
+    s = lock_user_string(arg1);
+    if (s == NULL) {
         return;
+    }
     gemu_log("%s(\"%s\",{", name->name, s);
     unlock_user(s, arg1, 0);
 
@@ -39,29 +75,56 @@ print_execve(const struct syscallname *name,
         abi_ulong *arg_ptr, arg_addr;
 
         arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
-        if (!arg_ptr)
+        if (!arg_ptr) {
             return;
+        }
         arg_addr = tswapl(*arg_ptr);
         unlock_user(arg_ptr, arg_ptr_addr, 0);
-        if (!arg_addr)
+        if (!arg_addr) {
             break;
+        }
         if ((s = lock_user_string(arg_addr))) {
             gemu_log("\"%s\",", s);
             unlock_user(s, arg_addr, 0);
         }
     }
-
     gemu_log("NULL})");
 }
 
+static void print_ioctl(const struct syscallname *name,
+        abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4,
+        abi_long arg5, abi_long arg6)
+{
+    /* Decode the ioctl request */
+    gemu_log("%s(%d, 0x%0lx { IO%s%s GRP:0x%x('%c') CMD:%d LEN:%d }, 0x"
+            TARGET_ABI_FMT_lx ", ...)",
+            name->name,
+            (int)arg1,
+            (unsigned long)arg2,
+            arg2 & IOC_OUT ? "R" : "",
+            arg2 & IOC_IN ? "W" : "",
+            (unsigned)IOCGROUP(arg2),
+            isprint(IOCGROUP(arg2)) ? (char)IOCGROUP(arg2) : '?',
+            (int)arg2 & 0xFF,
+            (int)IOCPARM_LEN(arg2),
+            arg3);
+}
+
+static void print_sysarch(const struct syscallname *name, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
+        abi_long arg6)
+{
+    /* This is os dependent. */
+    do_os_print_sysarch(name, arg1, arg2, arg3, arg4, arg5, arg6);
+}
+
 /*
  * Variants for the return value output function
  */
 
-static void
-print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
+static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
 {
-if( ret == -1 ) {
+    if (ret == -1) {
         gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno));
     } else {
         gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
@@ -90,10 +153,9 @@ static const struct syscallname openbsd_scnames[] = {
 #include "openbsd/strace.list"
 };
 
-static void
-print_syscall(int num, const struct syscallname *scnames, unsigned int nscnames,
-              abi_long arg1, abi_long arg2, abi_long arg3,
-              abi_long arg4, abi_long arg5, abi_long arg6)
+static void print_syscall(int num, const struct syscallname *scnames,
+        unsigned int nscnames, abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5, abi_long arg6)
 {
     unsigned int i;
     const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
@@ -102,36 +164,37 @@ print_syscall(int num, const struct syscallname *scnames, unsigned int nscnames,
 
     gemu_log("%d ", getpid() );
 
-    for (i = 0; i < nscnames; i++)
+    for (i = 0; i < nscnames; i++) {
         if (scnames[i].nr == num) {
             if (scnames[i].call != NULL) {
                 scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5,
-                                arg6);
+                        arg6);
             } else {
                 /* XXX: this format system is broken because it uses
                    host types and host pointers for strings */
-                if (scnames[i].format != NULL)
+                if (scnames[i].format != NULL) {
                     format = scnames[i].format;
-                gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4,
-                         arg5, arg6);
+                }
+                gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4, arg5,
+                        arg6);
             }
             return;
         }
+    }
     gemu_log("Unknown syscall %d\n", num);
 }
 
-static void
-print_syscall_ret(int num, abi_long ret, const struct syscallname *scnames,
-                  unsigned int nscnames)
+static void print_syscall_ret(int num, abi_long ret,
+        const struct syscallname *scnames, unsigned int nscnames)
 {
     unsigned int i;
 
-    for (i = 0; i < nscnames; i++)
+    for (i = 0; i < nscnames; i++) {
         if (scnames[i].nr == num) {
             if (scnames[i].result != NULL) {
                 scnames[i].result(&scnames[i], ret);
             } else {
-                if( ret < 0 ) {
+                if (ret < 0) {
                     gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret,
                              strerror(-ret));
                 } else {
@@ -140,52 +203,50 @@ print_syscall_ret(int num, abi_long ret, const struct syscallname *scnames,
             }
             break;
         }
+    }
 }
 
 /*
  * The public interface to this module.
  */
-void
-print_freebsd_syscall(int num,
-                      abi_long arg1, abi_long arg2, abi_long arg3,
-                      abi_long arg4, abi_long arg5, abi_long arg6)
+void print_freebsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5, abi_long arg6)
 {
-    print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames),
-                  arg1, arg2, arg3, arg4, arg5, arg6);
+
+    print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames), arg1, arg2,
+            arg3, arg4, arg5, arg6);
 }
 
-void
-print_freebsd_syscall_ret(int num, abi_long ret)
+void print_freebsd_syscall_ret(int num, abi_long ret)
 {
+
     print_syscall_ret(num, ret, freebsd_scnames, ARRAY_SIZE(freebsd_scnames));
 }
 
-void
-print_netbsd_syscall(int num,
-                      abi_long arg1, abi_long arg2, abi_long arg3,
-                      abi_long arg4, abi_long arg5, abi_long arg6)
+void print_netbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5, abi_long arg6)
 {
+
     print_syscall(num, netbsd_scnames, ARRAY_SIZE(netbsd_scnames),
                   arg1, arg2, arg3, arg4, arg5, arg6);
 }
 
-void
-print_netbsd_syscall_ret(int num, abi_long ret)
+void print_netbsd_syscall_ret(int num, abi_long ret)
 {
+
     print_syscall_ret(num, ret, netbsd_scnames, ARRAY_SIZE(netbsd_scnames));
 }
 
-void
-print_openbsd_syscall(int num,
-                      abi_long arg1, abi_long arg2, abi_long arg3,
-                      abi_long arg4, abi_long arg5, abi_long arg6)
+void print_openbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5, abi_long arg6)
 {
-    print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames),
-                  arg1, arg2, arg3, arg4, arg5, arg6);
+
+    print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames), arg1, arg2,
+            arg3, arg4, arg5, arg6);
 }
 
-void
-print_openbsd_syscall_ret(int num, abi_long ret)
+void print_openbsd_syscall_ret(int num, abi_long ret)
 {
+
     print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
 }
diff --git a/bsd-user/x86_64/syscall.h b/bsd-user/x86_64/syscall.h
index 630514a..4fff6a5 100644
--- a/bsd-user/x86_64/syscall.h
+++ b/bsd-user/x86_64/syscall.h
@@ -1,3 +1,23 @@
+/*
+ *  x86_64 system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _X86_64_SYSCALL_H_
+#define _X86_64_SYSCALL_H_
+
 #define __USER_CS	(0x33)
 #define __USER_DS	(0x2B)
 
@@ -108,9 +128,13 @@ struct target_msqid64_ds {
 #define TARGET_FREEBSD_AMD64_SET_GSBASE	131
 
 
-#define UNAME_MACHINE "x86_64"
+#define UNAME_MACHINE           "x86_64"
+#define TARGET_HW_MACHINE       "amd64"
+#define TARGET_HW_MACHINE_ARCH  "amd64"
 
 #define TARGET_ARCH_SET_GS 0x1001
 #define TARGET_ARCH_SET_FS 0x1002
 #define TARGET_ARCH_GET_FS 0x1003
 #define TARGET_ARCH_GET_GS 0x1004
+
+#endif /* ! _X86_64_SYSCALL_H_ */
diff --git a/bsd-user/x86_64/target_arch_sysarch.h b/bsd-user/x86_64/target_arch_sysarch.h
new file mode 100644
index 0000000..6d09d50
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_sysarch.h
@@ -0,0 +1,76 @@
+/*
+ *  x86_64 sysarch() syscall emulation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUX86State *env, int op,
+        abi_ulong parms)
+{
+    abi_long ret = 0;
+    abi_ulong val;
+    int idx;
+
+    switch (op) {
+    case TARGET_FREEBSD_AMD64_SET_GSBASE:
+    case TARGET_FREEBSD_AMD64_SET_FSBASE:
+        if (op == TARGET_FREEBSD_AMD64_SET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        if (get_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        cpu_x86_load_seg(env, idx, 0);
+        env->segs[idx].base = val;
+        break;
+
+    case TARGET_FREEBSD_AMD64_GET_GSBASE:
+    case TARGET_FREEBSD_AMD64_GET_FSBASE:
+        if (op == TARGET_FREEBSD_AMD64_GET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        val = env->segs[idx].base;
+        if (put_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    /* XXX handle the others... */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", "
+        TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4);
+}
+
+#endif /*! __ARCH_SYSARCH_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 04/19] bsd-user: move target arch and host OS dependent code out of main.c
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (23 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 03/19] bsd-user: move OS/arch dependent code for strace into separate directories Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 05/19] bsd-user: move target arch and host OS dependent code out of syscall.c Stacey Son
                   ` (14 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change moves the cpu initialization and main loop code from
main.c to the OS and arch dependent directories. This eliminates
many of the #ifdef's in main.c. The cpu initialization and loop
code is now located in the arch directory along with target arch
support code.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs                 |    2 +-
 bsd-user/arm/target_arch.h             |   10 +
 bsd-user/arm/target_arch_cpu.c         |   27 +
 bsd-user/arm/target_arch_cpu.h         |  375 +++++++++++++
 bsd-user/arm/target_arch_vmparam.h     |   51 ++
 bsd-user/elfload.c                     |    2 +-
 bsd-user/freebsd/host_os.h             |   46 ++
 bsd-user/freebsd/target_os_vmparam.h   |   23 +
 bsd-user/i386/target_arch.h            |   13 +
 bsd-user/i386/target_arch_cpu.c        |   79 +++
 bsd-user/i386/target_arch_cpu.h        |  302 +++++++++++
 bsd-user/i386/target_arch_vmparam.h    |   28 +
 bsd-user/i386/target_signal.h          |    6 -
 bsd-user/main.c                        |  926 +++++++-------------------------
 bsd-user/mips/target_arch.h            |   10 +
 bsd-user/mips/target_arch_cpu.c        |   27 +
 bsd-user/mips/target_arch_cpu.h        |  257 +++++++++
 bsd-user/mips/target_arch_vmparam.h    |   50 ++
 bsd-user/mips64/target_arch.h          |   10 +
 bsd-user/mips64/target_arch_cpu.c      |   27 +
 bsd-user/mips64/target_arch_cpu.h      |  243 +++++++++
 bsd-user/mips64/target_arch_vmparam.h  |   47 ++
 bsd-user/netbsd/host_os.h              |   31 ++
 bsd-user/openbsd/host_os.h             |   31 ++
 bsd-user/qemu.h                        |   10 +-
 bsd-user/sparc/target_arch.h           |   11 +
 bsd-user/sparc/target_arch_cpu.c       |  113 ++++
 bsd-user/sparc/target_arch_cpu.h       |  158 ++++++
 bsd-user/sparc/target_arch_vmparam.h   |   37 ++
 bsd-user/sparc/target_signal.h         |    5 -
 bsd-user/sparc64/target_arch.h         |   11 +
 bsd-user/sparc64/target_arch_cpu.c     |  118 ++++
 bsd-user/sparc64/target_arch_cpu.h     |  191 +++++++
 bsd-user/sparc64/target_arch_vmparam.h |   37 ++
 bsd-user/sparc64/target_signal.h       |    5 -
 bsd-user/x86_64/target_arch.h          |   13 +
 bsd-user/x86_64/target_arch_cpu.c      |   79 +++
 bsd-user/x86_64/target_arch_cpu.h      |  324 +++++++++++
 bsd-user/x86_64/target_arch_vmparam.h  |   28 +
 bsd-user/x86_64/target_signal.h        |    5 -
 40 files changed, 3004 insertions(+), 764 deletions(-)
 create mode 100644 bsd-user/arm/target_arch.h
 create mode 100644 bsd-user/arm/target_arch_cpu.c
 create mode 100644 bsd-user/arm/target_arch_cpu.h
 create mode 100644 bsd-user/arm/target_arch_vmparam.h
 create mode 100644 bsd-user/freebsd/host_os.h
 create mode 100644 bsd-user/freebsd/target_os_vmparam.h
 create mode 100644 bsd-user/i386/target_arch.h
 create mode 100644 bsd-user/i386/target_arch_cpu.c
 create mode 100644 bsd-user/i386/target_arch_cpu.h
 create mode 100644 bsd-user/i386/target_arch_vmparam.h
 create mode 100644 bsd-user/mips/target_arch.h
 create mode 100644 bsd-user/mips/target_arch_cpu.c
 create mode 100644 bsd-user/mips/target_arch_cpu.h
 create mode 100644 bsd-user/mips/target_arch_vmparam.h
 create mode 100644 bsd-user/mips64/target_arch.h
 create mode 100644 bsd-user/mips64/target_arch_cpu.c
 create mode 100644 bsd-user/mips64/target_arch_cpu.h
 create mode 100644 bsd-user/mips64/target_arch_vmparam.h
 create mode 100644 bsd-user/netbsd/host_os.h
 create mode 100644 bsd-user/openbsd/host_os.h
 create mode 100644 bsd-user/sparc/target_arch.h
 create mode 100644 bsd-user/sparc/target_arch_cpu.c
 create mode 100644 bsd-user/sparc/target_arch_cpu.h
 create mode 100644 bsd-user/sparc/target_arch_vmparam.h
 create mode 100644 bsd-user/sparc64/target_arch.h
 create mode 100644 bsd-user/sparc64/target_arch_cpu.c
 create mode 100644 bsd-user/sparc64/target_arch_cpu.h
 create mode 100644 bsd-user/sparc64/target_arch_vmparam.h
 create mode 100644 bsd-user/x86_64/target_arch.h
 create mode 100644 bsd-user/x86_64/target_arch_cpu.c
 create mode 100644 bsd-user/x86_64/target_arch_cpu.h
 create mode 100644 bsd-user/x86_64/target_arch_vmparam.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 5e77f57..41e8dce 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,2 +1,2 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o
+	        uaccess.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/arm/target_arch.h b/bsd-user/arm/target_arch.h
new file mode 100644
index 0000000..b5c5ddb
--- /dev/null
+++ b/bsd-user/arm/target_arch.h
@@ -0,0 +1,10 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+#include "qemu.h"
+
+void target_cpu_set_tls(CPUARMState *env, target_ulong newtls);
+target_ulong target_cpu_get_tls(CPUARMState *env);
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/arm/target_arch_cpu.c b/bsd-user/arm/target_arch_cpu.c
new file mode 100644
index 0000000..d94a32a
--- /dev/null
+++ b/bsd-user/arm/target_arch_cpu.c
@@ -0,0 +1,27 @@
+/*
+ *  arm cpu related code
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "target_arch.h"
+
+void target_cpu_set_tls(CPUARMState *env, target_ulong newtls)
+{
+    env->cp15.c13_tls2 = newtls;
+}
+
+target_ulong target_cpu_get_tls(CPUARMState *env)
+{
+    return (env->cp15.c13_tls2);
+}
diff --git a/bsd-user/arm/target_arch_cpu.h b/bsd-user/arm/target_arch_cpu.h
new file mode 100644
index 0000000..3eeb34a
--- /dev/null
+++ b/bsd-user/arm/target_arch_cpu.h
@@ -0,0 +1,375 @@
+/*
+ *  arm cpu init and loop
+ *
+ *  Olivier Houchard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+// #define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__)
+#define DEBUG_PRINTF(...)
+
+#define TARGET_DEFAULT_CPU_MODEL "any"
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUARMState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    cpsr_write(env, regs->uregs[16], 0xffffffff);
+    for (i = 0; i < 16; i++) {
+        env->regs[i] = regs->uregs[i];
+    }
+}
+
+static inline int do_strex(CPUARMState *env)
+{
+    uint32_t val;
+    int size;
+    int rc = 1;
+    int segv = 0;
+    uint32_t addr;
+    start_exclusive();
+    addr = env->exclusive_addr;
+    if (addr != env->exclusive_test) {
+        goto fail;
+    }
+    size = env->exclusive_info & 0xf;
+    switch (size) {
+    case 0:
+        segv = get_user_u8(val, addr);
+        break;
+    case 1:
+        segv = get_user_u16(val, addr);
+        break;
+    case 2:
+    case 3:
+        segv = get_user_u32(val, addr);
+        break;
+    default:
+        abort();
+    }
+    if (segv) {
+        env->cp15.c6_data = addr;
+        goto done;
+    }
+    if (val != env->exclusive_val) {
+        goto fail;
+    }
+    if (size == 3) {
+        segv = get_user_u32(val, addr + 4);
+        if (segv) {
+            env->cp15.c6_data = addr + 4;
+            goto done;
+        }
+        if (val != env->exclusive_high) {
+            goto fail;
+        }
+    }
+    val = env->regs[(env->exclusive_info >> 8) & 0xf];
+    switch (size) {
+    case 0:
+        segv = put_user_u8(val, addr);
+        break;
+    case 1:
+        segv = put_user_u16(val, addr);
+        break;
+    case 2:
+    case 3:
+        segv = put_user_u32(val, addr);
+        break;
+    }
+    if (segv) {
+        env->cp15.c6_data = addr;
+        goto done;
+    }
+    if (size == 3) {
+        val = env->regs[(env->exclusive_info >> 12) & 0xf];
+        segv = put_user_u32(val, addr + 4);
+        if (segv) {
+            env->cp15.c6_data = addr + 4;
+            goto done;
+        }
+    }
+    rc = 0;
+fail:
+    env->regs[15] += 4;
+    env->regs[(env->exclusive_info >> 4) & 0xf] = rc;
+done:
+    end_exclusive();
+    return segv;
+}
+
+static inline void target_cpu_loop(CPUARMState *env)
+{
+    int trapnr;
+    target_siginfo_t info;
+    unsigned int n;
+    uint32_t addr;
+    CPUState *cs = CPU(arm_env_get_cpu(env));
+
+    for (;;) {
+        DEBUG_PRINTF("CPU_LOOPING\n");
+        cpu_exec_start(cs);
+        DEBUG_PRINTF("EXECUTING...\n");
+        trapnr = cpu_arm_exec(env);
+        DEBUG_PRINTF("trapnr %d\n", trapnr);
+        cpu_exec_end(cs);
+        switch (trapnr) {
+        case EXCP_UDEF:
+            {
+                /* See arm/arm/undefined.c undefinedinstruction(); */
+                info.si_addr = env->regs[15];
+
+                /*
+                 * Make sure the PC is correctly aligned. (It should
+                 * be.)
+                 */
+                if ((info.si_addr & 3) != 0) {
+                    info.si_signo = SIGILL;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_ILL_ILLADR;
+                    queue_signal(env, info.si_signo, &info);
+                } else {
+                    int rc = 0;
+#ifdef NOT_YET
+                    uint32_t opcode;
+
+                    /*
+                     * Get the opcode.
+                     *
+                     * FIXME - what to do if get_user() fails?
+                     */
+                    get_user_u32(opcode, env->regs[15]);
+
+                    /* Check the opcode with CP handlers we may have. */
+                    rc = EmulateAll(opcode, &ts-fpa, env);
+#endif /* NOT_YET */
+                    if (rc == 0) {
+                        /* illegal instruction */
+                        info.si_signo = SIGILL;
+                        info.si_errno = 0;
+                        info.si_code = TARGET_ILL_ILLOPC;
+                        queue_signal(env, info.si_signo, &info);
+                    }
+                }
+            }
+            break;
+        case EXCP_SWI:
+        case EXCP_BKPT:
+            {
+                unsigned int insn;
+#ifdef FREEBSD_ARM_OABI
+                env->eabi = 0;
+#else
+                env->eabi = 1;
+#endif
+                /*
+                 * system call
+                 * See arm/arm/trap.c cpu_fetch_syscall_args()
+                 */
+                if (trapnr == EXCP_BKPT) {
+                    if (env->thumb) {
+                        if (env->eabi) {
+                            n = env->regs[7];
+                        } else {
+                            /* FIXME - what to do if get_user() fails? */
+                            get_user_u16(insn, env->regs[15]);
+                            n = insn & 0xff;
+                        }
+                        env->regs[15] += 2;
+                    } else {
+                        if (env->eabi) {
+                            n = env->regs[7];
+                        } else {
+                            /* FIXME - what to do if get_user() fails? */
+                            get_user_u32(insn, env->regs[15]);
+                            n = (insn & 0xf) | ((insn >> 4) & 0xff0);
+                        }
+                        env->regs[15] += 4;
+                    }
+                } else { /* trapnr != EXCP_BKPT */
+                    if (env->thumb) {
+                        if (env->eabi) {
+                            n = env->regs[7];
+                        } else {
+                            /* FIXME - what to do if get_user() fails? */
+                            get_user_u16(insn, env->regs[15] - 2);
+                            n = insn & 0xff;
+                        }
+                    } else {
+                        if (env->eabi) {
+                            n = env->regs[7];
+                        } else {
+                            /* FIXME - what to do if get_user() fails? */
+                            get_user_u32(insn, env->regs[15] - 4);
+                            n = insn & 0xffffff;
+                        }
+                    }
+                }
+                DEBUG_PRINTF("AVANT CALL %d\n", n);
+                if (bsd_type == target_freebsd) {
+                    int ret;
+                    abi_ulong params = get_sp_from_cpustate(env);
+                    int32_t syscall_nr = n;
+                    int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+                    /* See arm/arm/trap.c cpu_fetch_syscall_args() */
+                    if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                        syscall_nr = env->regs[0];
+                        arg1 = env->regs[1];
+                        arg2 = env->regs[2];
+                        arg3 = env->regs[3];
+                        get_user_s32(arg4, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg5, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg6, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg7, params);
+                        arg8 = 0;
+                    } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+#ifdef TARGET_WORDS_BIGENDIAN
+                        syscall_nr = env->regs[1];
+#else
+                        syscall_nr = env->regs[0];
+#endif
+                        arg1 = env->regs[2];
+                        arg2 = env->regs[3];
+                        get_user_s32(arg3, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg4, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg5, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg6, params);
+                        arg7 = 0;
+                        arg8 = 0;
+                    } else {
+                        arg1 = env->regs[0];
+                        arg2 = env->regs[1];
+                        arg3 = env->regs[2];
+                        arg4 = env->regs[3];
+                        get_user_s32(arg5, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg6, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg7, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg8, params);
+                    }
+                    ret = do_freebsd_syscall(env, syscall_nr, arg1, arg2, arg3,
+                            arg4, arg5, arg6, arg7, arg8);
+                    /*
+                     * Compare to arm/arm/vm_machdep.c
+                     * cpu_set_syscall_retval()
+                     */
+                    /* XXX armeb may need some extra magic here */
+                    if (-TARGET_EJUSTRETURN == ret) {
+                        /*
+                         * Returning from a successful sigreturn syscall.
+                         * Avoid clobbering register state.
+                         */
+                        break;
+                    }
+                    /*
+                     * XXX Need to handle ERESTART. Backup the PC by
+                     * 1 instruction.
+                     */
+                    if ((unsigned int)ret >= (unsigned int)(-515)) {
+                        ret = -ret;
+                        cpsr_write(env, CPSR_C, CPSR_C);
+                        env->regs[0] = ret;
+                    } else {
+                        cpsr_write(env, 0, CPSR_C);
+                        env->regs[0] = ret; /* XXX need to handle lseek()? */
+                        /* env->regs[1] = 0; */
+                    }
+                } /* else if (bsd_type == target_openbsd)... */
+                else {
+                    fprintf(stderr, "qemu: bsd_type (= %d) syscall "
+                            "not supported\n", bsd_type);
+                }
+                DEBUG_PRINTF("APRES CALL\n");
+            }
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_PREFETCH_ABORT:
+            /* See arm/arm/trap.c prefetch_abort_handler() */
+            addr = env->cp15.c6_insn;
+            goto do_segv;
+        case EXCP_DATA_ABORT:
+            /* See arm/arm/trap.c data_abort_handler() */
+            addr = env->cp15.c6_data;
+        do_segv:
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = 0;
+                info.si_addr = addr;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                }
+            }
+            break;
+        /* XXX case EXCP_KERNEL_TRAP: */
+        case EXCP_STREX:
+            if (do_strex(env)) {
+                addr = env->cp15.c6_data;
+                goto do_segv;
+            }
+            break;
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+                    trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            abort();
+        } /* switch() */
+        process_pending_signals(env);
+    } /* for (;;) */
+}
+
+static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[13] = newsp;
+    env->regs[0] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+}
+
+#endif /* !_TARGET_ARCH_CPU_H */
diff --git a/bsd-user/arm/target_arch_vmparam.h b/bsd-user/arm/target_arch_vmparam.h
new file mode 100644
index 0000000..a4f8ee3
--- /dev/null
+++ b/bsd-user/arm/target_arch_vmparam.h
@@ -0,0 +1,51 @@
+/*
+ *  arm VM parameters definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to sys/arm/include/vmparam.h */
+#define TARGET_MAXTSIZ      (64UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ      (128UL*1024*1024)   /* initial data size limit */
+#define TARGET_MAXDSIZ      (512UL*1024*1024)    /* max data size */
+#define TARGET_DFLSSIZ      (2UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ      (8UL*1024*1024)    /* max stack size */
+#define TARGET_SGROWSIZ     (128UL*1024)        /* amount to grow stack */
+
+#define TARGET_RESERVED_VA  0xf7000000
+
+                /* KERNBASE - 512 MB */
+#define TARGET_VM_MAXUSER_ADDRESS   (0xc0000000 - (512 * 1024 * 1024))
+#define TARGET_USRSTACK             TARGET_VM_MAXUSER_ADDRESS
+
+#define TARGET_SPACE_USRSPACE   4096
+#define TARGET_ARG_MAX          262144
+
+static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
+{
+    return state->regs[13]; /* sp */
+}
+
+static inline void set_second_rval(CPUARMState *state, abi_ulong retval2)
+{
+    state->regs[1] = retval2;
+}
+
+#endif  /* ! _TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 93fd9e4..ccf72d1 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -674,7 +674,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
     /* Create enough stack to hold everything.  If we don't use
      * it for args, we'll use it for something else...
      */
-    size = x86_stack_size;
+    size = target_dflssiz;
     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
     error = target_mmap(0,
diff --git a/bsd-user/freebsd/host_os.h b/bsd-user/freebsd/host_os.h
new file mode 100644
index 0000000..efe2351
--- /dev/null
+++ b/bsd-user/freebsd/host_os.h
@@ -0,0 +1,46 @@
+/*
+ *  FreeBSD host dependent code and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST_OS_H_
+#define __HOST_OS_H_
+
+#include <stdio.h>
+#include <sys/sysctl.h>
+
+#include "qemu.h"
+
+#define HOST_DEFAULT_BSD_TYPE target_freebsd
+
+static inline void save_proc_pathname(char *argv0)
+{
+    int mib[4];
+    size_t len;
+
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_PATHNAME;
+    mib[3] = -1;
+
+    len = PATH_MAX;
+    if (sysctl(mib, 4, qemu_proc_pathname, &len, NULL, 0)) {
+        perror("sysctl");
+    }
+}
+
+#endif /*!__HOST_OS_H_ */
diff --git a/bsd-user/freebsd/target_os_vmparam.h b/bsd-user/freebsd/target_os_vmparam.h
new file mode 100644
index 0000000..80ac6c8
--- /dev/null
+++ b/bsd-user/freebsd/target_os_vmparam.h
@@ -0,0 +1,23 @@
+#ifndef _TARGET_OS_VMPARAM_H_
+#define _TARGET_OS_VMPARAM_H_
+
+#include "target_arch_vmparam.h"
+
+#define TARGET_SPACE_USRSPACE   4096
+#define TARGET_ARG_MAX          262144
+
+/* Compare to sys/exec.h */
+struct target_ps_strings {
+    abi_ulong ps_argvstr;
+    uint32_t ps_nargvstr;
+    abi_ulong ps_envstr;
+    uint32_t ps_nenvstr;
+};
+
+extern abi_ulong target_stkbas;
+extern abi_ulong target_stksiz;
+
+#define TARGET_PS_STRINGS  ((target_stkbas + target_stksiz) - \
+		sizeof(struct target_ps_strings))
+
+#endif /* !TARGET_OS_VMPARAM_H_ */
diff --git a/bsd-user/i386/target_arch.h b/bsd-user/i386/target_arch.h
new file mode 100644
index 0000000..4cb398c
--- /dev/null
+++ b/bsd-user/i386/target_arch.h
@@ -0,0 +1,13 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+/* target_arch_cpu.c */
+void bsd_i386_write_dt(void *ptr, unsigned long addr, unsigned long limit,
+                int flags);
+void bsd_i386_set_idt(int n, unsigned int dpl);
+void bsd_i386_set_idt_base(uint64_t base);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* ! _TARGET_ARCH_H_ */
diff --git a/bsd-user/i386/target_arch_cpu.c b/bsd-user/i386/target_arch_cpu.c
new file mode 100644
index 0000000..2e0eec0
--- /dev/null
+++ b/bsd-user/i386/target_arch_cpu.c
@@ -0,0 +1,79 @@
+/*
+ *  i386 cpu related code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+#include "qemu/timer.h"
+
+#include "target_arch.h"
+
+static uint64_t *idt_table;
+
+/* CPUX86 core interface */
+void cpu_smm_update(CPUX86State *env)
+{
+}
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+    return cpu_get_real_ticks();
+}
+
+int cpu_get_pic_interrupt(CPUX86State *env)
+{
+    return -1;
+}
+
+void bsd_i386_write_dt(void *ptr, unsigned long addr, unsigned long limit,
+                     int flags)
+{
+    unsigned int e1, e2;
+    uint32_t *p;
+    e1 = (addr << 16) | (limit & 0xffff);
+    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+    e2 |= flags;
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+                     uint32_t addr, unsigned int sel)
+{
+    uint32_t *p, e1, e2;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+/* only dpl matters as we do only user space emulation */
+void bsd_i386_set_idt(int n, unsigned int dpl)
+{
+    set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+
+void bsd_i386_set_idt_base(uint64_t base)
+{
+    idt_table = g2h(base);
+}
+
diff --git a/bsd-user/i386/target_arch_cpu.h b/bsd-user/i386/target_arch_cpu.h
new file mode 100644
index 0000000..c3df814
--- /dev/null
+++ b/bsd-user/i386/target_arch_cpu.h
@@ -0,0 +1,302 @@
+/*
+ *  i386 cpu init and loop
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "qemu32"
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUX86State *env,
+        struct target_pt_regs *regs)
+{
+    uint64_t *gdt_table;
+
+    cpu_x86_set_cpl(env, 3);
+
+    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+    env->hflags |= HF_PE_MASK;
+    if (env->features[FEAT_1_EDX] & CPUID_SSE) {
+        env->cr[4] |= CR4_OSFXSR_MASK;
+        env->hflags |= HF_OSFXSR_MASK;
+    }
+
+    /* flags setup : we activate the IRQs by default as in user mode */
+    env->eflags |= IF_MASK;
+
+    /* register setup */
+    env->regs[R_EAX] = regs->eax;
+    env->regs[R_EBX] = regs->ebx;
+    env->regs[R_ECX] = regs->ecx;
+    env->regs[R_EDX] = regs->edx;
+    env->regs[R_ESI] = regs->esi;
+    env->regs[R_EDI] = regs->edi;
+    env->regs[R_EBP] = regs->ebp;
+    env->regs[R_ESP] = regs->esp;
+    env->eip = regs->eip;
+
+    /* interrupt setup */
+    env->idt.limit = 255;
+
+    env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+        PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    bsd_i386_set_idt_base(env->idt.base);
+    bsd_i386_set_idt(0, 0);
+    bsd_i386_set_idt(1, 0);
+    bsd_i386_set_idt(2, 0);
+    bsd_i386_set_idt(3, 3);
+    bsd_i386_set_idt(4, 3);
+    bsd_i386_set_idt(5, 0);
+    bsd_i386_set_idt(6, 0);
+    bsd_i386_set_idt(7, 0);
+    bsd_i386_set_idt(8, 0);
+    bsd_i386_set_idt(9, 0);
+    bsd_i386_set_idt(10, 0);
+    bsd_i386_set_idt(11, 0);
+    bsd_i386_set_idt(12, 0);
+    bsd_i386_set_idt(13, 0);
+    bsd_i386_set_idt(14, 0);
+    bsd_i386_set_idt(15, 0);
+    bsd_i386_set_idt(16, 0);
+    bsd_i386_set_idt(17, 0);
+    bsd_i386_set_idt(18, 0);
+    bsd_i386_set_idt(19, 0);
+    bsd_i386_set_idt(0x80, 3);
+
+    /* segment setup */
+    env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+            PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+    gdt_table = g2h(env->gdt.base);
+
+    bsd_i386_write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+            (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+
+    bsd_i386_write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+            (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+
+    cpu_x86_load_seg(env, R_CS, __USER_CS);
+    cpu_x86_load_seg(env, R_SS, __USER_DS);
+    cpu_x86_load_seg(env, R_DS, __USER_DS);
+    cpu_x86_load_seg(env, R_ES, __USER_DS);
+    cpu_x86_load_seg(env, R_FS, __USER_DS);
+    cpu_x86_load_seg(env, R_GS, __USER_DS);
+    /* This hack makes Wine work... */
+    env->segs[R_FS].selector = 0;
+}
+
+static inline void target_cpu_loop(CPUX86State *env)
+{
+    int trapnr;
+    abi_ulong pc;
+    /* target_siginfo_t info; */
+
+    for (;;) {
+        trapnr = cpu_x86_exec(env);
+        switch (trapnr) {
+        case 0x80:
+            /* syscall from int $0x80 */
+            if (bsd_type == target_freebsd) {
+                abi_ulong params = (abi_ulong) env->regs[R_ESP] +
+                    sizeof(int32_t);
+                int32_t syscall_nr = env->regs[R_EAX];
+                int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+                if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int32_t);
+                } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int64_t);
+                }
+                get_user_s32(arg1, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg2, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg3, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg4, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg5, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg6, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg7, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg8, params);
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      syscall_nr,
+                                                      arg1,
+                                                      arg2,
+                                                      arg3,
+                                                      arg4,
+                                                      arg5,
+                                                      arg6,
+                                                      arg7,
+                                                      arg8);
+            } else { /* if (bsd_type == target_openbsd) */
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EBX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_EBP]);
+            }
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
+            break;
+
+#if 0
+        case EXCP0B_NOSEG:
+        case EXCP0C_STACK:
+            info.si_signo = SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP0D_GPF:
+            /* XXX: potential problem if ABI32 */
+            if (env->eflags & VM_MASK) {
+                handle_vm86_fault(env);
+            } else {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+
+        case EXCP0E_PAGE:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            if (!(env->error_code & 1)) {
+                info.si_code = TARGET_SEGV_MAPERR;
+            } else {
+                info.si_code = TARGET_SEGV_ACCERR;
+            }
+            info._sifields._sigfault._addr = env->cr[2];
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP00_DIVZ:
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else {
+                /* division by zero */
+                info.si_signo = SIGFPE;
+                info.si_errno = 0;
+                info.si_code = TARGET_FPE_INTDIV;
+                info._sifields._sigfault._addr = env->eip;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+
+        case EXCP01_DB:
+        case EXCP03_INT3:
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else {
+                info.si_signo = SIGTRAP;
+                info.si_errno = 0;
+                if (trapnr == EXCP01_DB) {
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    info._sifields._sigfault._addr = env->eip;
+                } else {
+                    info.si_code = TARGET_SI_KERNEL;
+                    info._sifields._sigfault._addr = 0;
+                }
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+
+        case EXCP04_INTO:
+        case EXCP05_BOUND:
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+
+        case EXCP06_ILLOP:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(env, info.si_signo, &info);
+            break;
+#endif
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+#if 0
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(env, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                }
+            }
+            break;
+#endif
+        default:
+            pc = env->segs[R_CS].base + env->eip;
+            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - "
+                    "aborting\n", (long)pc, trapnr);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[R_ESP] = newsp;
+    env->regs[R_EAX] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+    cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/i386/target_arch_vmparam.h b/bsd-user/i386/target_arch_vmparam.h
new file mode 100644
index 0000000..f15af91
--- /dev/null
+++ b/bsd-user/i386/target_arch_vmparam.h
@@ -0,0 +1,28 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to i386/include/vmparam.h */
+#define TARGET_MAXTSIZ  (128UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ  (128UL*1024*1024)   /* initial data size limit */
+#define TARGET_MAXDSIZ  (512UL*1024*1024)   /* max data size */
+#define TARGET_DFLSSIZ  (8UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ  (64UL*1024*1024)    /* max stack size */
+#define TARGET_SGROWSIZ (128UL*1024)        /* amount to grow stack */
+
+#define TARGET_RESERVED_VA 0xf7000000
+
+#define TARGET_USRSTACK (0xbfc00000)
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+    return state->regs[R_ESP];
+}
+
+static inline void set_second_rval(CPUX86State *state, abi_ulong retval2)
+{
+    state->regs[R_EDX] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/i386/target_signal.h b/bsd-user/i386/target_signal.h
index 2ef36d1..5491687 100644
--- a/bsd-user/i386/target_signal.h
+++ b/bsd-user/i386/target_signal.h
@@ -11,10 +11,4 @@ typedef struct target_sigaltstack {
 	abi_ulong ss_size;
 } target_stack_t;
 
-
-static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
-{
-    return state->regs[R_ESP];
-}
-
 #endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/main.c b/bsd-user/main.c
index f9246aa..fa42456 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -1,7 +1,8 @@
 /*
- *  qemu user main
+ *  qemu bsd user main
  *
  *  Copyright (c) 2003-2008 Fabrice Bellard
+ *  Copyright (c) 2013 Stacey Son
  *
  *  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
@@ -23,652 +24,183 @@
 #include <errno.h>
 #include <unistd.h>
 #include <machine/trap.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
 #include <sys/mman.h>
 
 #include "qemu.h"
 #include "qemu-common.h"
-/* For tb_lock */
 #include "cpu.h"
 #include "tcg.h"
 #include "qemu/timer.h"
 #include "qemu/envlist.h"
 
+#include "host_os.h"
+#include "target_arch_cpu.h"
+
 int singlestep;
-#if defined(CONFIG_USE_GUEST_BASE)
+static const char *cpu_model;
 unsigned long mmap_min_addr;
+#if defined(CONFIG_USE_GUEST_BASE)
 unsigned long guest_base;
 int have_guest_base;
+#if (TARGET_LONG_BITS == 32) && (HOST_LONG_BITS == 64)
+/*
+ * When running 32-on-64 we should make sure we can fit all of the possible
+ * guest address space into a contiguous chunk of virtual host memory.
+ *
+ * This way we will never overlap with our own libraries or binaries or stack
+ * or anything else that QEMU maps.
+ */
+unsigned long reserved_va = TARGET_RESERVED_VA;
+#else
 unsigned long reserved_va;
 #endif
+#endif /* CONFIG_USE_GUEST_BASE */
 
 static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 extern char **environ;
 enum BSDType bsd_type;
 
-/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
-   we allocate a bigger stack. Need a better solution, for example
-   by remapping the process stack directly at the right place */
-unsigned long x86_stack_size = 512 * 1024;
-
-void gemu_log(const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-}
-
-#if defined(TARGET_I386)
-int cpu_get_pic_interrupt(CPUX86State *env)
-{
-    return -1;
-}
-#endif
-
-/* These are no-ops because we are not threadsafe.  */
-static inline void cpu_exec_start(CPUArchState *env)
-{
-}
+unsigned long target_maxtsiz = TARGET_MAXTSIZ;   /* max text size */
+unsigned long target_dfldsiz = TARGET_DFLDSIZ;   /* initial data size limit */
+unsigned long target_maxdsiz = TARGET_MAXDSIZ;   /* max data size */
+unsigned long target_dflssiz = TARGET_DFLSSIZ;   /* initial data size limit */
+unsigned long target_maxssiz = TARGET_MAXSSIZ;   /* max stack size */
+unsigned long target_sgrowsiz = TARGET_SGROWSIZ; /* amount to grow stack */
 
-static inline void cpu_exec_end(CPUArchState *env)
-{
-}
+char qemu_proc_pathname[PATH_MAX];  /* full path to exeutable */
 
-static inline void start_exclusive(void)
-{
-}
+/* Helper routines for implementing atomic operations. */
 
-static inline void end_exclusive(void)
-{
-}
+/*
+ * To implement exclusive operations we force all cpus to synchronize.
+ * We don't require a full sync, only that no cpus are executing guest code.
+ * The alternative is to map target atomic ops onto host eqivalents,
+ * which requires quite a lot of per host/target work.
+ */
+static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
+static int pending_cpus;
 
+/* Make sure everything is in a consistent state for calling fork(). */
 void fork_start(void)
 {
+    pthread_mutex_lock(&tcg_ctx.tb_ctx.tb_lock);
+    pthread_mutex_lock(&exclusive_lock);
+    mmap_fork_start();
 }
 
 void fork_end(int child)
 {
+    mmap_fork_end(child);
     if (child) {
+        CPUState *cpu, *next_cpu;
+        /*
+         * Child processes created by fork() only have a single thread.
+         * Discard information about the parent threads.
+         */
+        CPU_FOREACH_SAFE(cpu, next_cpu) {
+            if (cpu != thread_cpu) {
+                QTAILQ_REMOVE(&cpus, thread_cpu, node);
+            }
+        }
+        pending_cpus = 0;
+        pthread_mutex_init(&exclusive_lock, NULL);
+        pthread_mutex_init(&cpu_list_mutex, NULL);
+        pthread_cond_init(&exclusive_cond, NULL);
+        pthread_cond_init(&exclusive_resume, NULL);
+        pthread_mutex_init(&tcg_ctx.tb_ctx.tb_lock, NULL);
         gdbserver_fork((CPUArchState *)thread_cpu->env_ptr);
+    } else {
+        pthread_mutex_unlock(&exclusive_lock);
+        pthread_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
     }
 }
 
-void cpu_list_lock(void)
+/*
+ * Wait for pending exclusive operations to complete.  The exclusive lock
+ * must be held.
+ */
+static inline void exclusive_idle(void)
 {
+    while (pending_cpus) {
+        pthread_cond_wait(&exclusive_resume, &exclusive_lock);
+    }
 }
 
-void cpu_list_unlock(void)
+/* Start an exclusive operation.  Must only be called outside of cpu_exec. */
+void start_exclusive(void)
 {
-}
+    CPUState *other_cpu;
 
-#ifdef TARGET_I386
-/***********************************************************/
-/* CPUX86 core interface */
+    pthread_mutex_lock(&exclusive_lock);
+    exclusive_idle();
 
-void cpu_smm_update(CPUX86State *env)
-{
-}
-
-uint64_t cpu_get_tsc(CPUX86State *env)
-{
-    return cpu_get_real_ticks();
+    pending_cpus = 1;
+    /* Make all other cpus stop executing. */
+    CPU_FOREACH(other_cpu) {
+        if (other_cpu->running) {
+            pending_cpus++;
+            cpu_exit(other_cpu);
+        }
+    }
+    if (pending_cpus > 1) {
+        pthread_cond_wait(&exclusive_cond, &exclusive_lock);
+    }
 }
 
-static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
-                     int flags)
+/* Finish an exclusive operation. */
+void end_exclusive(void)
 {
-    unsigned int e1, e2;
-    uint32_t *p;
-    e1 = (addr << 16) | (limit & 0xffff);
-    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
-    e2 |= flags;
-    p = ptr;
-    p[0] = tswap32(e1);
-    p[1] = tswap32(e2);
+    pending_cpus = 0;
+    pthread_cond_broadcast(&exclusive_resume);
+    pthread_mutex_unlock(&exclusive_lock);
 }
 
-static uint64_t *idt_table;
-#ifdef TARGET_X86_64
-static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
-                       uint64_t addr, unsigned int sel)
-{
-    uint32_t *p, e1, e2;
-    e1 = (addr & 0xffff) | (sel << 16);
-    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
-    p = ptr;
-    p[0] = tswap32(e1);
-    p[1] = tswap32(e2);
-    p[2] = tswap32(addr >> 32);
-    p[3] = 0;
-}
-/* only dpl matters as we do only user space emulation */
-static void set_idt(int n, unsigned int dpl)
+/* Wait for exclusive ops to finish, and begin cpu execution. */
+void cpu_exec_start(CPUState *cpu)
 {
-    set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
-}
-#else
-static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
-                     uint32_t addr, unsigned int sel)
-{
-    uint32_t *p, e1, e2;
-    e1 = (addr & 0xffff) | (sel << 16);
-    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
-    p = ptr;
-    p[0] = tswap32(e1);
-    p[1] = tswap32(e2);
+    pthread_mutex_lock(&exclusive_lock);
+    exclusive_idle();
+    cpu->running = true;
+    pthread_mutex_unlock(&exclusive_lock);
 }
 
-/* only dpl matters as we do only user space emulation */
-static void set_idt(int n, unsigned int dpl)
+/* Mark cpu as not excuting, and release pending exclusive ops. */
+void cpu_exec_end(CPUState *cpu)
 {
-    set_gate(idt_table + n, 0, dpl, 0, 0);
-}
-#endif
-
-void cpu_loop(CPUX86State *env)
-{
-    int trapnr;
-    abi_ulong pc;
-    //target_siginfo_t info;
-
-    for(;;) {
-        trapnr = cpu_x86_exec(env);
-        switch(trapnr) {
-        case 0x80:
-            /* syscall from int $0x80 */
-            if (bsd_type == target_freebsd) {
-                abi_ulong params = (abi_ulong) env->regs[R_ESP] +
-                    sizeof(int32_t);
-                int32_t syscall_nr = env->regs[R_EAX];
-                int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
-
-                if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
-                    get_user_s32(syscall_nr, params);
-                    params += sizeof(int32_t);
-                } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
-                    get_user_s32(syscall_nr, params);
-                    params += sizeof(int64_t);
-                }
-                get_user_s32(arg1, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg2, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg3, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg4, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg5, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg6, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg7, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg8, params);
-                env->regs[R_EAX] = do_freebsd_syscall(env,
-                                                      syscall_nr,
-                                                      arg1,
-                                                      arg2,
-                                                      arg3,
-                                                      arg4,
-                                                      arg5,
-                                                      arg6,
-                                                      arg7,
-                                                      arg8);
-            } else { //if (bsd_type == target_openbsd)
-                env->regs[R_EAX] = do_openbsd_syscall(env,
-                                                      env->regs[R_EAX],
-                                                      env->regs[R_EBX],
-                                                      env->regs[R_ECX],
-                                                      env->regs[R_EDX],
-                                                      env->regs[R_ESI],
-                                                      env->regs[R_EDI],
-                                                      env->regs[R_EBP]);
-            }
-            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
-                env->regs[R_EAX] = -env->regs[R_EAX];
-                env->eflags |= CC_C;
-            } else {
-                env->eflags &= ~CC_C;
-            }
-            break;
-#ifndef TARGET_ABI32
-        case EXCP_SYSCALL:
-            /* syscall from syscall instruction */
-            if (bsd_type == target_freebsd)
-                env->regs[R_EAX] = do_freebsd_syscall(env,
-                                                      env->regs[R_EAX],
-                                                      env->regs[R_EDI],
-                                                      env->regs[R_ESI],
-                                                      env->regs[R_EDX],
-                                                      env->regs[R_ECX],
-                                                      env->regs[8],
-                                                      env->regs[9], 0, 0);
-            else { //if (bsd_type == target_openbsd)
-                env->regs[R_EAX] = do_openbsd_syscall(env,
-                                                      env->regs[R_EAX],
-                                                      env->regs[R_EDI],
-                                                      env->regs[R_ESI],
-                                                      env->regs[R_EDX],
-                                                      env->regs[10],
-                                                      env->regs[8],
-                                                      env->regs[9]);
-            }
-            env->eip = env->exception_next_eip;
-            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
-                env->regs[R_EAX] = -env->regs[R_EAX];
-                env->eflags |= CC_C;
-            } else {
-                env->eflags &= ~CC_C;
-            }
-            break;
-#endif
-#if 0
-        case EXCP0B_NOSEG:
-        case EXCP0C_STACK:
-            info.si_signo = SIGBUS;
-            info.si_errno = 0;
-            info.si_code = TARGET_SI_KERNEL;
-            info._sifields._sigfault._addr = 0;
-            queue_signal(env, info.si_signo, &info);
-            break;
-        case EXCP0D_GPF:
-            /* XXX: potential problem if ABI32 */
-#ifndef TARGET_X86_64
-            if (env->eflags & VM_MASK) {
-                handle_vm86_fault(env);
-            } else
-#endif
-            {
-                info.si_signo = SIGSEGV;
-                info.si_errno = 0;
-                info.si_code = TARGET_SI_KERNEL;
-                info._sifields._sigfault._addr = 0;
-                queue_signal(env, info.si_signo, &info);
-            }
-            break;
-        case EXCP0E_PAGE:
-            info.si_signo = SIGSEGV;
-            info.si_errno = 0;
-            if (!(env->error_code & 1))
-                info.si_code = TARGET_SEGV_MAPERR;
-            else
-                info.si_code = TARGET_SEGV_ACCERR;
-            info._sifields._sigfault._addr = env->cr[2];
-            queue_signal(env, info.si_signo, &info);
-            break;
-        case EXCP00_DIVZ:
-#ifndef TARGET_X86_64
-            if (env->eflags & VM_MASK) {
-                handle_vm86_trap(env, trapnr);
-            } else
-#endif
-            {
-                /* division by zero */
-                info.si_signo = SIGFPE;
-                info.si_errno = 0;
-                info.si_code = TARGET_FPE_INTDIV;
-                info._sifields._sigfault._addr = env->eip;
-                queue_signal(env, info.si_signo, &info);
-            }
-            break;
-        case EXCP01_DB:
-        case EXCP03_INT3:
-#ifndef TARGET_X86_64
-            if (env->eflags & VM_MASK) {
-                handle_vm86_trap(env, trapnr);
-            } else
-#endif
-            {
-                info.si_signo = SIGTRAP;
-                info.si_errno = 0;
-                if (trapnr == EXCP01_DB) {
-                    info.si_code = TARGET_TRAP_BRKPT;
-                    info._sifields._sigfault._addr = env->eip;
-                } else {
-                    info.si_code = TARGET_SI_KERNEL;
-                    info._sifields._sigfault._addr = 0;
-                }
-                queue_signal(env, info.si_signo, &info);
-            }
-            break;
-        case EXCP04_INTO:
-        case EXCP05_BOUND:
-#ifndef TARGET_X86_64
-            if (env->eflags & VM_MASK) {
-                handle_vm86_trap(env, trapnr);
-            } else
-#endif
-            {
-                info.si_signo = SIGSEGV;
-                info.si_errno = 0;
-                info.si_code = TARGET_SI_KERNEL;
-                info._sifields._sigfault._addr = 0;
-                queue_signal(env, info.si_signo, &info);
-            }
-            break;
-        case EXCP06_ILLOP:
-            info.si_signo = SIGILL;
-            info.si_errno = 0;
-            info.si_code = TARGET_ILL_ILLOPN;
-            info._sifields._sigfault._addr = env->eip;
-            queue_signal(env, info.si_signo, &info);
-            break;
-#endif
-        case EXCP_INTERRUPT:
-            /* just indicate that signals should be handled asap */
-            break;
-#if 0
-        case EXCP_DEBUG:
-            {
-                int sig;
-
-                sig = gdb_handlesig (env, TARGET_SIGTRAP);
-                if (sig)
-                  {
-                    info.si_signo = sig;
-                    info.si_errno = 0;
-                    info.si_code = TARGET_TRAP_BRKPT;
-                    queue_signal(env, info.si_signo, &info);
-                  }
-            }
-            break;
-#endif
-        default:
-            pc = env->segs[R_CS].base + env->eip;
-            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
-                    (long)pc, trapnr);
-            abort();
+    pthread_mutex_lock(&exclusive_lock);
+    cpu->running = false;
+    if (pending_cpus > 1) {
+        pending_cpus--;
+        if (pending_cpus == 1) {
+            pthread_cond_signal(&exclusive_cond);
         }
-        process_pending_signals(env);
     }
+    exclusive_idle();
+    pthread_mutex_unlock(&exclusive_lock);
 }
-#endif
-
-#ifdef TARGET_SPARC
-#define SPARC64_STACK_BIAS 2047
-
-//#define DEBUG_WIN
-/* WARNING: dealing with register windows _is_ complicated. More info
-   can be found at http://www.sics.se/~psm/sparcstack.html */
-static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
-{
-    index = (index + cwp * 16) % (16 * env->nwindows);
-    /* wrap handling : if cwp is on the last window, then we use the
-       registers 'after' the end */
-    if (index < 8 && env->cwp == env->nwindows - 1)
-        index += 16 * env->nwindows;
-    return index;
-}
-
-/* save the register window 'cwp1' */
-static inline void save_window_offset(CPUSPARCState *env, int cwp1)
-{
-    unsigned int i;
-    abi_ulong sp_ptr;
 
-    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
-#ifdef TARGET_SPARC64
-    if (sp_ptr & 3)
-        sp_ptr += SPARC64_STACK_BIAS;
-#endif
-#if defined(DEBUG_WIN)
-    printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
-           sp_ptr, cwp1);
-#endif
-    for(i = 0; i < 16; i++) {
-        /* FIXME - what to do if put_user() fails? */
-        put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
-        sp_ptr += sizeof(abi_ulong);
-    }
-}
-
-static void save_window(CPUSPARCState *env)
+void cpu_list_lock(void)
 {
-#ifndef TARGET_SPARC64
-    unsigned int new_wim;
-    new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
-        ((1LL << env->nwindows) - 1);
-    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
-    env->wim = new_wim;
-#else
-    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
-    env->cansave++;
-    env->canrestore--;
-#endif
+    pthread_mutex_lock(&cpu_list_mutex);
 }
 
-static void restore_window(CPUSPARCState *env)
-{
-#ifndef TARGET_SPARC64
-    unsigned int new_wim;
-#endif
-    unsigned int i, cwp1;
-    abi_ulong sp_ptr;
-
-#ifndef TARGET_SPARC64
-    new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
-        ((1LL << env->nwindows) - 1);
-#endif
-
-    /* restore the invalid window */
-    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
-    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
-#ifdef TARGET_SPARC64
-    if (sp_ptr & 3)
-        sp_ptr += SPARC64_STACK_BIAS;
-#endif
-#if defined(DEBUG_WIN)
-    printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
-           sp_ptr, cwp1);
-#endif
-    for(i = 0; i < 16; i++) {
-        /* FIXME - what to do if get_user() fails? */
-        get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
-        sp_ptr += sizeof(abi_ulong);
-    }
-#ifdef TARGET_SPARC64
-    env->canrestore++;
-    if (env->cleanwin < env->nwindows - 1)
-        env->cleanwin++;
-    env->cansave--;
-#else
-    env->wim = new_wim;
-#endif
-}
-
-static void flush_windows(CPUSPARCState *env)
+void cpu_list_unlock(void)
 {
-    int offset, cwp1;
-
-    offset = 1;
-    for(;;) {
-        /* if restore would invoke restore_window(), then we can stop */
-        cwp1 = cpu_cwp_inc(env, env->cwp + offset);
-#ifndef TARGET_SPARC64
-        if (env->wim & (1 << cwp1))
-            break;
-#else
-        if (env->canrestore == 0)
-            break;
-        env->cansave++;
-        env->canrestore--;
-#endif
-        save_window_offset(env, cwp1);
-        offset++;
-    }
-    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
-#ifndef TARGET_SPARC64
-    /* set wim so that restore will reload the registers */
-    env->wim = 1 << cwp1;
-#endif
-#if defined(DEBUG_WIN)
-    printf("flush_windows: nb=%d\n", offset - 1);
-#endif
+    pthread_mutex_unlock(&cpu_list_mutex);
 }
 
-void cpu_loop(CPUSPARCState *env)
+void cpu_loop(CPUArchState *env)
 {
-    CPUState *cs = CPU(sparc_env_get_cpu(env));
-    int trapnr, ret, syscall_nr;
-    //target_siginfo_t info;
 
-    while (1) {
-        trapnr = cpu_sparc_exec (env);
-
-        switch (trapnr) {
-#ifndef TARGET_SPARC64
-        case 0x80:
-#else
-        /* FreeBSD uses 0x141 for syscalls too */
-        case 0x141:
-            if (bsd_type != target_freebsd)
-                goto badtrap;
-        case 0x100:
-#endif
-            syscall_nr = env->gregs[1];
-            if (bsd_type == target_freebsd)
-                ret = do_freebsd_syscall(env, syscall_nr,
-                                         env->regwptr[0], env->regwptr[1],
-                                         env->regwptr[2], env->regwptr[3],
-                                         env->regwptr[4], env->regwptr[5], 0, 0);
-            else if (bsd_type == target_netbsd)
-                ret = do_netbsd_syscall(env, syscall_nr,
-                                        env->regwptr[0], env->regwptr[1],
-                                        env->regwptr[2], env->regwptr[3],
-                                        env->regwptr[4], env->regwptr[5]);
-            else { //if (bsd_type == target_openbsd)
-#if defined(TARGET_SPARC64)
-                syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
-                                TARGET_OPENBSD_SYSCALL_G2RFLAG);
-#endif
-                ret = do_openbsd_syscall(env, syscall_nr,
-                                         env->regwptr[0], env->regwptr[1],
-                                         env->regwptr[2], env->regwptr[3],
-                                         env->regwptr[4], env->regwptr[5]);
-            }
-            if ((unsigned int)ret >= (unsigned int)(-515)) {
-                ret = -ret;
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
-                env->xcc |= PSR_CARRY;
-#else
-                env->psr |= PSR_CARRY;
-#endif
-            } else {
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
-                env->xcc &= ~PSR_CARRY;
-#else
-                env->psr &= ~PSR_CARRY;
-#endif
-            }
-            env->regwptr[0] = ret;
-            /* next instruction */
-#if defined(TARGET_SPARC64)
-            if (bsd_type == target_openbsd &&
-                env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
-                env->pc = env->gregs[2];
-                env->npc = env->pc + 4;
-            } else if (bsd_type == target_openbsd &&
-                       env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
-                env->pc = env->gregs[7];
-                env->npc = env->pc + 4;
-            } else {
-                env->pc = env->npc;
-                env->npc = env->npc + 4;
-            }
-#else
-            env->pc = env->npc;
-            env->npc = env->npc + 4;
-#endif
-            break;
-        case 0x83: /* flush windows */
-#ifdef TARGET_ABI32
-        case 0x103:
-#endif
-            flush_windows(env);
-            /* next instruction */
-            env->pc = env->npc;
-            env->npc = env->npc + 4;
-            break;
-#ifndef TARGET_SPARC64
-        case TT_WIN_OVF: /* window overflow */
-            save_window(env);
-            break;
-        case TT_WIN_UNF: /* window underflow */
-            restore_window(env);
-            break;
-        case TT_TFAULT:
-        case TT_DFAULT:
-#if 0
-            {
-                info.si_signo = SIGSEGV;
-                info.si_errno = 0;
-                /* XXX: check env->error_code */
-                info.si_code = TARGET_SEGV_MAPERR;
-                info._sifields._sigfault._addr = env->mmuregs[4];
-                queue_signal(env, info.si_signo, &info);
-            }
-#endif
-            break;
-#else
-        case TT_SPILL: /* window overflow */
-            save_window(env);
-            break;
-        case TT_FILL: /* window underflow */
-            restore_window(env);
-            break;
-        case TT_TFAULT:
-        case TT_DFAULT:
-#if 0
-            {
-                info.si_signo = SIGSEGV;
-                info.si_errno = 0;
-                /* XXX: check env->error_code */
-                info.si_code = TARGET_SEGV_MAPERR;
-                if (trapnr == TT_DFAULT)
-                    info._sifields._sigfault._addr = env->dmmuregs[4];
-                else
-                    info._sifields._sigfault._addr = env->tsptr->tpc;
-                //queue_signal(env, info.si_signo, &info);
-            }
-#endif
-            break;
-#endif
-        case EXCP_INTERRUPT:
-            /* just indicate that signals should be handled asap */
-            break;
-        case EXCP_DEBUG:
-            {
-                int sig;
-
-                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
-#if 0
-                if (sig)
-                  {
-                    info.si_signo = sig;
-                    info.si_errno = 0;
-                    info.si_code = TARGET_TRAP_BRKPT;
-                    //queue_signal(env, info.si_signo, &info);
-                  }
-#endif
-            }
-            break;
-        default:
-#ifdef TARGET_SPARC64
-        badtrap:
-#endif
-            printf ("Unhandled trap: 0x%x\n", trapnr);
-            cpu_dump_state(cs, stderr, fprintf, 0);
-            exit (1);
-        }
-        process_pending_signals (env);
-    }
+    target_cpu_loop(env);
 }
 
-#endif
-
 static void usage(void)
 {
     printf("qemu-" TARGET_NAME " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
@@ -709,12 +241,21 @@ static void usage(void)
            ,
            TARGET_NAME,
            interp_prefix,
-           x86_stack_size);
+           target_dflssiz);
     exit(1);
 }
 
 THREAD CPUState *thread_cpu;
 
+void stop_all_tasks(void)
+{
+    /*
+     * We trust when using NPTL (pthreads) start_exclusive() handles thread
+     * stopping correctly.
+     */
+    start_exclusive();
+}
+
 /* Assumes contents are already zeroed.  */
 void init_task_state(TaskState *ts)
 {
@@ -728,6 +269,46 @@ void init_task_state(TaskState *ts)
     ts->sigqueue_table[i].next = NULL;
 }
 
+CPUArchState *cpu_copy(CPUArchState *env)
+{
+    CPUArchState *new_env = cpu_init(cpu_model);
+#if defined(TARGET_HAS_ICE)
+    CPUBreakpoint *bp;
+    CPUWatchpoint *wp;
+#endif
+
+    /* Reset non arch specific state */
+    cpu_reset(ENV_GET_CPU(new_env));
+
+    memcpy(new_env, env, sizeof(CPUArchState));
+
+    /* Clone all break/watchpoints.
+       Note: Once we support ptrace with hw-debug register access, make sure
+       BP_CPU break/watchpoints are handled correctly on clone. */
+    QTAILQ_INIT(&env->breakpoints);
+    QTAILQ_INIT(&env->watchpoints);
+#if defined(TARGET_HAS_ICE)
+    QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
+    }
+    QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+        cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
+                              wp->flags, NULL);
+    }
+#endif
+
+    return new_env;
+}
+
+void gemu_log(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+}
+
 int main(int argc, char **argv)
 {
     const char *filename;
@@ -736,6 +317,7 @@ int main(int argc, char **argv)
     const char *log_mask = NULL;
     struct target_pt_regs regs1, *regs = &regs1;
     struct image_info info1, *info = &info1;
+    struct bsd_binprm bprm;
     TaskState ts1, *ts = &ts1;
     CPUArchState *env;
     CPUState *cpu;
@@ -744,11 +326,13 @@ int main(int argc, char **argv)
     int gdbstub_port = 0;
     char **target_environ, **wrk;
     envlist_t *envlist = NULL;
-    bsd_type = target_openbsd;
+    bsd_type = HOST_DEFAULT_BSD_TYPE;
 
     if (argc <= 1)
         usage();
 
+    save_proc_pathname(argv[0]);
+
     module_call_init(MODULE_INIT_QOM);
 
     if ((envlist = envlist_create()) == NULL) {
@@ -767,7 +351,7 @@ int main(int argc, char **argv)
 #endif
 
     optind = 1;
-    for(;;) {
+    for (;;) {
         if (optind >= argc)
             break;
         r = argv[optind];
@@ -803,13 +387,18 @@ int main(int argc, char **argv)
                 usage();
         } else if (!strcmp(r, "s")) {
             r = argv[optind++];
-            x86_stack_size = strtol(r, (char **)&r, 0);
-            if (x86_stack_size <= 0)
+            target_dflssiz = strtol(r, (char **)&r, 0);
+            if (target_dflssiz <= 0) {
+                usage();
+            }
+            if (*r == 'M') {
+                target_dflssiz *= 1024 * 1024;
+            } else if (*r == 'k' || *r == 'K') {
+                target_dflssiz *= 1024;
+            }
+            if (target_dflssiz > target_maxssiz) {
                 usage();
-            if (*r == 'M')
-                x86_stack_size *= 1024 * 1024;
-            else if (*r == 'k' || *r == 'K')
-                x86_stack_size *= 1024;
+            }
         } else if (!strcmp(r, "L")) {
             interp_prefix = argv[optind++];
         } else if (!strcmp(r, "p")) {
@@ -881,6 +470,8 @@ int main(int argc, char **argv)
     /* Zero out regs */
     memset(regs, 0, sizeof(struct target_pt_regs));
 
+    memset(&bprm, 0, sizeof(bprm));
+
     /* Zero out image_info */
     memset(info, 0, sizeof(struct image_info));
 
@@ -888,21 +479,7 @@ int main(int argc, char **argv)
     init_paths(interp_prefix);
 
     if (cpu_model == NULL) {
-#if defined(TARGET_I386)
-#ifdef TARGET_X86_64
-        cpu_model = "qemu64";
-#else
-        cpu_model = "qemu32";
-#endif
-#elif defined(TARGET_SPARC)
-#ifdef TARGET_SPARC64
-        cpu_model = "TI UltraSparc II";
-#else
-        cpu_model = "Fujitsu MB86904";
-#endif
-#else
-        cpu_model = "any";
-#endif
+        cpu_model = TARGET_DEFAULT_CPU_MODEL;
     }
     tcg_exec_init(0);
     cpu_exec_init_all();
@@ -914,9 +491,7 @@ int main(int argc, char **argv)
         exit(1);
     }
     cpu = ENV_GET_CPU(env);
-#if defined(TARGET_SPARC) || defined(TARGET_PPC)
-    cpu_reset(cpu);
-#endif
+    TARGET_CPU_RESET(env);
     thread_cpu = cpu;
 
     if (getenv("QEMU_STRACE")) {
@@ -955,7 +530,7 @@ int main(int argc, char **argv)
     }
 #endif /* CONFIG_USE_GUEST_BASE */
 
-    if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
+    if (loader_exec(filename, argv+optind, target_environ, regs, info, &bprm)) {
         printf("Error loading %s\n", filename);
         _exit(1);
     }
@@ -1000,139 +575,10 @@ int main(int argc, char **argv)
     memset(ts, 0, sizeof(TaskState));
     init_task_state(ts);
     ts->info = info;
+    ts->bprm = &bprm;
     env->opaque = ts;
 
-#if defined(TARGET_I386)
-    cpu_x86_set_cpl(env, 3);
-
-    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
-    env->hflags |= HF_PE_MASK;
-    if (env->features[FEAT_1_EDX] & CPUID_SSE) {
-        env->cr[4] |= CR4_OSFXSR_MASK;
-        env->hflags |= HF_OSFXSR_MASK;
-    }
-#ifndef TARGET_ABI32
-    /* enable 64 bit mode if possible */
-    if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
-        fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
-        exit(1);
-    }
-    env->cr[4] |= CR4_PAE_MASK;
-    env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
-    env->hflags |= HF_LMA_MASK;
-#endif
-
-    /* flags setup : we activate the IRQs by default as in user mode */
-    env->eflags |= IF_MASK;
-
-    /* linux register setup */
-#ifndef TARGET_ABI32
-    env->regs[R_EAX] = regs->rax;
-    env->regs[R_EBX] = regs->rbx;
-    env->regs[R_ECX] = regs->rcx;
-    env->regs[R_EDX] = regs->rdx;
-    env->regs[R_ESI] = regs->rsi;
-    env->regs[R_EDI] = regs->rdi;
-    env->regs[R_EBP] = regs->rbp;
-    env->regs[R_ESP] = regs->rsp;
-    env->eip = regs->rip;
-#else
-    env->regs[R_EAX] = regs->eax;
-    env->regs[R_EBX] = regs->ebx;
-    env->regs[R_ECX] = regs->ecx;
-    env->regs[R_EDX] = regs->edx;
-    env->regs[R_ESI] = regs->esi;
-    env->regs[R_EDI] = regs->edi;
-    env->regs[R_EBP] = regs->ebp;
-    env->regs[R_ESP] = regs->esp;
-    env->eip = regs->eip;
-#endif
-
-    /* linux interrupt setup */
-#ifndef TARGET_ABI32
-    env->idt.limit = 511;
-#else
-    env->idt.limit = 255;
-#endif
-    env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
-                                PROT_READ|PROT_WRITE,
-                                MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-    idt_table = g2h(env->idt.base);
-    set_idt(0, 0);
-    set_idt(1, 0);
-    set_idt(2, 0);
-    set_idt(3, 3);
-    set_idt(4, 3);
-    set_idt(5, 0);
-    set_idt(6, 0);
-    set_idt(7, 0);
-    set_idt(8, 0);
-    set_idt(9, 0);
-    set_idt(10, 0);
-    set_idt(11, 0);
-    set_idt(12, 0);
-    set_idt(13, 0);
-    set_idt(14, 0);
-    set_idt(15, 0);
-    set_idt(16, 0);
-    set_idt(17, 0);
-    set_idt(18, 0);
-    set_idt(19, 0);
-    set_idt(0x80, 3);
-
-    /* linux segment setup */
-    {
-        uint64_t *gdt_table;
-        env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
-                                    PROT_READ|PROT_WRITE,
-                                    MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-        env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
-        gdt_table = g2h(env->gdt.base);
-#ifdef TARGET_ABI32
-        write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
-                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
-                 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
-#else
-        /* 64 bit code segment */
-        write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
-                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
-                 DESC_L_MASK |
-                 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
-#endif
-        write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
-                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
-                 (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
-    }
-
-    cpu_x86_load_seg(env, R_CS, __USER_CS);
-    cpu_x86_load_seg(env, R_SS, __USER_DS);
-#ifdef TARGET_ABI32
-    cpu_x86_load_seg(env, R_DS, __USER_DS);
-    cpu_x86_load_seg(env, R_ES, __USER_DS);
-    cpu_x86_load_seg(env, R_FS, __USER_DS);
-    cpu_x86_load_seg(env, R_GS, __USER_DS);
-    /* This hack makes Wine work... */
-    env->segs[R_FS].selector = 0;
-#else
-    cpu_x86_load_seg(env, R_DS, 0);
-    cpu_x86_load_seg(env, R_ES, 0);
-    cpu_x86_load_seg(env, R_FS, 0);
-    cpu_x86_load_seg(env, R_GS, 0);
-#endif
-#elif defined(TARGET_SPARC)
-    {
-        int i;
-        env->pc = regs->pc;
-        env->npc = regs->npc;
-        env->y = regs->y;
-        for(i = 0; i < 8; i++)
-            env->gregs[i] = regs->u_regs[i];
-        for(i = 0; i < 8; i++)
-            env->regwptr[i] = regs->u_regs[i + 8];
-    }
-#else
-#error unsupported target CPU
-#endif
+    target_cpu_init(env, regs);
 
     if (gdbstub_port) {
         gdbserver_start (gdbstub_port);
diff --git a/bsd-user/mips/target_arch.h b/bsd-user/mips/target_arch.h
new file mode 100644
index 0000000..b3d32ba
--- /dev/null
+++ b/bsd-user/mips/target_arch.h
@@ -0,0 +1,10 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+#include "qemu.h"
+
+void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls);
+target_ulong target_cpu_get_tls(CPUMIPSState *env);
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/mips/target_arch_cpu.c b/bsd-user/mips/target_arch_cpu.c
new file mode 100644
index 0000000..dd59435
--- /dev/null
+++ b/bsd-user/mips/target_arch_cpu.c
@@ -0,0 +1,27 @@
+/*
+ *  mips cpu related code
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "target_arch.h"
+
+void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls)
+{
+    env->tls_value = newtls;
+}
+
+target_ulong target_cpu_get_tls(CPUMIPSState *env)
+{
+    return (env->tls_value);
+}
diff --git a/bsd-user/mips/target_arch_cpu.h b/bsd-user/mips/target_arch_cpu.h
new file mode 100644
index 0000000..5098b7d
--- /dev/null
+++ b/bsd-user/mips/target_arch_cpu.h
@@ -0,0 +1,257 @@
+/*
+ *  mips cpu init and loop
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#if defined(TARGET_ABI_MIPSN32)
+#  define TARGET_DEFAULT_CPU_MODEL "24Kc"
+#else
+#  define TARGET_DEFAULT_CPU_MODEL "24Kf"
+#endif
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUMIPSState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    for (i = 0; i < 32; i++) {
+        env->active_tc.gpr[i] = regs->regs[i];
+    }
+    env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
+    if (regs->cp0_epc & 1) {
+        env->hflags |= MIPS_HFLAG_M16;
+    }
+}
+
+static int do_store_exclusive(CPUMIPSState *env)
+{
+    target_ulong addr;
+    target_ulong page_addr;
+    target_ulong val;
+    int flags;
+    int segv = 0;
+    int reg;
+    int d;
+
+    addr = env->lladdr;
+    page_addr = addr & TARGET_PAGE_MASK;
+    start_exclusive();
+    mmap_lock();
+    flags = page_get_flags(page_addr);
+    if ((flags & PAGE_READ) == 0) {
+        segv = 1;
+    } else {
+        reg = env->llreg & 0x1f;
+        d = (env->llreg & 0x20) != 0;
+        if (d) {
+            segv = get_user_s64(val, addr);
+        } else {
+            segv = get_user_s32(val, addr);
+        }
+        if (!segv) {
+            if (val != env->llval) {
+                env->active_tc.gpr[reg] = 0;
+            } else {
+                if (d) {
+                    segv = put_user_u64(env->llnewval, addr);
+                } else {
+                    segv = put_user_u32(env->llnewval, addr);
+                }
+                if (!segv) {
+                    env->active_tc.gpr[reg] = 1;
+                }
+            }
+        }
+    }
+    env->lladdr = -1;
+    if (!segv) {
+        env->active_tc.PC += 4;
+    }
+    mmap_unlock();
+    end_exclusive();
+    return segv;
+}
+
+static inline void target_cpu_loop(CPUMIPSState *env)
+{
+    CPUState *cs = CPU(mips_env_get_cpu(env));
+    target_siginfo_t info;
+    int trapnr;
+    abi_long ret;
+    unsigned int syscall_num;
+
+    for (;;) {
+        cpu_exec_start(cs);
+        trapnr = cpu_mips_exec(env);
+        cpu_exec_end(cs);
+        switch (trapnr) {
+        case EXCP_SYSCALL: /* syscall exception */
+            if (bsd_type == target_freebsd) {
+                syscall_num = env->active_tc.gpr[2]; /* v0 */
+                env->active_tc.PC += TARGET_INSN_SIZE;
+                if (syscall_num >= TARGET_FREEBSD_NR_MAXSYSCALL) {
+                    ret = -TARGET_ENOSYS;
+                } else {
+		    abi_ulong arg4 = 0, arg5 = 0, arg6 = 0, arg7 =0;
+		    abi_ulong sp_reg = env->active_tc.gpr[29];
+
+# ifdef TARGET_ABI_MIPSO32
+		    get_user_ual(arg4, sp_reg + 16);
+		    get_user_ual(arg5, sp_reg + 20);
+		    get_user_ual(arg6, sp_reg + 24);
+		    get_user_ual(arg7, sp_reg + 28);
+#else
+		    arg4 = env->active_tc.gpr[12]; /* t4/arg4 */
+		    arg5 = env->active_tc.gpr[13]; /* t5/arg5 */
+		    arg6 = env->active_tc.gpr[14]; /* t6/arg6 */
+		    arg7 = env->active_tc.gpr[15]; /* t7/arg7 */
+#endif
+                    /* mips(32) uses regs 4-7,12-15 for args */
+                    if (TARGET_FREEBSD_NR___syscall == syscall_num ||
+                            TARGET_FREEBSD_NR_syscall == syscall_num) {
+                        /* indirect syscall */
+                        ret = do_freebsd_syscall(env,
+                                env->active_tc.gpr[4],/* syscall #*/
+                                env->active_tc.gpr[5], /* a1/arg0 */
+                                env->active_tc.gpr[6], /* a2/arg1 */
+                                env->active_tc.gpr[7], /* a3/arg2 */
+				arg4,
+				arg5,
+				arg6,
+				arg7,
+                                0  /* no arg7 */
+                                );
+                    } else {
+                        /* direct syscall */
+                        ret = do_freebsd_syscall(env,
+                                syscall_num,
+                                env->active_tc.gpr[4], /* a0/arg0 */
+                                env->active_tc.gpr[5], /* a1/arg1 */
+                                env->active_tc.gpr[6], /* a2/arg2 */
+                                env->active_tc.gpr[7], /* a3/arg3 */
+				arg4,
+				arg5,
+				arg6,
+				arg7
+                                );
+                    }
+                }
+                /* Compare to mips/mips/vm_machdep.c cpu_set_syscall_retval() */
+                if (-TARGET_EJUSTRETURN == ret) {
+                    /*
+                     * Returning from a successful sigreturn
+                     * syscall.  Avoid clobbering register state.
+                     */
+                    break;
+                }
+                if (-TARGET_ERESTART == ret) {
+                    /* Backup the pc to point at the swi. */
+                    env->active_tc.PC -= TARGET_INSN_SIZE;
+                    break;
+                }
+                if ((unsigned int)ret >= (unsigned int)(-1133)) {
+                    env->active_tc.gpr[7] = 1;
+                    ret = -ret;
+                } else {
+                    env->active_tc.gpr[7] = 0;
+                }
+                env->active_tc.gpr[2] = ret; /* v0 <- ret */
+            } /* else if (bsd_type == target_openbsd)... */
+            else {
+                fprintf(stderr, "qemu: bsd_type (= %d) syscall not supported\n",
+                        bsd_type);
+            }
+            break;
+
+        case EXCP_TLBL: /* TLB miss on load */
+        case EXCP_TLBS: /* TLB miss on store */
+        case EXCP_AdEL: /* bad address on load */
+        case EXCP_AdES: /* bad address on store */
+            info.target_si_signo = TARGET_SIGSEGV;
+            info.target_si_errno = 0;
+            /* XXX: check env->error_code */
+            info.target_si_code = TARGET_SEGV_MAPERR;
+            info.target_si_addr = env->CP0_BadVAddr;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP_CpU: /* coprocessor unusable */
+        case EXCP_RI:  /* reserved instruction */
+            info.target_si_signo = TARGET_SIGILL;
+            info.target_si_errno = 0;
+            info.target_si_code = 0;
+            queue_signal(env, info.target_si_signo, &info);
+            break;
+
+        case EXCP_INTERRUPT: /* async interrupt */
+            /* just indicate that signals should be handled asap */
+            break;
+
+        case EXCP_DEBUG: /* cpu stopped after a breakpoint */
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+                if (sig) {
+                    info.target_si_signo = sig;
+                    info.target_si_errno = 0;
+                    info.target_si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.target_si_signo, &info);
+                }
+            }
+            break;
+
+        case EXCP_SC:
+            if (do_store_exclusive(env)) {
+                info.target_si_signo = TARGET_SIGSEGV;
+                info.target_si_errno = 0;
+                info.target_si_code = TARGET_SEGV_MAPERR;
+                info.target_si_addr = env->active_tc.PC;
+                queue_signal(env, info.target_si_signo, &info);
+            }
+            break;
+
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception "
+                "0x%x - aborting\n", trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUMIPSState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->active_tc.gpr[29] = newsp;
+    env->active_tc.gpr[7] = 0;
+    env->active_tc.gpr[2] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/mips/target_arch_vmparam.h b/bsd-user/mips/target_arch_vmparam.h
new file mode 100644
index 0000000..695877a
--- /dev/null
+++ b/bsd-user/mips/target_arch_vmparam.h
@@ -0,0 +1,50 @@
+/*
+ *  mips VM parameters definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to sys/mips/include/vmparam.h */
+#define TARGET_MAXTSIZ      (128UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ      (128UL*1024*1024)   /* initial data size limit */
+#define TARGET_MAXDSIZ      (1*1024UL*1024*1024)    /* max data size */
+#define TARGET_DFLSSIZ      (8UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ      (64UL*1024*1024)    /* max stack size */
+#define TARGET_SGROWSIZ     (128UL*1024)        /* amount to grow stack */
+
+/* MIPS only supports 31 bits of virtual address space for user space */
+#define TARGET_RESERVED_VA  0x77000000
+
+#define TARGET_VM_MINUSER_ADDRESS   (0x00000000)
+#define TARGET_VM_MAXUSER_ADDRESS   (0x80000000)
+
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
+{
+    return state->active_tc.gpr[29];
+}
+
+static inline void set_second_rval(CPUMIPSState *state, abi_ulong retval2)
+{
+    state->active_tc.gpr[3] = retval2;
+}
+
+#endif  /* ! _TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/mips64/target_arch.h b/bsd-user/mips64/target_arch.h
new file mode 100644
index 0000000..b3d32ba
--- /dev/null
+++ b/bsd-user/mips64/target_arch.h
@@ -0,0 +1,10 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+#include "qemu.h"
+
+void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls);
+target_ulong target_cpu_get_tls(CPUMIPSState *env);
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/mips64/target_arch_cpu.c b/bsd-user/mips64/target_arch_cpu.c
new file mode 100644
index 0000000..9d016a3
--- /dev/null
+++ b/bsd-user/mips64/target_arch_cpu.c
@@ -0,0 +1,27 @@
+/*
+ *  mips64 cpu related code
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "target_arch.h"
+
+void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls)
+{
+    env->tls_value = newtls;
+}
+
+target_ulong target_cpu_get_tls(CPUMIPSState *env)
+{
+    return (env->tls_value);
+}
diff --git a/bsd-user/mips64/target_arch_cpu.h b/bsd-user/mips64/target_arch_cpu.h
new file mode 100644
index 0000000..c5a4acd
--- /dev/null
+++ b/bsd-user/mips64/target_arch_cpu.h
@@ -0,0 +1,243 @@
+/*
+ *  mips64 cpu init and loop
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
+#  define TARGET_DEFAULT_CPU_MODEL "20Kc"
+#else
+#  define TARGET_DEFAULT_CPU_MODEL "24f"
+#endif
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUMIPSState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    for (i = 0; i < 32; i++) {
+        env->active_tc.gpr[i] = regs->regs[i];
+    }
+    env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
+    if (regs->cp0_epc & 1) {
+        env->hflags |= MIPS_HFLAG_M16;
+    }
+    env->hflags |= MIPS_HFLAG_UX | MIPS_HFLAG_64;
+}
+
+static int do_store_exclusive(CPUMIPSState *env)
+{
+    target_ulong addr;
+    target_ulong page_addr;
+    target_ulong val;
+    int flags;
+    int segv = 0;
+    int reg;
+    int d;
+
+    addr = env->lladdr;
+    page_addr = addr & TARGET_PAGE_MASK;
+    start_exclusive();
+    mmap_lock();
+    flags = page_get_flags(page_addr);
+    if ((flags & PAGE_READ) == 0) {
+        segv = 1;
+    } else {
+        reg = env->llreg & 0x1f;
+        d = (env->llreg & 0x20) != 0;
+        if (d) {
+            segv = get_user_s64(val, addr);
+        } else {
+            segv = get_user_s32(val, addr);
+        }
+        if (!segv) {
+            if (val != env->llval) {
+                env->active_tc.gpr[reg] = 0;
+            } else {
+                if (d) {
+                    segv = put_user_u64(env->llnewval, addr);
+                } else {
+                    segv = put_user_u32(env->llnewval, addr);
+                }
+                if (!segv) {
+                    env->active_tc.gpr[reg] = 1;
+                }
+            }
+        }
+    }
+    env->lladdr = -1;
+    if (!segv) {
+        env->active_tc.PC += 4;
+    }
+    mmap_unlock();
+    end_exclusive();
+    return segv;
+}
+
+static inline void target_cpu_loop(CPUMIPSState *env)
+{
+    CPUState *cs = CPU(mips_env_get_cpu(env));
+    target_siginfo_t info;
+    int trapnr;
+    abi_long ret;
+    unsigned int syscall_num;
+
+    for (;;) {
+        cpu_exec_start(cs);
+        trapnr = cpu_mips_exec(env);
+        cpu_exec_end(cs);
+        switch (trapnr) {
+        case EXCP_SYSCALL: /* syscall exception */
+            if (bsd_type == target_freebsd) {
+                syscall_num = env->active_tc.gpr[2]; /* v0 */
+                env->active_tc.PC += TARGET_INSN_SIZE;
+                if (syscall_num >= TARGET_FREEBSD_NR_MAXSYSCALL) {
+                    ret = -TARGET_ENOSYS;
+                } else {
+                    /* mips64 uses regs 4-11 for args */
+                    if (TARGET_FREEBSD_NR___syscall == syscall_num ||
+                            TARGET_FREEBSD_NR_syscall == syscall_num) {
+                        /* indirect syscall */
+                        ret = do_freebsd_syscall(env,
+                                env->active_tc.gpr[4],/* syscall #*/
+                                env->active_tc.gpr[5], /* arg0 */
+                                env->active_tc.gpr[6], /* arg1 */
+                                env->active_tc.gpr[7], /* arg2 */
+                                env->active_tc.gpr[8], /* arg3 */
+                                env->active_tc.gpr[9], /* arg4 */
+                                env->active_tc.gpr[10],/* arg5 */
+                                env->active_tc.gpr[11],/* arg6 */
+                                0 /* no arg 7 */);
+                    } else {
+                        /* direct syscall */
+                        ret = do_freebsd_syscall(env,
+                                syscall_num,
+                                env->active_tc.gpr[4],
+                                env->active_tc.gpr[5],
+                                env->active_tc.gpr[6],
+                                env->active_tc.gpr[7],
+                                env->active_tc.gpr[8],
+                                env->active_tc.gpr[9],
+                                env->active_tc.gpr[10],
+                                env->active_tc.gpr[11]
+                                );
+                    }
+                }
+                /* Compare to mips/mips/vm_machdep.c cpu_set_syscall_retval() */
+                if (-TARGET_EJUSTRETURN == ret) {
+                    /*
+                     * Returning from a successful sigreturn
+                     * syscall.  Avoid clobbering register state.
+                     */
+                    break;
+                }
+                if (-TARGET_ERESTART == ret) {
+                    /* Backup the pc to point at the swi. */
+                    env->active_tc.PC -= TARGET_INSN_SIZE;
+                    break;
+                }
+                if ((unsigned int)ret >= (unsigned int)(-1133)) {
+                    env->active_tc.gpr[7] = 1;
+                    ret = -ret;
+                } else {
+                    env->active_tc.gpr[7] = 0;
+                }
+                env->active_tc.gpr[2] = ret; /* v0 <- ret */
+            } /* else if (bsd_type == target_openbsd)... */
+            else {
+                fprintf(stderr, "qemu: bsd_type (= %d) syscall not supported\n",
+                        bsd_type);
+            }
+            break;
+
+        case EXCP_TLBL: /* TLB miss on load */
+        case EXCP_TLBS: /* TLB miss on store */
+        case EXCP_AdEL: /* bad address on load */
+        case EXCP_AdES: /* bad address on store */
+            info.target_si_signo = TARGET_SIGSEGV;
+            info.target_si_errno = 0;
+            /* XXX: check env->error_code */
+            info.target_si_code = TARGET_SEGV_MAPERR;
+            info.target_si_addr = env->CP0_BadVAddr;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP_CpU: /* coprocessor unusable */
+        case EXCP_RI:  /* reserved instruction */
+            info.target_si_signo = TARGET_SIGILL;
+            info.target_si_errno = 0;
+            info.target_si_code = 0;
+            queue_signal(env, info.target_si_signo, &info);
+            break;
+
+        case EXCP_INTERRUPT: /* async interrupt */
+            /* just indicate that signals should be handled asap */
+            break;
+
+        case EXCP_DEBUG: /* cpu stopped after a breakpoint */
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+                if (sig) {
+                    info.target_si_signo = sig;
+                    info.target_si_errno = 0;
+                    info.target_si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.target_si_signo, &info);
+                }
+            }
+            break;
+
+        case EXCP_SC:
+            if (do_store_exclusive(env)) {
+                info.target_si_signo = TARGET_SIGSEGV;
+                info.target_si_errno = 0;
+                info.target_si_code = TARGET_SEGV_MAPERR;
+                info.target_si_addr = env->active_tc.PC;
+                queue_signal(env, info.target_si_signo, &info);
+            }
+            break;
+
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception "
+                "0x%x - aborting\n", trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUMIPSState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->active_tc.gpr[29] = newsp;
+    env->active_tc.gpr[7] = 0;
+    env->active_tc.gpr[2] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/mips64/target_arch_vmparam.h b/bsd-user/mips64/target_arch_vmparam.h
new file mode 100644
index 0000000..1ba09e0
--- /dev/null
+++ b/bsd-user/mips64/target_arch_vmparam.h
@@ -0,0 +1,47 @@
+/*
+ *  mips64 VM parameters definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to sys/mips/include/vmparam.h */
+#define TARGET_MAXTSIZ      (128UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ      (128UL*1024*1024)   /* initial data size limit */
+#define TARGET_MAXDSIZ      (1*1024UL*1024*1024)    /* max data size */
+#define TARGET_DFLSSIZ      (8UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ      (64UL*1024*1024)    /* max stack size */
+#define TARGET_SGROWSIZ     (128UL*1024)        /* amount to grow stack */
+
+#define TARGET_VM_MINUSER_ADDRESS   (0x0000000000000000UL)
+#define TARGET_VM_MAXUSER_ADDRESS   (0x0000008000000000UL)
+
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
+{
+    return state->active_tc.gpr[29];
+}
+
+static inline void set_second_rval(CPUMIPSState *state, abi_ulong retval2)
+{
+    state->active_tc.gpr[3] = retval2;
+}
+
+#endif  /* ! _TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/netbsd/host_os.h b/bsd-user/netbsd/host_os.h
new file mode 100644
index 0000000..5c492e3
--- /dev/null
+++ b/bsd-user/netbsd/host_os.h
@@ -0,0 +1,31 @@
+/*
+ *  NetBSD host dependent code and definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST_OS_H_
+#define __HOST_OS_H_
+
+#include "qemu.h"
+
+#define HOST_DEFAULT_BSD_TYPE target_netbsd
+
+static inline void save_proc_pathname(char *argv0)
+{
+    /* XXX */
+}
+
+#endif /*!__HOST_OS_H_ */
diff --git a/bsd-user/openbsd/host_os.h b/bsd-user/openbsd/host_os.h
new file mode 100644
index 0000000..162ce58
--- /dev/null
+++ b/bsd-user/openbsd/host_os.h
@@ -0,0 +1,31 @@
+/*
+ *  OpenBSD host dependent code and definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST_OS_H_
+#define __HOST_OS_H_
+
+#include "qemu.h"
+
+#define HOST_DEFAULT_BSD_TYPE target_openbsd
+
+static inline void save_proc_pathname(char *argv0)
+{
+    /* XXX */
+}
+
+#endif /*!__HOST_OS_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index b8a34c7..cb77069 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -38,6 +38,7 @@ extern enum BSDType bsd_type;
 
 #include "syscall_defs.h"
 #include "syscall.h"
+#include "target_os_vmparam.h"
 #include "target_signal.h"
 #include "exec/gdbstub.h"
 
@@ -99,6 +100,7 @@ typedef struct TaskState {
 } __attribute__((aligned(16))) TaskState;
 
 void init_task_state(TaskState *ts);
+void stop_all_tasks(void);
 extern const char *qemu_uname_release;
 #if defined(CONFIG_USE_GUEST_BASE)
 extern unsigned long mmap_min_addr;
@@ -222,7 +224,13 @@ void mmap_fork_end(int child);
 #endif
 
 /* main.c */
-extern unsigned long x86_stack_size;
+extern unsigned long target_maxtsiz;
+extern unsigned long target_dfldsiz;
+extern unsigned long target_maxdsiz;
+extern unsigned long target_dflssiz;
+extern unsigned long target_maxssiz;
+extern unsigned long target_sgrowsiz;
+extern char qemu_proc_pathname[];
 
 /* user access */
 
diff --git a/bsd-user/sparc/target_arch.h b/bsd-user/sparc/target_arch.h
new file mode 100644
index 0000000..5ee479b
--- /dev/null
+++ b/bsd-user/sparc/target_arch.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+void bsd_sparc_save_window(CPUSPARCState *env);
+void bsd_sparc_restore_window(CPUSPARCState *env);
+void bsd_sparc_flush_windows(CPUSPARCState *env);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* ! _TARGET_ARCH_H_ */
diff --git a/bsd-user/sparc/target_arch_cpu.c b/bsd-user/sparc/target_arch_cpu.c
new file mode 100644
index 0000000..0af5c7e
--- /dev/null
+++ b/bsd-user/sparc/target_arch_cpu.c
@@ -0,0 +1,113 @@
+/*
+ *  sparc cpu related code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+
+#include "target_arch.h"
+
+/* #define DEBUG_WIN */
+/* WARNING: dealing with register windows _is_ complicated. More info
+   can be found at http://www.sics.se/~psm/sparcstack.html */
+static int get_reg_index(CPUSPARCState *env, int cwp, int index)
+{
+    index = (index + cwp * 16) % (16 * env->nwindows);
+    /* wrap handling : if cwp is on the last window, then we use the
+       registers 'after' the end */
+    if (index < 8 && env->cwp == env->nwindows - 1) {
+        index += 16 * env->nwindows;
+    }
+    return index;
+}
+
+/* save the register window 'cwp1' */
+static void save_window_offset(CPUSPARCState *env, int cwp1)
+{
+    unsigned int i;
+    abi_ulong sp_ptr;
+
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#if defined(DEBUG_WIN)
+    printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for (i = 0; i < 16; i++) {
+        /* FIXME - what to do if put_user() fails? */
+        put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+}
+
+void bsd_sparc_save_window(CPUSPARCState *env)
+{
+    unsigned int new_wim;
+
+    new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
+        ((1LL << env->nwindows) - 1);
+    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+    env->wim = new_wim;
+}
+
+void bsd_sparc_restore_window(CPUSPARCState *env)
+{
+    unsigned int new_wim;
+    unsigned int i, cwp1;
+    abi_ulong sp_ptr;
+
+    new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
+        ((1LL << env->nwindows) - 1);
+
+    /* restore the invalid window */
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#if defined(DEBUG_WIN)
+    printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for (i = 0; i < 16; i++) {
+        /* FIXME - what to do if get_user() fails? */
+        get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+    env->wim = new_wim;
+}
+
+void bsd_sparc_flush_windows(CPUSPARCState *env)
+{
+    int offset, cwp1;
+
+    offset = 1;
+    for (;;) {
+        /* if restore would invoke restore_window(), then we can stop */
+        cwp1 = cpu_cwp_inc(env, env->cwp + offset);
+        if (env->wim & (1 << cwp1)) {
+            break;
+        }
+        save_window_offset(env, cwp1);
+        offset++;
+    }
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+    /* set wim so that restore will reload the registers */
+    env->wim = 1 << cwp1;
+#if defined(DEBUG_WIN)
+    printf("bsd_sparc_flush_windows: nb=%d\n", offset - 1);
+#endif
+}
+
diff --git a/bsd-user/sparc/target_arch_cpu.h b/bsd-user/sparc/target_arch_cpu.h
new file mode 100644
index 0000000..f61884b
--- /dev/null
+++ b/bsd-user/sparc/target_arch_cpu.h
@@ -0,0 +1,158 @@
+/*
+ *  sparc cpu init and loop
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "Fujitsu MB86904"
+
+#define TARGET_CPU_RESET(env) cpu_reset(ENV_GET_CPU(env))
+
+static inline void target_cpu_init(CPUSPARCState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    env->pc = regs->pc;
+    env->npc = regs->npc;
+    env->y = regs->y;
+    for (i = 0; i < 8; i++) {
+        env->gregs[i] = regs->u_regs[i];
+    }
+    for (i = 0; i < 8; i++) {
+        env->regwptr[i] = regs->u_regs[i + 8];
+    }
+}
+
+static inline void target_cpu_loop(CPUSPARCState *env)
+{
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
+    int trapnr, ret, syscall_nr;
+    /* target_siginfo_t info; */
+
+    while (1) {
+        trapnr = cpu_sparc_exec(env);
+
+        switch (trapnr) {
+        case 0x80:
+            syscall_nr = env->gregs[1];
+            if (bsd_type == target_freebsd) {
+                ret = do_freebsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5], 0, 0);
+            } else if (bsd_type == target_netbsd) {
+                ret = do_netbsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5]);
+            } else { /* if (bsd_type == target_openbsd) */
+                ret = do_openbsd_syscall(env, syscall_nr,
+                                         env->regwptr[0], env->regwptr[1],
+                                         env->regwptr[2], env->regwptr[3],
+                                         env->regwptr[4], env->regwptr[5]);
+            }
+            if ((unsigned int)ret >= (unsigned int)(-515)) {
+                ret = -ret;
+                env->psr |= PSR_CARRY;
+            } else {
+                env->psr &= ~PSR_CARRY;
+            }
+            env->regwptr[0] = ret;
+            /* next instruction */
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+            break;
+        case 0x83: /* flush windows */
+#ifdef TARGET_ABI32
+        case 0x103:
+#endif
+            bsd_sparc_flush_windows(env);
+            /* next instruction */
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+            break;
+
+        case TT_WIN_OVF: /* window overflow */
+            bsd_sparc_save_window(env);
+            break;
+
+        case TT_WIN_UNF: /* window underflow */
+            bsd_sparc_restore_window(env);
+            break;
+
+        case TT_TFAULT:
+        case TT_DFAULT:
+#if 0
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = env->mmuregs[4];
+                queue_signal(env, info.si_signo, &info);
+            }
+#endif
+            break;
+
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+
+        case EXCP_DEBUG:
+#if 0
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    /* queue_signal(env, info.si_signo, &info); */
+                }
+            }
+#endif
+            break;
+        default:
+            printf("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            exit(1);
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUSPARCState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regwptr[22] = newsp;
+    env->regwptr[0] = 0;
+    /* FIXME: Do we also need to clear CF?  */
+    /* XXXXX */
+    printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+    cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/sparc/target_arch_vmparam.h b/bsd-user/sparc/target_arch_vmparam.h
new file mode 100644
index 0000000..5f28fcf
--- /dev/null
+++ b/bsd-user/sparc/target_arch_vmparam.h
@@ -0,0 +1,37 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+#define TARGET_MAXTSIZ  (1*1024*1024*1024)  /* max text size */
+#define TARGET_DFLDSIZ  (128*1024*1024)     /* initial data size limit */
+#define TARGET_MAXDSIZ  (1*1024*1024*1024)  /* max data size */
+#define TARGET_DFLSSIZ  (128*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ  (1*1024*1024*1024)  /* max stack size */
+#define TARGET_SGROWSIZ (128*1024)      /* amount to grow stack */
+
+#define TARGET_RESERVED_VA 0xf7000000
+
+/* XXX this may not be right */
+#define TARGET_VM_MAXUSER_ADDRESS   (0xc0000000 - (512 * 1024 * 1024))
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+#ifndef UREG_I6
+#define UREG_I6        6
+#endif
+#ifndef UREG_FP
+#define UREG_FP        UREG_I6
+#endif
+
+static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+    return state->regwptr[UREG_FP];
+}
+
+static inline void set_second_rval(CPUSPARCState *state, abi_ulong retval2)
+{
+    state->regwptr[1] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
+
diff --git a/bsd-user/sparc/target_signal.h b/bsd-user/sparc/target_signal.h
index 5b2abba..181867a 100644
--- a/bsd-user/sparc/target_signal.h
+++ b/bsd-user/sparc/target_signal.h
@@ -19,9 +19,4 @@ typedef struct target_sigaltstack {
 #define UREG_FP        UREG_I6
 #endif
 
-static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
-{
-    return state->regwptr[UREG_FP];
-}
-
 #endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/sparc64/target_arch.h b/bsd-user/sparc64/target_arch.h
new file mode 100644
index 0000000..46bbcf8
--- /dev/null
+++ b/bsd-user/sparc64/target_arch.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+void bsd_sparc64_save_window(CPUSPARCState *env);
+void bsd_sparc64_restore_window(CPUSPARCState *env);
+void bsd_sparc64_flush_windows(CPUSPARCState *env);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* ! _TARGET_ARCH_H_ */
diff --git a/bsd-user/sparc64/target_arch_cpu.c b/bsd-user/sparc64/target_arch_cpu.c
new file mode 100644
index 0000000..e7bede8
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_cpu.c
@@ -0,0 +1,118 @@
+/*
+ *  sparc64 cpu related code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+
+#include "target_arch.h"
+
+#define SPARC64_STACK_BIAS 2047
+
+/* #define DEBUG_WIN */
+/* WARNING: dealing with register windows _is_ complicated. More info
+   can be found at http://www.sics.se/~psm/sparcstack.html */
+static int get_reg_index(CPUSPARCState *env, int cwp, int index)
+{
+    index = (index + cwp * 16) % (16 * env->nwindows);
+    /* wrap handling : if cwp is on the last window, then we use the
+       registers 'after' the end */
+    if (index < 8 && env->cwp == env->nwindows - 1) {
+        index += 16 * env->nwindows;
+    }
+    return index;
+}
+
+/* save the register window 'cwp1' */
+static void save_window_offset(CPUSPARCState *env, int cwp1)
+{
+    unsigned int i;
+    abi_ulong sp_ptr;
+
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+    if (sp_ptr & 3) {
+        sp_ptr += SPARC64_STACK_BIAS;
+    }
+#if defined(DEBUG_WIN)
+    printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for (i = 0; i < 16; i++) {
+        /* FIXME - what to do if put_user() fails? */
+        put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+}
+
+void bsd_sparc64_save_window(CPUSPARCState *env)
+{
+    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+    env->cansave++;
+    env->canrestore--;
+}
+
+void bsd_sparc64_restore_window(CPUSPARCState *env)
+{
+    unsigned int i, cwp1;
+    abi_ulong sp_ptr;
+
+    /* restore the invalid window */
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+    if (sp_ptr & 3) {
+        sp_ptr += SPARC64_STACK_BIAS;
+    }
+#if defined(DEBUG_WIN)
+    printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for (i = 0; i < 16; i++) {
+        /* FIXME - what to do if get_user() fails? */
+        get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+    env->canrestore++;
+    if (env->cleanwin < env->nwindows - 1) {
+        env->cleanwin++;
+    }
+    env->cansave--;
+}
+
+void bsd_sparc64_flush_windows(CPUSPARCState *env)
+{
+    int offset, cwp1;
+
+    offset = 1;
+    for (;;) {
+        /* if restore would invoke restore_window(), then we can stop */
+        cwp1 = cpu_cwp_inc(env, env->cwp + offset);
+        if (env->canrestore == 0) {
+            break;
+        }
+        env->cansave++;
+        env->canrestore--;
+        save_window_offset(env, cwp1);
+        offset++;
+    }
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+#if defined(DEBUG_WIN)
+    printf("bsd_sparc64_flush_windows: nb=%d\n", offset - 1);
+#endif
+}
+
diff --git a/bsd-user/sparc64/target_arch_cpu.h b/bsd-user/sparc64/target_arch_cpu.h
new file mode 100644
index 0000000..e497711
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_cpu.h
@@ -0,0 +1,191 @@
+/*
+ *  sparc64 cpu init and loop
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "TI UltraSparc II"
+
+#define TARGET_CPU_RESET(env) cpu_reset(ENV_GET_CPU(env))
+
+static inline void target_cpu_init(CPUSPARCState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    env->pc = regs->pc;
+    env->npc = regs->npc;
+    env->y = regs->y;
+    for (i = 0; i < 8; i++) {
+        env->gregs[i] = regs->u_regs[i];
+    }
+    for (i = 0; i < 8; i++) {
+        env->regwptr[i] = regs->u_regs[i + 8];
+    }
+}
+
+
+static inline void target_cpu_loop(CPUSPARCState *env)
+{
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
+    int trapnr, ret, syscall_nr;
+    /* target_siginfo_t info; */
+
+    while (1) {
+        trapnr = cpu_sparc_exec(env);
+
+        switch (trapnr) {
+        /* FreeBSD uses 0x141 for syscalls too */
+        case 0x141:
+            if (bsd_type != target_freebsd) {
+                goto badtrap;
+            }
+        case 0x100:
+            syscall_nr = env->gregs[1];
+            if (bsd_type == target_freebsd) {
+                ret = do_freebsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5], 0, 0);
+            } else if (bsd_type == target_netbsd) {
+                ret = do_netbsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5]);
+            } else { /* if (bsd_type == target_openbsd) */
+                syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
+                                TARGET_OPENBSD_SYSCALL_G2RFLAG);
+                ret = do_openbsd_syscall(env, syscall_nr,
+                                         env->regwptr[0], env->regwptr[1],
+                                         env->regwptr[2], env->regwptr[3],
+                                         env->regwptr[4], env->regwptr[5]);
+            }
+            if ((unsigned int)ret >= (unsigned int)(-515)) {
+                ret = -ret;
+#if !defined(TARGET_ABI32)
+                env->xcc |= PSR_CARRY;
+#else
+                env->psr |= PSR_CARRY;
+#endif
+            } else {
+#if !defined(TARGET_ABI32)
+                env->xcc &= ~PSR_CARRY;
+#else
+                env->psr &= ~PSR_CARRY;
+#endif
+            }
+            env->regwptr[0] = ret;
+            /* next instruction */
+            if (bsd_type == target_openbsd &&
+                env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
+                env->pc = env->gregs[2];
+                env->npc = env->pc + 4;
+            } else if (bsd_type == target_openbsd &&
+                       env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
+                env->pc = env->gregs[7];
+                env->npc = env->pc + 4;
+            } else {
+                env->pc = env->npc;
+                env->npc = env->npc + 4;
+            }
+            break;
+
+        case 0x83: /* flush windows */
+#ifdef TARGET_ABI32
+        case 0x103:
+#endif
+            bsd_sparc64_flush_windows(env);
+            /* next instruction */
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+            break;
+
+        case TT_SPILL: /* window overflow */
+            bsd_sparc64_save_window(env);
+            break;
+
+        case TT_FILL: /* window underflow */
+            bsd_sparc64_restore_window(env);
+            break;
+
+        case TT_TFAULT:
+        case TT_DFAULT:
+#if 0
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                if (trapnr == TT_DFAULT) {
+                    info._sifields._sigfault._addr = env->dmmuregs[4];
+                } else {
+                    info._sifields._sigfault._addr = env->tsptr->tpc;
+                    /* queue_signal(env, info.si_signo, &info); */
+                }
+            }
+#endif
+            break;
+
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+#if 0
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    /* queue_signal(env, info.si_signo, &info); */
+                }
+#endif
+            }
+            break;
+
+        default:
+badtrap:
+            printf("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            exit(1);
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUSPARCState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regwptr[22] = newsp;
+    env->regwptr[0] = 0;
+    /* FIXME: Do we also need to clear CF?  */
+    /* XXXXX */
+    printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+    cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/sparc64/target_arch_vmparam.h b/bsd-user/sparc64/target_arch_vmparam.h
new file mode 100644
index 0000000..2c2323b
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_vmparam.h
@@ -0,0 +1,37 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to amd64/include/vmparam.h */
+#define TARGET_MAXTSIZ  (1*1024*1024*1024)  /* max text size */
+#define TARGET_DFLDSIZ  (128*1024*1024)     /* initial data size limit */
+#define TARGET_MAXDSIZ  (1*1024*1024*1024)  /* max data size */
+#define TARGET_DFLSSIZ  (128*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ  (1*1024*1024*1024)  /* max stack size */
+#define TARGET_SGROWSIZ (128*1024)      /* amount to grow stack */
+
+/* XXX */
+#define TARGET_VM_MINUSER_ADDRESS   (0x0000000000000000UL)
+#define TARGET_VM_MAXUSER_ADDRESS   (0x000007fe00000000UL)
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+#ifndef UREG_I6
+#define UREG_I6        6
+#endif
+#ifndef UREG_FP
+#define UREG_FP        UREG_I6
+#endif
+
+static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+    return state->regwptr[UREG_FP];
+}
+
+static inline void set_second_rval(CPUSPARCState *state, abi_ulong retval2)
+{
+    state->regwptr[1] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
+
diff --git a/bsd-user/sparc64/target_signal.h b/bsd-user/sparc64/target_signal.h
index 5b2abba..181867a 100644
--- a/bsd-user/sparc64/target_signal.h
+++ b/bsd-user/sparc64/target_signal.h
@@ -19,9 +19,4 @@ typedef struct target_sigaltstack {
 #define UREG_FP        UREG_I6
 #endif
 
-static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
-{
-    return state->regwptr[UREG_FP];
-}
-
 #endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/x86_64/target_arch.h b/bsd-user/x86_64/target_arch.h
new file mode 100644
index 0000000..7fe81dc
--- /dev/null
+++ b/bsd-user/x86_64/target_arch.h
@@ -0,0 +1,13 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+/* target_arch_cpu.c */
+void bsd_x86_64_write_dt(void *ptr, unsigned long addr, unsigned long limit,
+                int flags);
+void bsd_x86_64_set_idt(int n, unsigned int dpl);
+void bsd_x86_64_set_idt_base(uint64_t base);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/x86_64/target_arch_cpu.c b/bsd-user/x86_64/target_arch_cpu.c
new file mode 100644
index 0000000..5cfdfca
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_cpu.c
@@ -0,0 +1,79 @@
+/*
+ *  x86_64 cpu related code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+#include "qemu/timer.h"
+
+#include "target_arch.h"
+
+static uint64_t *idt_table;
+
+/* CPUX86 core interface */
+void cpu_smm_update(CPUX86State *env)
+{
+}
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+    return cpu_get_real_ticks();
+}
+
+int cpu_get_pic_interrupt(CPUX86State *env)
+{
+    return -1;
+}
+
+void bsd_x86_64_write_dt(void *ptr, unsigned long addr,
+        unsigned long limit, int flags)
+{
+    unsigned int e1, e2;
+    uint32_t *p;
+    e1 = (addr << 16) | (limit & 0xffff);
+    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+    e2 |= flags;
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
+        uint64_t addr, unsigned int sel)
+{
+    uint32_t *p, e1, e2;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+    p[2] = tswap32(addr >> 32);
+    p[3] = 0;
+}
+
+/* only dpl matters as we do only user space emulation */
+void bsd_x86_64_set_idt(int n, unsigned int dpl)
+{
+    set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
+}
+
+void bsd_x86_64_set_idt_base(uint64_t base)
+{
+    idt_table = g2h(base);
+}
diff --git a/bsd-user/x86_64/target_arch_cpu.h b/bsd-user/x86_64/target_arch_cpu.h
new file mode 100644
index 0000000..9a66b67
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_cpu.h
@@ -0,0 +1,324 @@
+/*
+ *  x86_64 cpu init and loop
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "qemu64"
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUX86State *env,
+        struct target_pt_regs *regs)
+{
+    uint64_t *gdt_table;
+
+    cpu_x86_set_cpl(env, 3);
+
+    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+    env->hflags |= HF_PE_MASK;
+    if (env->features[FEAT_1_EDX] & CPUID_SSE) {
+        env->cr[4] |= CR4_OSFXSR_MASK;
+        env->hflags |= HF_OSFXSR_MASK;
+    }
+
+    /* enable 64 bit mode if possible */
+    if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
+        fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
+        exit(1);
+    }
+    env->cr[4] |= CR4_PAE_MASK;
+    env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
+    env->hflags |= HF_LMA_MASK;
+
+    /* flags setup : we activate the IRQs by default as in user mode */
+    env->eflags |= IF_MASK;
+
+    /* register setup */
+    env->regs[R_EAX] = regs->rax;
+    env->regs[R_EBX] = regs->rbx;
+    env->regs[R_ECX] = regs->rcx;
+    env->regs[R_EDX] = regs->rdx;
+    env->regs[R_ESI] = regs->rsi;
+    env->regs[R_EDI] = regs->rdi;
+    env->regs[R_EBP] = regs->rbp;
+    env->regs[R_ESP] = regs->rsp;
+    env->eip = regs->rip;
+
+    /* interrupt setup */
+    env->idt.limit = 511;
+
+    env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+        PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    bsd_x86_64_set_idt_base(env->idt.base);
+    bsd_x86_64_set_idt(0, 0);
+    bsd_x86_64_set_idt(1, 0);
+    bsd_x86_64_set_idt(2, 0);
+    bsd_x86_64_set_idt(3, 3);
+    bsd_x86_64_set_idt(4, 3);
+    bsd_x86_64_set_idt(5, 0);
+    bsd_x86_64_set_idt(6, 0);
+    bsd_x86_64_set_idt(7, 0);
+    bsd_x86_64_set_idt(8, 0);
+    bsd_x86_64_set_idt(9, 0);
+    bsd_x86_64_set_idt(10, 0);
+    bsd_x86_64_set_idt(11, 0);
+    bsd_x86_64_set_idt(12, 0);
+    bsd_x86_64_set_idt(13, 0);
+    bsd_x86_64_set_idt(14, 0);
+    bsd_x86_64_set_idt(15, 0);
+    bsd_x86_64_set_idt(16, 0);
+    bsd_x86_64_set_idt(17, 0);
+    bsd_x86_64_set_idt(18, 0);
+    bsd_x86_64_set_idt(19, 0);
+    bsd_x86_64_set_idt(0x80, 3);
+
+    /* segment setup */
+    env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+            PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+    gdt_table = g2h(env->gdt.base);
+
+    /* 64 bit code segment */
+    bsd_x86_64_write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_L_MASK
+            | (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+
+    bsd_x86_64_write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+            (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+
+    cpu_x86_load_seg(env, R_CS, __USER_CS);
+    cpu_x86_load_seg(env, R_SS, __USER_DS);
+    cpu_x86_load_seg(env, R_DS, 0);
+    cpu_x86_load_seg(env, R_ES, 0);
+    cpu_x86_load_seg(env, R_FS, 0);
+    cpu_x86_load_seg(env, R_GS, 0);
+}
+
+static inline void target_cpu_loop(CPUX86State *env)
+{
+    int trapnr;
+    abi_ulong pc;
+    /* target_siginfo_t info; */
+
+    for (;;) {
+        trapnr = cpu_x86_exec(env);
+        switch (trapnr) {
+        case 0x80:
+            /* syscall from int $0x80 */
+            if (bsd_type == target_freebsd) {
+                abi_ulong params = (abi_ulong) env->regs[R_ESP] +
+                    sizeof(int32_t);
+                int32_t syscall_nr = env->regs[R_EAX];
+                int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+                if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int32_t);
+                } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int64_t);
+                }
+                get_user_s32(arg1, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg2, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg3, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg4, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg5, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg6, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg7, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg8, params);
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      syscall_nr,
+                                                      arg1,
+                                                      arg2,
+                                                      arg3,
+                                                      arg4,
+                                                      arg5,
+                                                      arg6,
+                                                      arg7,
+                                                      arg8);
+            } else { /* if (bsd_type == target_openbsd) */
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EBX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_EBP]);
+            }
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
+            break;
+
+        case EXCP_SYSCALL:
+            /* syscall from syscall instruction */
+            if (bsd_type == target_freebsd) {
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[8],
+                                                      env->regs[9], 0, 0);
+            } else { /* if (bsd_type == target_openbsd) */
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDX],
+                                                      env->regs[10],
+                                                      env->regs[8],
+                                                      env->regs[9]);
+            }
+            env->eip = env->exception_next_eip;
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
+            break;
+
+#if 0
+        case EXCP0B_NOSEG:
+        case EXCP0C_STACK:
+            info.si_signo = SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP0D_GPF:
+            /* XXX: potential problem if ABI32 */
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP0E_PAGE:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            if (!(env->error_code & 1)) {
+                info.si_code = TARGET_SEGV_MAPERR;
+            } else {
+                info.si_code = TARGET_SEGV_ACCERR;
+            }
+            info._sifields._sigfault._addr = env->cr[2];
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP00_DIVZ:
+            /* division by zero */
+            info.si_signo = SIGFPE;
+            info.si_errno = 0;
+            info.si_code = TARGET_FPE_INTDIV;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP01_DB:
+        case EXCP03_INT3:
+            info.si_signo = SIGTRAP;
+            info.si_errno = 0;
+            if (trapnr == EXCP01_DB) {
+                info.si_code = TARGET_TRAP_BRKPT;
+                info._sifields._sigfault._addr = env->eip;
+            } else {
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+            }
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP04_INTO:
+        case EXCP05_BOUND:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP06_ILLOP:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(env, info.si_signo, &info);
+            break;
+#endif
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+#if 0
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(env, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                }
+            }
+            break;
+#endif
+        default:
+            pc = env->segs[R_CS].base + env->eip;
+            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - "
+                    "aborting\n", (long)pc, trapnr);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[R_ESP] = newsp;
+    env->regs[R_EAX] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+    cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/x86_64/target_arch_vmparam.h b/bsd-user/x86_64/target_arch_vmparam.h
new file mode 100644
index 0000000..5e13076
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_vmparam.h
@@ -0,0 +1,28 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to amd64/include/vmparam.h */
+#define TARGET_MAXTSIZ  (128UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ  (32768UL*1024*1024) /* initial data size limit */
+#define TARGET_MAXDSIZ  (32768UL*1024*1024) /* max data size */
+#define TARGET_DFLSSIZ  (8UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ  (512UL*1024*1024)   /* max stack size */
+#define TARGET_SGROWSIZ (128UL*1024)        /* amount to grow stack */
+
+#define TARGET_VM_MAXUSER_ADDRESS   (0x0000800000000000UL)
+
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+    return state->regs[R_ESP];
+}
+
+static inline void set_second_rval(CPUX86State *state, abi_ulong retval2)
+{
+    state->regs[R_EDX] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/x86_64/target_signal.h b/bsd-user/x86_64/target_signal.h
index 659cd40..5491687 100644
--- a/bsd-user/x86_64/target_signal.h
+++ b/bsd-user/x86_64/target_signal.h
@@ -11,9 +11,4 @@ typedef struct target_sigaltstack {
 	abi_ulong ss_size;
 } target_stack_t;
 
-static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
-{
-    return state->regs[R_ESP];
-}
-
 #endif /* TARGET_SIGNAL_H */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 05/19] bsd-user: move target arch and host OS dependent code out of syscall.c
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (24 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 04/19] bsd-user: move target arch and host OS dependent code out of main.c Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 06/19] bsd-user: add support for freebsd time related system calls Stacey Son
                   ` (13 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change moves the system call handler for sysctl(2) and sysarch(2)
from syscall.c to the OS and arch dependent directories.  This
eliminates many of the #ifdef's in syscall.c.  These system call
handlers are now located in the host os and target arch directories.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs                  |    2 +-
 bsd-user/arm/target_arch_sigtramp.h     |   33 ++++
 bsd-user/bsdload.c                      |  170 ++++++++++++++------
 bsd-user/elfload.c                      |    9 +-
 bsd-user/freebsd/os-sys.c               |  268 +++++++++++++++++++++++++++++++
 bsd-user/freebsd/target_os_stack.h      |  157 ++++++++++++++++++
 bsd-user/i386/target_arch_sigtramp.h    |   11 ++
 bsd-user/mips/target_arch_sigtramp.h    |   23 +++
 bsd-user/mips64/target_arch_sigtramp.h  |   23 +++
 bsd-user/netbsd/os-sys.c                |   46 ++++++
 bsd-user/netbsd/target_os_stack.h       |   33 ++++
 bsd-user/openbsd/os-sys.c               |   46 ++++++
 bsd-user/openbsd/target_os_stack.h      |   33 ++++
 bsd-user/qemu.h                         |   30 +++-
 bsd-user/sparc/target_arch_sigtramp.h   |   11 ++
 bsd-user/sparc64/target_arch_sigtramp.h |   11 ++
 bsd-user/syscall.c                      |  210 +++---------------------
 bsd-user/x86_64/target_arch_sigtramp.h  |   11 ++
 18 files changed, 884 insertions(+), 243 deletions(-)
 create mode 100644 bsd-user/arm/target_arch_sigtramp.h
 create mode 100644 bsd-user/freebsd/os-sys.c
 create mode 100644 bsd-user/freebsd/target_os_stack.h
 create mode 100644 bsd-user/i386/target_arch_sigtramp.h
 create mode 100644 bsd-user/mips/target_arch_sigtramp.h
 create mode 100644 bsd-user/mips64/target_arch_sigtramp.h
 create mode 100644 bsd-user/netbsd/os-sys.c
 create mode 100644 bsd-user/netbsd/target_os_stack.h
 create mode 100644 bsd-user/openbsd/os-sys.c
 create mode 100644 bsd-user/openbsd/target_os_stack.h
 create mode 100644 bsd-user/sparc/target_arch_sigtramp.h
 create mode 100644 bsd-user/sparc64/target_arch_sigtramp.h
 create mode 100644 bsd-user/x86_64/target_arch_sigtramp.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 41e8dce..b5ed89e 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,2 +1,2 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o $(TARGET_ABI_DIR)/target_arch_cpu.o
+	        uaccess.o $(HOST_ABI_DIR)/os-sys.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/arm/target_arch_sigtramp.h b/bsd-user/arm/target_arch_sigtramp.h
new file mode 100644
index 0000000..98dc313
--- /dev/null
+++ b/bsd-user/arm/target_arch_sigtramp.h
@@ -0,0 +1,33 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+/* Compare to arm/arm/locore.S ENTRY_NP(sigcode) */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+    int i;
+    uint32_t sys_exit = TARGET_FREEBSD_NR_exit;
+    /*
+     * The code has to load r7 manually rather than using
+     * "ldr r7, =SYS_return to make sure the size of the
+     * code is correct.
+     */
+    uint32_t sigtramp_code[] = {
+    /* 1 */ 0xE1A0000D,         /* mov r0, sp */
+    /* 2 */ 0xE59F700C,         /* ldr r7, [pc, #12] */
+    /* 3 */ 0xEF000000 + sys_sigreturn, /* swi (SYS_sigreturn) */
+    /* 4 */ 0xE59F7008,         /* ldr r7, [pc, #8] */
+    /* 5 */ 0xEF000000 + sys_exit,      /* swi (SYS_exit)*/
+    /* 6 */ 0xEAFFFFFA,         /* b . -16 */
+    /* 7 */ sys_sigreturn,
+    /* 8 */ sys_exit
+    };
+
+    for (i = 0; i < 8; i++) {
+        tswap32s(&sigtramp_code[i]);
+    }
+
+    return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c
index 2abc713..45fdcf8 100644
--- a/bsd-user/bsdload.c
+++ b/bsd-user/bsdload.c
@@ -1,4 +1,19 @@
-/* Code for loading BSD executables.  Mostly linux kernel code.  */
+/*
+ *  Load BSD executables.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -26,38 +41,22 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src,
     return 0;
 }
 
-static int in_group_p(gid_t g)
-{
-    /* return TRUE if we're in the specified group, FALSE otherwise */
-    int         ngroup;
-    int         i;
-    gid_t       grouplist[TARGET_NGROUPS];
-
-    ngroup = getgroups(TARGET_NGROUPS, grouplist);
-    for(i = 0; i < ngroup; i++) {
-        if(grouplist[i] == g) {
-            return 1;
-        }
-    }
-    return 0;
-}
-
 static int count(char ** vec)
 {
     int         i;
 
-    for(i = 0; *vec; i++) {
+    for (i = 0; *vec; i++) {
         vec++;
     }
 
     return(i);
 }
 
-static int prepare_binprm(struct linux_binprm *bprm)
+static int prepare_binprm(struct bsd_binprm *bprm)
 {
     struct stat         st;
     int mode;
-    int retval, id_change;
+    int retval;
 
     if(fstat(bprm->fd, &st) < 0) {
         return(-errno);
@@ -73,14 +72,10 @@ static int prepare_binprm(struct linux_binprm *bprm)
 
     bprm->e_uid = geteuid();
     bprm->e_gid = getegid();
-    id_change = 0;
 
     /* Set-uid? */
     if(mode & S_ISUID) {
         bprm->e_uid = st.st_uid;
-        if(bprm->e_uid != geteuid()) {
-            id_change = 1;
-        }
     }
 
     /* Set-gid? */
@@ -91,9 +86,6 @@ static int prepare_binprm(struct linux_binprm *bprm)
      */
     if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
         bprm->e_gid = st.st_gid;
-        if (!in_group_p(bprm->e_gid)) {
-                id_change = 1;
-        }
     }
 
     memset(bprm->buf, 0, sizeof(bprm->buf));
@@ -154,34 +146,116 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
     return sp;
 }
 
+static int is_there(const char *candidate)
+{
+    struct stat fin;
+
+    /* XXX work around access(2) false positives for superuser */
+    if (access(candidate, X_OK) == 0 && stat(candidate, &fin) == 0 &&
+            S_ISREG(fin.st_mode) && (getuid() != 0 ||
+                (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static int find_in_path(char *path, const char *filename, char *retpath,
+        size_t rpsize)
+{
+    const char *d;
+    int found;
+
+    if (strchr(filename, '/') != NULL) {
+        if (is_there(filename)) {
+                if (!realpath(filename, retpath)) {
+                    return -1;
+                }
+                return 0;
+        } else {
+            return -1;
+        }
+    }
+
+    found = 0;
+    while ((d = strsep(&path, ":")) != NULL) {
+        if (*d == '\0') {
+            d = ".";
+        }
+        if (snprintf(retpath, rpsize, "%s/%s", d, filename) >= (int)rpsize) {
+            continue;
+        }
+        if (is_there((const char *)retpath)) {
+            found = 1;
+            break;
+        }
+    }
+    return found;
+}
+
 int loader_exec(const char * filename, char ** argv, char ** envp,
-             struct target_pt_regs * regs, struct image_info *infop)
+             struct target_pt_regs *regs, struct image_info *infop,
+             struct bsd_binprm *bprm)
 {
-    struct linux_binprm bprm;
-    int retval;
-    int i;
+    char *p, *path = NULL, fullpath[PATH_MAX];
+    const char *execname = NULL;
+    int retval, i, found;
 
-    bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
+    bprm->p = TARGET_PAGE_SIZE * MAX_ARG_PAGES; /* -sizeof(unsigned int); */
     for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
-            bprm.page[i] = NULL;
-    retval = open(filename, O_RDONLY);
-    if (retval < 0)
+            bprm->page[i] = NULL;
+
+    /* Find target executable in path, if not already an absolute path. */
+    p = getenv("PATH");
+    if (p != NULL) {
+        path = g_strdup(p);
+        if (path == NULL) {
+            fprintf(stderr, "Out of memory\n");
+            return -1;
+        }
+        execname = realpath(filename, NULL);
+        if (execname == NULL) {
+            execname = g_strdup(filename);
+        }
+        found = find_in_path(path, execname, fullpath, sizeof(fullpath));
+        /* Absolute path specified but not found? */
+        if (found == -1) {
+            return -1;
+        }
+        if (found) {
+            retval = open(fullpath, O_RDONLY);
+            bprm->fullpath = g_strdup(fullpath);
+        } else {
+            retval = open(execname, O_RDONLY);
+            bprm->fullpath = NULL;
+        }
+        if (execname) {
+            g_free((void *)execname);
+        }
+        g_free(path);
+    } else {
+        retval = open(filename, O_RDONLY);
+        bprm->fullpath = NULL;
+    }
+    if (retval < 0) {
         return retval;
-    bprm.fd = retval;
-    bprm.filename = (char *)filename;
-    bprm.argc = count(argv);
-    bprm.argv = argv;
-    bprm.envc = count(envp);
-    bprm.envp = envp;
+    }
+
+    bprm->fd = retval;
+    bprm->filename = (char *)filename;
+    bprm->argc = count(argv);
+    bprm->argv = argv;
+    bprm->envc = count(envp);
+    bprm->envp = envp;
 
-    retval = prepare_binprm(&bprm);
+    retval = prepare_binprm(bprm);
 
     if(retval>=0) {
-        if (bprm.buf[0] == 0x7f
-                && bprm.buf[1] == 'E'
-                && bprm.buf[2] == 'L'
-                && bprm.buf[3] == 'F') {
-            retval = load_elf_binary(&bprm,regs,infop);
+        if (bprm->buf[0] == 0x7f
+                && bprm->buf[1] == 'E'
+                && bprm->buf[2] == 'L'
+                && bprm->buf[3] == 'F') {
+            retval = load_elf_binary(bprm, regs, infop);
         } else {
             fprintf(stderr, "Unknown binary format\n");
             return -1;
@@ -196,7 +270,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
 
     /* Something went wrong, return the inode and free the argument pages*/
     for (i=0 ; i<MAX_ARG_PAGES ; i++) {
-        g_free(bprm.page[i]);
+        g_free(bprm->page[i]);
     }
     return(retval);
 }
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index ccf72d1..68d0209 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -91,6 +91,9 @@ enum {
 #define ELIBBAD 80
 #endif
 
+abi_ulong target_stksiz;
+abi_ulong target_stkbas;
+
 #ifdef TARGET_I386
 
 #define ELF_PLATFORM get_elf_platform()
@@ -665,7 +668,7 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
     return p;
 }
 
-static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
+static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm,
                                  struct image_info *info)
 {
     abi_ulong stack_base, size, error;
@@ -1147,8 +1150,8 @@ static void load_symbols(struct elfhdr *hdr, int fd)
     syminfos = s;
 }
 
-int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
-                    struct image_info * info)
+int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
+                    struct image_info *info)
 {
     struct elfhdr elf_ex;
     struct elfhdr interp_elf_ex;
diff --git a/bsd-user/freebsd/os-sys.c b/bsd-user/freebsd/os-sys.c
new file mode 100644
index 0000000..86b2826
--- /dev/null
+++ b/bsd-user/freebsd/os-sys.c
@@ -0,0 +1,268 @@
+/*
+ *  FreeBSD sysctl() and sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+#include "qemu.h"
+
+#include "target_arch_sysarch.h"
+#include "target_os_vmparam.h"
+
+/*
+ * XXX this uses the undocumented oidfmt interface to find the kind of
+ * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
+ * (compare to src/sbin/sysctl/sysctl.c)
+ */
+static int
+oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
+{
+    int qoid[CTL_MAXNAME+2];
+    uint8_t buf[BUFSIZ];
+    int i;
+    size_t j;
+
+    qoid[0] = 0;
+    qoid[1] = 4;
+    memcpy(qoid + 2, oid, len * sizeof(int));
+
+    j = sizeof(buf);
+    i = sysctl(qoid, len + 2, buf, &j, 0, 0);
+    if (i) {
+        return i;
+    }
+
+    if (kind) {
+        *kind = *(uint32_t *)buf;
+    }
+
+    if (fmt) {
+        strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
+    }
+    return 0;
+}
+
+/*
+ * try and convert sysctl return data for the target.
+ * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT.
+ */
+static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
+{
+    switch (kind & CTLTYPE) {
+    case CTLTYPE_INT:
+    case CTLTYPE_UINT:
+        *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp);
+        break;
+
+#ifdef TARGET_ABI32
+    case CTLTYPE_LONG:
+    case CTLTYPE_ULONG:
+        *(uint32_t *)holdp = tswap32(*(long *)holdp);
+        break;
+#else
+    case CTLTYPE_LONG:
+        *(uint64_t *)holdp = tswap64(*(long *)holdp);
+    case CTLTYPE_ULONG:
+        *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
+        break;
+#endif
+#if !defined(__FreeBSD_version) || __FreeBSD_version < 900031
+    case CTLTYPE_QUAD:
+#else
+    case CTLTYPE_U64:
+    case CTLTYPE_S64:
+#endif
+        *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
+        break;
+
+    case CTLTYPE_STRING:
+        break;
+
+    default:
+        /* XXX unhandled */
+        return -1;
+    }
+    return 0;
+}
+
+/*
+ * Convert the undocmented name2oid sysctl data for the target.
+ */
+static inline void sysctl_name2oid(uint32_t *holdp, size_t holdlen)
+{
+    size_t i;
+
+    for (i = 0; i < holdlen; i++) {
+        holdp[i] = tswap32(holdp[i]);
+    }
+}
+
+static inline void sysctl_oidfmt(uint32_t *holdp)
+{
+    /* byte swap the kind */
+    holdp[0] = tswap32(holdp[0]);
+}
+
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+    abi_long ret;
+    void *hnamep, *holdp = NULL, *hnewp = NULL;
+    size_t holdlen;
+    abi_ulong oldlen = 0;
+    int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
+    uint32_t kind = 0;
+    TaskState *ts = (TaskState *)env->opaque;
+
+    if (oldlenp) {
+        if (get_user_ual(oldlen, oldlenp)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    hnamep = lock_user(VERIFY_READ, namep, namelen, 1);
+    if (hnamep == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (newp) {
+        hnewp = lock_user(VERIFY_READ, newp, newlen, 1);
+        if (hnewp == NULL) {
+            return -TARGET_EFAULT;
+        }
+    }
+    if (oldp) {
+        holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0);
+        if (holdp == NULL) {
+            return -TARGET_EFAULT;
+        }
+    }
+    holdlen = oldlen;
+    for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++) {
+        *q++ = tswap32(*p);
+    }
+    oidfmt(snamep, namelen, NULL, &kind);
+
+    /* Handle some arch/emulator dependent sysctl()'s here. */
+    switch (snamep[0]) {
+    case CTL_KERN:
+        switch (snamep[1]) {
+        case KERN_USRSTACK:
+#if TARGET_USRSTACK != 0
+            (*(abi_ulong *)holdp) = tswapal(TARGET_USRSTACK);
+            holdlen = sizeof(abi_ulong);
+            ret = 0;
+#else
+            ret = -TARGET_ENOENT;
+#endif
+            goto out;
+
+        case KERN_PS_STRINGS:
+#if defined(TARGET_PS_STRINGS)
+            (*(abi_ulong *)holdp) = tswapal(TARGET_PS_STRINGS);
+            holdlen = sizeof(abi_ulong);
+            ret = 0;
+#else
+            ret = -TARGET_ENOENT;
+#endif
+            goto out;
+
+        case KERN_PROC:
+            switch (snamep[2]) {
+            case KERN_PROC_PATHNAME:
+                holdlen = strlen(ts->bprm->fullpath) + 1;
+                if (holdp) {
+                    if (oldlen < holdlen) {
+                        ret = -TARGET_EINVAL;
+                        goto out;
+                    }
+                    strlcpy(holdp, ts->bprm->fullpath, oldlen);
+                }
+                ret = 0;
+                goto out;
+
+            default:
+                break;
+            }
+            break;
+
+        default:
+            break;
+        }
+        break;
+
+    case CTL_HW:
+        switch (snamep[1]) {
+        case HW_MACHINE:
+            strlcpy(holdp, TARGET_HW_MACHINE, oldlen);
+            ret = 0;
+            goto out;
+
+        case HW_MACHINE_ARCH:
+            strlcpy(holdp, TARGET_HW_MACHINE_ARCH, oldlen);
+            ret = 0;
+            goto out;
+
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
+    if (!ret && (holdp != 0 && holdlen != 0)) {
+        if (0 == snamep[0] && (3 == snamep[1] || 4 == snamep[1])) {
+            if (3 == snamep[1]) {
+                /* Handle the undocumented name2oid special case. */
+                sysctl_name2oid(holdp, holdlen);
+            } else {
+                /* Handle oidfmt */
+                sysctl_oidfmt(holdp);
+            }
+        } else {
+            sysctl_oldcvt(holdp, holdlen, kind);
+        }
+    }
+#ifdef DEBUG
+    else {
+        printf("sysctl(mib[0]=%d, mib[1]=%d, mib[3]=%d...) returned %d\n",
+        snamep[0], snamep[1], snamep[2], (int)ret);
+    }
+#endif
+
+out:
+    if (oldlenp) {
+        put_user_ual(holdlen, oldlenp);
+    }
+    unlock_user(hnamep, namep, 0);
+    unlock_user(holdp, oldp, holdlen);
+    if (hnewp) {
+        unlock_user(hnewp, newp, 0);
+    }
+    g_free(snamep);
+    return ret;
+}
+
+/* sysarch() is architecture dependent. */
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+{
+
+    return do_freebsd_arch_sysarch(cpu_env, arg1, arg2);
+}
diff --git a/bsd-user/freebsd/target_os_stack.h b/bsd-user/freebsd/target_os_stack.h
new file mode 100644
index 0000000..c84b69e
--- /dev/null
+++ b/bsd-user/freebsd/target_os_stack.h
@@ -0,0 +1,157 @@
+#ifndef _TARGET_OS_STACK_H_
+#define _TARGET_OS_STACK_H_
+
+#include <sys/param.h>
+#include "target_arch_sigtramp.h"
+
+/*
+ * The inital FreeBSD stack is as follows:
+ * (see kern/kern_exec.c exec_copyout_strings() )
+ *
+ *  Hi Address -> char **ps_argvstr  (struct ps_strings for ps, w, etc.)
+ *                unsigned ps_nargvstr
+ *                char **ps_envstr
+ *  PS_STRINGS -> unsigned ps_nenvstr
+ *
+ *                machine dependent sigcode (sv_sigcode of size
+ *                                           sv_szsigcode)
+ *
+ *                execpath          (absolute image path for rtld)
+ *
+ *                SSP Canary        (sizeof(long) * 8)
+ *
+ *                page sizes array  (usually sizeof(u_long) )
+ *
+ *  "destp" ->    argv, env strings (up to 262144 bytes)
+ */
+static inline int setup_initial_stack(struct bsd_binprm *bprm,
+        abi_ulong *ret_addr)
+{
+    int i;
+    abi_ulong stack_hi_addr;
+    size_t execpath_len, stringspace;
+    abi_ulong destp, argvp, envp, p;
+    struct target_ps_strings ps_strs;
+    char canary[sizeof(abi_long) * 8];
+
+    stack_hi_addr = p = target_stkbas + target_stksiz;
+
+    /* Save some space for ps_strings. */
+    p -= sizeof(struct target_ps_strings);
+
+#ifdef TARGET_SZSIGCODE
+    /* Add machine depedent sigcode. */
+    p -= TARGET_SZSIGCODE;
+    if (setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc),
+            TARGET_FREEBSD_NR_sigreturn)) {
+        errno = EFAULT;
+        return -1;
+    }
+#endif
+    if (bprm->fullpath) {
+        execpath_len = strlen(bprm->fullpath) + 1;
+        p -= roundup(execpath_len, sizeof(abi_ulong));
+        if (memcpy_to_target(p, bprm->fullpath, execpath_len)) {
+            errno = EFAULT;
+            return -1;
+        }
+    }
+    /* Add canary for SSP. */
+    arc4random_buf(canary, sizeof(canary));
+    p -= roundup(sizeof(canary), sizeof(abi_ulong));
+    if (memcpy_to_target(p, canary, sizeof(canary))) {
+        errno = EFAULT;
+        return -1;
+    }
+    /* Add page sizes array. */
+    /* p -= sizeof(int); */
+    p -= sizeof(abi_ulong);
+    /* if (put_user_u32(TARGET_PAGE_SIZE, p)) { */
+    if (put_user_ual(TARGET_PAGE_SIZE, p)) {
+        errno = EFAULT;
+        return -1;
+    }
+    /* Calculate the string space needed */
+    stringspace = 0;
+    for (i = 0; i < bprm->argc; ++i) {
+        stringspace += strlen(bprm->argv[i]) + 1;
+    }
+    for (i = 0; i < bprm->envc; ++i) {
+        stringspace += strlen(bprm->envp[i]) + 1;
+    }
+    if (stringspace > TARGET_ARG_MAX) {
+       errno = ENOMEM;
+       return -1;
+    }
+
+    /* Make room for the argv and envp strings */
+    /* p = destp = roundup(p - TARGET_SPACE_USRSPACE - (TARGET_ARG_MAX - stringspace), sizeof(abi_ulong)); */
+    argvp = p - TARGET_SPACE_USRSPACE;
+    p = destp = roundup(p - TARGET_SPACE_USRSPACE - TARGET_ARG_MAX, sizeof(abi_ulong));
+
+    /*
+     * Add argv strings.  Note that the argv[] vectors are added by
+     * loader_build_argptr()
+     */
+    /* XXX need to make room for auxargs */
+    /* argvp = destp - ((bprm->argc + bprm->envc + 2) * sizeof(abi_ulong)); */
+    /* envp = argvp + (bprm->argc + 2) * sizeof(abi_ulong); */
+    envp = argvp + (bprm->argc + 1) * sizeof(abi_ulong);
+    ps_strs.ps_argvstr = tswapl(argvp);
+    ps_strs.ps_nargvstr = tswap32(bprm->argc);
+    for (i = 0; i < bprm->argc; ++i) {
+        size_t len = strlen(bprm->argv[i]) + 1;
+
+        if (memcpy_to_target(destp, bprm->argv[i], len)) {
+            errno = EFAULT;
+            return -1;
+        }
+        if (put_user_ual(destp, argvp)) {
+            errno = EFAULT;
+            return -1;
+        }
+        argvp += sizeof(abi_ulong);
+        destp += len;
+    }
+    if (put_user_ual(0, argvp)) {
+        errno = EFAULT;
+        return -1;
+    }
+    /*
+     * Add env strings. Note that the envp[] vectors are added by
+     * loader_build_argptr().
+     */
+    ps_strs.ps_envstr = tswapl(envp);
+    ps_strs.ps_nenvstr = tswap32(bprm->envc);
+    for (i = 0; i < bprm->envc; ++i) {
+        size_t len = strlen(bprm->envp[i]) + 1;
+
+        if (memcpy_to_target(destp, bprm->envp[i], len)) {
+            errno = EFAULT;
+            return -1;
+        }
+        if (put_user_ual(destp, envp)) {
+            errno = EFAULT;
+            return -1;
+        }
+        envp += sizeof(abi_ulong);
+        destp += len;
+    }
+    if (put_user_ual(0, envp)) {
+        errno = EFAULT;
+        return -1;
+    }
+    if (memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs,
+                sizeof(ps_strs))) {
+        errno = EFAULT;
+        return -1;
+    }
+
+    if (ret_addr) {
+       *ret_addr = p;
+    }
+
+    return 0;
+ }
+
+#endif /* !_TARGET_OS_STACK_H_ */
diff --git a/bsd-user/i386/target_arch_sigtramp.h b/bsd-user/i386/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/i386/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/mips/target_arch_sigtramp.h b/bsd-user/mips/target_arch_sigtramp.h
new file mode 100644
index 0000000..5e3c69a
--- /dev/null
+++ b/bsd-user/mips/target_arch_sigtramp.h
@@ -0,0 +1,23 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+/* Compare to mips/mips/locore.S sigcode() */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+    int i;
+    uint32_t sigtramp_code[TARGET_SZSIGCODE/TARGET_INSN_SIZE] = {
+    /* 1 */ 0x67A40000 + sigf_uc,       /* daddu   $a0, $sp, (sigf_uc) */
+    /* 2 */ 0x24020000 + sys_sigreturn, /* li      $v0, (sys_sigreturn) */
+    /* 3 */ 0x0000000C,                 /* syscall */
+    /* 4 */ 0x0000000D                  /* break */
+    };
+
+    for (i = 0; i < 4; i++) {
+        tswap32s(&sigtramp_code[i]);
+    }
+
+    return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/mips64/target_arch_sigtramp.h b/bsd-user/mips64/target_arch_sigtramp.h
new file mode 100644
index 0000000..5e3c69a
--- /dev/null
+++ b/bsd-user/mips64/target_arch_sigtramp.h
@@ -0,0 +1,23 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+/* Compare to mips/mips/locore.S sigcode() */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+    int i;
+    uint32_t sigtramp_code[TARGET_SZSIGCODE/TARGET_INSN_SIZE] = {
+    /* 1 */ 0x67A40000 + sigf_uc,       /* daddu   $a0, $sp, (sigf_uc) */
+    /* 2 */ 0x24020000 + sys_sigreturn, /* li      $v0, (sys_sigreturn) */
+    /* 3 */ 0x0000000C,                 /* syscall */
+    /* 4 */ 0x0000000D                  /* break */
+    };
+
+    for (i = 0; i < 4; i++) {
+        tswap32s(&sigtramp_code[i]);
+    }
+
+    return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/netbsd/os-sys.c b/bsd-user/netbsd/os-sys.c
new file mode 100644
index 0000000..68ea0e1
--- /dev/null
+++ b/bsd-user/netbsd/os-sys.c
@@ -0,0 +1,46 @@
+/*
+ *  NetBSD sysctl() and sysarch() system call emulation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+#include "qemu.h"
+
+#include "target_arch_sysarch.h"
+#include "target_os_vmparam.h"
+
+
+/* This must be emulated to support FreeBSD target binaries on NetBSD host. */
+
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+
+    qemu_log("qemu: Unsupported syscall __sysctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sysarch() is architecture dependent. */
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall sysarch()\n");
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/netbsd/target_os_stack.h b/bsd-user/netbsd/target_os_stack.h
new file mode 100644
index 0000000..1a26c3f
--- /dev/null
+++ b/bsd-user/netbsd/target_os_stack.h
@@ -0,0 +1,33 @@
+#ifndef _TARGET_OS_STACK_H_
+#define _TARGET_OS_STACK_H_
+
+#include "target_arch_sigtramp.h"
+
+static inline int setup_initial_stack(struct bsd_binprm *bprm, abi_ulong *p)
+{
+    int i;
+    abi_ulong stack_base;
+
+    stack_base = (target_stkbas + target_stksiz) -
+                  MAX_ARG_PAGES * TARGET_PAGE_SIZE;
+    if (p) {
+        *p = stack_base;
+    }
+
+    for (i = 0; i < MAX_ARG_PAGES; i++) {
+        if (bprm->page[i]) {
+            info->rss++;
+            if (!memcpy_to_target(stack_base, bprm->page[i],
+                        TARGET_PAGE_SIZE)) {
+                errno = EFAULT;
+                return -1;
+            }
+            g_free(bprm->page[i]);
+        }
+        stack_base += TARGET_PAGE_SIZE;
+    }
+
+    return 0;
+}
+
+#endif /* !_TARGET_OS_STACK_H_ */
diff --git a/bsd-user/openbsd/os-sys.c b/bsd-user/openbsd/os-sys.c
new file mode 100644
index 0000000..30df472
--- /dev/null
+++ b/bsd-user/openbsd/os-sys.c
@@ -0,0 +1,46 @@
+/*
+ *  OpenBSD sysctl() and sysarch() system call emulation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+#include "qemu.h"
+
+#include "target_arch_sysarch.h"
+#include "target_os_vmparam.h"
+
+
+/* This must be emulated to support FreeBSD target binaries on NetBSD host. */
+
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+
+    qemu_log("qemu: Unsupported syscall __sysctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sysarch() is architecture dependent. */
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall sysarch()\n");
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/openbsd/target_os_stack.h b/bsd-user/openbsd/target_os_stack.h
new file mode 100644
index 0000000..1a26c3f
--- /dev/null
+++ b/bsd-user/openbsd/target_os_stack.h
@@ -0,0 +1,33 @@
+#ifndef _TARGET_OS_STACK_H_
+#define _TARGET_OS_STACK_H_
+
+#include "target_arch_sigtramp.h"
+
+static inline int setup_initial_stack(struct bsd_binprm *bprm, abi_ulong *p)
+{
+    int i;
+    abi_ulong stack_base;
+
+    stack_base = (target_stkbas + target_stksiz) -
+                  MAX_ARG_PAGES * TARGET_PAGE_SIZE;
+    if (p) {
+        *p = stack_base;
+    }
+
+    for (i = 0; i < MAX_ARG_PAGES; i++) {
+        if (bprm->page[i]) {
+            info->rss++;
+            if (!memcpy_to_target(stack_base, bprm->page[i],
+                        TARGET_PAGE_SIZE)) {
+                errno = EFAULT;
+                return -1;
+            }
+            g_free(bprm->page[i]);
+        }
+        stack_base += TARGET_PAGE_SIZE;
+    }
+
+    return 0;
+}
+
+#endif /* !_TARGET_OS_STACK_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index cb77069..594de5c 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -90,6 +90,7 @@ typedef struct TaskState {
     struct TaskState *next;
     int used; /* non zero if used */
     struct image_info *info;
+    struct bsd_binprm *bprm;
 
     struct emulated_sigtable sigtab[TARGET_NSIG];
     struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
@@ -118,7 +119,7 @@ extern unsigned long mmap_min_addr;
  * This structure is used to hold the arguments that are
  * used when loading binaries.
  */
-struct linux_binprm {
+struct bsd_binprm {
         char buf[128];
         void *page[MAX_ARG_PAGES];
         abi_ulong p;
@@ -127,19 +128,23 @@ struct linux_binprm {
         int argc, envc;
         char **argv;
         char **envp;
-        char * filename;        /* Name of binary */
+        char *filename;         /* (Given) Name of binary */
+        char *fullpath;         /* Full path of binary */
+        int (*core_dump)(int, const CPUArchState *);
 };
 
 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
                               abi_ulong stringp, int push_ptr);
-int loader_exec(const char * filename, char ** argv, char ** envp,
-             struct target_pt_regs * regs, struct image_info *infop);
+int loader_exec(const char *filename, char **argv, char **envp,
+             struct target_pt_regs *regs, struct image_info *infop,
+             struct bsd_binprm *bprm);
 
-int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
-                    struct image_info * info);
-int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
-                    struct image_info * info);
+int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
+                    struct image_info *info);
+int load_flt_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
+                    struct image_info *info);
+int is_target_elf_binary(int fd);
 
 abi_long memcpy_to_target(abi_ulong dest, const void *src,
                           unsigned long len);
@@ -232,6 +237,15 @@ extern unsigned long target_maxssiz;
 extern unsigned long target_sgrowsiz;
 extern char qemu_proc_pathname[];
 
+/* syscall.c */
+abi_long get_errno(abi_long ret);
+int is_error(abi_long ret);
+
+/* os-sys.c */
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen);
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2);
+
 /* user access */
 
 #define VERIFY_READ 0
diff --git a/bsd-user/sparc/target_arch_sigtramp.h b/bsd-user/sparc/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/sparc/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/sparc64/target_arch_sigtramp.h b/bsd-user/sparc64/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index a4d1583..dbc212d 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -2,6 +2,7 @@
  *  BSD syscalls
  *
  *  Copyright (c) 2003 - 2008 Fabrice Bellard
+ *  Copyright (c) 2013 Stacey D. Son
  *
  *  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
@@ -36,12 +37,17 @@
 #include "qemu.h"
 #include "qemu-common.h"
 
-//#define DEBUG
+#define target_to_host_bitmask(x, tbl) (x)
+
+/* #define DEBUG */
 
 static abi_ulong target_brk;
 static abi_ulong target_original_brk;
 
-static inline abi_long get_errno(abi_long ret)
+/*
+ * errno conversion.
+ */
+abi_long get_errno(abi_long ret)
 {
     if (ret == -1)
         /* XXX need to translate host -> target errnos here */
@@ -50,9 +56,7 @@ static inline abi_long get_errno(abi_long ret)
         return ret;
 }
 
-#define target_to_host_bitmask(x, tbl) (x)
-
-static inline int is_error(abi_long ret)
+int is_error(abi_long ret)
 {
     return (abi_ulong)ret >= (abi_ulong)(-4096);
 }
@@ -96,175 +100,6 @@ static abi_long do_obreak(abi_ulong new_brk)
     return 0;
 }
 
-#if defined(TARGET_I386)
-static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms)
-{
-    abi_long ret = 0;
-    abi_ulong val;
-    int idx;
-
-    switch(op) {
-#ifdef TARGET_ABI32
-    case TARGET_FREEBSD_I386_SET_GSBASE:
-    case TARGET_FREEBSD_I386_SET_FSBASE:
-        if (op == TARGET_FREEBSD_I386_SET_GSBASE)
-#else
-    case TARGET_FREEBSD_AMD64_SET_GSBASE:
-    case TARGET_FREEBSD_AMD64_SET_FSBASE:
-        if (op == TARGET_FREEBSD_AMD64_SET_GSBASE)
-#endif
-            idx = R_GS;
-        else
-            idx = R_FS;
-        if (get_user(val, parms, abi_ulong))
-            return -TARGET_EFAULT;
-        cpu_x86_load_seg(env, idx, 0);
-        env->segs[idx].base = val;
-        break;
-#ifdef TARGET_ABI32
-    case TARGET_FREEBSD_I386_GET_GSBASE:
-    case TARGET_FREEBSD_I386_GET_FSBASE:
-        if (op == TARGET_FREEBSD_I386_GET_GSBASE)
-#else
-    case TARGET_FREEBSD_AMD64_GET_GSBASE:
-    case TARGET_FREEBSD_AMD64_GET_FSBASE:
-        if (op == TARGET_FREEBSD_AMD64_GET_GSBASE)
-#endif
-            idx = R_GS;
-        else
-            idx = R_FS;
-        val = env->segs[idx].base;
-        if (put_user(val, parms, abi_ulong))
-            return -TARGET_EFAULT;
-        break;
-    /* XXX handle the others... */
-    default:
-        ret = -TARGET_EINVAL;
-        break;
-    }
-    return ret;
-}
-#endif
-
-#ifdef TARGET_SPARC
-static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms)
-{
-    /* XXX handle
-     * TARGET_FREEBSD_SPARC_UTRAP_INSTALL,
-     * TARGET_FREEBSD_SPARC_SIGTRAMP_INSTALL
-     */
-    return -TARGET_EINVAL;
-}
-#endif
-
-#ifdef __FreeBSD__
-/*
- * XXX this uses the undocumented oidfmt interface to find the kind of
- * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
- * (this is mostly copied from src/sbin/sysctl/sysctl.c)
- */
-static int
-oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
-{
-    int qoid[CTL_MAXNAME+2];
-    uint8_t buf[BUFSIZ];
-    int i;
-    size_t j;
-
-    qoid[0] = 0;
-    qoid[1] = 4;
-    memcpy(qoid + 2, oid, len * sizeof(int));
-
-    j = sizeof(buf);
-    i = sysctl(qoid, len + 2, buf, &j, 0, 0);
-    if (i)
-        return i;
-
-    if (kind)
-        *kind = *(uint32_t *)buf;
-
-    if (fmt)
-        strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
-    return (0);
-}
-
-/*
- * try and convert sysctl return data for the target.
- * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT.
- */
-static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
-{
-    switch (kind & CTLTYPE) {
-    case CTLTYPE_INT:
-    case CTLTYPE_UINT:
-        *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp);
-        break;
-#ifdef TARGET_ABI32
-    case CTLTYPE_LONG:
-    case CTLTYPE_ULONG:
-        *(uint32_t *)holdp = tswap32(*(long *)holdp);
-        break;
-#else
-    case CTLTYPE_LONG:
-        *(uint64_t *)holdp = tswap64(*(long *)holdp);
-    case CTLTYPE_ULONG:
-        *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
-        break;
-#endif
-#ifdef CTLTYPE_U64
-    case CTLTYPE_S64:
-    case CTLTYPE_U64:
-#else
-    case CTLTYPE_QUAD:
-#endif
-        *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
-        break;
-    case CTLTYPE_STRING:
-        break;
-    default:
-        /* XXX unhandled */
-        return -1;
-    }
-    return 0;
-}
-
-/* XXX this needs to be emulated on non-FreeBSD hosts... */
-static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp,
-                          abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
-{
-    abi_long ret;
-    void *hnamep, *holdp, *hnewp = NULL;
-    size_t holdlen;
-    abi_ulong oldlen = 0;
-    int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
-    uint32_t kind = 0;
-
-    if (oldlenp)
-        get_user_ual(oldlen, oldlenp);
-    if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1)))
-        return -TARGET_EFAULT;
-    if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1)))
-        return -TARGET_EFAULT;
-    if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0)))
-        return -TARGET_EFAULT;
-    holdlen = oldlen;
-    for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++)
-       *q++ = tswap32(*p);
-    oidfmt(snamep, namelen, NULL, &kind);
-    /* XXX swap hnewp */
-    ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
-    if (!ret)
-        sysctl_oldcvt(holdp, holdlen, kind);
-    put_user_ual(holdlen, oldlenp);
-    unlock_user(hnamep, namep, 0);
-    unlock_user(holdp, oldp, holdlen);
-    if (hnewp)
-        unlock_user(hnewp, newp, 0);
-    g_free(snamep);
-    return ret;
-}
-#endif
-
 /* 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.
@@ -387,20 +222,27 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_FREEBSD_NR_break:
         ret = do_obreak(arg1);
         break;
-#ifdef __FreeBSD__
-    case TARGET_FREEBSD_NR___sysctl:
-        ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6);
+
+        /*
+         * sys{ctl, arch, call}
+         */
+    case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
+        ret = do_freebsd_sysctl(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
-#endif
-    case TARGET_FREEBSD_NR_sysarch:
+
+    case TARGET_FREEBSD_NR_sysarch: /* sysarch(2) */
         ret = do_freebsd_sysarch(cpu_env, arg1, arg2);
         break;
-    case TARGET_FREEBSD_NR_syscall:
-    case TARGET_FREEBSD_NR___syscall:
-        ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0);
+
+    case TARGET_FREEBSD_NR_syscall: /* syscall(2) */
+    case TARGET_FREEBSD_NR___syscall: /* __syscall(2) */
+        ret = do_freebsd_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4,
+                arg5, arg6, arg7, arg8, 0);
         break;
+
     default:
-        ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
+        ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+                    arg8));
         break;
     }
  fail:
@@ -467,6 +309,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NETBSD_NR_mprotect:
         ret = get_errno(target_mprotect(arg1, arg2, arg3));
         break;
+
     case TARGET_NETBSD_NR_syscall:
     case TARGET_NETBSD_NR___syscall:
         ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
@@ -539,6 +382,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_OPENBSD_NR_mprotect:
         ret = get_errno(target_mprotect(arg1, arg2, arg3));
         break;
+
     case TARGET_OPENBSD_NR_syscall:
     case TARGET_OPENBSD_NR___syscall:
         ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
diff --git a/bsd-user/x86_64/target_arch_sigtramp.h b/bsd-user/x86_64/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 06/19] bsd-user: add support for freebsd time related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (25 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 05/19] bsd-user: move target arch and host OS dependent code out of syscall.c Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 07/19] bsd-user: add support for freebsd signal " Stacey Son
                   ` (12 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for time related system calls including
nanosleep(2), clock_gettime(2), clock_settime(2), clock_getres(2),
gettimeofday(2), settimeofday(2), adjtime(2), ntp_adjtime(2),
ntp_gettime(2), utimes(2), lutimes(2), futimes(2), futimesat(2),
select(2), pselect(2), kqueue(2), kevent(2), setitimer(2),
getitimer(2), and the undocumented ktimer_*() calls.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs     |    3 +-
 bsd-user/freebsd/os-time.c |  205 +++++++++++
 bsd-user/freebsd/os-time.h |  643 +++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h |   53 +++
 bsd-user/netbsd/os-time.c  |    1 +
 bsd-user/netbsd/os-time.h  |  179 ++++++++++
 bsd-user/netbsd/qemu-os.h  |    1 +
 bsd-user/openbsd/os-time.c |    1 +
 bsd-user/openbsd/os-time.h |  179 ++++++++++
 bsd-user/openbsd/qemu-os.h |    1 +
 bsd-user/syscall.c         |  102 ++++++
 bsd-user/syscall_defs.h    |  800 ++++++++++++++++++++++++++++++++++++++------
 12 files changed, 2065 insertions(+), 103 deletions(-)
 create mode 100644 bsd-user/freebsd/os-time.c
 create mode 100644 bsd-user/freebsd/os-time.h
 create mode 100644 bsd-user/freebsd/qemu-os.h
 create mode 100644 bsd-user/netbsd/os-time.c
 create mode 100644 bsd-user/netbsd/os-time.h
 create mode 100644 bsd-user/netbsd/qemu-os.h
 create mode 100644 bsd-user/openbsd/os-time.c
 create mode 100644 bsd-user/openbsd/os-time.h
 create mode 100644 bsd-user/openbsd/qemu-os.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index b5ed89e..d92961a 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,2 +1,3 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o $(HOST_ABI_DIR)/os-sys.o $(TARGET_ABI_DIR)/target_arch_cpu.o
+	        uaccess.o $(HOST_ABI_DIR)/os-sys.o \
+			$(HOST_ABI_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/freebsd/os-time.c b/bsd-user/freebsd/os-time.c
new file mode 100644
index 0000000..7ac4397
--- /dev/null
+++ b/bsd-user/freebsd/os-time.c
@@ -0,0 +1,205 @@
+/*
+ *  FreeBSD time related system call helpers
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <time.h>
+#include <sys/timex.h>
+#include <sys/select.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+/*
+ * FreeBSD time conversion functions
+ */
+abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr)
+{
+    struct target_freebsd_timeval *target_tv;
+
+    if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __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, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr)
+{
+    struct target_freebsd_timeval *target_tv;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __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);
+
+    return 0;
+}
+
+abi_long t2h_freebsd_timespec(struct timespec *ts, abi_ulong target_ts_addr)
+{
+    struct target_freebsd_timespec *target_ts;
+
+    if (!lock_user_struct(VERIFY_READ, target_ts, target_ts_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(ts->tv_sec, &target_ts->tv_sec);
+    __get_user(ts->tv_nsec, &target_ts->tv_nsec);
+    unlock_user_struct(target_ts, target_ts_addr, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_timespec(abi_ulong target_ts_addr, struct timespec *ts)
+{
+    struct target_freebsd_timespec *target_ts;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ts, target_ts_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(ts->tv_sec, &target_ts->tv_sec);
+    __put_user(ts->tv_nsec, &target_ts->tv_nsec);
+    unlock_user_struct(target_ts, target_ts_addr, 1);
+
+    return 0;
+}
+
+abi_long t2h_freebsd_timex(struct timex *host_tx, abi_ulong target_tx_addr)
+{
+    struct target_freebsd_timex *target_tx;
+
+    if (!lock_user_struct(VERIFY_READ, target_tx, target_tx_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_tx->modes, &target_tx->modes);
+    __get_user(host_tx->offset, &target_tx->offset);
+    __get_user(host_tx->freq, &target_tx->freq);
+    __get_user(host_tx->maxerror, &target_tx->maxerror);
+    __get_user(host_tx->esterror, &target_tx->esterror);
+    __get_user(host_tx->status, &target_tx->status);
+    __get_user(host_tx->constant, &target_tx->constant);
+    __get_user(host_tx->precision, &target_tx->precision);
+    __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
+    __get_user(host_tx->jitter, &target_tx->jitter);
+    __get_user(host_tx->shift, &target_tx->shift);
+    __get_user(host_tx->stabil, &target_tx->stabil);
+    __get_user(host_tx->jitcnt, &target_tx->jitcnt);
+    __get_user(host_tx->calcnt, &target_tx->calcnt);
+    __get_user(host_tx->errcnt, &target_tx->errcnt);
+    __get_user(host_tx->stbcnt, &target_tx->stbcnt);
+    unlock_user_struct(target_tx, target_tx_addr, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_ntptimeval(abi_ulong target_ntv_addr,
+        struct ntptimeval *ntv)
+{
+    struct target_freebsd_ntptimeval *target_ntv;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ntv, target_ntv_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(ntv->time.tv_sec, &target_ntv->time.tv_sec);
+    __put_user(ntv->time.tv_nsec, &target_ntv->time.tv_nsec);
+    __put_user(ntv->maxerror, &target_ntv->maxerror);
+    __put_user(ntv->esterror, &target_ntv->esterror);
+    __put_user(ntv->tai, &target_ntv->tai);
+    __put_user(ntv->time_state, &target_ntv->time_state);
+
+    return 0;
+}
+
+/*
+ * select(2) fdset copy functions
+ */
+abi_ulong copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n)
+{
+    int i, nw, j, k;
+    abi_ulong b, *target_fds;
+
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    target_fds = lock_user(VERIFY_READ, target_fds_addr,
+            sizeof(abi_ulong) * nw, 1);
+    if (target_fds == NULL) {
+        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++;
+        }
+    }
+    unlock_user(target_fds, target_fds_addr, 0);
+
+    return 0;
+}
+
+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;
+}
+
+abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds, int n)
+{
+    int i, nw, j, k;
+    abi_long v;
+    abi_ulong *target_fds;
+
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    target_fds = lock_user(VERIFY_WRITE, target_fds_addr,
+            sizeof(abi_ulong) * nw, 0);
+    if (target_fds == NULL) {
+        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++;
+        }
+        __put_user(v, &target_fds[i]);
+    }
+    unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
+
+    return 0;
+}
+
diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h
new file mode 100644
index 0000000..c6b5b28
--- /dev/null
+++ b/bsd-user/freebsd/os-time.h
@@ -0,0 +1,643 @@
+/*
+ *  FreeBSD time related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_OS_TIME_H_
+#define __FREEBSD_OS_TIME_H_
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/select.h>
+#include <sys/timex.h>
+#include <signal.h>
+#include <time.h>
+
+#include "qemu-os.h"
+
+/* nanosleep(2) */
+static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct timespec req, rem;
+
+    ret = t2h_freebsd_timespec(&req, arg1);
+    if (!is_error(ret)) {
+        ret = get_errno(nanosleep(&req, &rem));
+        if (!is_error(ret) && arg2) {
+            h2t_freebsd_timespec(arg2, &rem);
+        }
+    }
+
+    return ret;
+}
+
+/* clock_gettime(2) */
+static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct timespec ts;
+
+    ret = get_errno(clock_gettime(arg1, &ts));
+    if (!is_error(ret)) {
+        if (h2t_freebsd_timespec(arg2, &ts)) {
+            return -TARGET_EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/* clock_settime(2) */
+static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2)
+{
+    struct timespec ts;
+
+    if (t2h_freebsd_timespec(&ts, arg2) != 0) {
+        return -TARGET_EFAULT;
+    }
+
+    return get_errno(clock_settime(arg1, &ts));
+}
+
+/* clock_getres(2) */
+static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct timespec ts;
+
+    ret = get_errno(clock_getres(arg1, &ts));
+    if (!is_error(ret)) {
+        if (h2t_freebsd_timespec(arg2, &ts)) {
+            return -TARGET_EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/* gettimeofday(2) */
+static inline abi_long do_freebsd_gettimeofday(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    struct timeval tv;
+    struct timezone tz, *target_tz; /* XXX */
+
+    if (arg2 != 0) {
+        if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
+        __get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
+        unlock_user_struct(target_tz, arg2, 1);
+    }
+    ret = get_errno(gettimeofday(&tv, arg2 != 0 ? &tz : NULL));
+    if (!is_error(ret)) {
+        if (h2t_freebsd_timeval(&tv, arg1)) {
+            return -TARGET_EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/* settimeofday(2) */
+static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2)
+{
+    struct timeval tv;
+    struct timezone tz, *target_tz; /* XXX */
+
+    if (arg2 != 0) {
+        if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
+        __get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
+        unlock_user_struct(target_tz, arg2, 1);
+    }
+    if (t2h_freebsd_timeval(&tv, arg1)) {
+        return -TARGET_EFAULT;
+    }
+
+    return get_errno(settimeofday(&tv, arg2 != 0 ? &tz : NULL));
+}
+
+/* adjtime(2) */
+static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr,
+        abi_ulong target_old_addr)
+{
+    abi_long ret;
+    struct timeval host_delta, host_old;
+
+    ret = t2h_freebsd_timeval(&host_delta, target_delta_addr);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    if (target_old_addr) {
+        ret = get_errno(adjtime(&host_delta, &host_old));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = h2t_freebsd_timeval(&host_old, target_old_addr);
+    } else {
+        ret = get_errno(adjtime(&host_delta, NULL));
+    }
+
+    return ret;
+}
+
+/* ntp_adjtime(2) */
+static abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr)
+{
+    abi_long ret;
+    struct timex host_tx;
+
+    ret = t2h_freebsd_timex(&host_tx, target_tx_addr);
+    if (ret == 0) {
+        ret = get_errno(ntp_adjtime(&host_tx));
+    }
+
+    return ret;
+}
+
+/* ntp_gettime(2) */
+static abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr)
+{
+    abi_long ret;
+    struct ntptimeval host_ntv;
+
+    ret = get_errno(ntp_gettime(&host_ntv));
+    if (ret == 0) {
+        ret = h2t_freebsd_ntptimeval(target_ntv_addr, &host_ntv);
+    }
+
+    return ret;
+}
+
+
+/* utimes(2) */
+static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct timeval *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg2) ||
+                t2h_freebsd_timeval(&tv[1], arg2 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(utimes(p, tvp));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* lutimes(2) */
+static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct timeval *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg2) ||
+                t2h_freebsd_timeval(&tv[1], arg2 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(lutimes(p, tvp));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* futimes(2) */
+static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2)
+{
+    struct timeval *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg2) ||
+                t2h_freebsd_timeval(&tv[1], arg2 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+
+    return get_errno(futimes(arg1, tvp));
+}
+
+/* futimesat(2) */
+static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    struct timeval *tvp, tv[2];
+
+    if (arg3 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg3) ||
+                t2h_freebsd_timeval(&tv[1], arg3 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+
+    p = lock_user_string(arg2);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(futimesat(arg1, p, tvp));
+    unlock_user(p, arg2, 0);
+
+    return ret;
+}
+
+/*
+ * undocumented ktimer_create(clockid_t clock_id,  struct sigevent *evp,
+ * int *timerid) syscall
+ */
+static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocumented ktimer_delete(int timerid) syscall */
+static inline abi_long do_freebsd_ktimer_delete(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_delete()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented ktimer_settime(int timerid, int flags,
+ * const struct itimerspec *value, struct itimerspec *ovalue) syscall
+ */
+static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_settime()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented ktimer_gettime(int timerid, struct itimerspec *value)
+ * syscall
+ */
+static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_gettime()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented ktimer_getoverrun(int timerid) syscall
+ */
+static inline abi_long do_freebsd_ktimer_getoverrun(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_getoverrun()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* select(2) */
+static inline abi_long do_freebsd_select(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong target_tv_addr)
+{
+    fd_set rfds, wfds, efds;
+    fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+    struct timeval tv, *tv_ptr;
+    abi_long ret, error;
+
+    ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+    if (ret != 0) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+    if (ret != 0) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+    if (ret != 0) {
+        return ret;
+    }
+
+    if (target_tv_addr != 0) {
+        if (t2h_freebsd_timeval(&tv, target_tv_addr)) {
+            return -TARGET_EFAULT;
+        }
+        tv_ptr = &tv;
+    } else {
+        tv_ptr = NULL;
+    }
+
+    ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
+
+    if (!is_error(ret)) {
+        if (rfd_addr != 0) {
+            error = copy_to_user_fdset(rfd_addr, &rfds, n);
+            if (error != 0) {
+                return error;
+            }
+        }
+        if (wfd_addr != 0) {
+            error = copy_to_user_fdset(wfd_addr, &wfds, n);
+            if (error != 0) {
+                return error;
+            }
+        }
+        if (efd_addr != 0) {
+            error = copy_to_user_fdset(efd_addr, &efds, n);
+            if (error != 0) {
+                return error;
+            }
+        }
+        if (target_tv_addr != 0) {
+            error = h2t_freebsd_timeval(&tv, target_tv_addr);
+            if (is_error(error)) {
+                return error;
+            }
+        }
+    }
+    return ret;
+}
+
+/* pselect(2) */
+static inline abi_long do_freebsd_pselect(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong ts_addr,
+        abi_ulong set_addr)
+{
+    fd_set rfds, wfds, efds;
+    fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+    sigset_t set, *set_ptr;
+    struct timespec ts, *ts_ptr;
+    void *p;
+    abi_long ret;
+
+    ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    /* Unlike select(), pselect() uses struct timespec instead of timeval */
+    if (ts_addr) {
+        if (t2h_freebsd_timespec(&ts, ts_addr)) {
+            return -TARGET_EFAULT;
+        }
+        ts_ptr = &ts;
+    } else {
+        ts_ptr = NULL;
+    }
+
+    if (set_addr != 0) {
+        p = lock_user(VERIFY_READ, set_addr, sizeof(target_sigset_t), 1);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        target_to_host_sigset(&set, p);
+        unlock_user(p, set_addr, 0);
+        set_ptr = &set;
+    } else {
+        set_ptr = NULL;
+    }
+
+    ret = get_errno(pselect(n, rfds_ptr, wfds_ptr, efds_ptr, ts_ptr, set_ptr));
+
+    if (!is_error(ret)) {
+        if (rfd_addr != 0) {
+            ret = copy_to_user_fdset(rfd_addr, &rfds, n);
+            if (is_error(ret)) {
+                return ret;
+            }
+        }
+        if (wfd_addr != 0) {
+            ret = copy_to_user_fdset(wfd_addr, &wfds, n);
+            if (is_error(ret)) {
+                return ret;
+            }
+        }
+        if (efd_addr != 0) {
+            ret = copy_to_user_fdset(efd_addr, &efds, n);
+            if (is_error(ret)) {
+                return ret;
+            }
+        }
+        if (ts_addr != 0) {
+            ret = h2t_freebsd_timespec(ts_addr, &ts);
+            if (is_error(ret)) {
+                return ret;
+            }
+        }
+    }
+    return ret;
+}
+
+/* kqueue(2) */
+static inline abi_long do_freebsd_kqueue(void)
+{
+
+    return get_errno(kqueue());
+}
+
+/* kevent(2) */
+static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
+        abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    struct kevent *changelist = NULL, *eventlist = NULL;
+    struct target_freebsd_kevent *target_changelist, *target_eventlist;
+    struct timespec ts;
+    int i;
+
+    if (arg3 != 0) {
+        target_changelist = lock_user(VERIFY_READ, arg2,
+                sizeof(struct target_freebsd_kevent) * arg3, 1);
+        if (target_changelist == NULL) {
+            return -TARGET_EFAULT;
+        }
+
+        changelist = alloca(sizeof(struct kevent) * arg3);
+        for (i = 0; i < arg3; i++) {
+            __get_user(changelist[i].ident, &target_changelist[i].ident);
+            __get_user(changelist[i].filter, &target_changelist[i].filter);
+            __get_user(changelist[i].flags, &target_changelist[i].flags);
+            __get_user(changelist[i].fflags, &target_changelist[i].fflags);
+            __get_user(changelist[i].data, &target_changelist[i].data);
+            /* __get_user(changelist[i].udata, &target_changelist[i].udata); */
+#if TARGET_ABI_BITS == 32
+            changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata;
+            tswap32s((uint32_t *)&changelist[i].udata);
+#else
+            changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata;
+            tswap64s((uint64_t *)&changelist[i].udata);
+#endif
+        }
+        unlock_user(target_changelist, arg2, 0);
+    }
+
+    if (arg5 != 0) {
+        eventlist = alloca(sizeof(struct kevent) * arg5);
+    }
+    if (arg6 != 0) {
+        if (t2h_freebsd_timespec(&ts, arg6)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    ret = get_errno(kevent(arg1, changelist, arg3, eventlist, arg5,
+                arg6 != 0 ? &ts : NULL));
+    if (!is_error(ret)) {
+        target_eventlist = lock_user(VERIFY_WRITE, arg4,
+                sizeof(struct target_freebsd_kevent) * arg5, 0);
+        if (target_eventlist == NULL) {
+                return -TARGET_EFAULT;
+        }
+        for (i = 0; i < arg5; i++) {
+            __put_user(eventlist[i].ident, &target_eventlist[i].ident);
+            __put_user(eventlist[i].filter, &target_eventlist[i].filter);
+            __put_user(eventlist[i].flags, &target_eventlist[i].flags);
+            __put_user(eventlist[i].fflags, &target_eventlist[i].fflags);
+            __put_user(eventlist[i].data, &target_eventlist[i].data);
+            /* __put_user(eventlist[i].udata, &target_eventlist[i].udata);*/
+#if TARGET_ABI_BITS == 32
+            tswap32s((uint32_t *)&eventlist[i].data);
+            target_eventlist[i].data = (uintptr_t)eventlist[i].data;
+#else
+            tswap64s((uint64_t *)&eventlist[i].data);
+            target_eventlist[i].data = (uintptr_t)eventlist[i].data;
+#endif
+        }
+        unlock_user(target_eventlist, arg4,
+                sizeof(struct target_freebsd_kevent) * arg5);
+    }
+    return ret;
+}
+
+/* sigtimedwait(2) */
+static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    struct timespec uts, *puts;
+    siginfo_t uinfo;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    if (arg3) {
+        puts = &uts;
+        t2h_freebsd_timespec(puts, arg3);
+    } else {
+        puts = NULL;
+    }
+    ret = get_errno(sigtimedwait(&set, &uinfo, puts));
+    if (!is_error(ret) && arg2) {
+        p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_siginfo(p, &uinfo);
+        unlock_user(p, arg2, sizeof(target_siginfo_t));
+    }
+    return ret;
+}
+
+/* setitimer(2) */
+static inline abi_long do_freebsd_setitimer(int arg1, abi_ulong arg2, abi_ulong arg3)
+{
+   abi_long ret = 0;
+   struct itimerval value, ovalue, *pvalue;
+
+   if (arg2) {
+       pvalue = &value;
+       if (t2h_freebsd_timeval(&pvalue->it_interval, arg2) ||
+           t2h_freebsd_timeval(&pvalue->it_value, arg2 + sizeof(struct target_freebsd_timeval))) {
+             return -TARGET_EFAULT;
+       } 
+   } else {
+       pvalue = NULL;
+   }
+   ret = get_errno(setitimer(arg1, pvalue, &ovalue));
+   if (!is_error(ret) && arg3) {
+       if (h2t_freebsd_timeval(&ovalue.it_interval, arg3)
+          || h2t_freebsd_timeval(&ovalue.it_value, arg3 + sizeof(struct target_freebsd_timeval))) {
+             return -TARGET_EFAULT;
+       }
+   }
+   return ret;
+}
+
+/* getitimer(2) */
+static inline abi_long do_freebsd_getitimer(int arg1, abi_ulong arg2)
+{
+   abi_long ret = 0;
+   struct itimerval value;
+
+   ret = get_errno(getitimer(arg1, &value));
+   if (!is_error(ret) && arg2) {
+       if (h2t_freebsd_timeval(&value.it_interval, arg2) ||
+           h2t_freebsd_timeval(&value.it_value, arg2 + sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+       }
+   }
+   return ret;
+}
+
+#endif /* __FREEBSD_OS_TIME_H_ */
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
new file mode 100644
index 0000000..bde610e
--- /dev/null
+++ b/bsd-user/freebsd/qemu-os.h
@@ -0,0 +1,53 @@
+/*
+ *  FreeBSD conversion extern declarations
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _QEMU_OS_H_
+#define _QEMU_OS_H_
+
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/mount.h>
+#include <sys/timex.h>
+#include <sys/rtprio.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#include <time.h>
+
+/* os-time.c */
+abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr);
+abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr);
+
+abi_long t2h_freebsd_timespec(struct timespec *ts, abi_ulong target_ts_addr);
+abi_long h2t_freebsd_timespec(abi_ulong target_ts_addr, struct timespec *ts);
+
+abi_long t2h_freebsd_timex(struct timex *host_tx, abi_ulong target_tx_addr);
+
+abi_long h2t_freebsd_ntptimeval(abi_ulong target_ntv_addr,
+        struct ntptimeval *ntv);
+
+abi_ulong copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n);
+abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
+        abi_ulong target_fds_addr, int n);
+abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds,
+        int n);
+
+#endif /* !_QEMU_OS_H_ */
diff --git a/bsd-user/netbsd/os-time.c b/bsd-user/netbsd/os-time.c
new file mode 100644
index 0000000..ee2c7a0
--- /dev/null
+++ b/bsd-user/netbsd/os-time.c
@@ -0,0 +1 @@
+/* XXX NetBSD time related helpers */
diff --git a/bsd-user/netbsd/os-time.h b/bsd-user/netbsd/os-time.h
new file mode 100644
index 0000000..6d0f1de
--- /dev/null
+++ b/bsd-user/netbsd/os-time.h
@@ -0,0 +1,179 @@
+#ifndef __NETBSD_OS_TIME_H_
+#define __NETBSD_OS_TIME_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need to
+ * be emulated.
+ */
+static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_gettimeofday(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr,
+        abi_ulong target_old_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_delete(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_getoverrun(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_select(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong target_tv_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+
+static inline abi_long do_freebsd_pselect(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong ts_addr,
+        abi_ulong set_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_kqueue(void)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
+        abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __NETBSD_OS_TIME_H_ */
diff --git a/bsd-user/netbsd/qemu-os.h b/bsd-user/netbsd/qemu-os.h
new file mode 100644
index 0000000..016618b
--- /dev/null
+++ b/bsd-user/netbsd/qemu-os.h
@@ -0,0 +1 @@
+/* NetBSD conversion extern declarations */
diff --git a/bsd-user/openbsd/os-time.c b/bsd-user/openbsd/os-time.c
new file mode 100644
index 0000000..accd886
--- /dev/null
+++ b/bsd-user/openbsd/os-time.c
@@ -0,0 +1 @@
+/* XXX OpenBSD time related helpers */
diff --git a/bsd-user/openbsd/os-time.h b/bsd-user/openbsd/os-time.h
new file mode 100644
index 0000000..fc444bb
--- /dev/null
+++ b/bsd-user/openbsd/os-time.h
@@ -0,0 +1,179 @@
+#ifndef __OPENBSD_OS_TIME_H_
+#define __OPENBSD_OS_TIME_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need to
+ * be emulated.
+ */
+static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_gettimeofday(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr,
+        abi_ulong target_old_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_delete(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_getoverrun(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_select(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong target_tv_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+
+static inline abi_long do_freebsd_pselect(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong ts_addr,
+        abi_ulong set_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_kqueue(void)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
+        abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_OS_TIME_H_ */
diff --git a/bsd-user/openbsd/qemu-os.h b/bsd-user/openbsd/qemu-os.h
new file mode 100644
index 0000000..f4ad3be
--- /dev/null
+++ b/bsd-user/openbsd/qemu-os.h
@@ -0,0 +1 @@
+/* OpenBSD conversion extern declarations */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index dbc212d..0996787 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -39,6 +39,9 @@
 
 #define target_to_host_bitmask(x, tbl) (x)
 
+/* *BSD dependent syscall shims */
+#include "os-time.h"
+
 /* #define DEBUG */
 
 static abi_ulong target_brk;
@@ -224,6 +227,105 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * time related system calls.
+         */
+    case TARGET_FREEBSD_NR_nanosleep: /* nanosleep(2) */
+        ret = do_freebsd_nanosleep(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_gettime: /* clock_gettime(2) */
+        ret = do_freebsd_clock_gettime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_settime: /* clock_settime(2) */
+        ret = do_freebsd_clock_settime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_getres: /* clock_getres(2) */
+        ret = do_freebsd_clock_getres(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_gettimeofday: /* gettimeofday(2) */
+        ret = do_freebsd_gettimeofday(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_settimeofday: /* settimeofday(2) */
+        ret = do_freebsd_settimeofday(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_adjtime: /* adjtime(2) */
+        ret = do_freebsd_adjtime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_ntp_adjtime: /* ntp_adjtime(2) */
+        ret = do_freebsd_ntp_adjtime(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_ntp_gettime: /* ntp_gettime(2) */
+        ret = do_freebsd_ntp_gettime(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_utimes: /* utimes(2) */
+        ret = do_freebsd_utimes(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lutimes: /* lutimes(2) */
+        ret = do_freebsd_lutimes(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_futimes: /* futimes(2) */
+        ret = do_freebsd_futimes(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_futimesat: /* futimesat(2) */
+        ret = do_freebsd_futimesat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_create: /* undocumented */
+        ret = do_freebsd_ktimer_create(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_delete: /* undocumented */
+        ret = do_freebsd_ktimer_delete(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_settime: /* undocumented */
+        ret = do_freebsd_ktimer_settime(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_gettime: /* undocumented */
+        ret = do_freebsd_ktimer_gettime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_getoverrun: /* undocumented */
+        ret = do_freebsd_ktimer_getoverrun(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_select: /* select(2) */
+        ret = do_freebsd_select(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_pselect: /* pselect(2) */
+        ret = do_freebsd_pselect(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_kqueue: /* kqueue(2) */
+        ret = do_freebsd_kqueue();
+        break;
+
+    case TARGET_FREEBSD_NR_kevent: /* kevent(2) */
+        ret = do_freebsd_kevent(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_setitimer: /* setitimer(2) */
+        ret = do_freebsd_setitimer(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getitimer: /* getitimer(2) */
+        ret = do_freebsd_getitimer(arg1, arg2);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 207ddee..2d3b658 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -1,105 +1,5 @@
-/*      $OpenBSD: signal.h,v 1.19 2006/01/08 14:20:16 millert Exp $     */
-/*      $NetBSD: signal.h,v 1.21 1996/02/09 18:25:32 christos Exp $     */
-
-/*
- * Copyright (c) 1982, 1986, 1989, 1991, 1993
- *      The Regents of the University of California.  All rights reserved.
- * (c) UNIX System Laboratories, Inc.
- * All or some portions of this file are derived from material licensed
- * to the University of California by American Telephone and Telegraph
- * Co. or Unix System Laboratories, Inc. and are reproduced herein with
- * the permission of UNIX System Laboratories, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *      @(#)signal.h    8.2 (Berkeley) 1/21/94
- */
-
-#define TARGET_NSIG     32              /* counting 0; could be 33 (mask is 1-32) */
-
-#define TARGET_SIGHUP  1       /* hangup */
-#define TARGET_SIGINT  2       /* interrupt */
-#define TARGET_SIGQUIT 3       /* quit */
-#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
-#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
-#define TARGET_SIGABRT 6       /* abort() */
-#define TARGET_SIGIOT  SIGABRT /* compatibility */
-#define TARGET_SIGEMT  7       /* EMT instruction */
-#define TARGET_SIGFPE  8       /* floating point exception */
-#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
-#define TARGET_SIGBUS  10      /* bus error */
-#define TARGET_SIGSEGV 11      /* segmentation violation */
-#define TARGET_SIGSYS  12      /* bad argument to system call */
-#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
-#define TARGET_SIGALRM 14      /* alarm clock */
-#define TARGET_SIGTERM 15      /* software termination signal from kill */
-#define TARGET_SIGURG  16      /* urgent condition on IO channel */
-#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
-#define TARGET_SIGTSTP 18      /* stop signal from tty */
-#define TARGET_SIGCONT 19      /* continue a stopped process */
-#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
-#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
-#define TARGET_SIGTTOU 22      /* like TTIN for output if (tp->t_local&LTOSTOP) */
-#define TARGET_SIGIO   23      /* input/output possible signal */
-#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
-#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
-#define TARGET_SIGVTALRM 26    /* virtual time alarm */
-#define TARGET_SIGPROF 27      /* profiling time alarm */
-#define TARGET_SIGWINCH 28      /* window size changes */
-#define TARGET_SIGINFO  29      /* information request */
-#define TARGET_SIGUSR1 30       /* user defined signal 1 */
-#define TARGET_SIGUSR2 31       /* user defined signal 2 */
-
-/*
- * Language spec says we must list exactly one parameter, even though we
- * actually supply three.  Ugh!
- */
-#define TARGET_SIG_DFL         (void (*)(int))0
-#define TARGET_SIG_IGN         (void (*)(int))1
-#define TARGET_SIG_ERR         (void (*)(int))-1
-
-#define TARGET_SA_ONSTACK       0x0001  /* take signal on signal stack */
-#define TARGET_SA_RESTART       0x0002  /* restart system on signal return */
-#define TARGET_SA_RESETHAND     0x0004  /* reset to SIG_DFL when taking signal */
-#define TARGET_SA_NODEFER       0x0010  /* don't mask the signal we're delivering */
-#define TARGET_SA_NOCLDWAIT     0x0020  /* don't create zombies (assign to pid 1) */
-#define TARGET_SA_USERTRAMP    0x0100  /* do not bounce off kernel's sigtramp */
-#define TARGET_SA_NOCLDSTOP     0x0008  /* do not generate SIGCHLD on child stop */
-#define TARGET_SA_SIGINFO       0x0040  /* generate siginfo_t */
-
-/*
- * Flags for sigprocmask:
- */
-#define TARGET_SIG_BLOCK       1       /* block specified signal set */
-#define TARGET_SIG_UNBLOCK     2       /* unblock specified signal set */
-#define TARGET_SIG_SETMASK     3       /* set specified signal set */
-
-#define TARGET_BADSIG          SIG_ERR
-
-#define TARGET_SS_ONSTACK       0x0001  /* take signals on alternate stack */
-#define TARGET_SS_DISABLE       0x0004  /* disable taking signals on alternate stack */
+#ifndef _SYSCALL_DEFS_H_
+#define _SYSCALL_DEFS_H_
 
 #include "errno_defs.h"
 
@@ -112,3 +12,699 @@ struct target_iovec {
     abi_long iov_len;   /* Number of bytes */
 };
 
+/*
+ * sys/ipc.h
+ */
+struct target_ipc_perm {
+    uint32_t    cuid;       /* creator user id */
+    uint32_t    cgid;       /* creator group id */
+    uint32_t    uid;        /* user id */
+    uint32_t    gid;        /* group id */
+    uint16_t    mode;       /* r/w permission */
+    uint16_t    seq;        /* sequence # */
+    abi_long    key;        /* user specified msg/sem/shm key */
+};
+
+#define TARGET_IPC_RMID 0   /* remove identifier */
+#define TARGET_IPC_SET  1   /* set options */
+#define TARGET_IPC_STAT 2   /* get options */
+
+/*
+ * sys/sem.h
+ */
+#define TARGET_GETNCNT  3   /* Return the value of semncnt {READ} */
+#define TARGET_GETPID   4   /* Return the value of sempid {READ} */
+#define TARGET_GETVAL   5   /* Return the value of semval {READ} */
+#define TARGET_GETALL   6   /* Return semvals into arg.array {READ} */
+#define TARGET_GETZCNT  7   /* Return the value of semzcnt {READ} */
+#define TARGET_SETVAL   8   /* Set the value of semval to arg.val {ALTER} */
+#define TARGET_SETALL   9   /* Set semvals from arg.array {ALTER} */
+#define TARGET_SEM_STAT 10 /* Like IPC_STAT but treats semid as sema-index */
+#define TARGET_SEM_INFO 11 /* Like IPC_INFO but treats semid as sema-index */
+
+struct target_sembuf {
+    unsigned short  sem_num;    /* semaphore # */
+    short       sem_op;         /* semaphore operation */
+    short       sem_flg;        /* operation flags */
+};
+
+union target_semun {
+    int     val;        /* value for SETVAL */
+    abi_ulong   buf;        /* buffer for IPC_STAT & IPC_SET */
+    abi_ulong   array;      /* array for GETALL & SETALL */
+};
+
+struct target_semid_ds {
+    struct target_ipc_perm sem_perm; /* operation permission struct */
+    abi_ulong   sem_base;   /* pointer to first semaphore in set */
+    uint16_t    sem_nsems;  /* number of sems in set */
+    abi_ulong   sem_otime;  /* last operation time */
+    abi_ulong   sem_ctime;  /* times measured in secs */
+};
+
+/*
+ * sys/shm.h
+ */
+struct target_shmid_ds {
+    struct  target_ipc_perm shm_perm; /* peration permission structure */
+    abi_ulong   shm_segsz;  /* size of segment in bytes */
+    int32_t     shm_lpid;   /* process ID of last shared memory op */
+    int32_t     shm_cpid;   /* process ID of creator */
+    int32_t     shm_nattch; /* number of current attaches */
+    abi_ulong   shm_atime;  /* time of last shmat() */
+    abi_ulong   shm_dtime;  /* time of last shmdt() */
+    abi_ulong   shm_ctime;  /* time of last change by shmctl() */
+};
+
+#define N_BSD_SHM_REGIONS   32
+struct bsd_shm_regions {
+    abi_long start;
+    abi_long size;
+};
+
+/*
+ * sys/msg.h
+ */
+struct target_msqid_ds {
+    struct  target_ipc_perm msg_perm; /* msg queue permission bits */
+    abi_ulong   msg_first;  /* first message in the queue */
+    abi_ulong   msg_last;   /* last message in the queue */
+    abi_ulong   msg_cbytes; /* # of bytes in use on the queue */
+    abi_ulong   msg_qnum;   /* number of msgs in the queue */
+    abi_ulong   msg_qbytes; /* max # of bytes on the queue */
+    int32_t     msg_lspid;  /* pid of last msgsnd() */
+    int32_t     msg_lrpid;  /* pid of last msgrcv() */
+    abi_ulong   msg_stime;  /* time of last msgsnd() */
+    abi_ulong   msg_rtime;  /* time of last msgrcv() */
+    abi_ulong   msg_ctime;  /* time of last msgctl() */
+};
+
+struct target_msgbuf {
+    abi_long    mtype;      /* message type */
+    char        mtext[1];   /* body of message */
+};
+
+/*
+ * sched.h
+ */
+struct target_sched_param {
+        int32_t sched_priority;
+};
+
+/*
+ *  sys/mman.h
+ */
+#define TARGET_FREEBSD_MAP_RESERVED0080 0x0080  /* previously misimplemented
+                                                   MAP_INHERIT */
+#define TARGET_FREEBSD_MAP_RESERVED0100 0x0100  /* previously unimplemented
+                                                   MAP_NOEXTEND */
+#define TARGET_FREEBSD_MAP_STACK        0x0400  /* region grows down, like a
+                                                   stack */
+#define TARGET_FREEBSD_MAP_NOSYNC       0x0800  /* page to but do not sync
+                                                   underlying file */
+
+#define TARGET_FREEBSD_MAP_FLAGMASK     0x1ff7
+
+#define TARGET_NETBSD_MAP_INHERIT       0x0080  /* region is retained after
+                                                   exec */
+#define TARGET_NETBSD_MAP_TRYFIXED      0x0400 /* attempt hint address, even
+                                                  within break */
+#define TARGET_NETBSD_MAP_WIRED         0x0800  /* mlock() mapping when it is
+                                                   established */
+
+#define TARGET_NETBSD_MAP_STACK         0x2000  /* allocated from memory, swap
+                                                   space (stack) */
+
+#define TARGET_NETBSD_MAP_FLAGMASK      0x3ff7
+
+#define TARGET_OPENBSD_MAP_INHERIT      0x0080  /* region is retained after
+                                                   exec */
+#define TARGET_OPENBSD_MAP_NOEXTEND     0x0100  /* for MAP_FILE, don't change
+                                                   file size */
+#define TARGET_OPENBSD_MAP_TRYFIXED     0x0400  /* attempt hint address,
+                                                   even within heap */
+
+#define TARGET_OPENBSD_MAP_FLAGMASK     0x17f7
+
+/* XXX */
+#define TARGET_BSD_MAP_FLAGMASK         0x3ff7
+
+/*
+ * sys/time.h
+ * sys/timex.h
+ */
+
+/*
+ * time_t seems to be very inconsistly defined for the different *BSD's...
+ *
+ * FreeBSD/{arm, mips} uses a 64bits time_t, even in 32bits mode,
+ * so we have to add a special case here.
+ *
+ * On NetBSD time_t is always defined as an int64_t.  On OpenBSD time_t
+ * is always defined as an int.
+ *
+ */
+#if (defined(TARGET_ARM) || defined(TARGET_MIPS))
+typedef int64_t target_freebsd_time_t;
+#else
+typedef abi_long target_freebsd_time_t;
+#endif
+
+typedef abi_long target_freebsd_suseconds_t;
+
+/* compare to sys/timespec.h */
+struct target_freebsd_timespec {
+    target_freebsd_time_t   tv_sec;     /* seconds */
+    abi_long                tv_nsec;    /* and nanoseconds */
+#if (defined(TARGET_ARM) || defined(TARGET_MIPS)) && TARGET_ABI_BITS == 32
+    abi_long _pad;
+#endif
+} __packed;
+
+struct target_freebsd_timeval {
+    target_freebsd_time_t       tv_sec; /* seconds */
+    target_freebsd_suseconds_t  tv_usec;/* and microseconds */
+#if (defined(TARGET_ARM) || defined(TARGET_MIPS)) && TARGET_ABI_BITS == 32
+    abi_long _pad;
+#endif
+} __packed;
+
+/* compare to sys/timex.h */
+struct target_freebsd_ntptimeval {
+    struct target_freebsd_timespec  time;
+    abi_long    maxerror;
+    abi_long    esterror;
+    abi_long    tai;
+    int32_t     time_state;
+};
+
+struct target_freebsd_timex {
+    uint32_t    modes;
+    abi_long    offset;
+    abi_long    freq;
+    abi_long    maxerror;
+    abi_long    esterror;
+    int32_t     status;
+    abi_long    constant;
+    abi_long    precision;
+    abi_long    tolerance;
+
+    abi_long    ppsfreq;
+    abi_long    jitter;
+    int32_t     shift;
+    abi_long    stabil;
+    abi_long    jitcnt;
+    abi_long    calcnt;
+    abi_long    errcnt;
+    abi_long    stbcnt;
+};
+
+/*
+ * sys/event.h
+ */
+struct target_freebsd_kevent {
+    abi_ulong  ident;
+    int16_t    filter;
+    uint16_t   flags;
+    uint32_t   fflags;
+    abi_long   data;
+    abi_ulong  udata;
+} __packed;
+
+/*
+ *  sys/resource.h
+ */
+#if defined(__FreeBSD__) && defined(TARGET_ALPHA)
+#define TARGET_RLIM_INFINITY    0x7fffffffffffffffull
+#elif defined(__FreeBSD__) && (defined(TARGET_MIPS) || \
+        (defined(TARGET_SPARC) && TARGET_ABI_BITS == 32))
+#define TARGET_RLIM_INFINITY    0x7fffffffUL
+#else
+#define TARGET_RLIM_INFINITY    ((abi_ulong)-1)
+#endif
+
+#define TARGET_RLIMIT_CPU       0
+#define TARGET_RLIMIT_FSIZE     1
+#define TARGET_RLIMIT_DATA      2
+#define TARGET_RLIMIT_STACK     3
+#define TARGET_RLIMIT_CORE      4
+#define TARGET_RLIMIT_RSS       5
+#define TARGET_RLIMIT_MEMLOCK   6
+#define TARGET_RLIMIT_NPROC     7
+#define TARGET_RLIMIT_NOFILE    8
+#define TARGET_RLIMIT_SBSIZE    9
+#define TARGET_RLIMIT_AS        10
+#define TARGET_RLIMIT_NPTS      11
+#define TARGET_RLIMIT_SWAP      12
+
+struct target_rlimit {
+    uint64_t rlim_cur;
+    uint64_t rlim_max;
+};
+
+struct target_freebsd_rusage {
+    struct target_freebsd_timeval ru_utime; /* user time used */
+    struct target_freebsd_timeval ru_stime; /* system time used */
+    abi_long    ru_maxrss;      /* maximum resident set size */
+    abi_long    ru_ixrss;       /* integral shared memory size */
+    abi_long    ru_idrss;       /* integral unshared data size */
+    abi_long    ru_isrss;       /* integral unshared stack size */
+    abi_long    ru_minflt;      /* page reclaims */
+    abi_long    ru_majflt;      /* page faults */
+    abi_long    ru_nswap;       /* swaps */
+    abi_long    ru_inblock;     /* block input operations */
+    abi_long    ru_oublock;     /* block output operations */
+    abi_long    ru_msgsnd;      /* messages sent */
+    abi_long    ru_msgrcv;      /* messages received */
+    abi_long    ru_nsignals;    /* signals received */
+    abi_long    ru_nvcsw;       /* voluntary context switches */
+    abi_long    ru_nivcsw;      /* involuntary context switches */
+};
+
+/*
+ * sys/socket.h
+ */
+
+/*
+ * Types
+ */
+#define TARGET_SOCK_STREAM      1   /* stream socket */
+#define TARGET_SOCK_DGRAM       2   /* datagram socket */
+#define TARGET_SOCK_RAW         3   /* raw-protocol interface */
+#define TARGET_SOCK_RDM         4   /* reliably-delivered message */
+#define TARGET_SOCK_SEQPACKET   5   /* sequenced packet stream */
+
+
+/*
+ * Option flags per-socket.
+ */
+
+#define TARGET_SO_DEBUG         0x0001  /* turn on debugging info recording */
+#define TARGET_SO_ACCEPTCONN    0x0002  /* socket has had listen() */
+#define TARGET_SO_REUSEADDR     0x0004  /* allow local address reuse */
+#define TARGET_SO_KEEPALIVE     0x0008  /* keep connections alive */
+#define TARGET_SO_DONTROUTE     0x0010  /* just use interface addresses */
+#define TARGET_SO_BROADCAST     0x0020  /* permit sending of broadcast msgs */
+#define TARGET_SO_USELOOPBACK   0x0040  /* bypass hardware when possible */
+#define TARGET_SO_LINGER        0x0080  /* linger on close if data present */
+#define TARGET_SO_OOBINLINE     0x0100  /* leave received OOB data in line */
+#define TARGET_SO_REUSEPORT     0x0200  /* allow local address & port reuse */
+#define TARGET_SO_TIMESTAMP     0x0400  /* timestamp received dgram traffic */
+#define TARGET_SO_NOSIGPIPE     0x0800  /* no SIGPIPE from EPIPE */
+#define TARGET_SO_ACCEPTFILTER  0x1000  /* there is an accept filter */
+#define TARGET_SO_BINTIME       0x2000  /* timestamp received dgram traffic */
+#define TARGET_SO_NO_OFFLOAD    0x4000  /* socket cannot be offloaded */
+#define TARGET_SO_NO_DDP        0x8000  /* disable direct data placement */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define TARGET_SO_SNDBUF        0x1001  /* send buffer size */
+#define TARGET_SO_RCVBUF        0x1002  /* receive buffer size */
+#define TARGET_SO_SNDLOWAT      0x1003  /* send low-water mark */
+#define TARGET_SO_RCVLOWAT      0x1004  /* receive low-water mark */
+#define TARGET_SO_SNDTIMEO      0x1005  /* send timeout */
+#define TARGET_SO_RCVTIMEO      0x1006  /* receive timeout */
+#define TARGET_SO_ERROR         0x1007  /* get error status and clear */
+#define TARGET_SO_TYPE          0x1008  /* get socket type */
+#define TARGET_SO_LABEL         0x1009  /* socket's MAC label */
+#define TARGET_SO_PEERLABEL     0x1010  /* socket's peer's MAC label */
+#define TARGET_SO_LISTENQLIMIT  0x1011  /* socket's backlog limit */
+#define TARGET_SO_LISTENQLEN    0x1012  /* socket's complete queue length */
+#define TARGET_SO_LISTENINCQLEN 0x1013  /* socket's incomplete queue length */
+#define TARGET_SO_SETFIB        0x1014  /* use this FIB to route */
+#define TARGET_SO_USER_COOKIE   0x1015  /* user cookie (dummynet etc.) */
+#define TARGET_SO_PROTOCOL      0x1016  /* get socket protocol (Linux name) */
+
+/* alias for SO_PROTOCOL (SunOS name) */
+#define TARGET_SO_PROTOTYPE     TARGET_SO_PROTOCOL
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define TARGET_SOL_SOCKET       0xffff  /* options for socket level */
+
+#ifndef CMSG_ALIGN
+#define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1))
+#endif
+
+struct target_msghdr {
+    abi_long    msg_name;       /* So cket name */
+    int32_t     msg_namelen;    /* Length of name */
+    abi_long    msg_iov;        /* Data blocks */
+    abi_long    msg_iovlen;     /* Number of blocks */
+    abi_long    msg_control;    /* Per protocol magic
+                                   (eg BSD file descriptor passing) */
+    abi_long    msg_controllen; /* Length of cmsg list */
+    int32_t     msg_flags;      /* flags on received message */
+};
+
+struct target_sockaddr {
+    uint8_t sa_len;
+    uint8_t sa_family;
+    uint8_t sa_data[14];
+} QEMU_PACKED;
+
+struct target_in_addr {
+    uint32_t s_addr; /* big endian */
+};
+
+struct target_cmsghdr {
+    abi_long    cmsg_len;
+    int32_t     cmsg_level;
+    int32_t     cmsg_type;
+};
+
+#define TARGET_CMSG_DATA(cmsg)  \
+    ((unsigned char *)((struct target_cmsghdr *) (cmsg) + 1))
+#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr(mhdr, cmsg)
+#define TARGET_CMSG_ALIGN(len) (((len) + sizeof(abi_long) - 1) \
+    & (size_t) ~(sizeof(abi_long) - 1))
+#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN(len) \
+    + TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr)))
+#define TARGET_CMSG_LEN(len)  \
+    (TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr)) + (len))
+
+static inline struct target_cmsghdr *__target_cmsg_nxthdr(
+        struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg)
+{
+    struct target_cmsghdr *__ptr;
+
+    __ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg +
+        TARGET_CMSG_ALIGN(tswapal(__cmsg->cmsg_len)));
+    if ((unsigned long)((char *)(__ptr+1) -
+        (char *)(size_t)tswapal(__mhdr->msg_control)) >
+        tswapal(__mhdr->msg_controllen)) {
+        /* No more entries.  */
+        return (struct target_cmsghdr *)0;
+    }
+    return __cmsg;
+}
+
+/*
+ * netinet/in.h
+ */
+struct target_ip_mreq {
+    struct target_in_addr   imr_multiaddr;
+    struct target_in_addr   imr_interface;
+};
+
+struct target_ip_mreqn {
+    struct target_in_addr   imr_multiaddr;
+    struct target_in_addr   imr_address;
+    int32_t                 imr_ifindex;
+};
+
+/*
+ * sys/stat.h
+ */
+#if defined(__FreeBSD_version) && __FreeBSD_version < 900000
+#define st_atim st_atimespec
+#define st_ctim st_ctimespec
+#define st_mtim st_mtimespec
+#define st_birthtim st_birthtimespec
+#endif
+
+struct target_freebsd_stat {
+    uint32_t  st_dev;       /* inode's device */
+    uint32_t  st_ino;       /* inode's number */
+    int16_t   st_mode;      /* inode protection mode */
+    int16_t   st_nlink;     /* number of hard links */
+    uint32_t  st_uid;       /* user ID of the file's owner */
+    uint32_t  st_gid;       /* group ID of the file's group */
+    uint32_t  st_rdev;      /* device type */
+    struct  target_freebsd_timespec st_atim; /* time last accessed */
+    struct  target_freebsd_timespec st_mtim; /* time last data modification */
+    struct  target_freebsd_timespec st_ctim; /* time last file status change */
+    int64_t    st_size;     /* file size, in bytes */
+    int64_t    st_blocks;   /* blocks allocated for file */
+    uint32_t   st_blksize;  /* optimal blocksize for I/O */
+    uint32_t   st_flags;    /* user defined flags for file */
+    __uint32_t st_gen;      /* file generation number */
+    __int32_t  st_lspare;
+    struct target_freebsd_timespec st_birthtim; /* time of file creation */
+    /*
+     * Explicitly pad st_birthtim to 16 bytes so that the size of
+     * struct stat is backwards compatible.  We use bitfields instead
+     * of an array of chars so that this doesn't require a C99 compiler
+     * to compile if the size of the padding is 0.  We use 2 bitfields
+     * to cover up to 64 bits on 32-bit machines.  We assume that
+     * CHAR_BIT is 8...
+     */
+    unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec));
+    unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec));
+} __packed;
+
+/* struct nstat is the same as stat above but without the st_lspare field */
+struct target_freebsd_nstat {
+    uint32_t  st_dev;       /* inode's device */
+    uint32_t  st_ino;       /* inode's number */
+    int16_t   st_mode;      /* inode protection mode */
+    int16_t   st_nlink;     /* number of hard links */
+    uint32_t  st_uid;       /* user ID of the file's owner */
+    uint32_t  st_gid;       /* group ID of the file's group */
+    uint32_t  st_rdev;      /* device type */
+    struct  target_freebsd_timespec st_atim; /* time last accessed */
+    struct  target_freebsd_timespec st_mtim; /* time last data modification */
+    struct  target_freebsd_timespec st_ctim; /* time last file status change */
+    int64_t    st_size;     /* file size, in bytes */
+    int64_t    st_blocks;   /* blocks allocated for file */
+    uint32_t   st_blksize;  /* optimal blocksize for I/O */
+    uint32_t   st_flags;    /* user defined flags for file */
+    __uint32_t st_gen;      /* file generation number */
+    /* __int32_t  st_lspare; */
+    struct target_freebsd_timespec st_birthtim; /* time of file creation */
+    /*
+     * Explicitly pad st_birthtim to 16 bytes so that the size of
+     * struct stat is backwards compatible.  We use bitfields instead
+     * of an array of chars so that this doesn't require a C99 compiler
+     * to compile if the size of the padding is 0.  We use 2 bitfields
+     * to cover up to 64 bits on 32-bit machines.  We assume that
+     * CHAR_BIT is 8...
+     */
+    unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec));
+    unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec));
+} __packed;
+
+/*
+ * sys/mount.h
+ */
+
+/* filesystem id type */
+typedef struct target_freebsd_fsid { int32_t val[2]; } target_freebsd_fsid_t;
+
+/* filesystem statistics */
+#define TARGET_MFSNAMELEN   16  /* length of type name include null */
+#define TARGET_MNAMELEN     88  /* size of on/from name bufs */
+#define TARGET_STATFS_VERSION   0x20030518  /* current version number */
+struct target_freebsd_statfs {
+    uint32_t f_version; /* structure version number */
+    uint32_t f_type;    /* type of filesystem */
+    uint64_t f_flags;   /* copy of mount exported flags */
+    uint64_t f_bsize;   /* filesystem fragment size */
+    uint64_t f_iosize;  /* optimal transfer block size */
+    uint64_t f_blocks;  /* total data blocks in filesystem */
+    uint64_t f_bfree;   /* free blocks in filesystem */
+    int64_t  f_bavail;  /* free blocks avail to non-superuser */
+    uint64_t f_files;   /* total file nodes in filesystem */
+    int64_t  f_ffree;   /* free nodes avail to non-superuser */
+    uint64_t f_syncwrites;  /* count of sync writes since mount */
+    uint64_t f_asyncwrites; /* count of async writes since mount */
+    uint64_t f_syncreads;   /* count of sync reads since mount */
+    uint64_t f_asyncreads;  /* count of async reads since mount */
+    uint64_t f_spare[10];   /* unused spare */
+    uint32_t f_namemax; /* maximum filename length */
+    uint32_t f_owner;   /* user that mounted the filesystem */
+    target_freebsd_fsid_t   f_fsid; /* filesystem id */
+    char     f_charspare[80];           /* spare string space */
+    char     f_fstypename[TARGET_MFSNAMELEN];   /* filesys type name */
+    char     f_mntfromname[TARGET_MNAMELEN];    /* mount filesystem */
+    char     f_mntonname[TARGET_MNAMELEN];      /* dir on which mounted*/
+};
+
+/* File identifier. These are unique per filesystem on a single machine. */
+#define TARGET_MAXFIDSZ     16
+
+struct target_freebsd_fid {
+    u_short     fid_len;            /* len of data in bytes */
+    u_short     fid_data0;          /* force longword align */
+    char        fid_data[TARGET_MAXFIDSZ];  /* data (variable len) */
+};
+
+/* Generic file handle */
+struct target_freebsd_fhandle {
+    target_freebsd_fsid_t   fh_fsid;    /* Filesystem id of mount point */
+    struct target_freebsd_fid fh_fid;   /* Filesys specific id */
+};
+typedef struct target_freebsd_fhandle target_freebsd_fhandle_t;
+
+/*
+ * sys/fcntl.h
+ */
+#define TARGET_F_DUPFD              0
+#define TARGET_F_GETFD              1
+#define TARGET_F_SETFD              2
+#define TARGET_F_GETFL              3
+#define TARGET_F_SETFL              4
+#define TARGET_F_GETOWN             5
+#define TARGET_F_SETOWN             6
+#define TARGET_F_OGETLK             7
+#define TARGET_F_OSETLK             8
+#define TARGET_F_OSETLKW            9
+#define TARGET_F_DUP2FD             10
+#define TARGET_F_GETLK              11
+#define TARGET_F_SETLK              12
+#define TARGET_F_SETLKW             13
+#define TARGET_F_SETLK_REMOTE       14
+#define TARGET_F_READAHEAD          15
+#define TARGET_F_RDAHEAD            16
+#define TARGET_F_DUPFD_CLOEXEC     17
+#define TARGET_F_DUP2FD_CLOEXEC    18
+
+struct target_freebsd_flock {
+    int64_t l_start;
+    int64_t l_len;
+    int32_t l_pid;
+    int16_t l_type;
+    int16_t l_whence;
+    int32_t l_sysid;
+} QEMU_PACKED;
+
+/*
+ * FreeBSD thread and user mutex support.
+ */
+
+/* sys/thr.h */
+#define TARGET_THR_SUSPENDED    0x0001
+#define TARGET_THR_SYSTEM_SCOPE 0x0002
+
+struct target_freebsd_thr_param {
+    abi_ulong   start_func; /* thread entry function. */
+    abi_ulong   arg;        /* argument for entry function. */
+    abi_ulong   stack_base; /* stack base address. */
+    abi_ulong   stack_size; /* stack size. */
+    abi_ulong   tls_base;   /* tls base address. */
+    abi_ulong   tls_size;   /* tls size. */
+    abi_ulong   child_tid;  /* address to store new TID. */
+    abi_ulong   parent_tid; /* parent access the new TID here. */
+    int32_t     flags;      /* thread flags. */
+    abi_ulong   rtp;        /* Real-time scheduling priority. */
+    abi_ulong   spare[3];   /* spares. */
+};
+
+/* sys/rtprio.h */
+struct target_freebsd_rtprio {
+    uint16_t    type;
+    uint16_t    prio;
+};
+
+typedef struct {
+    CPUArchState *env;
+    long parent_tid;
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    pthread_t thread;
+    sigset_t sigmask;
+    struct target_freebsd_thr_param param;
+} new_freebsd_thread_info_t;
+
+/* sys/utmx.h */
+/* op code for _umtx_op */
+#define TARGET_UMTX_OP_LOCK                 0
+#define TARGET_UMTX_OP_UNLOCK               1
+#define TARGET_UMTX_OP_WAIT                 2
+#define TARGET_UMTX_OP_WAKE                 3
+#define TARGET_UMTX_OP_MUTEX_TRYLOCK        4
+#define TARGET_UMTX_OP_MUTEX_LOCK           5
+#define TARGET_UMTX_OP_MUTEX_UNLOCK         6
+#define TARGET_UMTX_OP_SET_CEILING          7
+#define TARGET_UMTX_OP_CV_WAIT              8
+#define TARGET_UMTX_OP_CV_SIGNAL            9
+#define TARGET_UMTX_OP_CV_BROADCAST         10
+#define TARGET_UMTX_OP_WAIT_UINT            11
+#define TARGET_UMTX_OP_RW_RDLOCK            12
+#define TARGET_UMTX_OP_RW_WRLOCK            13
+#define TARGET_UMTX_OP_RW_UNLOCK            14
+#define TARGET_UMTX_OP_WAIT_UINT_PRIVATE    15
+#define TARGET_UMTX_OP_WAKE_PRIVATE         16
+#define TARGET_UMTX_OP_MUTEX_WAIT           17
+#define TARGET_UMTX_OP_MUTEX_WAKE           18
+#define TARGET_UMTX_OP_SEM_WAIT             19
+#define TARGET_UMTX_OP_SEM_WAKE             20
+#define TARGET_UMTX_OP_NWAKE_PRIVATE        21
+#define TARGET_UMTX_OP_MUTEX_WAKE2          22
+#define TARGET_UMTX_OP_MAX                  23
+
+/* flags for UMTX_OP_CV_WAIT */
+#define TARGET_CVWAIT_CHECK_UNPARKING       0x01
+#define TARGET_CVWAIT_ABSTIME               0x02
+#define TARGET_CVWAIT_CLOCKID               0x04
+
+#define TARGET_UMTX_UNOWNED                 0x0
+#define TARGET_UMUTEX_UNOWNED               0x0
+#if TARGET_ABI_BITS == 32
+# define TARGET_UMTX_CONTESTED              0x80000000
+#else
+# define TARGET_UMTX_CONTESTED              0x8000000000000000LL
+#endif /* ! TARGET_ABI_BITS == 32 */
+#define TARGET_UMUTEX_CONTESTED             0x80000000U
+
+/* flags for umutex */
+#define TARGET_UMUTEX_ERROR_CHECK   0x0002  /* Error-checking mutex */
+#define TARGET_UMUTEX_PRIO_INHERIT  0x0004  /* Priority inherited mutex */
+#define TARGET_UMUTEX_PRIO_PROTECT  0x0008  /* Priority protect mutex */
+
+#define TARGET_UMUTEX_TRY           1
+#define TARGET_UMUTEX_WAIT          2
+
+/* urwlock flags */
+#define TARGET_URWLOCK_PREFER_READER    0x0002
+#define TARGET_URWLOCK_WRITE_OWNER      0x80000000U
+#define TARGET_URWLOCK_WRITE_WAITERS    0x40000000U
+#define TARGET_URWLOCK_READ_WAITERS     0x20000000U
+#define TARGET_URWLOCK_MAX_READERS      0x1fffffffU
+#define TARGET_URWLOCK_READER_COUNT(c)  ((c) & TARGET_URWLOCK_MAX_READERS)
+
+/*
+ * sys/acl.h
+ */
+#define TARGET_FREEBSD_ACL_MAX_ENTRIES          254
+
+/* vaild acl_type_t arguments */
+#define TARGET_FREEBSD_ACL_TYPE_ACCESS_OLD      0x00000000
+#define TARGET_FREEBSD_ACL_TYPE_DEFAULT_OLD     0x00000001
+#define TARGET_FREEBSD_ACL_TYPE_ACCESS          0x00000002
+#define TARGET_FREEBSD_ACL_TYPE_DEFAULT         0x00000003
+#define TARGET_FREEBSD_ACL_TYPE_NFS4            0x00000004
+
+struct target_freebsd_acl_entry {
+    int32_t     ae_tag;
+    uint32_t    ae_id;
+    uint16_t    ae_perm;
+    uint16_t    ae_entry_type;
+    uint16_t    ae_flags;
+};
+
+struct target_freebsd_acl {
+    uint32_t            acl_maxcnt;
+    uint32_t            acl_cnt;
+    int32_t             acl_space[4];
+    struct target_freebsd_acl_entry  acl_entry[TARGET_FREEBSD_ACL_MAX_ENTRIES];
+};
+
+/*
+ *  sys/uuid.h
+ */
+
+#define TARGET_UUID_NODE_LEN    6
+
+struct target_uuid {
+    uint32_t    time_low;
+    uint16_t    time_mid;
+    uint16_t    time_hi_and_version;
+    uint8_t     clock_seq_hi_and_reserved;
+    uint8_t     clock_seq_low;
+    uint8_t     node[TARGET_UUID_NODE_LEN];
+};
+
+#endif /* ! _SYSCALL_DEFS_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 07/19] bsd-user: add support for freebsd signal related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (26 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 06/19] bsd-user: add support for freebsd time related system calls Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 08/19] bsd-user: move target arch and host OS dependent code out of elfload.c Stacey Son
                   ` (11 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for signal related system calls including
sigtimedwait(2), sigaction(2), sigprocmask(2), sigpending(2), sigsuspend(2),
sigreturn(2), sigwait(2), sigwaitinfo(2), sigqueue(2), sigaltstack(2),
kill(2), killpg(2), and pdkill(2).

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/arm/target_arch_signal.h     |  257 ++++++++++
 bsd-user/bsd-signal.h                 |  232 +++++++++
 bsd-user/errno_defs.h                 |   13 +-
 bsd-user/freebsd/os-signal.h          |   43 ++
 bsd-user/freebsd/target_os_siginfo.h  |  110 ++++
 bsd-user/freebsd/target_os_signal.h   |   79 +++
 bsd-user/i386/target_arch_signal.h    |   94 ++++
 bsd-user/mips/target_arch_signal.h    |  237 +++++++++
 bsd-user/mips64/target_arch_signal.h  |  236 +++++++++
 bsd-user/netbsd/target_os_siginfo.h   |   82 +++
 bsd-user/netbsd/target_os_signal.h    |   70 +++
 bsd-user/openbsd/target_os_siginfo.h  |   82 +++
 bsd-user/openbsd/target_os_signal.h   |   70 +++
 bsd-user/qemu.h                       |   33 +-
 bsd-user/signal.c                     |  907 ++++++++++++++++++++++++++++++++-
 bsd-user/sparc/target_arch_signal.h   |   77 +++
 bsd-user/sparc64/target_arch_signal.h |   94 ++++
 bsd-user/syscall.c                    |   59 +++
 bsd-user/x86_64/target_arch_signal.h  |   94 ++++
 19 files changed, 2852 insertions(+), 17 deletions(-)
 create mode 100644 bsd-user/arm/target_arch_signal.h
 create mode 100644 bsd-user/bsd-signal.h
 create mode 100644 bsd-user/freebsd/os-signal.h
 create mode 100644 bsd-user/freebsd/target_os_siginfo.h
 create mode 100644 bsd-user/freebsd/target_os_signal.h
 create mode 100644 bsd-user/i386/target_arch_signal.h
 create mode 100644 bsd-user/mips/target_arch_signal.h
 create mode 100644 bsd-user/mips64/target_arch_signal.h
 create mode 100644 bsd-user/netbsd/target_os_siginfo.h
 create mode 100644 bsd-user/netbsd/target_os_signal.h
 create mode 100644 bsd-user/openbsd/target_os_siginfo.h
 create mode 100644 bsd-user/openbsd/target_os_signal.h
 create mode 100644 bsd-user/sparc/target_arch_signal.h
 create mode 100644 bsd-user/sparc64/target_arch_signal.h
 create mode 100644 bsd-user/x86_64/target_arch_signal.h

diff --git a/bsd-user/arm/target_arch_signal.h b/bsd-user/arm/target_arch_signal.h
new file mode 100644
index 0000000..048bd4f
--- /dev/null
+++ b/bsd-user/arm/target_arch_signal.h
@@ -0,0 +1,257 @@
+/*
+ *  arm signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+#define TARGET_REG_R0   0
+#define TARGET_REG_R1   1
+#define TARGET_REG_R2   2
+#define TARGET_REG_R3   3
+#define TARGET_REG_R4   4
+#define TARGET_REG_R5   5
+#define TARGET_REG_R6   6
+#define TARGET_REG_R7   7
+#define TARGET_REG_R8   8
+#define TARGET_REG_R9   9
+#define TARGET_REG_R10  10
+#define TARGET_REG_R11  11
+#define TARGET_REG_R12  12
+#define TARGET_REG_R13  13
+#define TARGET_REG_R14  14
+#define TARGET_REG_R15  15
+#define TARGET_REG_CPSR 16
+#define TARGET__NGREG   17
+/* Convenience synonyms */
+#define TARGET_REG_FP   TARGET_REG_R11
+#define TARGET_REG_SP   TARGET_REG_R13
+#define TARGET_REG_LR   TARGET_REG_R14
+#define TARGET_REG_PC   TARGET_REG_R15
+
+#define TARGET_INSN_SIZE    4       /* arm instruction size */
+
+/* Size of the signal trampolin code. See _sigtramp(). */
+#define TARGET_SZSIGCODE    ((abi_ulong)(8 * TARGET_INSN_SIZE))
+
+/* compare to arm/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (1024 * 4)                  /* min sig stack size */
+#define TARGET_SIGSTKSZ     (TARGET_MINSIGSTKSZ + 32768)  /* recommended size */
+
+/* arm/arm/machdep.c */
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC     0x0002
+#define TARGET_MC_SET_ONSTACK   0x0004
+
+struct target_sigcontext {
+    target_sigset_t sc_mask;    /* signal mask to retstore */
+    int32_t     sc_onstack;     /* sigstack state to restore */
+    abi_long    sc_pc;          /* pc at time of signal */
+    abi_long    sc_reg[32];     /* processor regs 0 to 31 */
+    abi_long    mullo, mulhi;   /* mullo and mulhi registers */
+    int32_t     sc_fpused;      /* fp has been used */
+    abi_long    sc_fpregs[33];  /* fp regs 0 to 31 & csr */
+    abi_long    sc_fpc_eir;     /* fp exception instr reg */
+    /* int32_t reserved[8]; */
+};
+
+typedef struct {
+    uint32_t    __fp_fpsr;
+    struct {
+        uint32_t    __fp_exponent;
+        uint32_t    __fp_mantissa_hi;
+        uint32_t    __fp_mantissa_lo;
+    }       __fp_fr[8];
+} target__fpregset_t;
+
+typedef struct {
+    uint32_t    __vfp_fpscr;
+    uint32_t    __vfp_fstmx[33];
+    uint32_t    __vfp_fpsid;
+} target__vfpregset_t;
+
+typedef struct target_mcontext {
+    uint32_t        __gregs[TARGET__NGREG];
+    union {
+        target__fpregset_t  __fpregs;
+        target__vfpregset_t __vfpregs;
+    } __fpu;
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t     uc_sigmask;
+    target_mcontext_t   uc_mcontext;
+    abi_ulong           uc_link;
+    target_stack_t      uc_stack;
+    int32_t             uc_flags;
+    int32_t             __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    target_siginfo_t    sf_si;  /* saved siginfo */
+    target_ucontext_t   sf_uc;  /* saved ucontext */
+};
+
+
+/* compare to sys/arm/include/frame.h */
+struct target_trapframe {
+    abi_ulong tf_spsr; /* Zero on arm26 */
+    abi_ulong tf_r0;
+    abi_ulong tf_r1;
+    abi_ulong tf_r2;
+    abi_ulong tf_r3;
+    abi_ulong tf_r4;
+    abi_ulong tf_r5;
+    abi_ulong tf_r6;
+    abi_ulong tf_r7;
+    abi_ulong tf_r8;
+    abi_ulong tf_r9;
+    abi_ulong tf_r10;
+    abi_ulong tf_r11;
+    abi_ulong tf_r12;
+    abi_ulong tf_usr_sp;
+    abi_ulong tf_usr_lr;
+    abi_ulong tf_svc_sp; /* Not used on arm26 */
+    abi_ulong tf_svc_lr; /* Not used on arm26 */
+    abi_ulong tf_pc;
+};
+
+/*
+ * Compare to arm/arm/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUARMState *regs, int sig, struct target_sigframe *frame,
+    abi_ulong frame_addr, struct target_sigaction *ka)
+{
+    /*
+     * Arguments to signal handler:
+     *  r0 = signal number
+     *  r1 = siginfo pointer
+     *  r2 = ucontext pointer
+     *  r5 = ucontext pointer
+     *  pc = signal handler pointer
+     *  sp = sigframe struct pointer
+     *  lr = sigtramp at base of user stack
+     */
+
+    regs->regs[0] = sig;
+    regs->regs[1] = frame_addr +
+        offsetof(struct target_sigframe, sf_si);
+    regs->regs[2] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+
+    /* the trampoline uses r5 as the uc address */
+    regs->regs[5] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+    regs->regs[TARGET_REG_PC] = ka->_sa_handler;
+    regs->regs[TARGET_REG_SP] = frame_addr;
+    regs->regs[TARGET_REG_LR] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+
+    return 0;
+}
+
+/*
+ * Compare to arm/arm/machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long get_mcontext(CPUARMState *regs, target_mcontext_t *mcp,
+        int flags)
+{
+    int err = 0;
+    uint32_t *gr = mcp->__gregs;
+
+
+    if (flags & TARGET_MC_GET_CLEAR_RET) {
+        gr[TARGET_REG_R0] = 0;
+    } else {
+        gr[TARGET_REG_R0] = tswap32(regs->regs[0]);
+    }
+
+    gr[TARGET_REG_R1] = tswap32(regs->regs[1]);
+    gr[TARGET_REG_R2] = tswap32(regs->regs[2]);
+    gr[TARGET_REG_R3] = tswap32(regs->regs[3]);
+    gr[TARGET_REG_R4] = tswap32(regs->regs[4]);
+    gr[TARGET_REG_R5] = tswap32(regs->regs[5]);
+    gr[TARGET_REG_R6] = tswap32(regs->regs[6]);
+    gr[TARGET_REG_R7] = tswap32(regs->regs[7]);
+    gr[TARGET_REG_R8] = tswap32(regs->regs[8]);
+    gr[TARGET_REG_R9] = tswap32(regs->regs[9]);
+    gr[TARGET_REG_R10] = tswap32(regs->regs[10]);
+    gr[TARGET_REG_R11] = tswap32(regs->regs[11]);
+    gr[TARGET_REG_R12] = tswap32(regs->regs[12]);
+
+    gr[TARGET_REG_SP] = tswap32(regs->regs[13]);
+    gr[TARGET_REG_LR] = tswap32(regs->regs[14]);
+    gr[TARGET_REG_PC] = tswap32(regs->regs[15]);
+    gr[TARGET_REG_CPSR] = tswap32(cpsr_read(regs));
+
+    return err;
+}
+
+/* Compare to arm/arm/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUARMState *regs, target_mcontext_t *mcp,
+        int srflag)
+{
+    int err = 0;
+    const uint32_t *gr = mcp->__gregs;
+    uint32_t cpsr;
+
+    regs->regs[0] = tswap32(gr[TARGET_REG_R0]);
+    regs->regs[1] = tswap32(gr[TARGET_REG_R1]);
+    regs->regs[2] = tswap32(gr[TARGET_REG_R2]);
+    regs->regs[3] = tswap32(gr[TARGET_REG_R3]);
+    regs->regs[4] = tswap32(gr[TARGET_REG_R4]);
+    regs->regs[5] = tswap32(gr[TARGET_REG_R5]);
+    regs->regs[6] = tswap32(gr[TARGET_REG_R6]);
+    regs->regs[7] = tswap32(gr[TARGET_REG_R7]);
+    regs->regs[8] = tswap32(gr[TARGET_REG_R8]);
+    regs->regs[9] = tswap32(gr[TARGET_REG_R9]);
+    regs->regs[10] = tswap32(gr[TARGET_REG_R10]);
+    regs->regs[11] = tswap32(gr[TARGET_REG_R11]);
+    regs->regs[12] = tswap32(gr[TARGET_REG_R12]);
+
+    regs->regs[13] = tswap32(gr[TARGET_REG_SP]);
+    regs->regs[14] = tswap32(gr[TARGET_REG_LR]);
+    regs->regs[15] = tswap32(gr[TARGET_REG_PC]);
+    cpsr = tswap32(gr[TARGET_REG_CPSR]);
+    cpsr_write(regs, cpsr, CPSR_USER | CPSR_EXEC);
+
+    return err;
+}
+
+/* Compare to arm/arm/machdep.c sys_sigreturn() */
+static inline abi_long get_ucontext_sigreturn(CPUARMState *regs,
+        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    uint32_t cpsr = cpsr_read(regs);
+
+    *target_uc = 0;
+
+    if ((cpsr & CPSR_M) != ARM_CPU_MODE_USR ||
+            (cpsr & (CPSR_I | CPSR_F)) != 0) {
+        return -TARGET_EINVAL;
+    }
+
+    *target_uc = target_sf + offsetof(struct target_sigframe, sf_uc);
+
+    return 0;
+}
+
+
+#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/bsd-signal.h b/bsd-user/bsd-signal.h
new file mode 100644
index 0000000..48a8b56
--- /dev/null
+++ b/bsd-user/bsd-signal.h
@@ -0,0 +1,232 @@
+/*
+ *  signal related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_SIGNAL_H_
+#define __BSD_SIGNAL_H_
+
+/* sigaction(2) */
+static inline abi_long do_bsd_sigaction(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    struct target_sigaction *old_act, act, oact, *pact;
+
+    if (arg2) {
+        if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) {
+            return -TARGET_EFAULT;
+        }
+        act._sa_handler = old_act->_sa_handler;
+        act.sa_flags = old_act->sa_flags;
+        memcpy(&act.sa_mask, &old_act->sa_mask, sizeof(target_sigset_t));
+        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)) {
+            return -TARGET_EFAULT;
+        }
+        old_act->_sa_handler = oact._sa_handler;
+        old_act->sa_flags = oact.sa_flags;
+        memcpy(&old_act->sa_mask, &oact.sa_mask, sizeof(target_sigset_t));
+        unlock_user_struct(old_act, arg3, 1);
+    }
+    return ret;
+}
+
+
+/* sigprocmask(2) */
+static inline abi_long do_bsd_sigprocmask(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set, oldset, *set_ptr;
+    int how;
+
+    if (arg2) {
+        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:
+            return -TARGET_EFAULT;
+        }
+        p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        target_to_host_sigset(&set, p);
+        unlock_user(p, arg2, 0);
+        set_ptr = &set;
+    } else {
+        how = 0;
+        set_ptr = NULL;
+    }
+    ret = get_errno(sigprocmask(how, set_ptr, &oldset));
+    if (!is_error(ret) && arg3) {
+        p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_sigset(p, &oldset);
+        unlock_user(p, arg3, sizeof(target_sigset_t));
+    }
+    return ret;
+}
+
+/* sigpending(2) */
+static inline abi_long do_bsd_sigpending(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+
+    ret = get_errno(sigpending(&set));
+    if (!is_error(ret)) {
+        p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_sigset(p, &set);
+        unlock_user(p, arg1, sizeof(target_sigset_t));
+    }
+    return ret;
+}
+
+/* sigsuspend(2) */
+static inline abi_long do_bsd_sigsuspend(abi_long arg1, abi_long arg2)
+{
+    void *p;
+    sigset_t set;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+
+    return get_errno(sigsuspend(&set));
+}
+
+/* sigreturn(2) */
+static inline abi_long do_bsd_sigreturn(void *cpu_env, abi_long arg1)
+{
+
+    return do_sigreturn(cpu_env, arg1);
+}
+
+/* sigvec(2) - not defined */
+/* sigblock(2) - not defined */
+/* sigsetmask(2) - not defined */
+/* sigstack(2) - not defined */
+
+/* sigwait(2) */
+static inline abi_long do_bsd_sigwait(abi_ulong arg1, abi_ulong arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    int sig;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    ret = get_errno(sigwait(&set, &sig));
+    if (!is_error(ret) && arg2) {
+        ret = put_user_s32(sig, arg2);
+    }
+    return ret;
+}
+
+/* sigwaitinfo(2) */
+static inline abi_long do_bsd_sigwaitinfo(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    siginfo_t uinfo;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    ret = get_errno(sigwaitinfo(&set, &uinfo));
+    if (!is_error(ret) && arg2) {
+        p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_siginfo(p, &uinfo);
+        unlock_user(p, arg2, sizeof(target_siginfo_t));
+    }
+    return ret;
+}
+
+/* sigqueue(2) */
+static inline abi_long do_bsd_sigqueue(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    union sigval value;
+
+    value.sival_ptr = (void *)(uintptr_t)arg3;
+    return get_errno(sigqueue(arg1, target_to_host_signal(arg2), value));
+}
+
+/* sigaltstck(2) */
+static inline abi_long do_bsd_sigaltstack(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    return do_sigaltstack(arg1, arg2, get_sp_from_cpustate(cpu_env));
+}
+
+/* kill(2) */
+static inline abi_long do_bsd_kill(abi_long pid, abi_long sig)
+{
+
+    return get_errno(kill(pid, target_to_host_signal(sig)));
+}
+
+/* killpg(2) */
+static inline abi_long do_bsd_killpg(abi_long pg, abi_long sig)
+{
+
+    return get_errno(killpg(pg, target_to_host_signal(sig)));
+}
+
+#endif /* !  __BSD_SIGNAL_H_ */
diff --git a/bsd-user/errno_defs.h b/bsd-user/errno_defs.h
index 1efa502..f01181d 100644
--- a/bsd-user/errno_defs.h
+++ b/bsd-user/errno_defs.h
@@ -1,6 +1,3 @@
-/*      $OpenBSD: errno.h,v 1.20 2007/09/03 14:37:52 millert Exp $      */
-/*      $NetBSD: errno.h,v 1.10 1996/01/20 01:33:53 jtc Exp $   */
-
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
  *      The Regents of the University of California.  All rights reserved.
@@ -37,6 +34,9 @@
  *      @(#)errno.h     8.5 (Berkeley) 1/21/94
  */
 
+#ifndef _ERRNO_DEFS_H_
+#define _ERRNO_DEFS_H_
+
 #define TARGET_EPERM            1               /* Operation not permitted */
 #define TARGET_ENOENT           2               /* No such file or directory */
 #define TARGET_ESRCH            3               /* No such process */
@@ -147,3 +147,10 @@
 #define TARGET_EIDRM            89              /* Identifier removed */
 #define TARGET_ENOMSG           90              /* No message of desired type */
 #define TARGET_ELAST            90              /* Must be equal largest errno */
+
+/* Internal errors: */
+#define TARGET_EJUSTRETURN      254             /* Just return without
+                                                   modifing regs */
+#define TARGET_ERESTART         255             /* Restart syscall */
+
+#endif /* !  _ERRNO_DEFS_H_ */
diff --git a/bsd-user/freebsd/os-signal.h b/bsd-user/freebsd/os-signal.h
new file mode 100644
index 0000000..d4a26da
--- /dev/null
+++ b/bsd-user/freebsd/os-signal.h
@@ -0,0 +1,43 @@
+/*
+ *  FreeBSD signal system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_OS_SIGNAL_H_
+#define __FREEBSD_OS_SIGNAL_H_
+
+#include <sys/procdesc.h>
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+/* pdkill(2) */
+static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(pdkill(arg1, arg2));
+}
+
+#else
+
+static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdkill()\n");
+    return -TARGET_ENOSYS;
+}
+#endif /* ! __FreeBSD_version > 900000 */
+
+#endif /* ! __FREEBSD_OS_SIGNAL_H_ */
diff --git a/bsd-user/freebsd/target_os_siginfo.h b/bsd-user/freebsd/target_os_siginfo.h
new file mode 100644
index 0000000..39180ec
--- /dev/null
+++ b/bsd-user/freebsd/target_os_siginfo.h
@@ -0,0 +1,110 @@
+/*
+ *  FreeBSD siginfo related definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_OS_SIGINFO_H_
+#define _TARGET_OS_SIGINFO_H_
+
+#define TARGET_NSIG         128
+#define TARGET_NSIG_BPW     (sizeof(uint32_t) * 8)
+#define TARGET_NSIG_WORDS   (TARGET_NSIG / TARGET_NSIG_BPW)
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+    abi_long    ss_sp;
+    abi_ulong   ss_size;
+    abi_long    ss_flags;
+} target_stack_t;
+
+typedef struct {
+    uint32_t __bits[TARGET_NSIG_WORDS];
+} target_sigset_t;
+
+struct target_sigaction {
+    abi_ulong   _sa_handler;
+    int32_t     sa_flags;
+    target_sigset_t sa_mask;
+};
+
+union target_sigval {
+    int32_t sival_int;
+    abi_ulong sival_ptr;
+    int32_t sigval_int;
+    abi_ulong sigval_ptr;
+};
+
+typedef struct target_siginfo {
+    int32_t si_signo;   /* signal number */
+    int32_t si_errno;   /* errno association */
+    int32_t si_code;    /* signal code */
+    int32_t si_pid;     /* sending process */
+    int32_t si_uid;     /* sender's ruid */
+    int32_t si_status;  /* exit value */
+    abi_ulong si_addr;  /* faulting instruction */
+    union target_sigval si_value;   /* signal value */
+    union {
+        struct {
+            int32_t _trapno;    /* machine specific trap code */
+        } _fault;
+
+        /* POSIX.1b timers */
+        struct {
+            int32_t _timerid;
+            int32_t _overrun;
+        } _timer;
+
+        struct {
+            int32_t _mqd;
+        } _mesgp;
+
+        /* SIGPOLL */
+        struct {
+            int _band;  /* POLL_IN, POLL_OUT, POLL_MSG */
+        } _poll;
+
+        struct {
+            abi_long __spare1__;
+            int32_t  __spare2_[7];
+        } __spare__;
+    } _reason;
+} target_siginfo_t;
+
+#define target_si_signo     si_signo
+#define target_si_code      si_code
+#define target_si_errno     si_errno
+#define target_si_addr      si_addr
+
+/* SIGILL si_codes */
+#define TARGET_ILL_ILLOPC   (1) /* Illegal opcode. */
+#define TARGET_ILL_ILLOPN   (2) /* Illegal operand. */
+#define TARGET_ILL_ILLADR   (3) /* Illegal addressing mode. */
+#define TARGET_ILL_ILLTRP   (4) /* Illegal trap. */
+#define TARGET_ILL_PRVOPC   (5) /* Privileged opcode. */
+#define TARGET_ILL_PRVREG   (6) /* Privileged register. */
+#define TARGET_ILL_COPROC   (7) /* Coprocessor error. */
+#define TARGET_ILL_BADSTK   (8) /* Internal stack error. */
+
+/* SIGSEGV si_codes */
+#define TARGET_SEGV_MAPERR  (1) /* address not mapped to object */
+#define TARGET_SEGV_ACCERR  (2) /* invalid permissions for mapped
+                                           object */
+
+/* SIGTRAP si_codes */
+#define TARGET_TRAP_BRKPT   (1) /* process beakpoint */
+#define TARGET_TRAP_TRACE   (2) /* process trace trap */
+
+#endif /* !_TARGET_OS_SIGINFO_H_ */
diff --git a/bsd-user/freebsd/target_os_signal.h b/bsd-user/freebsd/target_os_signal.h
new file mode 100644
index 0000000..d7004c8
--- /dev/null
+++ b/bsd-user/freebsd/target_os_signal.h
@@ -0,0 +1,79 @@
+#ifndef _TARGET_OS_SIGNAL_H_
+#define _TARGET_OS_SIGNAL_H_
+
+#include "target_os_siginfo.h"
+#include "target_arch_signal.h"
+
+/* Compare to sys/signal.h */
+#define TARGET_SIGHUP  1       /* hangup */
+#define TARGET_SIGINT  2       /* interrupt */
+#define TARGET_SIGQUIT 3       /* quit */
+#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
+#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
+#define TARGET_SIGABRT 6       /* abort() */
+#define TARGET_SIGIOT  SIGABRT /* compatibility */
+#define TARGET_SIGEMT  7       /* EMT instruction */
+#define TARGET_SIGFPE  8       /* floating point exception */
+#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
+#define TARGET_SIGBUS  10      /* bus error */
+#define TARGET_SIGSEGV 11      /* segmentation violation */
+#define TARGET_SIGSYS  12      /* bad argument to system call */
+#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
+#define TARGET_SIGALRM 14      /* alarm clock */
+#define TARGET_SIGTERM 15      /* software termination signal from kill */
+#define TARGET_SIGURG  16      /* urgent condition on IO channel */
+#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
+#define TARGET_SIGTSTP 18      /* stop signal from tty */
+#define TARGET_SIGCONT 19      /* continue a stopped process */
+#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
+#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
+#define TARGET_SIGTTOU 22      /* like TTIN for output if(tp->t_local&LTOSTOP)*/
+#define TARGET_SIGIO   23      /* input/output possible signal */
+#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
+#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
+#define TARGET_SIGVTALRM 26    /* virtual time alarm */
+#define TARGET_SIGPROF 27      /* profiling time alarm */
+#define TARGET_SIGWINCH 28     /* window size changes */
+#define TARGET_SIGINFO  29     /* information request */
+#define TARGET_SIGUSR1 30      /* user defined signal 1 */
+#define TARGET_SIGUSR2 31      /* user defined signal 2 */
+#define TARGET_SIGTHR 32       /* reserved by thread library */
+#define TARGET_SIGLWP SIGTHR   /* compatibility */
+#define TARGET_SIGLIBRT 33     /* reserved by the real-time library */
+#define TARGET_SIGRTMIN 65
+#define TARGET_SIGRTMAX 126
+#define TARGET_QEMU_ESIGRETURN  255 /* fake errno value for use by sigreturn */
+
+/*
+ * Language spec says we must list exactly one parameter, even though we
+ * actually supply three.  Ugh!
+ */
+#define TARGET_SIG_DFL      ((abi_long)0)   /* default signal handling */
+#define TARGET_SIG_IGN      ((abi_long)1)   /* ignore signal */
+#define TARGET_SIG_ERR      ((abi_long)-1)  /* error return from signal */
+
+#define TARGET_SA_ONSTACK   0x0001  /* take signal on signal stack */
+#define TARGET_SA_RESTART   0x0002  /* restart system on signal return */
+#define TARGET_SA_RESETHAND 0x0004  /* reset to SIG_DFL when taking signal */
+#define TARGET_SA_NODEFER   0x0010  /* don't mask the signal we're delivering */
+#define TARGET_SA_NOCLDWAIT 0x0020  /* don't create zombies (assign to pid 1) */
+#define TARGET_SA_USERTRAMP 0x0100  /* do not bounce off kernel's sigtramp */
+#define TARGET_SA_NOCLDSTOP 0x0008  /* do not generate SIGCHLD on child stop */
+#define TARGET_SA_SIGINFO   0x0040  /* generate siginfo_t */
+
+/*
+ * Flags for sigprocmask:
+ */
+#define TARGET_SIG_BLOCK        1   /* block specified signal set */
+#define TARGET_SIG_UNBLOCK      2   /* unblock specified signal set */
+#define TARGET_SIG_SETMASK      3   /* set specified signal set */
+
+#define TARGET_BADSIG           SIG_ERR
+
+/*
+ * sigaltstack control
+ */
+#define TARGET_SS_ONSTACK 0x0001  /* take signals on alternate stack */
+#define TARGET_SS_DISABLE 0x0004  /* disable taking signals on alternate stack*/
+
+#endif /* !_TARGET_OS_SIGNAL_H_ */
diff --git a/bsd-user/i386/target_arch_signal.h b/bsd-user/i386/target_arch_signal.h
new file mode 100644
index 0000000..e2387b2
--- /dev/null
+++ b/bsd-user/i386/target_arch_signal.h
@@ -0,0 +1,94 @@
+/*
+ *  i386 dependent signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef TARGET_ARCH_SIGNAL_H
+#define TARGET_ARCH_SIGNAL_H
+
+#include "cpu.h"
+
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE    (0) */      /* XXX to be added. */
+
+/* compare to  x86/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (512 * 4)               /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to i386/i386/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long set_sigtramp_args(CPUX86State *regs,
+        int sig, struct target_sigframe *frame, abi_ulong frame_addr,
+        struct target_sigaction *ka)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to i386/i386/machdep.c get_mcontext() */
+static inline abi_long get_mcontext(CPUX86State *regs,
+        target_mcontext_t *mcp, int flags)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to i386/i386/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUX86State *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUX86State *regs,
+                        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    /* XXX */
+    *target_uc = 0;
+    return -TARGET_EOPNOTSUPP;
+}
+
+#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/mips/target_arch_signal.h b/bsd-user/mips/target_arch_signal.h
new file mode 100644
index 0000000..79d6f65
--- /dev/null
+++ b/bsd-user/mips/target_arch_signal.h
@@ -0,0 +1,237 @@
+/*
+ *  mips signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+#define TARGET_INSN_SIZE    4       /* mips instruction size */
+
+/* Size of the signal trampolin code. See insall_sigtramp(). */
+#define TARGET_SZSIGCODE    ((abi_ulong)(4 * TARGET_INSN_SIZE))
+
+/* compare to mips/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (512 * 4)                   /* min sig stack size */
+#define TARGET_SIGSTKSZ     (TARGET_MINSIGSTKSZ + 32768)  /* recommended size */
+
+/* compare to sys/mips/include/asm.h */
+#define TARGET_SZREG        8
+#define TARGET_CALLFRAME_SIZ    (TARGET_SZREG * 4)
+
+/* mips/mips/pm_machdep.c */
+#define TARGET_UCONTEXT_MAGIC   0xACEDBADE
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC     0x0002
+#define TARGET_MC_SET_ONSTACK   0x0004
+
+struct target_sigcontext {
+    target_sigset_t sc_mask;    /* signal mask to retstore */
+    int32_t     sc_onstack;     /* sigstack state to restore */
+    abi_long    sc_pc;          /* pc at time of signal */
+    abi_long    sc_reg[32];     /* processor regs 0 to 31 */
+    abi_long    mullo, mulhi;   /* mullo and mulhi registers */
+    int32_t     sc_fpused;      /* fp has been used */
+    abi_long    sc_fpregs[33];  /* fp regs 0 to 31 & csr */
+    abi_long    sc_fpc_eir;     /* fp exception instr reg */
+    /* int32_t reserved[8]; */
+};
+
+typedef struct target_mcontext {
+    int32_t     mc_onstack;     /* sigstack state to restore */
+    abi_long    mc_pc;          /* pc at time of signal */
+    abi_long    mc_regs[32];    /* process regs 0 to 31 */
+    abi_long    sr;             /* status register */
+    abi_long    mullo, mulhi;
+    int32_t     mc_fpused;      /* fp has been used */
+    abi_long    mc_fpregs[33];  /* fp regs 0 to 32 & csr */
+    abi_long    mc_fpc_eir;     /* fp exception instr reg */
+    abi_ulong   mc_tls;         /* pointer to TLS area */
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to mips/mips/pm_machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
+    abi_ulong frame_addr, struct target_sigaction *ka)
+{
+
+    /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */
+
+    /* MIPS only struct target_sigframe members: */
+    frame->sf_signum = sig;
+    frame->sf_siginfo = frame_addr + offsetof(struct target_sigframe, sf_si);
+    frame->sf_ucontext = frame_addr + offsetof(struct target_sigframe, sf_uc);
+
+    /*
+     * Arguments to signal handler:
+     *  a0 ($4) = signal number
+     *  a1 ($5) = siginfo pointer
+     *  a2 ($6) = ucontext pointer
+     *  PC = signal handler pointer
+     *  t9 ($25) = signal handler pointer
+     *  $29 = point to sigframe struct
+     *  ra ($31) = sigtramp at base of user stack
+     */
+    regs->active_tc.gpr[4] = sig;
+    regs->active_tc.gpr[5] = frame_addr +
+        offsetof(struct target_sigframe, sf_si);
+    regs->active_tc.gpr[6] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+    regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler;
+    regs->active_tc.gpr[29] = frame_addr;
+    regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+
+    return 0;
+}
+
+/*
+ * Compare to mips/mips/pm_machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
+        int flags)
+{
+    int i, err = 0;
+
+    if (flags & TARGET_MC_ADD_MAGIC) {
+        mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC);
+    } else {
+        mcp->mc_regs[0] = 0;
+    }
+
+    if (flags & TARGET_MC_SET_ONSTACK) {
+        mcp->mc_onstack = tswapal(1);
+    } else {
+        mcp->mc_onstack = 0;
+    }
+
+    for (i = 1; i < 32; i++) {
+        mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]);
+    }
+
+#if 0 /* XXX FP is not used right now */
+    abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0;
+
+    mcp->mc_fpused = used_fp;
+    if (used_fp) {
+        preempt_disable();
+        if (!is_fpu_owner()) {
+            own_fpu();
+            for (i = 0; i < 33; i++) {
+                mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]);
+            }
+        }
+        preempt_enable();
+    }
+#else
+    mcp->mc_fpused = 0;
+#endif
+
+    if (flags & TARGET_MC_GET_CLEAR_RET) {
+        mcp->mc_regs[2] = 0;    /* v0 = 0 */
+        mcp->mc_regs[3] = 0;    /* v1 = 0 */
+        mcp->mc_regs[7] = 0;    /* a3 = 0 */
+    }
+
+    mcp->mc_pc = tswapal(regs->active_tc.PC);
+    mcp->mullo = tswapal(regs->active_tc.LO[0]);
+    mcp->mulhi = tswapal(regs->active_tc.HI[0]);
+    mcp->mc_tls = tswapal(regs->tls_value);
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+/* Compare to mips/mips/pm_machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
+        int srflag)
+{
+    int i, err = 0;
+
+    for (i = 1; i < 32; i++) {
+        regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]);
+    }
+
+#if 0  /* XXX FP is not used right now */
+    abi_ulong used_fp = 0;
+
+    used_fp = tswapal(mcp->mc_fpused)
+    conditional_used_math(used_fp);
+
+    preempt_disabled();
+    if (used_math()) {
+        /* restore fpu context if we have used it before */
+        own_fpu();
+        for (i = 0; i < 32; i++) {
+            regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]);
+        }
+    } else {
+        /* Signal handler may have used FPU.  Give it up. */
+        lose_fpu();
+    }
+    preempt_enable();
+#endif
+
+    regs->CP0_EPC = tswapal(mcp->mc_pc);
+    regs->active_tc.LO[0] = tswapal(mcp->mullo);
+    regs->active_tc.HI[0] = tswapal(mcp->mulhi);
+    regs->tls_value = tswapal(mcp->mc_tls);
+
+    if (srflag) {
+        /* doing sigreturn() */
+        regs->active_tc.PC = regs->CP0_EPC;
+        regs->CP0_EPC = 0;  /* XXX  for nested signals ? */
+    }
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUMIPSState *regs,
+                abi_ulong target_sf, abi_ulong *target_uc)
+{
+
+    *target_uc = target_sf;
+    return 0;
+}
+
+
+#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/mips64/target_arch_signal.h b/bsd-user/mips64/target_arch_signal.h
new file mode 100644
index 0000000..07d281e
--- /dev/null
+++ b/bsd-user/mips64/target_arch_signal.h
@@ -0,0 +1,236 @@
+/*
+ *  mips64 signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+#define TARGET_INSN_SIZE     4  /* mips64 instruction size */
+
+/* Size of the signal trampolin code placed on the stack. */
+#define TARGET_SZSIGCODE    ((abi_ulong)(4 * TARGET_INSN_SIZE))
+
+#define TARGET_MINSIGSTKSZ  (512 * 4)
+#define TARGET_SIGSTKSZ     (TARGET_MINSIGSTKSZ + 32768)
+
+/* compare to sys/mips/include/asm.h */
+#define TARGET_SZREG        8
+#define TARGET_CALLFRAME_SIZ    (TARGET_SZREG * 4)
+
+/* mips/mips/pm_machdep.c */
+#define TARGET_UCONTEXT_MAGIC   0xACEDBADE
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC     0x0002
+#define TARGET_MC_SET_ONSTACK   0x0004
+
+struct target_sigcontext {
+    target_sigset_t sc_mask;    /* signal mask to retstore */
+    int32_t     sc_onstack;     /* sigstack state to restore */
+    abi_long    sc_pc;          /* pc at time of signal */
+    abi_long    sc_reg[32];     /* processor regs 0 to 31 */
+    abi_long    mullo, mulhi;   /* mullo and mulhi registers */
+    int32_t     sc_fpused;      /* fp has been used */
+    abi_long    sc_fpregs[33];  /* fp regs 0 to 31 & csr */
+    abi_long    sc_fpc_eir;     /* fp exception instr reg */
+    /* int32_t reserved[8]; */
+};
+
+typedef struct target_mcontext {
+    int32_t     mc_onstack;     /* sigstack state to restore */
+    abi_long    mc_pc;          /* pc at time of signal */
+    abi_long    mc_regs[32];    /* process regs 0 to 31 */
+    abi_long    sr;             /* status register */
+    abi_long    mullo, mulhi;
+    int32_t     mc_fpused;      /* fp has been used */
+    abi_long    mc_fpregs[33];  /* fp regs 0 to 32 & csr */
+    abi_long    mc_fpc_eir;     /* fp exception instr reg */
+    abi_ulong   mc_tls;         /* pointer to TLS area */
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to mips/mips/pm_machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
+    abi_ulong frame_addr, struct target_sigaction *ka)
+{
+
+    /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */
+
+    /* MIPS only struct target_sigframe members: */
+    frame->sf_signum = sig;
+    frame->sf_siginfo = frame_addr + offsetof(struct target_sigframe, sf_si);
+    frame->sf_ucontext = frame_addr + offsetof(struct target_sigframe, sf_uc);
+
+    /*
+     * Arguments to signal handler:
+     *  a0 ($4) = signal number
+     *  a1 ($5) = siginfo pointer
+     *  a2 ($6) = ucontext pointer
+     *  PC = signal handler pointer
+     *  t9 ($25) = signal handler pointer
+     *  $29 = point to sigframe struct
+     *  ra ($31) = sigtramp at base of user stack
+     */
+    regs->active_tc.gpr[4] = sig;
+    regs->active_tc.gpr[5] = frame_addr +
+        offsetof(struct target_sigframe, sf_si);
+    regs->active_tc.gpr[6] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+    regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler;
+    regs->active_tc.gpr[29] = frame_addr;
+    regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+
+    return 0;
+}
+
+/*
+ * Compare to mips/mips/pm_machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
+        int flags)
+{
+    int i, err = 0;
+
+    if (flags & TARGET_MC_ADD_MAGIC) {
+        mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC);
+    } else {
+        mcp->mc_regs[0] = 0;
+    }
+
+    if (flags & TARGET_MC_SET_ONSTACK) {
+        mcp->mc_onstack = tswapal(1);
+    } else {
+        mcp->mc_onstack = 0;
+    }
+
+    for (i = 1; i < 32; i++) {
+        mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]);
+    }
+
+#if 0 /* XXX FP is not used right now */
+    abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0;
+
+    mcp->mc_fpused = used_fp;
+    if (used_fp) {
+        preempt_disable();
+        if (!is_fpu_owner()) {
+            own_fpu();
+            for (i = 0; i < 33; i++) {
+                mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]);
+            }
+        }
+        preempt_enable();
+    }
+#else
+    mcp->mc_fpused = 0;
+#endif
+
+    if (flags & TARGET_MC_GET_CLEAR_RET) {
+        mcp->mc_regs[2] = 0;    /* v0 = 0 */
+        mcp->mc_regs[3] = 0;    /* v1 = 0 */
+        mcp->mc_regs[7] = 0;    /* a3 = 0 */
+    }
+
+    mcp->mc_pc = tswapal(regs->active_tc.PC);
+    mcp->mullo = tswapal(regs->active_tc.LO[0]);
+    mcp->mulhi = tswapal(regs->active_tc.HI[0]);
+    mcp->mc_tls = tswapal(regs->tls_value);
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+/* Compare to mips/mips/pm_machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
+        int srflag)
+{
+    int i, err = 0;
+
+    for (i = 1; i < 32; i++) {
+        regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]);
+    }
+
+#if 0  /* XXX FP is not used right now */
+    abi_ulong used_fp = 0;
+
+    used_fp = tswapal(mcp->mc_fpused)
+    conditional_used_math(used_fp);
+
+    preempt_disabled();
+    if (used_math()) {
+        /* restore fpu context if we have used it before */
+        own_fpu();
+        for (i = 0; i < 32; i++) {
+            regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]);
+        }
+    } else {
+        /* Signal handler may have used FPU.  Give it up. */
+        lose_fpu();
+    }
+    preempt_enable();
+#endif
+
+    regs->CP0_EPC = tswapal(mcp->mc_pc);
+    regs->active_tc.LO[0] = tswapal(mcp->mullo);
+    regs->active_tc.HI[0] = tswapal(mcp->mulhi);
+    regs->tls_value = tswapal(mcp->mc_tls);
+
+    if (srflag) {
+        /* doing sigreturn() */
+        regs->active_tc.PC = regs->CP0_EPC;
+        regs->CP0_EPC = 0;  /* XXX  for nested signals ? */
+    }
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUMIPSState *regs,
+                        abi_ulong target_sf, abi_ulong *target_uc)
+{
+
+    /* mips passes ucontext struct as the stack frame */
+    *target_uc = target_sf;
+    return 0;
+}
+
+#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/netbsd/target_os_siginfo.h b/bsd-user/netbsd/target_os_siginfo.h
new file mode 100644
index 0000000..667c19c
--- /dev/null
+++ b/bsd-user/netbsd/target_os_siginfo.h
@@ -0,0 +1,82 @@
+#ifndef _TARGET_OS_SIGINFO_H_
+#define _TARGET_OS_SIGINFO_H_
+
+#define TARGET_NSIG     32  /* counting 0; could be 33 (mask is 1-32) */
+#define TARGET_NSIG_BPW     (sizeof(uint32_t) * 8)
+#define TARGET_NSIG_WORDS   (TARGET_NSIG / TARGET_NSIG_BPW)
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+    abi_long    ss_sp;
+    abi_ulong   ss_size;
+    abi_long    ss_flags;
+} target_stack_t;
+
+typedef struct {
+    uint32_t __bits[TARGET_NSIG_WORDS];
+} target_sigset_t
+
+struct target_sigaction {
+    abi_ulong   _sa_handler;
+    int32_t     sa_flags;
+    target_sigset_t sa_mask;
+};
+
+/* Compare to sys/siginfo.h */
+typedef union target_sigval {
+    int         sival_int;
+    abi_ulong   sival_ptr;
+} target_sigval_t;
+
+struct target_ksiginfo {
+    int32_t     _signo;
+    int32_t     _code;
+    int32_t     _errno;
+#if TARGET_ABI_BITS == 64
+    int32_t     _pad;
+#endif
+    union {
+        struct {
+            int32_t             _pid;
+            int32_t             _uid;
+            target_sigval_t    _value;
+        } _rt;
+
+        struct {
+            int32_t             _pid;
+            int32_t             _uid;
+            int32_t             _struct;
+            /* clock_t          _utime; */
+            /* clock_t          _stime; */
+        } _child;
+
+        struct {
+            abi_ulong           _addr;
+            int32_t             _trap;
+        } _fault;
+
+        struct {
+            long                _band;
+            int                 _fd;
+        } _poll;
+    } _reason;
+};
+
+typedef union target_siginfo {
+    int8_t     si_pad[128];
+    struct     target_ksiginfo  _info;
+} target_siginfo_t;
+
+#define target_si_signo     _info._signo
+#define target_si_code      _info._code
+#define target_si_errno     _info._errno
+#define target_si_addr      _info._reason._fault._addr
+
+#define TARGET_SEGV_MAPERR  1
+#define TARGET_SEGV_ACCERR  2
+
+#define TARGET_TRAP_BRKPT   1
+#define TARGET_TRAP_TRACE   2
+
+
+#endif /* ! _TARGET_OS_SIGINFO_H_ */
diff --git a/bsd-user/netbsd/target_os_signal.h b/bsd-user/netbsd/target_os_signal.h
new file mode 100644
index 0000000..d39a26f
--- /dev/null
+++ b/bsd-user/netbsd/target_os_signal.h
@@ -0,0 +1,70 @@
+#ifndef _TARGET_OS_SIGNAL_H_
+#define _TARGET_OS_SIGNAL_H_
+
+#include "target_os_siginfo.h"
+#include "target_arch_signal.h"
+
+#define TARGET_SIGHUP  1       /* hangup */
+#define TARGET_SIGINT  2       /* interrupt */
+#define TARGET_SIGQUIT 3       /* quit */
+#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
+#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
+#define TARGET_SIGABRT 6       /* abort() */
+#define TARGET_SIGIOT  SIGABRT /* compatibility */
+#define TARGET_SIGEMT  7       /* EMT instruction */
+#define TARGET_SIGFPE  8       /* floating point exception */
+#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
+#define TARGET_SIGBUS  10      /* bus error */
+#define TARGET_SIGSEGV 11      /* segmentation violation */
+#define TARGET_SIGSYS  12      /* bad argument to system call */
+#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
+#define TARGET_SIGALRM 14      /* alarm clock */
+#define TARGET_SIGTERM 15      /* software termination signal from kill */
+#define TARGET_SIGURG  16      /* urgent condition on IO channel */
+#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
+#define TARGET_SIGTSTP 18      /* stop signal from tty */
+#define TARGET_SIGCONT 19      /* continue a stopped process */
+#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
+#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
+#define TARGET_SIGTTOU 22      /* like TTIN for output if
+                                  (tp->t_local&LTOSTOP) */
+#define TARGET_SIGIO   23      /* input/output possible signal */
+#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
+#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
+#define TARGET_SIGVTALRM 26    /* virtual time alarm */
+#define TARGET_SIGPROF   27    /* profiling time alarm */
+#define TARGET_SIGWINCH  28    /* window size changes */
+#define TARGET_SIGINFO   29    /* information request */
+#define TARGET_SIGUSR1   30    /* user defined signal 1 */
+#define TARGET_SIGUSR2   31    /* user defined signal 2 */
+
+/*
+ * Language spec says we must list exactly one parameter, even though we
+ * actually supply three.  Ugh!
+ */
+#define TARGET_SIG_DFL         ((void (*)(int))0)
+#define TARGET_SIG_IGN         ((void (*)(int))1)
+#define TARGET_SIG_ERR         ((void (*)(int))-1)
+
+#define TARGET_SA_ONSTACK   0x0001  /* take signal on signal stack */
+#define TARGET_SA_RESTART   0x0002  /* restart system on signal return */
+#define TARGET_SA_RESETHAND 0x0004  /* reset to SIG_DFL when taking signal */
+#define TARGET_SA_NODEFER   0x0010  /* don't mask the signal we're delivering */
+#define TARGET_SA_NOCLDWAIT 0x0020  /* don't create zombies (assign to pid 1) */
+#define TARGET_SA_USERTRAMP 0x0100  /* do not bounce off kernel's sigtramp */
+#define TARGET_SA_NOCLDSTOP 0x0008  /* do not generate SIGCHLD on child stop */
+#define TARGET_SA_SIGINFO   0x0040  /* generate siginfo_t */
+
+/*
+ * Flags for sigprocmask:
+ */
+#define TARGET_SIG_BLOCK       1       /* block specified signal set */
+#define TARGET_SIG_UNBLOCK     2       /* unblock specified signal set */
+#define TARGET_SIG_SETMASK     3       /* set specified signal set */
+
+#define TARGET_BADSIG       SIG_ERR
+
+#define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */
+#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */
+
+#endif /* !_TARGET_OS_SIGNAL_H_ */
diff --git a/bsd-user/openbsd/target_os_siginfo.h b/bsd-user/openbsd/target_os_siginfo.h
new file mode 100644
index 0000000..baf646a
--- /dev/null
+++ b/bsd-user/openbsd/target_os_siginfo.h
@@ -0,0 +1,82 @@
+#ifndef _TARGET_OS_SIGINFO_H_
+#define _TARGET_OS_SIGINFO_H_
+
+#define TARGET_NSIG     32   /* counting 0; could be 33 (mask is 1-32) */
+#define TARGET_NSIG_BPW     (sizeof(uint32_t) * 8)
+#define TARGET_NSIG_WORDS   (TARGET_NSIG / TARGET_NSIG_BPW)
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+    abi_long    ss_sp;
+    abi_ulong   ss_size;
+    abi_long    ss_flags;
+} target_stack_t;
+
+typedef struct {
+    uint32_t __bits[TARGET_NSIG_WORDS];
+} target_sigset_t
+
+struct target_sigaction {
+    abi_ulong   _sa_handler;
+    int32_t     sa_flags;
+    target_sigset_t sa_mask;
+};
+
+/* Compare to sys/siginfo.h */
+typedef union target_sigval {
+    int         sival_int;
+    abi_ulong   sival_ptr;
+} target_sigval_t;
+
+struct target_ksiginfo {
+    int32_t     _signo;
+    int32_t     _code;
+    int32_t     _errno;
+#if TARGET_ABI_BITS == 64
+    int32_t     _pad;
+#endif
+    union {
+        struct {
+            int32_t             _pid;
+            int32_t             _uid;
+            target_sigval_t    _value;
+        } _rt;
+
+        struct {
+            int32_t             _pid;
+            int32_t             _uid;
+            int32_t             _struct;
+            /* clock_t          _utime; */
+            /* clock_t          _stime; */
+        } _child;
+
+        struct {
+            abi_ulong           _addr;
+            int32_t             _trap;
+        } _fault;
+
+        struct {
+            long                _band;
+            int                 _fd;
+        } _poll;
+    } _reason;
+};
+
+typedef union target_siginfo {
+    int8_t     si_pad[128];
+    struct     target_ksiginfo  _info;
+} target_siginfo_t;
+
+#define target_si_signo     _info._signo
+#define target_si_code      _info._code
+#define target_si_errno     _info._errno
+#define target_si_addr      _info._reason._fault._addr
+
+#define TARGET_SEGV_MAPERR  1
+#define TARGET_SEGV_ACCERR  2
+
+#define TARGET_TRAP_BRKPT   1
+#define TARGET_TRAP_TRACE   2
+
+
+#endif /* ! _TARGET_OS_SIGINFO_H_ */
diff --git a/bsd-user/openbsd/target_os_signal.h b/bsd-user/openbsd/target_os_signal.h
new file mode 100644
index 0000000..d39a26f
--- /dev/null
+++ b/bsd-user/openbsd/target_os_signal.h
@@ -0,0 +1,70 @@
+#ifndef _TARGET_OS_SIGNAL_H_
+#define _TARGET_OS_SIGNAL_H_
+
+#include "target_os_siginfo.h"
+#include "target_arch_signal.h"
+
+#define TARGET_SIGHUP  1       /* hangup */
+#define TARGET_SIGINT  2       /* interrupt */
+#define TARGET_SIGQUIT 3       /* quit */
+#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
+#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
+#define TARGET_SIGABRT 6       /* abort() */
+#define TARGET_SIGIOT  SIGABRT /* compatibility */
+#define TARGET_SIGEMT  7       /* EMT instruction */
+#define TARGET_SIGFPE  8       /* floating point exception */
+#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
+#define TARGET_SIGBUS  10      /* bus error */
+#define TARGET_SIGSEGV 11      /* segmentation violation */
+#define TARGET_SIGSYS  12      /* bad argument to system call */
+#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
+#define TARGET_SIGALRM 14      /* alarm clock */
+#define TARGET_SIGTERM 15      /* software termination signal from kill */
+#define TARGET_SIGURG  16      /* urgent condition on IO channel */
+#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
+#define TARGET_SIGTSTP 18      /* stop signal from tty */
+#define TARGET_SIGCONT 19      /* continue a stopped process */
+#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
+#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
+#define TARGET_SIGTTOU 22      /* like TTIN for output if
+                                  (tp->t_local&LTOSTOP) */
+#define TARGET_SIGIO   23      /* input/output possible signal */
+#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
+#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
+#define TARGET_SIGVTALRM 26    /* virtual time alarm */
+#define TARGET_SIGPROF   27    /* profiling time alarm */
+#define TARGET_SIGWINCH  28    /* window size changes */
+#define TARGET_SIGINFO   29    /* information request */
+#define TARGET_SIGUSR1   30    /* user defined signal 1 */
+#define TARGET_SIGUSR2   31    /* user defined signal 2 */
+
+/*
+ * Language spec says we must list exactly one parameter, even though we
+ * actually supply three.  Ugh!
+ */
+#define TARGET_SIG_DFL         ((void (*)(int))0)
+#define TARGET_SIG_IGN         ((void (*)(int))1)
+#define TARGET_SIG_ERR         ((void (*)(int))-1)
+
+#define TARGET_SA_ONSTACK   0x0001  /* take signal on signal stack */
+#define TARGET_SA_RESTART   0x0002  /* restart system on signal return */
+#define TARGET_SA_RESETHAND 0x0004  /* reset to SIG_DFL when taking signal */
+#define TARGET_SA_NODEFER   0x0010  /* don't mask the signal we're delivering */
+#define TARGET_SA_NOCLDWAIT 0x0020  /* don't create zombies (assign to pid 1) */
+#define TARGET_SA_USERTRAMP 0x0100  /* do not bounce off kernel's sigtramp */
+#define TARGET_SA_NOCLDSTOP 0x0008  /* do not generate SIGCHLD on child stop */
+#define TARGET_SA_SIGINFO   0x0040  /* generate siginfo_t */
+
+/*
+ * Flags for sigprocmask:
+ */
+#define TARGET_SIG_BLOCK       1       /* block specified signal set */
+#define TARGET_SIG_UNBLOCK     2       /* unblock specified signal set */
+#define TARGET_SIG_SETMASK     3       /* set specified signal set */
+
+#define TARGET_BADSIG       SIG_ERR
+
+#define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */
+#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */
+
+#endif /* !_TARGET_OS_SIGNAL_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 594de5c..0e332af 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -39,7 +39,7 @@ extern enum BSDType bsd_type;
 #include "syscall_defs.h"
 #include "syscall.h"
 #include "target_os_vmparam.h"
-#include "target_signal.h"
+#include "target_os_signal.h"
 #include "exec/gdbstub.h"
 
 #if defined(CONFIG_USE_NPTL)
@@ -72,16 +72,16 @@ struct image_info {
 
 #define MAX_SIGQUEUE_SIZE 1024
 
-struct sigqueue {
-    struct sigqueue *next;
-    //target_siginfo_t info;
+struct qemu_sigqueue {
+    struct qemu_sigqueue *next;
+    target_siginfo_t info;
 };
 
 struct emulated_sigtable {
     int pending; /* true if signal is pending */
-    struct sigqueue *first;
-    struct sigqueue info; /* in order to always have memory for the
-                             first signal, we put it here */
+    struct qemu_sigqueue *first;
+    struct qemu_sigqueue info; /* in order to always have memory for the
+                                  first signal, we put it here */
 };
 
 /* NOTE: we force a big alignment so that the stack stored after is
@@ -93,8 +93,8 @@ typedef struct TaskState {
     struct bsd_binprm *bprm;
 
     struct emulated_sigtable sigtab[TARGET_NSIG];
-    struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
-    struct sigqueue *first_free; /* first free siginfo queue entry */
+    struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
+    struct qemu_sigqueue *first_free; /* first free siginfo queue entry */
     int signal_pending; /* non zero if a signal may be pending */
 
     uint8_t stack[0];
@@ -202,12 +202,19 @@ extern int do_strace;
 /* signal.c */
 void process_pending_signals(CPUArchState *cpu_env);
 void signal_init(void);
-//int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
-//void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
-//void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
-long do_sigreturn(CPUArchState *env);
+int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
+int target_to_host_signal(int sig);
+int host_to_target_signal(int sig);
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
+long do_sigreturn(CPUArchState *env, abi_ulong addr);
 long do_rt_sigreturn(CPUArchState *env);
 abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
+int do_sigaction(int sig, const struct target_sigaction *act,
+                struct target_sigaction *oact);
+void QEMU_NORETURN force_sig(int target_sig);
 
 /* mmap.c */
 int target_mprotect(abi_ulong start, abi_ulong len, int prot);
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index 445f69e..3619b00 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -2,6 +2,7 @@
  *  Emulation of BSD signals
  *
  *  Copyright (c) 2003 - 2008 Fabrice Bellard
+ *  Copyright (c) 2013 Stacey Son
  *
  *  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
@@ -23,16 +24,920 @@
 #include <unistd.h>
 #include <signal.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 
 #include "qemu.h"
-#include "target_signal.h"
 
 //#define DEBUG_SIGNAL
 
+static target_stack_t target_sigaltstack_used = {
+    .ss_sp = 0,
+    .ss_size = 0,
+    .ss_flags = TARGET_SS_DISABLE,
+};
+
+static uint8_t host_to_target_signal_table[TARGET_NSIG] = {
+    [SIGHUP]    =   TARGET_SIGHUP,
+    [SIGINT]    =   TARGET_SIGINT,
+    [SIGQUIT]   =   TARGET_SIGQUIT,
+    [SIGILL]    =   TARGET_SIGILL,
+    [SIGTRAP]   =   TARGET_SIGTRAP,
+    [SIGABRT]   =   TARGET_SIGABRT,
+    [SIGEMT]    =   TARGET_SIGEMT,
+    [SIGFPE]    =   TARGET_SIGFPE,
+    [SIGKILL]   =   TARGET_SIGKILL,
+    [SIGBUS]    =   TARGET_SIGBUS,
+    [SIGSEGV]   =   TARGET_SIGSEGV,
+    [SIGSYS]    =   TARGET_SIGSYS,
+    [SIGPIPE]   =   TARGET_SIGPIPE,
+    [SIGALRM]   =   TARGET_SIGALRM,
+    [SIGTERM]   =   TARGET_SIGTERM,
+    [SIGURG]    =   TARGET_SIGURG,
+    [SIGSTOP]   =   TARGET_SIGSTOP,
+    [SIGTSTP]   =   TARGET_SIGTSTP,
+    [SIGCONT]   =   TARGET_SIGCONT,
+    [SIGCHLD]   =   TARGET_SIGCHLD,
+    [SIGTTIN]   =   TARGET_SIGTTIN,
+    [SIGTTOU]   =   TARGET_SIGTTOU,
+    [SIGIO]     =   TARGET_SIGIO,
+    [SIGXCPU]   =   TARGET_SIGXCPU,
+    [SIGXFSZ]   =   TARGET_SIGXFSZ,
+    [SIGVTALRM] =   TARGET_SIGVTALRM,
+    [SIGPROF]   =   TARGET_SIGPROF,
+    [SIGWINCH]  =   TARGET_SIGWINCH,
+    [SIGINFO]   =   TARGET_SIGINFO,
+    [SIGUSR1]   =   TARGET_SIGUSR1,
+    [SIGUSR2]   =   TARGET_SIGUSR2,
+#ifdef SIGTHR
+    [SIGTHR + 3]    =   TARGET_SIGTHR,
+#endif
+    /* [SIGLWP] =   TARGET_SIGLWP, */
+#ifdef SIGLIBRT
+    [SIGLIBRT]  =   TARGET_SIGLIBRT,
+#endif
+
+    /*
+     * The following signals stay the same.
+     * Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
+     * host libpthread signals.  This assumes no one actually uses
+     * SIGRTMAX.  To fix this properly we need to manual signal delivery
+     * multiplexed over a single host signal.
+     */
+    [SIGRTMIN]  =   SIGRTMAX,
+    [SIGRTMAX]  =   SIGRTMIN,
+};
+
+static uint8_t target_to_host_signal_table[TARGET_NSIG];
+static struct target_sigaction sigact_table[TARGET_NSIG];
+static void host_signal_handler(int host_signum, siginfo_t *info, void *puc);
+static void target_to_host_sigset_internal(sigset_t *d,
+        const target_sigset_t *s);
+
+static inline int on_sig_stack(unsigned long sp)
+{
+    return sp - target_sigaltstack_used.ss_sp < target_sigaltstack_used.ss_size;
+}
+
+static inline int sas_ss_flags(unsigned long sp)
+{
+    return target_sigaltstack_used.ss_size == 0 ? SS_DISABLE : on_sig_stack(sp)
+        ? SS_ONSTACK : 0;
+}
+
+int host_to_target_signal(int sig)
+{
+
+    if (sig < 0 || sig >= TARGET_NSIG) {
+        return sig;
+    }
+
+    return host_to_target_signal_table[sig];
+}
+
+int target_to_host_signal(int sig)
+{
+
+    if (sig >= TARGET_NSIG) {
+        return sig;
+    }
+
+    return target_to_host_signal_table[sig];
+}
+
+static inline void target_sigemptyset(target_sigset_t *set)
+{
+
+    memset(set, 0, sizeof(*set));
+}
+
+static inline void target_sigaddset(target_sigset_t *set, int signum)
+{
+
+    signum--;
+    uint32_t mask = (uint32_t)1 << (signum % TARGET_NSIG_BPW);
+    set->__bits[signum / TARGET_NSIG_BPW] |= mask;
+}
+
+static inline int target_sigismember(const target_sigset_t *set, int signum)
+{
+
+    signum--;
+    abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
+    return (set->__bits[signum / TARGET_NSIG_BPW] & mask) != 0;
+}
+
+static void host_to_target_sigset_internal(target_sigset_t *d,
+        const sigset_t *s)
+{
+    int i;
+
+    target_sigemptyset(d);
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        if (sigismember(s, i)) {
+            target_sigaddset(d, host_to_target_signal(i));
+        }
+    }
+}
+
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
+{
+    target_sigset_t d1;
+    int i;
+
+    host_to_target_sigset_internal(&d1, s);
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        d->__bits[i] = tswap32(d1.__bits[i]);
+    }
+}
+
+static void target_to_host_sigset_internal(sigset_t *d,
+        const target_sigset_t *s)
+{
+    int i;
+
+    sigemptyset(d);
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        if (target_sigismember(s, i)) {
+            sigaddset(d, target_to_host_signal(i));
+        }
+    }
+}
+
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
+{
+    target_sigset_t s1;
+    int i;
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        s1.__bits[i] = tswap32(s->__bits[i]);
+    }
+    target_to_host_sigset_internal(d, &s1);
+}
+
+/* Siginfo conversion. */
+static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
+        const siginfo_t *info)
+{
+    int sig, code;
+
+    sig = host_to_target_signal(info->si_signo);
+    /* XXX should have host_to_target_si_code() */
+    code = tswap32(info->si_code);
+    tinfo->si_signo = sig;
+    tinfo->si_errno = info->si_errno;
+    tinfo->si_code = info->si_code;
+    tinfo->si_pid = info->si_pid;
+    tinfo->si_uid = info->si_uid;
+    tinfo->si_addr = (abi_ulong)(unsigned long)info->si_addr;
+    /* si_value is opaque to kernel */
+    tinfo->si_value.sival_ptr =
+        (abi_ulong)(unsigned long)info->si_value.sival_ptr;
+    if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig ||
+            SIGTRAP == sig) {
+        tinfo->_reason._fault._trapno = info->_reason._fault._trapno;
+    }
+#ifdef SIGPOLL
+    if (SIGPOLL == sig) {
+        tinfo->_reason._poll._band = info->_reason._poll._band;
+    }
+#endif
+    if (SI_TIMER == code) {
+        tinfo->_reason._timer._timerid = info->_reason._timer._timerid;
+        tinfo->_reason._timer._overrun = info->_reason._timer._overrun;
+    }
+}
+
+static void tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info)
+{
+    int sig, code;
+
+    sig = info->si_signo;
+    code = info->si_code;
+    tinfo->si_signo = tswap32(sig);
+    tinfo->si_errno = tswap32(info->si_errno);
+    tinfo->si_code = tswap32(info->si_code);
+    tinfo->si_pid = tswap32(info->si_pid);
+    tinfo->si_uid = tswap32(info->si_uid);
+    tinfo->si_addr = tswapal(info->si_addr);
+    if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig ||
+            SIGTRAP == sig) {
+        tinfo->_reason._fault._trapno = tswap32(info->_reason._fault._trapno);
+    }
+#ifdef SIGPOLL
+    if (SIGPOLL == sig) {
+        tinfo->_reason._poll._band = tswap32(info->_reason._poll._band);
+    }
+#endif
+    if (SI_TIMER == code) {
+        tinfo->_reason._timer._timerid = tswap32(info->_reason._timer._timerid);
+        tinfo->_reason._timer._overrun = tswap32(info->_reason._timer._overrun);
+    }
+}
+
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
+{
+
+    host_to_target_siginfo_noswap(tinfo, info);
+    tswap_siginfo(tinfo, tinfo);
+}
+
+/* Returns 1 if given signal should dump core if not handled. */
+static int core_dump_signal(int sig)
+{
+    switch (sig) {
+    case TARGET_SIGABRT:
+    case TARGET_SIGFPE:
+    case TARGET_SIGILL:
+    case TARGET_SIGQUIT:
+    case TARGET_SIGSEGV:
+    case TARGET_SIGTRAP:
+    case TARGET_SIGBUS:
+        return 1;
+    default:
+        return 0;
+    }
+}
+
+/* Signal queue handling. */
+static inline struct qemu_sigqueue *alloc_sigqueue(CPUArchState *env)
+{
+    TaskState *ts = env->opaque;
+    struct qemu_sigqueue *q = ts->first_free;
+
+    if (!q) {
+        return NULL;
+    }
+    ts->first_free = q->next;
+    return q;
+}
+
+static inline void free_sigqueue(CPUArchState *env, struct qemu_sigqueue *q)
+{
+
+    TaskState *ts = env->opaque;
+    q->next = ts->first_free;
+    ts->first_free = q;
+}
+
+/* Abort execution with signal. */
+void QEMU_NORETURN force_sig(int target_sig)
+{
+    CPUArchState *env = thread_cpu->env_ptr;
+    TaskState *ts = (TaskState *)env->opaque;
+    int core_dumped = 0;
+    int host_sig;
+    struct sigaction act;
+
+    host_sig = target_to_host_signal(target_sig);
+    gdb_signalled(env, target_sig);
+
+    /* Dump core if supported by target binary format */
+    if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
+        stop_all_tasks();
+        core_dumped =
+            ((*ts->bprm->core_dump)(target_sig, env) == 0);
+    }
+    if (core_dumped) {
+        struct rlimit nodump;
+
+        /*
+         * We already dumped the core of target process, we don't want
+         * a coredump of qemu itself.
+         */
+         getrlimit(RLIMIT_CORE, &nodump);
+         nodump.rlim_cur = 0;
+         setrlimit(RLIMIT_CORE, &nodump);
+         (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) "
+             "- %s\n", target_sig, strsignal(host_sig), "core dumped");
+    }
+
+    /*
+     * The proper exit code for dying from an uncaught signal is
+     * -<signal>.  The kernel doesn't allow exit() or _exit() to pass
+     * a negative value.  To get the proper exit code we need to
+     * actually die from an uncaught signal.  Here the default signal
+     * handler is installed, we send ourself a signal and we wait for
+     * it to arrive.
+     */
+    memset(&act, 0, sizeof(act));
+    sigfillset(&act.sa_mask);
+    act.sa_handler = SIG_DFL;
+    sigaction(host_sig, &act, NULL);
+
+    kill(getpid(), host_sig);
+
+    /*
+     * Make sure the signal isn't masked (just reuse the mask inside
+     * of act).
+     */
+    sigdelset(&act.sa_mask, host_sig);
+    sigsuspend(&act.sa_mask);
+
+    /* unreachable */
+    abort();
+}
+
+/*
+ * Queue a signal so that it will be send to the virtual CPU as soon as
+ * possible.
+ */
+int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
+{
+    TaskState *ts = env->opaque;
+    struct emulated_sigtable *k;
+    struct qemu_sigqueue *q, **pq;
+    abi_ulong handler;
+    int queue;
+
+    k = &ts->sigtab[sig - 1];
+    queue = gdb_queuesig();
+    handler = sigact_table[sig - 1]._sa_handler;
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "queue_signal: sig=%d handler=0x%lx flags=0x%x\n", sig,
+        handler, (uint32_t)sigact_table[sig - 1].sa_flags);
+#endif
+    if (!queue && (TARGET_SIG_DFL == handler)) {
+        if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN ||
+            sig == TARGET_SIGTTOU) {
+            kill(getpid(), SIGSTOP);
+            return 0;
+        } else {
+            if (sig != TARGET_SIGCHLD &&
+                sig != TARGET_SIGURG &&
+                sig != TARGET_SIGWINCH &&
+                sig != TARGET_SIGCONT) {
+                force_sig(sig);
+            } else {
+                return 0; /* The signal was ignored. */
+            }
+        }
+    } else if (!queue && (TARGET_SIG_IGN == handler)) {
+        return 0; /* Ignored signal. */
+    } else if (!queue && (TARGET_SIG_ERR == handler)) {
+        force_sig(sig);
+    } else {
+        pq = &k->first;
+
+        /*
+         * FreeBSD signals are always queued.
+         * Linux only queues real time signals.
+         * XXX this code is not thread safe.
+         */
+        if (!k->pending) {
+            /* first signal */
+            q = &k->info;
+        } else {
+            q = alloc_sigqueue(env);
+            if (!q) {
+                return -EAGAIN;
+            }
+            while (*pq != NULL) {
+                pq = &(*pq)->next;
+            }
+        }
+        *pq = q;
+        q->info = *info;
+        q->next = NULL;
+        k->pending = 1;
+        /* Signal that a new signal is pending. */
+        ts->signal_pending = 1;
+        return 1; /* Indicates that the signal was queued. */
+    }
+}
+
+static void host_signal_handler(int host_signum, siginfo_t *info, void *puc)
+{
+    CPUArchState *env = thread_cpu->env_ptr;
+    int sig;
+    target_siginfo_t tinfo;
+
+    /*
+     * The CPU emulator uses some host signal to detect exceptions so
+     * we forward to it some signals.
+     */
+    if ((host_signum == SIGSEGV || host_signum == SIGBUS) &&
+            info->si_code < 0x10000) {
+        if (cpu_signal_handler(host_signum, info, puc)) {
+            return;
+        }
+    }
+
+    /* Get the target signal number. */
+    sig = host_to_target_signal(host_signum);
+    if (sig < 1 || sig > TARGET_NSIG) {
+        return;
+    }
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: got signal %d\n", sig);
+#endif
+    host_to_target_siginfo_noswap(&tinfo, info);
+    if (queue_signal(env, sig, &tinfo) == 1) {
+        /* Interrupt the virtual CPU as soon as possible. */
+        cpu_exit(thread_cpu);
+    }
+}
+
+/* do_sigaltstack() returns target values and errnos.  */
+/* compare to kern/kern_sig.c sys_sigaltstack() and kern_sigaltstack() */
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
+{
+    int ret = 0;
+    target_stack_t ss, oss, *uss;
+
+    if (uoss_addr) {
+        /* Save current signal stack params */
+        oss.ss_sp = tswapl(target_sigaltstack_used.ss_sp);
+        oss.ss_size = tswapl(target_sigaltstack_used.ss_size);
+        oss.ss_flags = tswapl(sas_ss_flags(sp));
+    }
+
+    if (uss_addr) {
+
+        if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1) ||
+            __get_user(ss.ss_sp, &uss->ss_sp) ||
+            __get_user(ss.ss_size, &uss->ss_size) ||
+            __get_user(ss.ss_flags, &uss->ss_flags)) {
+            ret = -TARGET_EFAULT;
+            goto out;
+        }
+        unlock_user_struct(uss, uss_addr, 0);
+
+        if (on_sig_stack(sp)) {
+            ret = -TARGET_EPERM;
+            goto out;
+        }
+
+        if ((ss.ss_flags & ~TARGET_SS_DISABLE) != 0) {
+            ret = -TARGET_EINVAL;
+            goto out;
+        }
+
+        if (!(ss.ss_flags & ~TARGET_SS_DISABLE)) {
+            if (ss.ss_size < TARGET_MINSIGSTKSZ) {
+                ret = -TARGET_ENOMEM;
+                goto out;
+            }
+        } else {
+            ss.ss_size = 0;
+            ss.ss_sp = 0;
+        }
+
+        target_sigaltstack_used.ss_sp = ss.ss_sp;
+        target_sigaltstack_used.ss_size = ss.ss_size;
+    }
+
+    if (uoss_addr) {
+        /* Copy out to user saved signal stack params */
+        if (copy_to_user(uoss_addr, &oss, sizeof(oss))) {
+            ret = -TARGET_EFAULT;
+            goto out;
+        }
+    }
+
+out:
+    return ret;
+}
+
+static int fatal_signal(int sig)
+{
+
+    switch (sig) {
+    case TARGET_SIGCHLD:
+    case TARGET_SIGURG:
+    case TARGET_SIGWINCH:
+        /* Ignored by default. */
+        return 0;
+    case TARGET_SIGCONT:
+    case TARGET_SIGSTOP:
+    case TARGET_SIGTSTP:
+    case TARGET_SIGTTIN:
+    case TARGET_SIGTTOU:
+        /* Job control signals.  */
+        return 0;
+    default:
+        return 1;
+    }
+}
+
+/* do_sigaction() return host values and errnos */
+int do_sigaction(int sig, const struct target_sigaction *act,
+        struct target_sigaction *oact)
+{
+    struct target_sigaction *k;
+    struct sigaction act1;
+    int host_sig;
+    int ret = 0;
+
+    if (sig < 1 || sig > TARGET_NSIG || TARGET_SIGKILL == sig ||
+            TARGET_SIGSTOP == sig) {
+        return -EINVAL;
+    }
+    k = &sigact_table[sig - 1];
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_sigaction sig=%d act=%p, oact=%p\n",
+        sig, act, oact);
+#endif
+    if (oact) {
+        oact->_sa_handler = tswapal(k->_sa_handler);
+        oact->sa_flags = tswap32(k->sa_flags);
+        oact->sa_mask = k->sa_mask;
+    }
+    if (act) {
+        /* XXX: this is most likely not threadsafe. */
+        k->_sa_handler = tswapal(act->_sa_handler);
+        k->sa_flags = tswap32(act->sa_flags);
+        k->sa_mask = act->sa_mask;
+
+        /* Update the host signal state. */
+        host_sig = target_to_host_signal(sig);
+        if (host_sig != SIGSEGV && host_sig != SIGBUS) {
+            memset(&act1, 0, sizeof(struct sigaction));
+            sigfillset(&act1.sa_mask);
+            if (k->sa_flags & TARGET_SA_RESTART) {
+                act1.sa_flags |= SA_RESTART;
+            }
+            /*
+             *  Note: It is important to update the host kernel signal mask to
+             *  avoid getting unexpected interrupted system calls.
+             */
+            if (k->_sa_handler == TARGET_SIG_IGN) {
+                act1.sa_sigaction = (void *)SIG_IGN;
+            } else if (k->_sa_handler == TARGET_SIG_DFL) {
+                if (fatal_signal(sig)) {
+                    act1.sa_flags = SA_SIGINFO;
+                    act1.sa_sigaction = host_signal_handler;
+                } else {
+                    act1.sa_sigaction = (void *)SIG_DFL;
+                }
+            } else {
+                act1.sa_flags = SA_SIGINFO;
+                act1.sa_sigaction = host_signal_handler;
+            }
+            ret = sigaction(host_sig, &act1, NULL);
+#if defined(DEBUG_SIGNAL)
+            fprintf(stderr, "sigaction (action = %p "
+                    "(host_signal_handler = %p)) returned: %d\n",
+                    act1.sa_sigaction, host_signal_handler, ret);
+#endif
+        }
+    }
+    return ret;
+}
+
+static inline abi_ulong get_sigframe(struct target_sigaction *ka,
+        CPUArchState *regs, size_t frame_size)
+{
+    abi_ulong sp;
+
+    /* Use default user stack */
+    sp = get_sp_from_cpustate(regs);
+
+    if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
+        sp = target_sigaltstack_used.ss_sp +
+            target_sigaltstack_used.ss_size;
+    }
+
+#if defined(TARGET_MIPS) || defined(TARGET_ARM)
+    return (sp - frame_size) & ~7;
+#else
+    return sp - frame_size;
+#endif
+}
+
+/* compare to mips/mips/pm_machdep.c and sparc64/sparc64/machdep.c sendsig() */
+static void setup_frame(int sig, int code, struct target_sigaction *ka,
+    target_sigset_t *set, target_siginfo_t *tinfo, CPUArchState *regs)
+{
+    struct target_sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "setup_frame()\n");
+#endif
+    frame_addr = get_sigframe(ka, regs, sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+        goto give_sigsegv;
+    }
+
+    memset(frame, 0, sizeof(*frame));
+#if defined(TARGET_MIPS)
+    int mflags = on_sig_stack(frame_addr) ? TARGET_MC_ADD_MAGIC :
+        TARGET_MC_SET_ONSTACK | TARGET_MC_ADD_MAGIC;
+#else
+    int mflags = 0;
+#endif
+    if (get_mcontext(regs, &frame->sf_uc.uc_mcontext, mflags)) {
+        goto give_sigsegv;
+    }
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        if (__put_user(set->__bits[i], &frame->sf_uc.uc_sigmask.__bits[i])) {
+            goto give_sigsegv;
+        }
+    }
+
+    if (tinfo) {
+        frame->sf_si.si_signo = tinfo->si_signo;
+        frame->sf_si.si_errno = tinfo->si_errno;
+        frame->sf_si.si_code = tinfo->si_code;
+        frame->sf_si.si_pid = tinfo->si_pid;
+        frame->sf_si.si_uid = tinfo->si_uid;
+        frame->sf_si.si_status = tinfo->si_status;
+        frame->sf_si.si_addr = tinfo->si_addr;
+
+        if (TARGET_SIGILL == sig || TARGET_SIGFPE == sig ||
+                TARGET_SIGSEGV == sig || TARGET_SIGBUS == sig ||
+                TARGET_SIGTRAP == sig) {
+            frame->sf_si._reason._fault._trapno = tinfo->_reason._fault._trapno;
+        }
+
+        /*
+         * If si_code is one of SI_QUEUE, SI_TIMER, SI_ASYNCIO, or
+         * SI_MESGQ, then si_value contains the application-specified
+         * signal value. Otherwise, the contents of si_value are
+         * undefined.
+         */
+        if (SI_QUEUE == code || SI_TIMER == code || SI_ASYNCIO == code ||
+                SI_MESGQ == code) {
+            frame->sf_si.si_value.sival_int = tinfo->si_value.sival_int;
+        }
+
+        if (SI_TIMER == code) {
+            frame->sf_si._reason._timer._timerid =
+                tinfo->_reason._timer._timerid;
+            frame->sf_si._reason._timer._overrun =
+                tinfo->_reason._timer._overrun;
+        }
+
+#ifdef SIGPOLL
+        if (SIGPOLL == sig) {
+            frame->sf_si._reason._band = tinfo->_reason._band;
+        }
+#endif
+
+    }
+
+    if (set_sigtramp_args(regs, sig, frame, frame_addr, ka)) {
+        goto give_sigsegv;
+    }
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+static int reset_signal_mask(target_ucontext_t *ucontext)
+{
+    int i;
+    sigset_t blocked;
+    target_sigset_t target_set;
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++)
+        if (__get_user(target_set.__bits[i],
+                    &ucontext->uc_sigmask.__bits[i])) {
+            return -TARGET_EFAULT;
+        }
+    target_to_host_sigset_internal(&blocked, &target_set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    return 0;
+}
+
+long do_sigreturn(CPUArchState *regs, abi_ulong addr)
+{
+    long ret;
+    abi_ulong target_ucontext;
+    target_ucontext_t *ucontext = NULL;
+
+    /* Get the target ucontext address from the stack frame */
+    ret = get_ucontext_sigreturn(regs, addr, &target_ucontext);
+    if (is_error(ret)) {
+        return ret;
+    }
+    if (!lock_user_struct(VERIFY_READ, ucontext, target_ucontext, 0)) {
+        goto badframe;
+    }
+
+    /* Set the register state back to before the signal. */
+    if (set_mcontext(regs, &ucontext->uc_mcontext, 1)) {
+        goto badframe;
+    }
+
+    /* And reset the signal mask. */
+    if (reset_signal_mask(ucontext)) {
+        goto badframe;
+    }
+
+    unlock_user_struct(ucontext, target_ucontext, 0);
+    return -TARGET_EJUSTRETURN;
+
+badframe:
+    if (ucontext != NULL) {
+        unlock_user_struct(ucontext, target_ucontext, 0);
+    }
+    force_sig(TARGET_SIGSEGV);
+    return -TARGET_EFAULT;
+}
+
 void signal_init(void)
 {
+    struct sigaction act;
+    struct sigaction oact;
+    int i, j;
+    int host_sig;
+
+    /* Generate the signal conversion tables.  */
+    for (i = 1; i < TARGET_NSIG; i++) {
+        if (host_to_target_signal_table[i] == 0) {
+            host_to_target_signal_table[i] = i;
+        }
+    }
+    for (i = 1; i < TARGET_NSIG; i++) {
+        j = host_to_target_signal_table[i];
+        target_to_host_signal_table[j] = i;
+    }
+
+    /*
+     * Set all host signal handlers. ALL signals are blocked during the
+     * handlers to serialize them.
+     */
+    memset(sigact_table, 0, sizeof(sigact_table));
+
+    sigfillset(&act.sa_mask);
+    act.sa_sigaction = host_signal_handler;
+    act.sa_flags = SA_SIGINFO;
+
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        host_sig = target_to_host_signal(i);
+        sigaction(host_sig, NULL, &oact);
+        if (oact.sa_sigaction == (void *)SIG_IGN) {
+            sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
+        } else if (oact.sa_sigaction == (void *)SIG_DFL) {
+            sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
+        }
+        /*
+         * If there's already a handler installed then something has
+         * gone horribly wrong, so don't even try to handle that case.
+         * Install some handlers for our own use.  We need at least
+         * SIGSEGV and SIGBUS, to detect exceptions.  We can not just
+         * trap all signals because it affects syscall interrupt
+         * behavior.  But do trap all default-fatal signals.
+         */
+        if (fatal_signal(i)) {
+            sigaction(host_sig, &act, NULL);
+        }
+    }
 }
 
 void process_pending_signals(CPUArchState *cpu_env)
 {
+    CPUState *cpu = ENV_GET_CPU(cpu_env);
+    int sig, code;
+    abi_ulong handler;
+    sigset_t set, old_set;
+    target_sigset_t target_old_set;
+    target_siginfo_t tinfo;
+    struct emulated_sigtable *k;
+    struct target_sigaction *sa;
+    struct qemu_sigqueue *q;
+    TaskState *ts = cpu_env->opaque;
+
+    if (!ts->signal_pending) {
+        return;
+    }
+
+    /* FIXME: This is not threadsafe.  */
+    k  = ts->sigtab;
+    for (sig = 1; sig <= TARGET_NSIG; sig++) {
+        if (k->pending) {
+            goto handle_signal;
+        }
+        k++;
+    }
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: process_pending_signals has no signals\n");
+#endif
+    /* If no signal is pending then just return. */
+    ts->signal_pending = 0;
+    return;
+
+handle_signal:
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: process signal %d\n", sig);
+#endif
+
+    /* Dequeue signal. */
+    q = k->first;
+    k->first = q->next;
+    if (!k->first) {
+        k->pending = 0;
+    }
+
+    sig = gdb_handlesig(cpu, sig);
+    if (!sig) {
+        sa = NULL;
+        handler = TARGET_SIG_IGN;
+    } else {
+        sa = &sigact_table[sig - 1];
+        handler = sa->_sa_handler;
+    }
+
+    if (handler == TARGET_SIG_DFL) {
+#ifdef DEBUG_SIGNAL
+        fprintf(stderr, "qemu: TARGET_SIG_DFL\n");
+#endif
+        /*
+         * default handler : ignore some signal. The other are job
+         * control or fatal.
+         */
+        if (TARGET_SIGTSTP == sig || TARGET_SIGTTIN == sig ||
+                TARGET_SIGTTOU == sig) {
+            kill(getpid(), SIGSTOP);
+        } else if (TARGET_SIGCHLD != sig && TARGET_SIGURG != sig &&
+            TARGET_SIGWINCH != sig && TARGET_SIGCONT != sig) {
+            force_sig(sig);
+        }
+    } else if (TARGET_SIG_IGN == handler) {
+        /* ignore sig */
+#ifdef DEBUG_SIGNAL
+        fprintf(stderr, "qemu: TARGET_SIG_IGN\n");
+#endif
+    } else if (TARGET_SIG_ERR == handler) {
+#ifdef DEBUG_SIGNAL
+        fprintf(stderr, "qemu: TARGET_SIG_ERR\n");
+#endif
+        force_sig(sig);
+    } else {
+        /* compute the blocked signals during the handler execution */
+        target_to_host_sigset(&set, &sa->sa_mask);
+        /*
+         * SA_NODEFER indicates that the current signal should not be
+         * blocked during the handler.
+         */
+        if (!(sa->sa_flags & TARGET_SA_NODEFER)) {
+            sigaddset(&set, target_to_host_signal(sig));
+        }
+
+        /* block signals in the handler */
+        sigprocmask(SIG_BLOCK, &set, &old_set);
+
+        /*
+         * Save the previous blocked signal state to restore it at the
+         * end of the signal execution (see do_sigreturn).
+         */
+        host_to_target_sigset_internal(&target_old_set, &old_set);
+
+#if 0  /* not yet */
+#if defined(TARGET_I386) && !defined(TARGET_X86_64)
+        /* if the CPU is in VM86 mode, we restore the 32 bit values */
+        {
+            CPUX86State *env = cpu_env;
+            if (env->eflags & VM_MASK) {
+                save_v86_state(env);
+            }
+        }
+#endif
+#endif /* not yet */
+
+        code = q->info.si_code;
+        /* prepare the stack frame of the virtual CPU */
+        if (sa->sa_flags & TARGET_SA_SIGINFO) {
+            tswap_siginfo(&tinfo, &q->info);
+            setup_frame(sig, code, sa, &target_old_set, &tinfo, cpu_env);
+        } else {
+            setup_frame(sig, code, sa, &target_old_set, NULL, cpu_env);
+        }
+        if (sa->sa_flags & TARGET_SA_RESETHAND) {
+            sa->_sa_handler = TARGET_SIG_DFL;
+        }
+    }
+    if (q != &k->info) {
+        free_sigqueue(cpu_env, q);
+    }
 }
diff --git a/bsd-user/sparc/target_arch_signal.h b/bsd-user/sparc/target_arch_signal.h
new file mode 100644
index 0000000..f934f8c
--- /dev/null
+++ b/bsd-user/sparc/target_arch_signal.h
@@ -0,0 +1,77 @@
+#ifndef TARGET_ARCH_SIGNAL_H
+#define TARGET_ARCH_SIGNAL_H
+
+#include "cpu.h"
+
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE   (0) */       /* XXX to be added. */
+
+/* compare to  sparc64/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (1024 * 4)              /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to sparc64/sparc64/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long set_sigtramp_args(CPUSPARCState *regs,
+        int sig, struct target_sigframe *frame, abi_ulong frame_addr,
+        struct target_sigaction *ka)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to sparc64/sparc64/machdep.c get_mcontext() */
+static inline abi_long get_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int flags)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to sparc64/space64/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUSPARCState *regs,
+        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    /* XXX */
+    *target_uc = 0;
+    return -TARGET_EOPNOTSUPP;
+}
+
+#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/sparc64/target_arch_signal.h b/bsd-user/sparc64/target_arch_signal.h
new file mode 100644
index 0000000..1529b0f
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_signal.h
@@ -0,0 +1,94 @@
+/*
+ *  sparc64 dependent signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE    (0) */      /* XXX to be added. */
+
+/* compare to  sparc64/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (1024 * 4)              /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to sparc64/sparc64/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long set_sigtramp_args(CPUSPARCState *regs,
+        int sig, struct target_sigframe *frame, abi_ulong frame_addr,
+        struct target_sigaction *ka)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to sparc64/sparc64/machdep.c get_mcontext() */
+static inline abi_long get_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int flags)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to sparc64/space64/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUSPARCState *regs,
+        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    /* XXX */
+    *target_uc = 0;
+    return -TARGET_EOPNOTSUPP;
+}
+
+#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 0996787..bc4a7e4 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -39,8 +39,12 @@
 
 #define target_to_host_bitmask(x, tbl) (x)
 
+/* BSD independent syscall shims */
+#include "bsd-signal.h"
+
 /* *BSD dependent syscall shims */
 #include "os-time.h"
+#include "os-signal.h"
 
 /* #define DEBUG */
 
@@ -326,6 +330,61 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * signal system calls
+         */
+    case TARGET_FREEBSD_NR_sigtimedwait: /* sigtimedwait(2) */
+        ret = do_freebsd_sigtimedwait(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigaction: /* sigaction(2) */
+        ret = do_bsd_sigaction(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigprocmask: /* sigprocmask(2) */
+        ret = do_bsd_sigprocmask(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigpending: /* sigpending(2) */
+        ret = do_bsd_sigpending(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sigsuspend: /* sigsuspend(2) */
+        ret = do_bsd_sigsuspend(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sigreturn: /* sigreturn(2) */
+        ret = do_bsd_sigreturn(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sigwait: /* sigwait(2) */
+        ret = do_bsd_sigwait(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigwaitinfo: /* sigwaitinfo(2) */
+        ret = do_bsd_sigwaitinfo(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sigqueue: /* sigqueue(2) */
+        ret = do_bsd_sigqueue(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigaltstack: /* sigaltstack(2) */
+        ret = do_bsd_sigaltstack(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kill: /* kill(2) */
+        ret = do_bsd_kill(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_killpg: /* killpg(2) */
+        ret = do_bsd_killpg(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_pdkill: /* pdkill(2) */
+        ret = do_freebsd_pdkill(arg1, arg2);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
diff --git a/bsd-user/x86_64/target_arch_signal.h b/bsd-user/x86_64/target_arch_signal.h
new file mode 100644
index 0000000..1998570
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_signal.h
@@ -0,0 +1,94 @@
+/*
+ *  x86_64 signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE    (0) */   /* XXX to be added */
+
+/* compare to  x86/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (512 * 4)               /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to amd64/amd64/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long set_sigtramp_args(CPUX86State *regs,
+        int sig, struct target_sigframe *frame, abi_ulong frame_addr,
+        struct target_sigaction *ka)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to amd64/amd64/machdep.c get_mcontext() */
+static inline abi_long get_mcontext(CPUX86State *regs,
+                target_mcontext_t *mcp, int flags)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to amd64/amd64/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUX86State *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUX86State *regs,
+        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    /* XXX */
+    *target_uc = 0;
+    return -TARGET_EOPNOTSUPP;
+}
+
+#endif /* !TARGET_ARCH_SIGNAL_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 08/19] bsd-user: move target arch and host OS dependent code out of elfload.c
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (27 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 07/19] bsd-user: add support for freebsd signal " Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 09/19] bsd-user: add support for freebsd process related system calls Stacey Son
                   ` (10 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change moves ELF and thread start up code from elfload.c to the host
OS and arch dependent directories.  This eliminates many of the #ifdef's
in elfload.c and moves the target arch and OS dependent code into its own
directories.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/arm/target_arch_elf.h        |   54 ++
 bsd-user/arm/target_arch_thread.h     |   67 +++
 bsd-user/elfload.c                    |  947 +++++++--------------------------
 bsd-user/freebsd/target_os_elf.h      |  145 +++++
 bsd-user/freebsd/target_os_thread.h   |    6 +
 bsd-user/i386/target_arch_elf.h       |   62 +++
 bsd-user/i386/target_arch_thread.h    |   45 ++
 bsd-user/mips/target_arch_elf.h       |   36 ++
 bsd-user/mips/target_arch_thread.h    |   54 ++
 bsd-user/mips64/target_arch_elf.h     |   36 ++
 bsd-user/mips64/target_arch_thread.h  |   54 ++
 bsd-user/netbsd/target_os_elf.h       |  226 ++++++++
 bsd-user/netbsd/target_os_thread.h    |    6 +
 bsd-user/openbsd/target_os_elf.h      |  226 ++++++++
 bsd-user/openbsd/target_os_thread.h   |    6 +
 bsd-user/sparc/target_arch_elf.h      |   30 +
 bsd-user/sparc/target_arch_thread.h   |   39 ++
 bsd-user/sparc64/target_arch_elf.h    |   34 ++
 bsd-user/sparc64/target_arch_thread.h |   55 ++
 bsd-user/syscall_defs.h               |   64 +++
 bsd-user/x86_64/target_arch_elf.h     |   55 ++
 bsd-user/x86_64/target_arch_thread.h  |   40 ++
 22 files changed, 1530 insertions(+), 757 deletions(-)
 create mode 100644 bsd-user/arm/target_arch_elf.h
 create mode 100644 bsd-user/arm/target_arch_thread.h
 create mode 100644 bsd-user/freebsd/target_os_elf.h
 create mode 100644 bsd-user/freebsd/target_os_thread.h
 create mode 100644 bsd-user/i386/target_arch_elf.h
 create mode 100644 bsd-user/i386/target_arch_thread.h
 create mode 100644 bsd-user/mips/target_arch_elf.h
 create mode 100644 bsd-user/mips/target_arch_thread.h
 create mode 100644 bsd-user/mips64/target_arch_elf.h
 create mode 100644 bsd-user/mips64/target_arch_thread.h
 create mode 100644 bsd-user/netbsd/target_os_elf.h
 create mode 100644 bsd-user/netbsd/target_os_thread.h
 create mode 100644 bsd-user/openbsd/target_os_elf.h
 create mode 100644 bsd-user/openbsd/target_os_thread.h
 create mode 100644 bsd-user/sparc/target_arch_elf.h
 create mode 100644 bsd-user/sparc/target_arch_thread.h
 create mode 100644 bsd-user/sparc64/target_arch_elf.h
 create mode 100644 bsd-user/sparc64/target_arch_thread.h
 create mode 100644 bsd-user/x86_64/target_arch_elf.h
 create mode 100644 bsd-user/x86_64/target_arch_thread.h

diff --git a/bsd-user/arm/target_arch_elf.h b/bsd-user/arm/target_arch_elf.h
new file mode 100644
index 0000000..c408cea
--- /dev/null
+++ b/bsd-user/arm/target_arch_elf.h
@@ -0,0 +1,54 @@
+/*
+ *  arm ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_ARM )
+
+#define ELF_CLASS       ELFCLASS32
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+#define ELF_ARCH        EM_ARM
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+enum
+{
+  ARM_HWCAP_ARM_SWP       = 1 << 0,
+  ARM_HWCAP_ARM_HALF      = 1 << 1,
+  ARM_HWCAP_ARM_THUMB     = 1 << 2,
+  ARM_HWCAP_ARM_26BIT     = 1 << 3,
+  ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
+  ARM_HWCAP_ARM_FPA       = 1 << 5,
+  ARM_HWCAP_ARM_VFP       = 1 << 6,
+  ARM_HWCAP_ARM_EDSP      = 1 << 7,
+};
+
+#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
+                    | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
+                    | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
+
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/arm/target_arch_thread.h b/bsd-user/arm/target_arch_thread.h
new file mode 100644
index 0000000..e69f612
--- /dev/null
+++ b/bsd-user/arm/target_arch_thread.h
@@ -0,0 +1,67 @@
+/*
+ *  arm thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to arm/arm/vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUARMState *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    abi_ulong sp;
+
+    /*
+     * Make sure the stack is properly aligned.
+     * arm/include/param.h (STACKLIGN() macro)
+     */
+    sp = ((u_int)(stack_base + stack_size) & ~(8-1)) -
+        sizeof(struct target_trapframe);
+
+    /* sp = stack base */
+    regs->regs[13] = sp;
+    /* pc = start function entry */
+    regs->regs[15] = entry & 0xfffffffe;
+    /* r0 = arg */
+    regs->regs[0] = arg;
+    regs->spsr = ARM_CPU_MODE_USR;
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    abi_long stack = infop->start_stack;
+    memset(regs, 0, sizeof(*regs));
+    regs->ARM_cpsr = 0x10;
+    if (infop->entry & 1)
+      regs->ARM_cpsr |= CPSR_T;
+    regs->ARM_pc = infop->entry & 0xfffffffe;
+    regs->ARM_sp = infop->start_stack;
+    if (bsd_type == target_freebsd) {
+        regs->ARM_lr = infop->entry & 0xfffffffe;
+    }
+    /* FIXME - what to for failure of get_user()? */
+    get_user_ual(regs->ARM_r2, stack + 8); /* envp */
+    get_user_ual(regs->ARM_r1, stack + 4); /* envp */
+    /* XXX: it seems that r0 is zeroed after ! */
+    regs->ARM_r0 = 0;
+    /* For uClinux PIC binaries.  */
+    /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
+    regs->ARM_r10 = infop->start_data;
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 68d0209..ef96b8c 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -1,4 +1,20 @@
-/* This is the Linux kernel elf-loading code, ported into user space */
+/*
+ *  ELF loading code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
 
 #include <stdio.h>
 #include <sys/types.h>
@@ -11,548 +27,13 @@
 
 #include "qemu.h"
 #include "disas/disas.h"
-
-#ifdef _ARCH_PPC64
-#undef ARCH_DLINFO
-#undef ELF_PLATFORM
-#undef ELF_HWCAP
-#undef ELF_CLASS
-#undef ELF_DATA
-#undef ELF_ARCH
-#endif
-
-/* from personality.h */
-
-/*
- * Flags for bug emulation.
- *
- * These occupy the top three bytes.
- */
-enum {
-        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA space */
-        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs point to descriptors
-                                                 * (signal handling)
-                                                 */
-        MMAP_PAGE_ZERO =        0x0100000,
-        ADDR_COMPAT_LAYOUT =    0x0200000,
-        READ_IMPLIES_EXEC =     0x0400000,
-        ADDR_LIMIT_32BIT =      0x0800000,
-        SHORT_INODE =           0x1000000,
-        WHOLE_SECONDS =         0x2000000,
-        STICKY_TIMEOUTS =       0x4000000,
-        ADDR_LIMIT_3GB =        0x8000000,
-};
-
-/*
- * Personality types.
- *
- * These go in the low byte.  Avoid using the top bit, it will
- * conflict with error returns.
- */
-enum {
-        PER_LINUX =             0x0000,
-        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
-        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
-        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
-        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
-        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
-                                         WHOLE_SECONDS | SHORT_INODE,
-        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
-        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
-        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
-        PER_BSD =               0x0006,
-        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
-        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
-        PER_LINUX32 =           0x0008,
-        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
-        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
-        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
-        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
-        PER_RISCOS =            0x000c,
-        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
-        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
-        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
-        PER_HPUX =              0x0010,
-        PER_MASK =              0x00ff,
-};
-
-/*
- * Return the base personality without flags.
- */
-#define personality(pers)       (pers & PER_MASK)
-
-/* this flag is uneffective under linux too, should be deleted */
-#ifndef MAP_DENYWRITE
-#define MAP_DENYWRITE 0
-#endif
-
-/* should probably go in elf.h */
-#ifndef ELIBBAD
-#define ELIBBAD 80
-#endif
+#include "target_os_elf.h"
+#include "target_os_stack.h"
+#include "target_os_thread.h"
 
 abi_ulong target_stksiz;
 abi_ulong target_stkbas;
 
-#ifdef TARGET_I386
-
-#define ELF_PLATFORM get_elf_platform()
-
-static const char *get_elf_platform(void)
-{
-    static char elf_platform[] = "i386";
-    int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
-    if (family > 6)
-        family = 6;
-    if (family >= 3)
-        elf_platform[1] = '0' + family;
-    return elf_platform;
-}
-
-#define ELF_HWCAP get_elf_hwcap()
-
-static uint32_t get_elf_hwcap(void)
-{
-    X86CPU *cpu = X86_CPU(thread_cpu);
-
-    return cpu->env.features[FEAT_1_EDX];
-}
-
-#ifdef TARGET_X86_64
-#define ELF_START_MMAP 0x2aaaaab000ULL
-#define elf_check_arch(x) ( ((x) == ELF_ARCH) )
-
-#define ELF_CLASS      ELFCLASS64
-#define ELF_DATA       ELFDATA2LSB
-#define ELF_ARCH       EM_X86_64
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->rax = 0;
-    regs->rsp = infop->start_stack;
-    regs->rip = infop->entry;
-    if (bsd_type == target_freebsd) {
-        regs->rdi = infop->start_stack;
-    }
-}
-
-#else
-
-#define ELF_START_MMAP 0x80000000
-
-/*
- * This is used to ensure we don't load something for the wrong architecture.
- */
-#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
-
-/*
- * These are used to set parameters in the core dumps.
- */
-#define ELF_CLASS       ELFCLASS32
-#define ELF_DATA        ELFDATA2LSB
-#define ELF_ARCH        EM_386
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->esp = infop->start_stack;
-    regs->eip = infop->entry;
-
-    /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
-       starts %edx contains a pointer to a function which might be
-       registered using `atexit'.  This provides a mean for the
-       dynamic linker to call DT_FINI functions for shared libraries
-       that have been loaded before the code runs.
-
-       A value of 0 tells we have no such handler.  */
-    regs->edx = 0;
-}
-#endif
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       4096
-
-#endif
-
-#ifdef TARGET_ARM
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_ARM )
-
-#define ELF_CLASS       ELFCLASS32
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA        ELFDATA2MSB
-#else
-#define ELF_DATA        ELFDATA2LSB
-#endif
-#define ELF_ARCH        EM_ARM
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    abi_long stack = infop->start_stack;
-    memset(regs, 0, sizeof(*regs));
-    regs->ARM_cpsr = 0x10;
-    if (infop->entry & 1)
-      regs->ARM_cpsr |= CPSR_T;
-    regs->ARM_pc = infop->entry & 0xfffffffe;
-    regs->ARM_sp = infop->start_stack;
-    /* FIXME - what to for failure of get_user()? */
-    get_user_ual(regs->ARM_r2, stack + 8); /* envp */
-    get_user_ual(regs->ARM_r1, stack + 4); /* envp */
-    /* XXX: it seems that r0 is zeroed after ! */
-    regs->ARM_r0 = 0;
-    /* For uClinux PIC binaries.  */
-    /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
-    regs->ARM_r10 = infop->start_data;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       4096
-
-enum
-{
-  ARM_HWCAP_ARM_SWP       = 1 << 0,
-  ARM_HWCAP_ARM_HALF      = 1 << 1,
-  ARM_HWCAP_ARM_THUMB     = 1 << 2,
-  ARM_HWCAP_ARM_26BIT     = 1 << 3,
-  ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
-  ARM_HWCAP_ARM_FPA       = 1 << 5,
-  ARM_HWCAP_ARM_VFP       = 1 << 6,
-  ARM_HWCAP_ARM_EDSP      = 1 << 7,
-};
-
-#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
-                    | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
-                    | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
-
-#endif
-
-#ifdef TARGET_SPARC
-#ifdef TARGET_SPARC64
-
-#define ELF_START_MMAP 0x80000000
-
-#ifndef TARGET_ABI32
-#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
-#else
-#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
-#endif
-
-#define ELF_CLASS   ELFCLASS64
-#define ELF_DATA    ELFDATA2MSB
-#define ELF_ARCH    EM_SPARCV9
-
-#define STACK_BIAS              2047
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-#ifndef TARGET_ABI32
-    regs->tstate = 0;
-#endif
-    regs->pc = infop->entry;
-    regs->npc = regs->pc + 4;
-    regs->y = 0;
-#ifdef TARGET_ABI32
-    regs->u_regs[14] = infop->start_stack - 16 * 4;
-#else
-    if (personality(infop->personality) == PER_LINUX32)
-        regs->u_regs[14] = infop->start_stack - 16 * 4;
-    else {
-        regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
-        if (bsd_type == target_freebsd) {
-            regs->u_regs[8] = infop->start_stack;
-            regs->u_regs[11] = infop->start_stack;
-        }
-    }
-#endif
-}
-
-#else
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_SPARC )
-
-#define ELF_CLASS   ELFCLASS32
-#define ELF_DATA    ELFDATA2MSB
-#define ELF_ARCH    EM_SPARC
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->psr = 0;
-    regs->pc = infop->entry;
-    regs->npc = regs->pc + 4;
-    regs->y = 0;
-    regs->u_regs[14] = infop->start_stack - 16 * 4;
-}
-
-#endif
-#endif
-
-#ifdef TARGET_PPC
-
-#define ELF_START_MMAP 0x80000000
-
-#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-
-#define elf_check_arch(x) ( (x) == EM_PPC64 )
-
-#define ELF_CLASS       ELFCLASS64
-
-#else
-
-#define elf_check_arch(x) ( (x) == EM_PPC )
-
-#define ELF_CLASS       ELFCLASS32
-
-#endif
-
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA        ELFDATA2MSB
-#else
-#define ELF_DATA        ELFDATA2LSB
-#endif
-#define ELF_ARCH        EM_PPC
-
-/*
- * We need to put in some extra aux table entries to tell glibc what
- * the cache block size is, so it can use the dcbz instruction safely.
- */
-#define AT_DCACHEBSIZE          19
-#define AT_ICACHEBSIZE          20
-#define AT_UCACHEBSIZE          21
-/* A special ignored type value for PPC, for glibc compatibility.  */
-#define AT_IGNOREPPC            22
-/*
- * The requirements here are:
- * - keep the final alignment of sp (sp & 0xf)
- * - make sure the 32-bit value at the first 16 byte aligned position of
- *   AUXV is greater than 16 for glibc compatibility.
- *   AT_IGNOREPPC is used for that.
- * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
- *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
- */
-#define DLINFO_ARCH_ITEMS       5
-#define ARCH_DLINFO                                                     \
-do {                                                                    \
-        NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);                              \
-        NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);                              \
-        NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                                 \
-        /*                                                              \
-         * Now handle glibc compatibility.                              \
-         */                                                             \
-        NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);                        \
-        NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);                        \
- } while (0)
-
-static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
-{
-    abi_ulong pos = infop->start_stack;
-    abi_ulong tmp;
-#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-    abi_ulong entry, toc;
-#endif
-
-    _regs->gpr[1] = infop->start_stack;
-#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-    entry = ldq_raw(infop->entry) + infop->load_addr;
-    toc = ldq_raw(infop->entry + 8) + infop->load_addr;
-    _regs->gpr[2] = toc;
-    infop->entry = entry;
-#endif
-    _regs->nip = infop->entry;
-    /* Note that isn't exactly what regular kernel does
-     * but this is what the ABI wants and is needed to allow
-     * execution of PPC BSD programs.
-     */
-    /* FIXME - what to for failure of get_user()? */
-    get_user_ual(_regs->gpr[3], pos);
-    pos += sizeof(abi_ulong);
-    _regs->gpr[4] = pos;
-    for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong))
-        tmp = ldl(pos);
-    _regs->gpr[5] = pos;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       4096
-
-#endif
-
-#ifdef TARGET_MIPS
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_MIPS )
-
-#ifdef TARGET_MIPS64
-#define ELF_CLASS   ELFCLASS64
-#else
-#define ELF_CLASS   ELFCLASS32
-#endif
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA        ELFDATA2MSB
-#else
-#define ELF_DATA        ELFDATA2LSB
-#endif
-#define ELF_ARCH    EM_MIPS
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->cp0_status = 2 << CP0St_KSU;
-    regs->cp0_epc = infop->entry;
-    regs->regs[29] = infop->start_stack;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE        4096
-
-#endif /* TARGET_MIPS */
-
-#ifdef TARGET_SH4
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_SH )
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA  ELFDATA2LSB
-#define ELF_ARCH  EM_SH
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-  /* Check other registers XXXXX */
-  regs->pc = infop->entry;
-  regs->regs[15] = infop->start_stack;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE        4096
-
-#endif
-
-#ifdef TARGET_CRIS
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_CRIS )
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA  ELFDATA2LSB
-#define ELF_ARCH  EM_CRIS
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-  regs->erp = infop->entry;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE        8192
-
-#endif
-
-#ifdef TARGET_M68K
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_68K )
-
-#define ELF_CLASS       ELFCLASS32
-#define ELF_DATA        ELFDATA2MSB
-#define ELF_ARCH        EM_68K
-
-/* ??? Does this need to do anything?
-#define ELF_PLAT_INIT(_r) */
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->usp = infop->start_stack;
-    regs->sr = 0;
-    regs->pc = infop->entry;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       8192
-
-#endif
-
-#ifdef TARGET_ALPHA
-
-#define ELF_START_MMAP (0x30000000000ULL)
-
-#define elf_check_arch(x) ( (x) == ELF_ARCH )
-
-#define ELF_CLASS      ELFCLASS64
-#define ELF_DATA       ELFDATA2MSB
-#define ELF_ARCH       EM_ALPHA
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->pc = infop->entry;
-    regs->ps = 8;
-    regs->usp = infop->start_stack;
-    regs->unique = infop->start_data; /* ? */
-    printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n",
-           regs->unique, infop->start_data);
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE        8192
-
-#endif /* TARGET_ALPHA */
-
-#ifndef ELF_PLATFORM
-#define ELF_PLATFORM (NULL)
-#endif
-
-#ifndef ELF_HWCAP
-#define ELF_HWCAP 0
-#endif
-
-#ifdef TARGET_ABI32
-#undef ELF_CLASS
-#define ELF_CLASS ELFCLASS32
-#undef bswaptls
-#define bswaptls(ptr) bswap32s(ptr)
-#endif
-
-#include "elf.h"
-
-struct exec
-{
-  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
-  unsigned int a_text;   /* length of text, in bytes */
-  unsigned int a_data;   /* length of data, in bytes */
-  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
-  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
-  unsigned int a_entry;  /* start address */
-  unsigned int a_trsize; /* length of relocation info for text, in bytes */
-  unsigned int a_drsize; /* length of relocation info for data, in bytes */
-};
-
-
-#define N_MAGIC(exec) ((exec).a_info & 0xffff)
-#define OMAGIC 0407
-#define NMAGIC 0410
-#define ZMAGIC 0413
-#define QMAGIC 0314
-
-/* max code+data+bss space allocated to elf interpreter */
-#define INTERP_MAP_SIZE (32 * 1024 * 1024)
-
-/* max code+data+bss+brk space allocated to ET_DYN executables */
-#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
-
-/* Necessary parameters */
-#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
-#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
-#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
-
-#define INTERPRETER_NONE 0
-#define INTERPRETER_AOUT 1
-#define INTERPRETER_ELF 2
-
-#define DLINFO_ITEMS 12
-
 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
 {
         memcpy(to, from, n);
@@ -563,7 +44,7 @@ static int load_aout_interp(void * exptr, int interp_fd);
 #ifdef BSWAP_NEEDED
 static void bswap_ehdr(struct elfhdr *ehdr)
 {
-    bswap16s(&ehdr->e_type);                    /* Object file type */
+    bswap16s(&ehdr->e_type);            /* Object file type */
     bswap16s(&ehdr->e_machine);         /* Architecture */
     bswap32s(&ehdr->e_version);         /* Object file version */
     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
@@ -571,37 +52,45 @@ static void bswap_ehdr(struct elfhdr *ehdr)
     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
-    bswap16s(&ehdr->e_phentsize);               /* Program header table entry size */
+    bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
-    bswap16s(&ehdr->e_shentsize);               /* Section header table entry size */
+    bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
-    bswap16s(&ehdr->e_shstrndx);                /* Section header string table index */
+    bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
 }
 
-static void bswap_phdr(struct elf_phdr *phdr)
+static void bswap_phdr(struct elf_phdr *phdr, int phnum)
 {
-    bswap32s(&phdr->p_type);                    /* Segment type */
-    bswaptls(&phdr->p_offset);          /* Segment file offset */
-    bswaptls(&phdr->p_vaddr);           /* Segment virtual address */
-    bswaptls(&phdr->p_paddr);           /* Segment physical address */
-    bswaptls(&phdr->p_filesz);          /* Segment size in file */
-    bswaptls(&phdr->p_memsz);           /* Segment size in memory */
-    bswap32s(&phdr->p_flags);           /* Segment flags */
-    bswaptls(&phdr->p_align);           /* Segment alignment */
+    int i;
+
+    for (i = 0; i < phnum; i++, phdr++) {
+        bswap32s(&phdr->p_type);        /* Segment type */
+        bswaptls(&phdr->p_offset);      /* Segment file offset */
+        bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
+        bswaptls(&phdr->p_paddr);       /* Segment physical address */
+        bswaptls(&phdr->p_filesz);      /* Segment size in file */
+        bswaptls(&phdr->p_memsz);       /* Segment size in memory */
+        bswap32s(&phdr->p_flags);       /* Segment flags */
+        bswaptls(&phdr->p_align);       /* Segment alignment */
+    }
 }
 
-static void bswap_shdr(struct elf_shdr *shdr)
+static void bswap_shdr(struct elf_shdr *shdr, int shnum)
 {
-    bswap32s(&shdr->sh_name);
-    bswap32s(&shdr->sh_type);
-    bswaptls(&shdr->sh_flags);
-    bswaptls(&shdr->sh_addr);
-    bswaptls(&shdr->sh_offset);
-    bswaptls(&shdr->sh_size);
-    bswap32s(&shdr->sh_link);
-    bswap32s(&shdr->sh_info);
-    bswaptls(&shdr->sh_addralign);
-    bswaptls(&shdr->sh_entsize);
+    int i;
+
+    for (i = 0; i < shnum; i++, shdr++) {
+        bswap32s(&shdr->sh_name);
+        bswap32s(&shdr->sh_type);
+        bswaptls(&shdr->sh_flags);
+        bswaptls(&shdr->sh_addr);
+        bswaptls(&shdr->sh_offset);
+        bswaptls(&shdr->sh_size);
+        bswap32s(&shdr->sh_link);
+        bswap32s(&shdr->sh_info);
+        bswaptls(&shdr->sh_addralign);
+        bswaptls(&shdr->sh_entsize);
+    }
 }
 
 static void bswap_sym(struct elf_sym *sym)
@@ -611,7 +100,15 @@ static void bswap_sym(struct elf_sym *sym)
     bswaptls(&sym->st_size);
     bswap16s(&sym->st_shndx);
 }
-#endif
+
+#else /* ! BSWAP_NEEDED */
+
+static void bswap_ehdr(struct elfhdr *ehdr) { }
+static void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
+static void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
+static void bswap_sym(struct elf_sym *sym) { }
+
+#endif /* ! BSWAP_NEEDED */
 
 /*
  * 'copy_elf_strings()' copies argument/envelope strings from user
@@ -671,39 +168,31 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
 static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm,
                                  struct image_info *info)
 {
-    abi_ulong stack_base, size, error;
-    int i;
+    abi_ulong stack_base, size;
+    abi_long addr;
 
     /* Create enough stack to hold everything.  If we don't use
      * it for args, we'll use it for something else...
      */
     size = target_dflssiz;
-    if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
-        size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
-    error = target_mmap(0,
-                        size + qemu_host_page_size,
-                        PROT_READ | PROT_WRITE,
-                        MAP_PRIVATE | MAP_ANON,
-                        -1, 0);
-    if (error == -1) {
+    stack_base = TARGET_USRSTACK - size;
+    addr = target_mmap(stack_base , size + qemu_host_page_size,
+            PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+    if (addr == -1) {
         perror("stk mmap");
         exit(-1);
     }
     /* we reserve one extra page at the top of the stack as guard */
-    target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
+    target_mprotect(addr + size, qemu_host_page_size, PROT_NONE);
 
-    stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
-    p += stack_base;
+    target_stksiz = size;
+    target_stkbas = addr;
 
-    for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-        if (bprm->page[i]) {
-            info->rss++;
-            /* FIXME - check return value of memcpy_to_target() for failure */
-            memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
-            g_free(bprm->page[i]);
-        }
-        stack_base += TARGET_PAGE_SIZE;
+    if (setup_initial_stack(bprm, &p) != 0) {
+        perror("stk setup");
+        exit(-1);
     }
+
     return p;
 }
 
@@ -761,86 +250,6 @@ static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
         }
 }
 
-
-static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
-                                   struct elfhdr * exec,
-                                   abi_ulong load_addr,
-                                   abi_ulong load_bias,
-                                   abi_ulong interp_load_addr, int ibcs,
-                                   struct image_info *info)
-{
-        abi_ulong sp;
-        int size;
-        abi_ulong u_platform;
-        const char *k_platform;
-        const int n = sizeof(elf_addr_t);
-
-        sp = p;
-        u_platform = 0;
-        k_platform = ELF_PLATFORM;
-        if (k_platform) {
-            size_t len = strlen(k_platform) + 1;
-            sp -= (len + n - 1) & ~(n - 1);
-            u_platform = sp;
-            /* FIXME - check return value of memcpy_to_target() for failure */
-            memcpy_to_target(sp, k_platform, len);
-        }
-        /*
-         * Force 16 byte _final_ alignment here for generality.
-         */
-        sp = sp &~ (abi_ulong)15;
-        size = (DLINFO_ITEMS + 1) * 2;
-        if (k_platform)
-          size += 2;
-#ifdef DLINFO_ARCH_ITEMS
-        size += DLINFO_ARCH_ITEMS * 2;
-#endif
-        size += envc + argc + 2;
-        size += (!ibcs ? 3 : 1);        /* argc itself */
-        size *= n;
-        if (size & 15)
-            sp -= 16 - (size & 15);
-
-        /* This is correct because Linux defines
-         * elf_addr_t as Elf32_Off / Elf64_Off
-         */
-#define NEW_AUX_ENT(id, val) do {               \
-            sp -= n; put_user_ual(val, sp);     \
-            sp -= n; put_user_ual(id, sp);      \
-          } while(0)
-
-        NEW_AUX_ENT (AT_NULL, 0);
-
-        /* There must be exactly DLINFO_ITEMS entries here.  */
-        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
-        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
-        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
-        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
-        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
-        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
-        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
-        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
-        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
-        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
-        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
-        NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
-        NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
-        if (k_platform)
-            NEW_AUX_ENT(AT_PLATFORM, u_platform);
-#ifdef ARCH_DLINFO
-        /*
-         * ARCH_DLINFO must come last so platform specific code can enforce
-         * special alignment requirements on the AUXV if necessary (eg. PPC).
-         */
-        ARCH_DLINFO;
-#endif
-#undef NEW_AUX_ENT
-
-        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
-        return sp;
-}
-
-
 static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                                  int interpreter_fd,
                                  abi_ulong *interp_load_addr)
@@ -858,9 +267,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
         last_bss = 0;
         error = 0;
 
-#ifdef BSWAP_NEEDED
         bswap_ehdr(interp_elf_ex);
-#endif
         /* First of all, some simple consistency checks */
         if ((interp_elf_ex->e_type != ET_EXEC &&
              interp_elf_ex->e_type != ET_DYN) ||
@@ -901,12 +308,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                 free (elf_phdata);
                 return retval;
         }
-#ifdef BSWAP_NEEDED
-        eppnt = elf_phdata;
-        for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
-            bswap_phdr(eppnt);
-        }
-#endif
+        bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
 
         if (interp_elf_ex->e_type == ET_DYN) {
             /* in order to avoid hardcoding the interpreter load
@@ -923,54 +325,57 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
         }
 
         eppnt = elf_phdata;
-        for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
-          if (eppnt->p_type == PT_LOAD) {
-            int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
-            int elf_prot = 0;
-            abi_ulong vaddr = 0;
-            abi_ulong k;
-
-            if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
-            if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-            if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-            if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
-                elf_type |= MAP_FIXED;
-                vaddr = eppnt->p_vaddr;
-            }
-            error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
-                 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
-                 elf_prot,
-                 elf_type,
-                 interpreter_fd,
-                 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
-
-            if (error == -1) {
-              /* Real error */
-              close(interpreter_fd);
-              free(elf_phdata);
-              return ~((abi_ulong)0UL);
-            }
-
-            if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
-              load_addr = error;
-              load_addr_set = 1;
+        for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++)
+            if (eppnt->p_type == PT_LOAD) {
+                int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+                int elf_prot = 0;
+                abi_ulong vaddr = 0;
+                abi_ulong k;
+
+                if (eppnt->p_flags & PF_R) {
+                    elf_prot =  PROT_READ;
+                }
+                if (eppnt->p_flags & PF_W) {
+                    elf_prot |= PROT_WRITE;
+                }
+                if (eppnt->p_flags & PF_X) {
+                    elf_prot |= PROT_EXEC;
+                }
+                if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
+                    elf_type |= MAP_FIXED;
+                    vaddr = eppnt->p_vaddr;
+                }
+                error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
+                        eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
+                        elf_prot, elf_type, interpreter_fd, eppnt->p_offset -
+                        TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
+                if (error == -1) {
+                    /* Real error */
+                    close(interpreter_fd);
+                    free(elf_phdata);
+                    return ~((abi_ulong)0UL);
+                }
+                if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+                    load_addr = error;
+                    load_addr_set = 1;
+                }
+                /*
+                 * Find the end of the file  mapping for this phdr, and keep
+                 * track of the largest address we see for this.
+                 */
+                k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
+                if (k > elf_bss) {
+                    elf_bss = k;
+                }
+                /*
+                 * Do the same thing for the memory mapping - between
+                 * elf_bss and last_bss is the bss section.
+                 */
+                k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+                if (k > last_bss) {
+                    last_bss = k;
+                }
             }
-
-            /*
-             * Find the end of the file  mapping for this phdr, and keep
-             * track of the largest address we see for this.
-             */
-            k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
-            if (k > elf_bss) elf_bss = k;
-
-            /*
-             * Do the same thing for the memory mapping - between
-             * elf_bss and last_bss is the bss section.
-             */
-            k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
-            if (k > last_bss) last_bss = k;
-          }
-
         /* Now use mmap to map the library into memory. */
 
         close(interpreter_fd);
@@ -982,7 +387,8 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
          * bss page.
          */
         padzero(elf_bss, last_bss);
-        elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
+        /* What we have mapped so far */
+        elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1);
 
         /* Map the last of the bss segment */
         if (last_bss > elf_bss) {
@@ -1051,9 +457,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
     for (i = 0; i < hdr->e_shnum; i++) {
         if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
             return;
-#ifdef BSWAP_NEEDED
-        bswap_shdr(&sechdr);
-#endif
+        bswap_shdr(&sechdr, 1);
         if (sechdr.sh_type == SHT_SYMTAB) {
             symtab = sechdr;
             lseek(fd, hdr->e_shoff
@@ -1061,9 +465,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
             if (read(fd, &strtab, sizeof(strtab))
                 != sizeof(strtab))
                 return;
-#ifdef BSWAP_NEEDED
-            bswap_shdr(&strtab);
-#endif
+            bswap_shdr(&strtab, 1);
             goto found;
         }
     }
@@ -1096,9 +498,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
 
     i = 0;
     while (i < nsyms) {
-#ifdef BSWAP_NEEDED
         bswap_sym(syms + i);
-#endif
         // Throw away entries which we do not need.
         if (syms[i].st_shndx == SHN_UNDEF ||
                 syms[i].st_shndx >= SHN_LORESERVE ||
@@ -1150,6 +550,30 @@ static void load_symbols(struct elfhdr *hdr, int fd)
     syminfos = s;
 }
 
+/* Check the elf header and see if this a target elf binary. */
+int is_target_elf_binary(int fd)
+{
+    uint8_t buf[128];
+    struct elfhdr elf_ex;
+
+    if (lseek(fd, 0L, SEEK_SET) < 0) {
+        return 0;
+    }
+    if (read(fd, buf, sizeof(buf)) < 0) {
+        return 0;
+    }
+
+    elf_ex = *((struct elfhdr *)buf);
+    bswap_ehdr(&elf_ex);
+
+    if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
+        (!elf_check_arch(elf_ex.e_machine))) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
 int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
                     struct image_info *info)
 {
@@ -1169,20 +593,18 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
     int retval;
     char * elf_interpreter;
     abi_ulong elf_entry, interp_load_addr = 0;
-    int status;
     abi_ulong start_code, end_code, start_data, end_data;
     abi_ulong reloc_func_desc = 0;
+#ifdef LOW_ELF_STACK
     abi_ulong elf_stack;
+#endif
     char passed_fileno[6];
 
     ibcs2_interpreter = 0;
-    status = 0;
     load_addr = 0;
     load_bias = 0;
     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
-#ifdef BSWAP_NEEDED
     bswap_ehdr(&elf_ex);
-#endif
 
     /* First of all, some simple consistency checks */
     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
@@ -1190,12 +612,14 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
             return -ENOEXEC;
     }
 
+#ifndef __FreeBSD__
     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
     if (!bprm->p) {
         retval = -E2BIG;
     }
+#endif /* ! __FreeBSD__ */
 
     /* Now read in all of the header information */
     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
@@ -1216,19 +640,16 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
         return -errno;
     }
 
-#ifdef BSWAP_NEEDED
-    elf_ppnt = elf_phdata;
-    for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
-        bswap_phdr(elf_ppnt);
-    }
-#endif
+    bswap_phdr(elf_phdata, elf_ex.e_phnum);
     elf_ppnt = elf_phdata;
 
     elf_bss = 0;
     elf_brk = 0;
 
 
+#ifdef LOW_ELF_STACK
     elf_stack = ~((abi_ulong)0UL);
+#endif
     elf_interpreter = NULL;
     start_code = ~((abi_ulong)0UL);
     end_code = 0;
@@ -1236,7 +657,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
     end_data = 0;
     interp_ex.a_info = 0;
 
-    for(i=0;i < elf_ex.e_phnum; i++) {
+    for (i = 0; i < elf_ex.e_phnum; i++) {
         if (elf_ppnt->p_type == PT_INTERP) {
             if ( elf_interpreter != NULL )
             {
@@ -1274,9 +695,9 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
 
             /* JRP - Need to add X86 lib dir stuff here... */
 
-            if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
-                strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
-              ibcs2_interpreter = 1;
+            if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0 ||
+                    strcmp(elf_interpreter, "/usr/lib/ld-elf.so.1") == 0) {
+                ibcs2_interpreter = 1;
             }
 
 #if 0
@@ -1406,7 +827,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
      * address.
      */
 
-    for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+    for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
         int elf_prot = 0;
         int elf_flags = 0;
         abi_ulong error;
@@ -1423,7 +844,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
         } else if (elf_ex.e_type == ET_DYN) {
             /* Try and get dynamic programs out of the way of the default mmap
                base, as well as whatever program they might try to exec.  This
-               is because the brk will follow the loader, and is not movable.  */
+               is because the brk will follow the loader, and is not movable. */
             /* NOTE: for qemu, we do a big mmap to get enough space
                without hardcoding any address */
             error = target_mmap(0, ET_DYN_MAP_SIZE,
@@ -1520,7 +941,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
 #ifdef LOW_ELF_STACK
     info->start_stack = bprm->p = elf_stack - 4;
 #endif
-    bprm->p = create_elf_tables(bprm->p,
+    bprm->p = target_create_elf_tables(bprm->p,
                     bprm->argc,
                     bprm->envc,
                     &elf_ex,
@@ -1536,19 +957,22 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
     info->end_data = end_data;
     info->start_stack = bprm->p;
 
-    /* Calling set_brk effectively mmaps the pages that we need for the bss and break
-       sections */
+    /*
+     * Calling set_brk effectively mmaps the pages that we need for the bss
+     * and break sections.
+     */
     set_brk(elf_bss, elf_brk);
 
     padzero(elf_bss, elf_brk);
 
 #if 0
-    printf("(start_brk) %x\n" , info->start_brk);
-    printf("(end_code) %x\n" , info->end_code);
-    printf("(start_code) %x\n" , info->start_code);
-    printf("(end_data) %x\n" , info->end_data);
-    printf("(start_stack) %x\n" , info->start_stack);
-    printf("(brk) %x\n" , info->brk);
+    printf("(start_brk) 0x" TARGET_FMT_lx "\n" , info->start_brk);
+    printf("(end_code) 0x" TARGET_FMT_lx "\n" , info->end_code);
+    printf("(start_code) 0x" TARGET_FMT_lx "\n" , info->start_code);
+    printf("(start_data) 0x" TARGET_FMT_lx "\n" , info->start_data);
+    printf("(end_data) 0x" TARGET_FMT_lx "\n" , info->end_data);
+    printf("(start_stack) 0x" TARGET_FMT_lx "\n" , info->start_stack);
+    printf("(brk) 0x" TARGET_FMT_lx "\n" , info->brk);
 #endif
 
     if ( info->personality == PER_SVR4 )
@@ -1557,12 +981,21 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
                and some applications "depend" upon this behavior.
                Since we do not have the power to recompile these, we
                emulate the SVr4 behavior.  Sigh.  */
-            mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
-                                      MAP_FIXED | MAP_PRIVATE, -1, 0);
+            mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ |
+                    PROT_EXEC, MAP_FIXED | MAP_PRIVATE, -1, 0);
+	    if (mapped_addr == -1) {
+		    return -1;
+	    }
     }
 
     info->entry = elf_entry;
 
+#ifdef USE_ELF_CORE_DUMP
+    /* not yet */
+    /* bprm->core_dump = &elf_core_dump; */
+    bprm->core_dump = NULL;
+#endif
+
     return 0;
 }
 
@@ -1574,5 +1007,5 @@ static int load_aout_interp(void * exptr, int interp_fd)
 
 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
 {
-    init_thread(regs, infop);
+    target_thread_init(regs, infop);
 }
diff --git a/bsd-user/freebsd/target_os_elf.h b/bsd-user/freebsd/target_os_elf.h
new file mode 100644
index 0000000..67637a0
--- /dev/null
+++ b/bsd-user/freebsd/target_os_elf.h
@@ -0,0 +1,145 @@
+/*
+ *  freebsd ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_OS_ELF_H_
+#define _TARGET_OS_ELF_H_
+
+#include "target_arch_elf.h"
+#include "elf.h"
+
+/* this flag is uneffective under linux too, should be deleted */
+#ifndef MAP_DENYWRITE
+#define MAP_DENYWRITE 0
+#endif
+
+/* should probably go in elf.h */
+#ifndef ELIBBAD
+#define ELIBBAD 80
+#endif
+
+#ifndef ELF_PLATFORM
+#define ELF_PLATFORM (NULL)
+#endif
+
+#ifndef ELF_HWCAP
+#define ELF_HWCAP 0
+#endif
+
+#ifdef TARGET_ABI32
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+#undef bswaptls
+#define bswaptls(ptr) bswap32s(ptr)
+#endif
+
+struct exec
+{
+  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
+  unsigned int a_text;   /* length of text, in bytes */
+  unsigned int a_data;   /* length of data, in bytes */
+  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
+  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
+  unsigned int a_entry;  /* start address */
+  unsigned int a_trsize; /* length of relocation info for text, in bytes */
+  unsigned int a_drsize; /* length of relocation info for data, in bytes */
+};
+
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+
+/* max code+data+bss space allocated to elf interpreter */
+#define INTERP_MAP_SIZE (32 * 1024 * 1024)
+
+/* max code+data+bss+brk space allocated to ET_DYN executables */
+#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
+
+/* Necessary parameters */
+#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
+#define TARGET_ELF_PAGESTART(_v) ((_v) & \
+        ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+#define DLINFO_ITEMS 12
+
+static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc,
+                                   struct elfhdr * exec,
+                                   abi_ulong load_addr,
+                                   abi_ulong load_bias,
+                                   abi_ulong interp_load_addr, int ibcs,
+                                   struct image_info *info)
+{
+        abi_ulong sp;
+        int size;
+        const int n = sizeof(elf_addr_t);
+
+        sp = p;
+        /*
+         * Force 16 byte _final_ alignment here for generality.
+         */
+        sp = sp &~ (abi_ulong)15;
+        size = (DLINFO_ITEMS + 1) * 2;
+        size += envc + argc + 2;
+        size += (!ibcs ? 3 : 1);        /* argc itself */
+        size *= n;
+        if (size & 15)
+            sp -= 16 - (size & 15);
+
+        /* This is correct because Linux defines
+         * elf_addr_t as Elf32_Off / Elf64_Off
+         */
+#define NEW_AUX_ENT(id, val) do {               \
+            sp -= n; put_user_ual(val, sp);     \
+            sp -= n; put_user_ual(id, sp);      \
+          } while(0)
+
+        NEW_AUX_ENT (AT_NULL, 0);
+
+        /* There must be exactly DLINFO_ITEMS entries here.  */
+        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+#ifdef ARCH_DLINFO
+        /*
+         * ARCH_DLINFO must come last so platform specific code can enforce
+         * special alignment requirements on the AUXV if necessary (eg. PPC).
+         */
+        ARCH_DLINFO;
+#endif
+#undef NEW_AUX_ENT
+
+        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+        return sp;
+}
+
+#endif /* _TARGET_OS_ELF_H_ */
diff --git a/bsd-user/freebsd/target_os_thread.h b/bsd-user/freebsd/target_os_thread.h
new file mode 100644
index 0000000..519aad8
--- /dev/null
+++ b/bsd-user/freebsd/target_os_thread.h
@@ -0,0 +1,6 @@
+#ifndef _TARGET_OS_THREAD_H_
+#define _TARGET_OS_THREAD_H_
+
+#include "target_arch_thread.h"
+
+#endif /* !_TARGET_OS_THREAD_H_ */
diff --git a/bsd-user/i386/target_arch_elf.h b/bsd-user/i386/target_arch_elf.h
new file mode 100644
index 0000000..83b2197
--- /dev/null
+++ b/bsd-user/i386/target_arch_elf.h
@@ -0,0 +1,62 @@
+/*
+ *  i386 ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x80000000
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS       ELFCLASS32
+#define ELF_DATA        ELFDATA2LSB
+#define ELF_ARCH        EM_386
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+/* XXX */
+#ifndef __FreeBSD__
+#define ELF_PLATFORM target_elf_get_platform()
+
+static const char *target_elf_get_platform(void)
+{
+    static char elf_platform[] = "i386";
+    int family = (thread_env->cpuid_version >> 8) & 0xff;
+    if (family > 6)
+        family = 6;
+    if (family >= 3)
+        elf_platform[1] = '0' + family;
+    return elf_platform;
+}
+
+#define ELF_HWCAP target_elf_get_hwcap()
+
+static uint32_t target_elf_get_hwcap(void)
+{
+    return thread_env->features[FEAT_1_EDX];
+}
+#endif /* ! __FreeBSD__ */
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/i386/target_arch_thread.h b/bsd-user/i386/target_arch_thread.h
new file mode 100644
index 0000000..407aa6c
--- /dev/null
+++ b/bsd-user/i386/target_arch_thread.h
@@ -0,0 +1,45 @@
+/*
+ *  i386 thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUX86State *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    /* XXX */
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    regs->esp = infop->start_stack;
+    regs->eip = infop->entry;
+
+    /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
+       starts %edx contains a pointer to a function which might be
+       registered using `atexit'.  This provides a mean for the
+       dynamic linker to call DT_FINI functions for shared libraries
+       that have been loaded before the code runs.
+
+       A value of 0 tells we have no such handler.  */
+    regs->edx = 0;
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/mips/target_arch_elf.h b/bsd-user/mips/target_arch_elf.h
new file mode 100644
index 0000000..8630f34
--- /dev/null
+++ b/bsd-user/mips/target_arch_elf.h
@@ -0,0 +1,36 @@
+/*
+ *  mips ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define elf_check_arch(x) ( (x) == EM_MIPS )
+#define ELF_START_MMAP 0x80000000
+#define ELF_CLASS   ELFCLASS32
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+#define ELF_ARCH    EM_MIPS
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        4096
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/mips/target_arch_thread.h b/bsd-user/mips/target_arch_thread.h
new file mode 100644
index 0000000..c76b0d6
--- /dev/null
+++ b/bsd-user/mips/target_arch_thread.h
@@ -0,0 +1,54 @@
+/*
+ *  mips thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to mips/mips/vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUMIPSState *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    abi_ulong sp;
+
+    /*
+     * At the point where a function is called, sp must be 8
+     * byte aligned[for compatibility with 64-bit CPUs]
+     * in ``See MIPS Run'' by D. Sweetman, p. 269
+     * align stack
+     */
+    sp = ((stack_base + stack_size) & ~0x7) - TARGET_CALLFRAME_SIZ;
+
+    /* t9 = pc = start function entry */
+    regs->active_tc.gpr[25] = regs->active_tc.PC = entry;
+    /* a0 = arg */
+    regs->active_tc.gpr[4] = arg;
+    /* sp = top of the stack */
+    regs->active_tc.gpr[29] = sp;
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    regs->cp0_status = 2 << CP0St_KSU;
+    regs->regs[25] = regs->cp0_epc = infop->entry & ~3;  /* t9/pc = entry */
+    regs->regs[4] = regs->regs[29] = infop->start_stack; /* a0/sp = stack */
+    regs->regs[5] = regs->regs[6] = 0;                   /* a1/a2 = 0 */
+    regs->regs[7] = TARGET_PS_STRINGS;                   /* a3 = ps_strings */
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/mips64/target_arch_elf.h b/bsd-user/mips64/target_arch_elf.h
new file mode 100644
index 0000000..ca0da03
--- /dev/null
+++ b/bsd-user/mips64/target_arch_elf.h
@@ -0,0 +1,36 @@
+/*
+ *  mips64 ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define elf_check_arch(x) ( (x) == EM_MIPS )
+#define ELF_START_MMAP 0x2aaaaab000ULL
+#define ELF_CLASS   ELFCLASS64
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+#define ELF_ARCH    EM_MIPS
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        4096
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/mips64/target_arch_thread.h b/bsd-user/mips64/target_arch_thread.h
new file mode 100644
index 0000000..7fcd866
--- /dev/null
+++ b/bsd-user/mips64/target_arch_thread.h
@@ -0,0 +1,54 @@
+/*
+ *  mips64 thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _MIPS64_ARCH_THREAD_H_
+#define _MIPS64_ARCH_THREAD_H_
+
+/* Compare to mips/mips/vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUMIPSState *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    abi_ulong sp;
+
+    /*
+     * At the point where a function is called, sp must be 8
+     * byte aligned[for compatibility with 64-bit CPUs]
+     * in ``See MIPS Run'' by D. Sweetman, p. 269
+     * align stack
+     */
+    sp = ((stack_base + stack_size) & ~0x7) - TARGET_CALLFRAME_SIZ;
+
+    /* t9 = pc = start function entry */
+    regs->active_tc.gpr[25] = regs->active_tc.PC = entry;
+    /* a0 = arg */
+    regs->active_tc.gpr[4] = arg;
+    /* sp = top of the stack */
+    regs->active_tc.gpr[29] = sp;
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    regs->cp0_status = 2 << CP0St_KSU;
+    regs->regs[25] = regs->cp0_epc = infop->entry & ~3;  /* t9/pc = entry */
+    regs->regs[4] = regs->regs[29] = infop->start_stack; /* a0/sp = stack */
+    regs->regs[5] = regs->regs[6] = 0;                   /* a1/a2 = 0 */
+    regs->regs[7] = TARGET_PS_STRINGS;                   /* a3 = ps_strings */
+}
+
+#endif /* !_MIPS64_ARCH_THREAD_H_ */
diff --git a/bsd-user/netbsd/target_os_elf.h b/bsd-user/netbsd/target_os_elf.h
new file mode 100644
index 0000000..bf663d2
--- /dev/null
+++ b/bsd-user/netbsd/target_os_elf.h
@@ -0,0 +1,226 @@
+/*
+ *  netbsd ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_OS_ELF_H_
+#define _TARGET_OS_ELF_H_
+
+#include "target_arch_elf.h"
+#include "elf.h"
+
+/* from personality.h */
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA
+                                                   space */
+        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs
+                                                   point to descriptors
+                                                   (signal handling) */
+        MMAP_PAGE_ZERO =        0x0100000,
+        ADDR_COMPAT_LAYOUT =    0x0200000,
+        READ_IMPLIES_EXEC =     0x0400000,
+        ADDR_LIMIT_32BIT =      0x0800000,
+        SHORT_INODE =           0x1000000,
+        WHOLE_SECONDS =         0x2000000,
+        STICKY_TIMEOUTS =       0x4000000,
+        ADDR_LIMIT_3GB =        0x8000000,
+};
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+        PER_LINUX =             0x0000,
+        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
+        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
+        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
+                                         WHOLE_SECONDS | SHORT_INODE,
+        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
+        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
+        PER_BSD =               0x0006,
+        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
+        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_LINUX32 =           0x0008,
+        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
+        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
+        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
+        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
+        PER_RISCOS =            0x000c,
+        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
+        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
+        PER_HPUX =              0x0010,
+        PER_MASK =              0x00ff,
+};
+
+/*
+ * Return the base personality without flags.
+ */
+#define personality(pers)       (pers & PER_MASK)
+
+/* this flag is uneffective under linux too, should be deleted */
+#ifndef MAP_DENYWRITE
+#define MAP_DENYWRITE 0
+#endif
+
+/* should probably go in elf.h */
+#ifndef ELIBBAD
+#define ELIBBAD 80
+#endif
+
+#ifndef ELF_PLATFORM
+#define ELF_PLATFORM (NULL)
+#endif
+
+#ifndef ELF_HWCAP
+#define ELF_HWCAP 0
+#endif
+
+#ifdef TARGET_ABI32
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+#undef bswaptls
+#define bswaptls(ptr) bswap32s(ptr)
+#endif
+
+struct exec
+{
+  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
+  unsigned int a_text;   /* length of text, in bytes */
+  unsigned int a_data;   /* length of data, in bytes */
+  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
+  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
+  unsigned int a_entry;  /* start address */
+  unsigned int a_trsize; /* length of relocation info for text, in bytes */
+  unsigned int a_drsize; /* length of relocation info for data, in bytes */
+};
+
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+
+/* max code+data+bss space allocated to elf interpreter */
+#define INTERP_MAP_SIZE (32 * 1024 * 1024)
+
+/* max code+data+bss+brk space allocated to ET_DYN executables */
+#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
+
+/* Necessary parameters */
+#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
+#define TARGET_ELF_PAGESTART(_v) ((_v) & \
+        ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+#define DLINFO_ITEMS 12
+
+static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc,
+                                   struct elfhdr * exec,
+                                   abi_ulong load_addr,
+                                   abi_ulong load_bias,
+                                   abi_ulong interp_load_addr, int ibcs,
+                                   struct image_info *info)
+{
+        abi_ulong sp;
+        int size;
+        abi_ulong u_platform;
+        const char *k_platform;
+        const int n = sizeof(elf_addr_t);
+
+        sp = p;
+        u_platform = 0;
+        k_platform = ELF_PLATFORM;
+        if (k_platform) {
+            size_t len = strlen(k_platform) + 1;
+            sp -= (len + n - 1) & ~(n - 1);
+            u_platform = sp;
+            /* FIXME - check return value of memcpy_to_target() for failure */
+            memcpy_to_target(sp, k_platform, len);
+        }
+        /*
+         * Force 16 byte _final_ alignment here for generality.
+         */
+        sp = sp &~ (abi_ulong)15;
+        size = (DLINFO_ITEMS + 1) * 2;
+        if (k_platform)
+          size += 2;
+#ifdef DLINFO_ARCH_ITEMS
+        size += DLINFO_ARCH_ITEMS * 2;
+#endif
+        size += envc + argc + 2;
+        size += (!ibcs ? 3 : 1);        /* argc itself */
+        size *= n;
+        if (size & 15)
+            sp -= 16 - (size & 15);
+
+        /* This is correct because Linux defines
+         * elf_addr_t as Elf32_Off / Elf64_Off
+         */
+#define NEW_AUX_ENT(id, val) do {               \
+            sp -= n; put_user_ual(val, sp);     \
+            sp -= n; put_user_ual(id, sp);      \
+          } while(0)
+
+        NEW_AUX_ENT (AT_NULL, 0);
+
+        /* There must be exactly DLINFO_ITEMS entries here.  */
+        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+        NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
+        NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+        if (k_platform)
+            NEW_AUX_ENT(AT_PLATFORM, u_platform);
+#ifdef ARCH_DLINFO
+        /*
+         * ARCH_DLINFO must come last so platform specific code can enforce
+         * special alignment requirements on the AUXV if necessary (eg. PPC).
+         */
+        ARCH_DLINFO;
+#endif
+#undef NEW_AUX_ENT
+
+        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+        return sp;
+}
+
+#endif /* _TARGET_OS_ELF_H_ */
diff --git a/bsd-user/netbsd/target_os_thread.h b/bsd-user/netbsd/target_os_thread.h
new file mode 100644
index 0000000..519aad8
--- /dev/null
+++ b/bsd-user/netbsd/target_os_thread.h
@@ -0,0 +1,6 @@
+#ifndef _TARGET_OS_THREAD_H_
+#define _TARGET_OS_THREAD_H_
+
+#include "target_arch_thread.h"
+
+#endif /* !_TARGET_OS_THREAD_H_ */
diff --git a/bsd-user/openbsd/target_os_elf.h b/bsd-user/openbsd/target_os_elf.h
new file mode 100644
index 0000000..978d944
--- /dev/null
+++ b/bsd-user/openbsd/target_os_elf.h
@@ -0,0 +1,226 @@
+/*
+ *  openbsd ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_OS_ELF_H_
+#define _TARGET_OS_ELF_H_
+
+#include "target_arch_elf.h"
+#include "elf.h"
+
+/* from personality.h */
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA
+                                                   space */
+        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs
+                                                   point to descriptors
+                                                   (signal handling) */
+        MMAP_PAGE_ZERO =        0x0100000,
+        ADDR_COMPAT_LAYOUT =    0x0200000,
+        READ_IMPLIES_EXEC =     0x0400000,
+        ADDR_LIMIT_32BIT =      0x0800000,
+        SHORT_INODE =           0x1000000,
+        WHOLE_SECONDS =         0x2000000,
+        STICKY_TIMEOUTS =       0x4000000,
+        ADDR_LIMIT_3GB =        0x8000000,
+};
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+        PER_LINUX =             0x0000,
+        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
+        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
+        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
+                                         WHOLE_SECONDS | SHORT_INODE,
+        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
+        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
+        PER_BSD =               0x0006,
+        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
+        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_LINUX32 =           0x0008,
+        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
+        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
+        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
+        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
+        PER_RISCOS =            0x000c,
+        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
+        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
+        PER_HPUX =              0x0010,
+        PER_MASK =              0x00ff,
+};
+
+/*
+ * Return the base personality without flags.
+ */
+#define personality(pers)       (pers & PER_MASK)
+
+/* this flag is uneffective under linux too, should be deleted */
+#ifndef MAP_DENYWRITE
+#define MAP_DENYWRITE 0
+#endif
+
+/* should probably go in elf.h */
+#ifndef ELIBBAD
+#define ELIBBAD 80
+#endif
+
+#ifndef ELF_PLATFORM
+#define ELF_PLATFORM (NULL)
+#endif
+
+#ifndef ELF_HWCAP
+#define ELF_HWCAP 0
+#endif
+
+#ifdef TARGET_ABI32
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+#undef bswaptls
+#define bswaptls(ptr) bswap32s(ptr)
+#endif
+
+struct exec
+{
+  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
+  unsigned int a_text;   /* length of text, in bytes */
+  unsigned int a_data;   /* length of data, in bytes */
+  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
+  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
+  unsigned int a_entry;  /* start address */
+  unsigned int a_trsize; /* length of relocation info for text, in bytes */
+  unsigned int a_drsize; /* length of relocation info for data, in bytes */
+};
+
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+
+/* max code+data+bss space allocated to elf interpreter */
+#define INTERP_MAP_SIZE (32 * 1024 * 1024)
+
+/* max code+data+bss+brk space allocated to ET_DYN executables */
+#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
+
+/* Necessary parameters */
+#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
+#define TARGET_ELF_PAGESTART(_v) ((_v) & \
+        ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+#define DLINFO_ITEMS 12
+
+static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc,
+                                   struct elfhdr * exec,
+                                   abi_ulong load_addr,
+                                   abi_ulong load_bias,
+                                   abi_ulong interp_load_addr, int ibcs,
+                                   struct image_info *info)
+{
+        abi_ulong sp;
+        int size;
+        abi_ulong u_platform;
+        const char *k_platform;
+        const int n = sizeof(elf_addr_t);
+
+        sp = p;
+        u_platform = 0;
+        k_platform = ELF_PLATFORM;
+        if (k_platform) {
+            size_t len = strlen(k_platform) + 1;
+            sp -= (len + n - 1) & ~(n - 1);
+            u_platform = sp;
+            /* FIXME - check return value of memcpy_to_target() for failure */
+            memcpy_to_target(sp, k_platform, len);
+        }
+        /*
+         * Force 16 byte _final_ alignment here for generality.
+         */
+        sp = sp &~ (abi_ulong)15;
+        size = (DLINFO_ITEMS + 1) * 2;
+        if (k_platform)
+          size += 2;
+#ifdef DLINFO_ARCH_ITEMS
+        size += DLINFO_ARCH_ITEMS * 2;
+#endif
+        size += envc + argc + 2;
+        size += (!ibcs ? 3 : 1);        /* argc itself */
+        size *= n;
+        if (size & 15)
+            sp -= 16 - (size & 15);
+
+        /* This is correct because Linux defines
+         * elf_addr_t as Elf32_Off / Elf64_Off
+         */
+#define NEW_AUX_ENT(id, val) do {               \
+            sp -= n; put_user_ual(val, sp);     \
+            sp -= n; put_user_ual(id, sp);      \
+          } while(0)
+
+        NEW_AUX_ENT (AT_NULL, 0);
+
+        /* There must be exactly DLINFO_ITEMS entries here.  */
+        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+        NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
+        NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+        if (k_platform)
+            NEW_AUX_ENT(AT_PLATFORM, u_platform);
+#ifdef ARCH_DLINFO
+        /*
+         * ARCH_DLINFO must come last so platform specific code can enforce
+         * special alignment requirements on the AUXV if necessary (eg. PPC).
+         */
+        ARCH_DLINFO;
+#endif
+#undef NEW_AUX_ENT
+
+        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+        return sp;
+}
+
+#endif /* _TARGET_OS_ELF_H_ */
diff --git a/bsd-user/openbsd/target_os_thread.h b/bsd-user/openbsd/target_os_thread.h
new file mode 100644
index 0000000..519aad8
--- /dev/null
+++ b/bsd-user/openbsd/target_os_thread.h
@@ -0,0 +1,6 @@
+#ifndef _TARGET_OS_THREAD_H_
+#define _TARGET_OS_THREAD_H_
+
+#include "target_arch_thread.h"
+
+#endif /* !_TARGET_OS_THREAD_H_ */
diff --git a/bsd-user/sparc/target_arch_elf.h b/bsd-user/sparc/target_arch_elf.h
new file mode 100644
index 0000000..b93e2ed
--- /dev/null
+++ b/bsd-user/sparc/target_arch_elf.h
@@ -0,0 +1,30 @@
+/*
+ *  sparc ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_SPARC )
+
+#define ELF_CLASS   ELFCLASS32
+#define ELF_DATA    ELFDATA2MSB
+#define ELF_ARCH    EM_SPARC
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/sparc/target_arch_thread.h b/bsd-user/sparc/target_arch_thread.h
new file mode 100644
index 0000000..fe607be
--- /dev/null
+++ b/bsd-user/sparc/target_arch_thread.h
@@ -0,0 +1,39 @@
+/*
+ *  sparc thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUSPARCState *regs,
+    abi_ulong entry, abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    /* XXX */
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    regs->psr = 0;
+    regs->pc = infop->entry;
+    regs->npc = regs->pc + 4;
+    regs->y = 0;
+    regs->u_regs[14] = infop->start_stack - 16 * 4;
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/sparc64/target_arch_elf.h b/bsd-user/sparc64/target_arch_elf.h
new file mode 100644
index 0000000..f2b8e12
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_elf.h
@@ -0,0 +1,34 @@
+/*
+ *  sparc64 ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x80000000
+
+#ifndef TARGET_ABI32
+#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
+#else
+#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
+#endif
+
+#define ELF_CLASS   ELFCLASS64
+#define ELF_DATA    ELFDATA2MSB
+#define ELF_ARCH    EM_SPARCV9
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/sparc64/target_arch_thread.h b/bsd-user/sparc64/target_arch_thread.h
new file mode 100644
index 0000000..2e5585a
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_thread.h
@@ -0,0 +1,55 @@
+/*
+ *  sparc64 thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+#define STACK_BIAS              2047
+
+/* Compare to vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUSPARCState *regs,
+    abi_ulong entry, abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    /* XXX */
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+#ifndef TARGET_ABI32
+    regs->tstate = 0;
+#endif
+    regs->pc = infop->entry;
+    regs->npc = regs->pc + 4;
+    regs->y = 0;
+#ifdef TARGET_ABI32
+    regs->u_regs[14] = infop->start_stack - 16 * 4;
+#else
+    if (personality(infop->personality) == PER_LINUX32)
+        regs->u_regs[14] = infop->start_stack - 16 * 4;
+    else {
+        regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
+        if (bsd_type == target_freebsd) {
+            regs->u_regs[8] = infop->start_stack;
+            regs->u_regs[11] = infop->start_stack;
+        }
+    }
+#endif
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 2d3b658..4646fb1 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -707,4 +707,68 @@ struct target_uuid {
     uint8_t     node[TARGET_UUID_NODE_LEN];
 };
 
+
+/*
+ * from personality.h
+ */
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA
+                                                   space */
+        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs
+                                                   point to descriptors
+                                                   (signal handling) */
+        MMAP_PAGE_ZERO =        0x0100000,
+        ADDR_COMPAT_LAYOUT =    0x0200000,
+        READ_IMPLIES_EXEC =     0x0400000,
+        ADDR_LIMIT_32BIT =      0x0800000,
+        SHORT_INODE =           0x1000000,
+        WHOLE_SECONDS =         0x2000000,
+        STICKY_TIMEOUTS =       0x4000000,
+        ADDR_LIMIT_3GB =        0x8000000,
+};
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+        PER_LINUX =             0x0000,
+        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
+        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
+        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
+                                         WHOLE_SECONDS | SHORT_INODE,
+        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
+        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
+        PER_BSD =               0x0006,
+        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
+        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_LINUX32 =           0x0008,
+        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
+        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
+        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
+        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
+        PER_RISCOS =            0x000c,
+        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
+        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
+        PER_HPUX =              0x0010,
+        PER_MASK =              0x00ff,
+};
+
+/*
+ * Return the base personality without flags.
+ */
+#define personality(pers)       (pers & PER_MASK)
+
 #endif /* ! _SYSCALL_DEFS_H_ */
diff --git a/bsd-user/x86_64/target_arch_elf.h b/bsd-user/x86_64/target_arch_elf.h
new file mode 100644
index 0000000..bc7c6a1
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_elf.h
@@ -0,0 +1,55 @@
+/*
+ *  x86_64 ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x2aaaaab000ULL
+#define elf_check_arch(x) ( ((x) == ELF_ARCH) )
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_DATA       ELFDATA2LSB
+#define ELF_ARCH       EM_X86_64
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+/* XXX */
+#ifndef __FreeBSD__
+#define ELF_PLATFORM target_elf_get_platform()
+
+static const char *target_elf_get_platform(void)
+{
+    static char elf_platform[] = "i386";
+    int family = (thread_env->cpuid_version >> 8) & 0xff;
+    if (family > 6)
+        family = 6;
+    if (family >= 3)
+        elf_platform[1] = '0' + family;
+    return elf_platform;
+}
+
+#define ELF_HWCAP target_elf_get_hwcap()
+
+static uint32_t target_elf_get_hwcap(void)
+{
+    return thread_env->features[FEAT_1_EDX];
+}
+#endif /* ! __FreeBSD__ */
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/x86_64/target_arch_thread.h b/bsd-user/x86_64/target_arch_thread.h
new file mode 100644
index 0000000..d105e43
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_thread.h
@@ -0,0 +1,40 @@
+/*
+ *  x86_64 thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUX86State *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    /* XXX */
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+    struct image_info *infop)
+{
+    regs->rax = 0;
+    regs->rsp = infop->start_stack;
+    regs->rip = infop->entry;
+    if (bsd_type == target_freebsd) {
+        regs->rdi = infop->start_stack;
+    }
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 09/19] bsd-user: add support for freebsd process related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (28 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 08/19] bsd-user: move target arch and host OS dependent code out of elfload.c Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 10/19] bsd-user: add support for file system " Stacey Son
                   ` (9 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change add support or stubs for process related system calls including
fork(2), vfork(2), rfork(2), pdfork(2), execve(2), fexecve(2), wait4(2), exit(2),
getgroups(2), setgroups(2), umask(2), setlogin(2), getlogin(2), getrusage(2),
getrlimit(2), setrlimit(2), getpid(2), getppid(2), getuid(2), geteuid(2),
getgid(2), getegid(2), setuid(2), seteuid(2), setgid(2), setegid(2), getpgrp(2),
setreuid(2), setregid(2), getresuid(2), getresgid(2), getsid(2), setsid(2),
issetugid(2), profil(2), ktrace(2), setloginclass(2), getloginclass(2),
pdgetpid(2), jail*(2), cap_*(2), *audit*(2), utrace(2), ptrace(2), getpriority(2),
and setpriority(2).

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs     |    4 +-
 bsd-user/bsd-proc.c        |  160 ++++++++++++++++
 bsd-user/bsd-proc.h        |  434 ++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-proc.c |  234 ++++++++++++++++++++++++
 bsd-user/freebsd/os-proc.h |  428 +++++++++++++++++++++++++++++++++++++++++++
 bsd-user/netbsd/os-proc.c  |   11 +
 bsd-user/netbsd/os-proc.h  |  243 +++++++++++++++++++++++++
 bsd-user/openbsd/os-proc.c |   11 +
 bsd-user/openbsd/os-proc.h |  243 +++++++++++++++++++++++++
 bsd-user/qemu-bsd.h        |   43 +++++
 bsd-user/qemu.h            |    4 +
 bsd-user/syscall.c         |  262 ++++++++++++++++++++++++++-
 12 files changed, 2069 insertions(+), 8 deletions(-)
 create mode 100644 bsd-user/bsd-proc.c
 create mode 100644 bsd-user/bsd-proc.h
 create mode 100644 bsd-user/freebsd/os-proc.c
 create mode 100644 bsd-user/freebsd/os-proc.h
 create mode 100644 bsd-user/netbsd/os-proc.c
 create mode 100644 bsd-user/netbsd/os-proc.h
 create mode 100644 bsd-user/openbsd/os-proc.c
 create mode 100644 bsd-user/openbsd/os-proc.h
 create mode 100644 bsd-user/qemu-bsd.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index d92961a..6a2fc37 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,3 +1,5 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o $(HOST_ABI_DIR)/os-sys.o \
+	        uaccess.o bsd-proc.o \
+			$(HOST_ABI_DIR)/os-proc.o \
+			$(HOST_ABI_DIR)/os-sys.o \
 			$(HOST_ABI_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/bsd-proc.c b/bsd-user/bsd-proc.c
new file mode 100644
index 0000000..a4bcdc8
--- /dev/null
+++ b/bsd-user/bsd-proc.c
@@ -0,0 +1,160 @@
+/*
+ *  BSD process related system call helpers
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+/*
+ * resource/rusage conversion
+ */
+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_MEMLOCK:
+        return RLIMIT_MEMLOCK;
+
+    case TARGET_RLIMIT_NOFILE:
+        return RLIMIT_NOFILE;
+
+    case TARGET_RLIMIT_NPROC:
+        return RLIMIT_NPROC;
+
+    case TARGET_RLIMIT_RSS:
+        return RLIMIT_RSS;
+
+    case TARGET_RLIMIT_SBSIZE:
+        return RLIMIT_SBSIZE;
+
+    case TARGET_RLIMIT_STACK:
+        return RLIMIT_STACK;
+
+    case TARGET_RLIMIT_SWAP:
+        return RLIMIT_SWAP;
+
+    case TARGET_RLIMIT_NPTS:
+        return RLIMIT_NPTS;
+
+    default:
+        return code;
+    }
+}
+
+rlim_t target_to_host_rlim(abi_ulong target_rlim)
+{
+    abi_ulong target_rlim_swap;
+    rlim_t result;
+
+    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;
+    }
+
+    return result;
+}
+
+abi_ulong host_to_target_rlim(rlim_t rlim)
+{
+    abi_ulong target_rlim_swap;
+    abi_ulong result;
+
+    if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim) {
+        target_rlim_swap = TARGET_RLIM_INFINITY;
+    } else {
+        target_rlim_swap = rlim;
+    }
+    result = tswapal(target_rlim_swap);
+
+    return result;
+}
+
+abi_long host_to_target_rusage(abi_ulong target_addr,
+        const struct rusage *rusage)
+{
+    struct target_freebsd_rusage *target_rusage;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(rusage->ru_utime.tv_sec, &target_rusage->ru_utime.tv_sec);
+    __put_user(rusage->ru_utime.tv_usec, &target_rusage->ru_utime.tv_usec);
+
+    __put_user(rusage->ru_stime.tv_sec, &target_rusage->ru_stime.tv_sec);
+    __put_user(rusage->ru_stime.tv_usec, &target_rusage->ru_stime.tv_usec);
+
+    __put_user(rusage->ru_maxrss, &target_rusage->ru_maxrss);
+    __put_user(rusage->ru_idrss, &target_rusage->ru_idrss);
+    __put_user(rusage->ru_idrss, &target_rusage->ru_idrss);
+    __put_user(rusage->ru_isrss, &target_rusage->ru_isrss);
+    __put_user(rusage->ru_minflt, &target_rusage->ru_minflt);
+    __put_user(rusage->ru_majflt, &target_rusage->ru_majflt);
+    __put_user(rusage->ru_nswap, &target_rusage->ru_nswap);
+    __put_user(rusage->ru_inblock, &target_rusage->ru_inblock);
+    __put_user(rusage->ru_oublock, &target_rusage->ru_oublock);
+    __put_user(rusage->ru_msgsnd, &target_rusage->ru_msgsnd);
+    __put_user(rusage->ru_msgrcv, &target_rusage->ru_msgrcv);
+    __put_user(rusage->ru_nsignals, &target_rusage->ru_nsignals);
+    __put_user(rusage->ru_nvcsw, &target_rusage->ru_nvcsw);
+    __put_user(rusage->ru_nivcsw, &target_rusage->ru_nivcsw);
+    unlock_user_struct(target_rusage, target_addr, 1);
+
+    return 0;
+}
+
+/*
+ * wait status conversion.
+ *
+ * Map host to target signal numbers for the wait family of syscalls.
+ * Assume all other status bits are the same.
+ */
+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;
+}
+
diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h
new file mode 100644
index 0000000..d1c732a
--- /dev/null
+++ b/bsd-user/bsd-proc.h
@@ -0,0 +1,434 @@
+/*
+ *  process related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_PROC_H_
+#define __BSD_PROC_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#include "qemu-bsd.h"
+
+extern int _getlogin(char*, int);
+
+/* exit(2) */
+static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1)
+{
+#ifdef TARGET_GPROF
+    _mcleanup();
+#endif
+    gdb_exit(cpu_env, arg1);
+    /* XXX: should free thread stack and CPU env here  */
+    _exit(arg1);
+
+    return 0;
+}
+
+/* getgroups(2) */
+static inline abi_long do_bsd_getgroups(abi_long gidsetsize, abi_long arg2)
+{
+    abi_long ret;
+    uint32_t *target_grouplist;
+    gid_t *grouplist;
+    int i;
+
+    grouplist = alloca(gidsetsize * sizeof(gid_t));
+    ret = get_errno(getgroups(gidsetsize, grouplist));
+    if (gidsetsize != 0) {
+        if (!is_error(ret)) {
+            target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
+            if (!target_grouplist) {
+                return -TARGET_EFAULT;
+            }
+            for (i = 0; i < ret; i++) {
+                target_grouplist[i] = tswap32(grouplist[i]);
+            }
+            unlock_user(target_grouplist, arg2, gidsetsize * 2);
+        }
+    }
+    return ret;
+}
+
+/* setgroups(2) */
+static inline abi_long do_bsd_setgroups(abi_long gidsetsize, abi_long arg2)
+{
+    uint32_t *target_grouplist;
+    gid_t *grouplist;
+    int i;
+
+    grouplist = alloca(gidsetsize * sizeof(gid_t));
+    target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
+    if (!target_grouplist) {
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < gidsetsize; i++) {
+        grouplist[i] = tswap32(target_grouplist[i]);
+    }
+    unlock_user(target_grouplist, arg2, 0);
+    return get_errno(setgroups(gidsetsize, grouplist));
+}
+
+/* umask(2) */
+static inline abi_long do_bsd_umask(abi_long arg1)
+{
+
+    return get_errno(umask(arg1));
+}
+
+/* setlogin(2) */
+static inline abi_long do_bsd_setlogin(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(setlogin(p));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* getlogin(2) */
+static inline abi_long do_bsd_getlogin(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(_getlogin(p, arg2));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* getrusage(2) */
+static inline abi_long do_bsd_getrusage(abi_long who, abi_ulong target_addr)
+{
+    abi_long ret;
+    struct rusage rusage;
+
+    ret = get_errno(getrusage(who, &rusage));
+    if (!is_error(ret)) {
+        host_to_target_rusage(target_addr, &rusage);
+    }
+    return ret;
+}
+
+/* getrlimit(2) */
+static inline abi_long do_bsd_getrlimit(abi_long arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    int resource = target_to_host_resource(arg1);
+    struct target_rlimit *target_rlim;
+    struct rlimit rlim;
+
+    switch (resource) {
+    case RLIMIT_STACK:
+        rlim.rlim_cur = target_dflssiz;
+        rlim.rlim_max = target_maxssiz;
+        ret = 0;
+        break;
+
+    case RLIMIT_DATA:
+        rlim.rlim_cur = target_dfldsiz;
+        rlim.rlim_max = target_maxdsiz;
+        ret = 0;
+        break;
+
+    default:
+        ret = get_errno(getrlimit(resource, &rlim));
+        break;
+    }
+    if (!is_error(ret)) {
+        if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) {
+            return -TARGET_EFAULT;
+        }
+        target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
+        target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
+        unlock_user_struct(target_rlim, arg2, 1);
+    }
+    return ret;
+}
+
+/* setrlimit(2) */
+static inline abi_long do_bsd_setrlimit(abi_long arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    int resource = target_to_host_resource(arg1);
+    struct target_rlimit *target_rlim;
+    struct rlimit rlim;
+
+    if (RLIMIT_STACK == resource) {
+        /* XXX We should, maybe, allow the stack size to shrink */
+        ret = -TARGET_EPERM;
+    } else {
+        if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) {
+            return -TARGET_EFAULT;
+        }
+        rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
+        rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
+        unlock_user_struct(target_rlim, arg2, 0);
+        ret = get_errno(setrlimit(resource, &rlim));
+    }
+    return ret;
+}
+
+/* getpid(2) */
+static inline abi_long do_bsd_getpid(void)
+{
+
+    return get_errno(getpid());
+}
+
+/* getppid(2) */
+static inline abi_long do_bsd_getppid(void)
+{
+
+    return get_errno(getppid());
+}
+
+/* getuid(2) */
+static inline abi_long do_bsd_getuid(void)
+{
+
+    return get_errno(getuid());
+}
+
+/* geteuid(2) */
+static inline abi_long do_bsd_geteuid(void)
+{
+
+    return get_errno(geteuid());
+}
+
+/* getgid(2) */
+static inline abi_long do_bsd_getgid(void)
+{
+
+    return get_errno(getgid());
+}
+
+/* getegid(2) */
+static inline abi_long do_bsd_getegid(void)
+{
+
+    return get_errno(getegid());
+}
+
+/* setuid(2) */
+static inline abi_long do_bsd_setuid(abi_long arg1)
+{
+
+    return get_errno(setuid(arg1));
+}
+
+/* seteuid(2) */
+static inline abi_long do_bsd_seteuid(abi_long arg1)
+{
+
+    return get_errno(seteuid(arg1));
+}
+
+/* setgid(2) */
+static inline abi_long do_bsd_setgid(abi_long arg1)
+{
+
+    return get_errno(setgid(arg1));
+}
+
+/* setegid(2) */
+static inline abi_long do_bsd_setegid(abi_long arg1)
+{
+
+    return get_errno(setegid(arg1));
+}
+
+/* getpgrp(2) */
+static inline abi_long do_bsd_getpgrp(void)
+{
+
+    return get_errno(getpgrp());
+}
+
+/* setreuid(2) */
+static inline abi_long do_bsd_setreuid(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(setreuid(arg1, arg2));
+}
+
+/* setregid(2) */
+static inline abi_long do_bsd_setregid(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(setregid(arg1, arg2));
+}
+
+/* setresuid(2) */
+static inline abi_long do_bsd_setresuid(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    return get_errno(setresuid(arg1, arg2, arg3));
+}
+
+/* getresuid(2) */
+static inline abi_long do_bsd_getresuid(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    uid_t ruid, euid, suid;
+
+    ret = get_errno(getresuid(&ruid, &euid, &suid));
+    if (is_error(ret)) {
+            return ret;
+    }
+    if (put_user_s32(ruid, arg1)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(euid, arg2)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(suid, arg3)) {
+        return -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+/* getresgid(2) */
+static inline abi_long do_bsd_getresgid(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    uid_t ruid, euid, suid;
+
+    ret = get_errno(getresgid(&ruid, &euid, &suid));
+    if (is_error(ret)) {
+            return ret;
+    }
+    if (put_user_s32(ruid, arg1)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(euid, arg2)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(suid, arg3)) {
+        return -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+/* getsid(2) */
+static inline abi_long do_bsd_getsid(abi_long arg1)
+{
+
+    return get_errno(getsid(arg1));
+}
+
+/* setsid(2) */
+static inline abi_long do_bsd_setsid(void)
+{
+
+    return get_errno(setsid());
+}
+
+/* issetugid(2) */
+static inline abi_long do_bsd_issetugid(void)
+{
+
+    return get_errno(issetugid());
+}
+
+/* profil(2) */
+static inline abi_long do_bsd_profil(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall profil()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* ktrace(2) */
+static inline abi_long do_bsd_ktrace(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall ktrace()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* utrace(2) */
+static inline abi_long do_bsd_utrace(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall ptrace()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* ptrace(2) */
+static inline abi_long do_bsd_ptrace(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall ptrace()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getpriority(2) */
+static inline abi_long do_bsd_getpriority(abi_long which, abi_long who)
+{
+    abi_long ret;
+    /*
+     * Note that negative values are valid for getpriority, so we must
+     * differentiate based on errno settings.
+     */
+    errno = 0;
+    ret = getpriority(which, who);
+    if (ret == -1 && errno != 0) {
+        ret = -host_to_target_errno(errno);
+        return ret;
+    }
+    /* Return value is a biased priority to avoid negative numbers. */
+    ret = 20 - ret;
+
+    return ret;
+}
+
+/* setpriority(2) */
+static inline abi_long do_bsd_setpriority(abi_long which, abi_long who,
+        abi_long prio)
+{
+
+    return get_errno(setpriority(which, who, prio));
+}
+
+
+#endif /* !__BSD_PROC_H_ */
+
diff --git a/bsd-user/freebsd/os-proc.c b/bsd-user/freebsd/os-proc.c
new file mode 100644
index 0000000..b696222
--- /dev/null
+++ b/bsd-user/freebsd/os-proc.c
@@ -0,0 +1,234 @@
+/*
+ *  FreeBSD process related emulation code
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#include <libprocstat.h>
+#endif
+
+#include "qemu.h"
+
+/*
+ * Get the filename for the given file descriptor.
+ * Note that this may return NULL (fail) if no longer cached in the kernel.
+ */
+static char *
+get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len)
+{
+    char *ret = NULL;
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+    unsigned int cnt;
+    struct procstat *procstat = NULL;
+    struct kinfo_proc *kipp = NULL;
+    struct filestat_list *head = NULL;
+    struct filestat *fst;
+
+    procstat = procstat_open_sysctl();
+    if (NULL == procstat) {
+        goto out;
+    }
+
+    kipp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt);
+    if (NULL == kipp) {
+        goto out;
+    }
+
+    head = procstat_getfiles(procstat, kipp, 0);
+    if (NULL == head) {
+        goto out;
+    }
+
+    STAILQ_FOREACH(fst, head, next) {
+        if (fd == fst->fs_fd) {
+            if (fst->fs_path != NULL) {
+                (void)strlcpy(filename, fst->fs_path, len);
+                ret = filename;
+            }
+            break;
+        }
+    }
+
+out:
+    if (head != NULL) {
+        procstat_freefiles(procstat, head);
+    }
+    if (kipp != NULL) {
+        procstat_freeprocs(procstat, kipp);
+    }
+    if (procstat != NULL) {
+        procstat_close(procstat);
+    }
+#endif
+    return ret;
+}
+
+/*
+ * execve/fexecve
+ */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec)
+{
+    char **argp, **envp, **qargp, **qarg1;
+    int argc, envc;
+    abi_ulong gp;
+    abi_ulong addr;
+    char **q;
+    int total_size = 0;
+    void *p;
+    abi_long ret;
+
+    argc = 0;
+    for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
+        if (get_user_ual(addr, gp)) {
+            return -TARGET_EFAULT;
+        }
+        if (!addr) {
+            break;
+        }
+        argc++;
+    }
+    envc = 0;
+    for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
+        if (get_user_ual(addr, gp)) {
+            return -TARGET_EFAULT;
+        }
+        if (!addr) {
+            break;
+        }
+        envc++;
+    }
+
+    qargp = argp =  alloca((argc + 3) * sizeof(void *));
+    /* save the first agrument for the emulator */
+    *argp++ = (char *)getprogname();
+    qarg1 = argp;
+    envp = alloca((envc + 1) * sizeof(void *));
+    for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp)) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+        if (!addr) {
+            break;
+        }
+        *q = lock_user_string(addr);
+        if (*q == NULL) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+        total_size += strlen(*q) + 1;
+    }
+    *q = NULL;
+
+    for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp)) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+        if (!addr) {
+            break;
+        }
+        *q = lock_user_string(addr);
+        if (*q == NULL) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+        total_size += strlen(*q) + 1;
+    }
+    *q = NULL;
+
+    /*
+     * 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;
+    }
+
+    if (do_fexec) {
+        if (((int)path_or_fd > 0 &&
+            is_target_elf_binary((int)path_or_fd)) == 1) {
+            char execpath[PATH_MAX];
+
+            /*
+             * The executable is an elf binary for the target
+             * arch.  execve() it using the emulator if we can
+             * determine the filename path from the fd.
+             */
+            if (get_filename_from_fd(getpid(), (int)path_or_fd, execpath,
+                        sizeof(execpath)) != NULL) {
+                *qarg1 = execpath;
+                ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
+            } else {
+                /* Getting the filename path failed. */
+                ret = -TARGET_EBADF;
+                goto execve_end;
+            }
+        } else {
+            ret = get_errno(fexecve((int)path_or_fd, argp, envp));
+        }
+    } else {
+        int fd;
+
+        p = lock_user_string(path_or_fd);
+        if (p == NULL) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+
+        /*
+         * Check the header and see if it a target elf binary.  If so
+         * then execute using qemu user mode emulator.
+         */
+        fd = open(p, O_RDONLY | O_CLOEXEC);
+        if (fd > 0 && is_target_elf_binary(fd) == 1) {
+            close(fd);
+            /* Execve() as a target binary using emulator. */
+            *qarg1 = (char *)p;
+            ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
+        } else {
+            close(fd);
+            /* Execve() as a host native binary. */
+            ret = get_errno(execve(p, argp, envp));
+        }
+        unlock_user(p, path_or_fd, 0);
+    }
+
+execve_end:
+    for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp) || !addr) {
+            break;
+        }
+        unlock_user(*q, addr, 0);
+    }
+
+    for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp) || !addr) {
+            break;
+        }
+        unlock_user(*q, addr, 0);
+    }
+    return ret;
+}
+
+
diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h
new file mode 100644
index 0000000..b31f7c4
--- /dev/null
+++ b/bsd-user/freebsd/os-proc.h
@@ -0,0 +1,428 @@
+/*
+ *  process related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_PROC_H_
+#define __FREEBSD_PROC_H_
+
+#include <sys/types.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#include <sys/procdesc.h>
+#endif
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "target_arch_cpu.h"
+
+extern int __setugid(int flag);
+extern int pdwait4(int fd, int *status, int options, struct rusage *rusage);
+
+/* execve(2) */
+static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    return freebsd_exec_common(path_or_fd, argp, envp, 0);
+}
+
+/* fexecve(2) */
+static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    return freebsd_exec_common(path_or_fd, argp, envp, 1);
+}
+
+/* wait4(2) */
+static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
+        abi_long arg3, abi_ulong target_rusage)
+{
+    abi_long ret;
+    int status;
+    struct rusage rusage, *rusage_ptr = NULL;
+
+    if (target_rusage) {
+        rusage_ptr = &rusage;
+    }
+    ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
+    if (!is_error(ret)) {
+        status = host_to_target_waitstatus(status);
+        if (put_user_s32(status, target_status) != 0) {
+            return -TARGET_EFAULT;
+        }
+        if (target_rusage != 0) {
+            host_to_target_rusage(target_rusage, &rusage);
+        }
+    }
+    return ret;
+}
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(setloginclass(p));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(getloginclass(p, arg2));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+    abi_long ret;
+    int status;
+    struct rusage rusage, *rusage_ptr = NULL;
+
+    if (target_rusage) {
+        rusage_ptr = &rusage;
+    }
+    ret = get_errno(pdwait4(arg1, &status, arg3, rusage_ptr));
+    if (!is_error(ret)) {
+        status = host_to_target_waitstatus(status);
+        if (put_user_s32(status, target_status) != 0) {
+            return -TARGET_EFAULT;
+        }
+        if (target_rusage != 0) {
+            host_to_target_rusage(target_rusage, &rusage);
+        }
+    }
+    return ret;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+    abi_long ret;
+    pid_t pid;
+
+    ret = get_errno(pdgetpid(fd, &pid));
+    if (!is_error(ret)) {
+        if (put_user_u32(pid, target_pidp)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+#else
+
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall pdwait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+
+    qemu_log("qemu: Unsupported syscall pdgetpid()\n");
+    return -TARGET_ENOSYS;
+}
+#endif /* !  __FreeBSD_version > 900000 */
+
+/* undocumented __setugid */
+static inline abi_long do_freebsd___setugid(abi_long arg1)
+{
+
+    return get_errno(__setugid(arg1));
+}
+
+/* fork(2) */
+static inline abi_long do_freebsd_fork(void *cpu_env)
+{
+    abi_long ret;
+    abi_ulong child_flag = 0;
+
+    fork_start();
+    ret = fork();
+    if (ret == 0) {
+        /* child */
+        child_flag = 1;
+        target_cpu_clone_regs(cpu_env, 0);
+    } else {
+        /* parent */
+        fork_end(0);
+    }
+
+    /*
+     * The fork system call sets a child flag in the second return
+     * value: 0 for parent process, 1 for child process.
+     */
+    set_second_rval(cpu_env, child_flag);
+
+    return ret;
+}
+
+/* vfork(2) */
+static inline abi_long do_freebsd_vfork(void *cpu_env)
+{
+
+    return do_freebsd_fork(cpu_env);
+}
+
+/* rfork(2) */
+static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+{
+    abi_long ret;
+    abi_ulong child_flag = 0;
+
+    fork_start();
+    ret = rfork(flags);
+    if (ret == 0) {
+        /* child */
+        child_flag = 1;
+        target_cpu_clone_regs(cpu_env, 0);
+    } else {
+        /* parent */
+        fork_end(0);
+    }
+
+    /*
+     * The fork system call sets a child flag in the second return
+     * value: 0 for parent process, 1 for child process.
+     */
+    set_second_rval(cpu_env, child_flag);
+
+    return ret;
+
+}
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp,
+        abi_long flags)
+{
+    abi_long ret;
+    abi_ulong child_flag = 0;
+    int fd;
+
+    fork_start();
+    ret = pdfork(&fd, flags);
+    if (ret == 0) {
+        /* child */
+        child_flag = 1;
+        target_cpu_clone_regs(cpu_env, 0);
+    } else {
+        /* parent */
+        fork_end(0);
+    }
+    if (put_user_s32(fd, target_fdp)) {
+        return -TARGET_EFAULT;
+    }
+
+    /*
+     * The fork system call sets a child flag in the second return
+     * value: 0 for parent process, 1 for child process.
+     */
+    set_second_rval(cpu_env, child_flag);
+
+    return ret;
+}
+
+#else
+
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* __FreeBSD_version > 900000 */
+
+/* jail(2) */
+static inline abi_long do_freebsd_jail(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_attach(2) */
+static inline abi_long do_freebsd_jail_attach(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_attach()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_remove(2) */
+static inline abi_long do_freebsd_jail_remove(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_remove()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_get(2) */
+static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_get()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_set(2) */
+static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_set()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_enter(2) */
+static inline abi_long do_freebsd_cap_enter(void)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_enter()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_new(2) */
+static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getrights(2) */
+static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getrights()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getmode(2) */
+static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getmode()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* audit(2) */
+static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall audit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditon(2) */
+static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall auditon()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit(2) */
+static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit(2) */
+static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit_addr(2) */
+static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit_addr(2) */
+static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditctl(2) */
+static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall auditctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __FREEBSD_PROC_H_ */
diff --git a/bsd-user/netbsd/os-proc.c b/bsd-user/netbsd/os-proc.c
new file mode 100644
index 0000000..bc11d29
--- /dev/null
+++ b/bsd-user/netbsd/os-proc.c
@@ -0,0 +1,11 @@
+/*
+ * XXX To support FreeBSD binaries on NetBSD the following will need to be
+ * emulated.
+ */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec)
+{
+
+    qemu_log("qemu: Unsupported %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/netbsd/os-proc.h b/bsd-user/netbsd/os-proc.h
new file mode 100644
index 0000000..f34d616
--- /dev/null
+++ b/bsd-user/netbsd/os-proc.h
@@ -0,0 +1,243 @@
+#ifndef __NETBSD_PROC_H_
+#define __NETBSD_PROC_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* execve(2) */
+static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall execve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fexecve(2) */
+static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall fexecve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* wait4(2) */
+static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
+        abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall wait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall pdwait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+
+    qemu_log("qemu: Unsupported syscall pdgetpid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocumented __setugid */
+static inline abi_long do_freebsd___setugid(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall __setugid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fork(2) */
+static inline abi_long do_freebsd_fork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall fork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* vfork(2) */
+static inline abi_long do_freebsd_vfork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall vfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rfork(2) */
+static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall rfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdfork()\n");
+    return -TARGET_ENOSYS
+}
+
+/* jail(2) */
+static inline abi_long do_freebsd_jail(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_attach(2) */
+static inline abi_long do_freebsd_jail_attach(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_attach()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_remove(2) */
+static inline abi_long do_freebsd_jail_remove(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_remove()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_get(2) */
+static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_get()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_set(2) */
+static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_set()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_enter(2) */
+static inline abi_long do_freebsd_cap_enter(void)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_enter()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_new(2) */
+static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getrights(2) */
+static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getrights()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getmode(2) */
+static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getmode()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* audit(2) */
+static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall audit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditon(2) */
+static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall auditon()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit(2) */
+static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit(2) */
+static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit_addr(2) */
+static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit_addr(2) */
+static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditctl(2) */
+static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall auditctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __NETBSD_PROC_H_ */
diff --git a/bsd-user/openbsd/os-proc.c b/bsd-user/openbsd/os-proc.c
new file mode 100644
index 0000000..bc11d29
--- /dev/null
+++ b/bsd-user/openbsd/os-proc.c
@@ -0,0 +1,11 @@
+/*
+ * XXX To support FreeBSD binaries on NetBSD the following will need to be
+ * emulated.
+ */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec)
+{
+
+    qemu_log("qemu: Unsupported %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/openbsd/os-proc.h b/bsd-user/openbsd/os-proc.h
new file mode 100644
index 0000000..9cce719
--- /dev/null
+++ b/bsd-user/openbsd/os-proc.h
@@ -0,0 +1,243 @@
+#ifndef __OPENBSD_PROC_H_
+#define __OPENBSD_PROC_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* execve(2) */
+static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall execve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fexecve(2) */
+static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall fexecve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* wait4(2) */
+static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
+        abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall wait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall pdwait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+
+    qemu_log("qemu: Unsupported syscall pdgetpid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocumented __setugid */
+static inline abi_long do_freebsd___setugid(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall __setugid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fork(2) */
+static inline abi_long do_freebsd_fork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall fork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* vfork(2) */
+static inline abi_long do_freebsd_vfork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall vfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rfork(2) */
+static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall rfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdfork()\n");
+    return -TARGET_ENOSYS
+}
+
+/* jail(2) */
+static inline abi_long do_freebsd_jail(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_attach(2) */
+static inline abi_long do_freebsd_jail_attach(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_attach()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_remove(2) */
+static inline abi_long do_freebsd_jail_remove(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_remove()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_get(2) */
+static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_get()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_set(2) */
+static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_set()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_enter(2) */
+static inline abi_long do_freebsd_cap_enter(void)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_enter()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_new(2) */
+static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
+{
+
+        qemu_log("qemu: Unsupported syscall cap_new()\n");
+            return -TARGET_ENOSYS;
+}
+
+/* cap_getrights(2) */
+static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
+{
+
+        qemu_log("qemu: Unsupported syscall cap_getrights()\n");
+            return -TARGET_ENOSYS;
+}
+
+/* cap_getmode(2) */
+static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getmode()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* audit(2) */
+static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall audit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditon(2) */
+static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall auditon()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit(2) */
+static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit(2) */
+static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit_addr(2) */
+static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit_addr(2) */
+static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditctl(2) */
+static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall auditctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_PROC_H_ */
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
new file mode 100644
index 0000000..590c36b
--- /dev/null
+++ b/bsd-user/qemu-bsd.h
@@ -0,0 +1,43 @@
+/*
+ *  BSD conversion extern declarations
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _QEMU_BSD_H_
+#define _QEMU_BSD_H_
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/resource.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uuid.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+
+/* bsd-proc.c */
+int target_to_host_resource(int code);
+rlim_t target_to_host_rlim(abi_ulong target_rlim);
+abi_ulong host_to_target_rlim(rlim_t rlim);
+abi_long host_to_target_rusage(abi_ulong target_addr,
+        const struct rusage *rusage);
+int host_to_target_waitstatus(int status);
+
+#endif /* !_QEMU_BSD_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 0e332af..a9f5666 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -248,6 +248,10 @@ extern char qemu_proc_pathname[];
 abi_long get_errno(abi_long ret);
 int is_error(abi_long ret);
 
+/* os-proc.c */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec);
+
 /* os-sys.c */
 abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
         abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen);
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index bc4a7e4..f8a40f0 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -38,12 +38,15 @@
 #include "qemu-common.h"
 
 #define target_to_host_bitmask(x, tbl) (x)
+static int host_to_target_errno(int err);
 
 /* BSD independent syscall shims */
+#include "bsd-proc.h"
 #include "bsd-signal.h"
 
 /* *BSD dependent syscall shims */
 #include "os-time.h"
+#include "os-proc.h"
 #include "os-signal.h"
 
 /* #define DEBUG */
@@ -63,6 +66,12 @@ abi_long get_errno(abi_long ret)
         return ret;
 }
 
+static int host_to_target_errno(int err)
+{
+    /* XXX need to translate host errnos here */
+    return err;
+}
+
 int is_error(abi_long ret)
 {
     return (abi_ulong)ret >= (abi_ulong)(-4096);
@@ -176,15 +185,254 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
 
     switch(num) {
-    case TARGET_FREEBSD_NR_exit:
-#ifdef TARGET_GPROF
-        _mcleanup();
+        /*
+         * process system calls
+         */
+    case TARGET_FREEBSD_NR_fork: /* fork(2) */
+        ret = do_freebsd_fork(cpu_env);
+        break;
+
+    case TARGET_FREEBSD_NR_vfork: /* vfork(2) */
+        ret = do_freebsd_vfork(cpu_env);
+        break;
+
+    case TARGET_FREEBSD_NR_rfork: /* rfork(2) */
+        ret = do_freebsd_rfork(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_pdfork: /* pdfork(2) */
+        ret = do_freebsd_pdfork(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_execve: /* execve(2) */
+        ret = do_freebsd_execve(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_fexecve: /* fexecve(2) */
+        ret = do_freebsd_fexecve(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_wait4: /* wait4(2) */
+        ret = do_freebsd_wait4(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_exit: /* exit(2) */
+        ret = do_bsd_exit(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getgroups: /* getgroups(2) */
+        ret = do_bsd_getgroups(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setgroups: /* setgroups(2) */
+        ret = do_bsd_setgroups(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_umask: /* umask(2) */
+        ret = do_bsd_umask(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setlogin: /* setlogin(2) */
+        ret = do_bsd_setlogin(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getlogin: /* getlogin(2) */
+        ret = do_bsd_getlogin(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getrusage: /* getrusage(2) */
+        ret = do_bsd_getrusage(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getrlimit: /* getrlimit(2) */
+        ret = do_bsd_getrlimit(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setrlimit: /* setrlimit(2) */
+        ret = do_bsd_setrlimit(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getpid: /* getpid(2) */
+        ret = do_bsd_getpid();
+        break;
+
+    case TARGET_FREEBSD_NR_getppid: /* getppid(2) */
+        ret = do_bsd_getppid();
+        break;
+
+    case TARGET_FREEBSD_NR_getuid: /* getuid(2) */
+        ret = do_bsd_getuid();
+        break;
+
+    case TARGET_FREEBSD_NR_geteuid: /* geteuid(2) */
+        ret = do_bsd_geteuid();
+        break;
+
+    case TARGET_FREEBSD_NR_getgid: /* getgid(2) */
+        ret = do_bsd_getgid();
+        break;
+
+    case TARGET_FREEBSD_NR_getegid: /* getegid(2) */
+        ret = do_bsd_getegid();
+        break;
+
+    case TARGET_FREEBSD_NR_setuid: /* setuid(2) */
+        ret = do_bsd_setuid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_seteuid: /* seteuid(2) */
+        ret = do_bsd_seteuid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setgid: /* setgid(2) */
+        ret = do_bsd_setgid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setegid: /* setegid(2) */
+        ret = do_bsd_setegid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getpgrp: /* getpgrp(2) */
+        ret = do_bsd_getpgrp();
+        break;
+
+    case TARGET_FREEBSD_NR_setreuid: /* setreuid(2) */
+        ret = do_bsd_setreuid(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setregid: /* setregid(2) */
+        ret = do_bsd_setregid(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getresuid: /* getresuid(2) */
+        ret = do_bsd_getresuid(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getresgid: /* getresgid(2) */
+        ret = do_bsd_getresgid(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getsid: /* getsid(2) */
+        ret = do_bsd_getsid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setsid: /* setsid(2) */
+        ret = do_bsd_setsid();
+        break;
+
+    case TARGET_FREEBSD_NR_issetugid: /* issetugid(2) */
+        ret = do_bsd_issetugid();
+        break;
+
+    case TARGET_FREEBSD_NR_profil: /* profil(2) */
+        ret = do_bsd_profil(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ktrace: /* ktrace(2) */
+        ret = do_bsd_ktrace(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_setloginclass: /* setloginclass(2) */
+        ret = do_freebsd_setloginclass(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getloginclass: /* getloginclass(2) */
+        ret = do_freebsd_getloginclass(arg1, arg2);
+        break;
+#if 0
+    case TARGET_FREEBSD_NR_pdwait4: /* pdwait4(2) */
+        ret = do_freebsd_pdwait4(arg1, arg2, arg3, arg4);
+        break;
 #endif
-        gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
-        _exit(arg1);
-        ret = 0; /* avoid warning */
+
+    case TARGET_FREEBSD_NR_pdgetpid: /* pdgetpid(2) */
+        ret = do_freebsd_pdgetpid(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___setugid: /* undocumented */
+        ret = do_freebsd___setugid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail: /* jail(2) */
+        ret = do_freebsd_jail(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_attach: /* jail_attach(2) */
+        ret = do_freebsd_jail_attach(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_remove: /* jail_remove(2) */
+        ret = do_freebsd_jail_remove(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_get: /* jail_get(2) */
+        ret = do_freebsd_jail_get(arg1, arg2, arg3);
         break;
+
+    case TARGET_FREEBSD_NR_jail_set: /* jail_set(2) */
+        ret = do_freebsd_jail_set(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_cap_enter: /* cap_enter(2) */
+        ret = do_freebsd_cap_enter();
+        break;
+
+    case TARGET_FREEBSD_NR_cap_new: /* cap_new(2) */
+        ret = do_freebsd_cap_new(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_cap_getrights: /* cap_getrights(2) */
+        ret = do_freebsd_cap_getrights(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_cap_getmode: /* cap_getmode(2) */
+        ret = do_freebsd_cap_getmode(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_audit: /* audit(2) */
+        ret = do_freebsd_audit(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_auditon: /* auditon(2) */
+        ret = do_freebsd_auditon(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getaudit: /* getaudit(2) */
+        ret = do_freebsd_getaudit(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setaudit: /* setaudit(2) */
+        ret = do_freebsd_setaudit(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getaudit_addr: /* getaudit_addr(2) */
+        ret = do_freebsd_getaudit_addr(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setaudit_addr: /* setaudit_addr(2) */
+        ret = do_freebsd_setaudit_addr(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_auditctl: /* auditctl(2) */
+        ret = do_freebsd_auditctl(arg1);
+        break;
+    case TARGET_FREEBSD_NR_utrace: /* utrace(2) */
+        ret = do_bsd_utrace(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_ptrace: /* ptrace(2) */
+        ret = do_bsd_ptrace(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_getpriority: /* getpriority(2) */
+        ret = do_bsd_getpriority(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setpriority: /* setpriority(2) */
+        ret = do_bsd_setpriority(arg1, arg2, arg3);
+        break;
+
+
     case TARGET_FREEBSD_NR_read:
         if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
             goto efault;
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 10/19] bsd-user: add support for file system related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (29 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 09/19] bsd-user: add support for freebsd process related system calls Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 11/19] bsd-user: add support for stat, directory, and file control " Stacey Son
                   ` (8 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for file system (except stat) related system
calls including read(2), pread(2), readv(2), write(2), pwrite(2), writev(2),
pwritev(2),  open(2), openat(2), close(2), closefrom(2), revoke(2), access(2),
eaccess(2), faccessat(2), chdir(2), fchdir(2), rename(2), renameat(2), link(2),
linkat(2), unlink(2), unlinkat(2), mkdir(2), mkdirat(2), rmdir(2), __getcwd(),
dup(2), dup2(2), truncate(2), ftruncate(2), acct(2), sync(2), mount(2), nmount(2),
symlink(2), symlinkat(2), readlink(2), readlinkat(2), chmod(2), fchmod(2),
lchmod(2), fchmodat(2), mknod(2), mknodat(2), chown(2), fchown(2), lchown(2),
fchownat(2), chflags(2), lchflags(2), fchflags(2), chroot(2), flock(2), mkfifo(2),
mkfifoat(2), pathconf(2), lpathconf(2), fpathconf(2), undelete(2), poll(2),
lseek(2), pipe(2), swapon(2), swapoff(2), and the undocumented openbsd_poll()
and freebsd6_*() system calls.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/bsd-file.h | 1111 +++++++++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/qemu.h     |   36 ++
 bsd-user/syscall.c  |  391 ++++++++++++++----
 3 files changed, 1454 insertions(+), 84 deletions(-)
 create mode 100644 bsd-user/bsd-file.h

diff --git a/bsd-user/bsd-file.h b/bsd-user/bsd-file.h
new file mode 100644
index 0000000..fc279a8
--- /dev/null
+++ b/bsd-user/bsd-file.h
@@ -0,0 +1,1111 @@
+/*
+ *  file related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_FILE_H_
+#define __BSD_FILE_H_
+
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define target_to_host_bitmask(x, tbl) (x)
+
+#define LOCK_PATH(p, arg)  do {             \
+    (p) =  lock_user_string(arg);           \
+    if ((p) == NULL) {                      \
+        return -TARGET_EFAULT;              \
+    }                                       \
+} while (0)
+
+#define UNLOCK_PATH(p, arg)   unlock_user((p), (arg), 0)
+
+struct target_pollfd {
+    int32_t fd;         /* file descriptor */
+    int16_t events;     /* requested events */
+    int16_t revents;    /* returned events */
+};
+
+static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
+        int count, int copy);
+static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
+        int count, int copy);
+extern int __getcwd(char *path, size_t len);
+
+/* read(2) */
+static inline abi_long do_bsd_read(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(read(arg1, p, arg3));
+    unlock_user(p, arg2, ret);
+
+    return ret;
+}
+
+/* pread(2) */
+static inline abi_long do_bsd_pread(void *cpu_env, abi_long arg1,
+    abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg4 = arg5;
+        arg5 = arg6;
+    }
+    ret = get_errno(pread(arg1, p, arg3, target_offset64(arg4, arg5)));
+    unlock_user(p, arg2, ret);
+
+    return ret;
+}
+
+/* readv(2) */
+static inline abi_long do_bsd_readv(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    int count = arg3;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (vec == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(readv(arg1, vec, count));
+    unlock_iovec(vec, arg2, count, 1);
+
+    return ret;
+}
+
+/* write(2) */
+static inline abi_long do_bsd_write(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_READ, arg2, arg3, 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(write(arg1, p, arg3));
+    unlock_user(p, arg2, 0);
+
+    return ret;
+}
+
+/* pwrite(2) */
+static inline abi_long do_bsd_pwrite(void *cpu_env, abi_long arg1,
+    abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_READ, arg2, arg3, 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg4 = arg5;
+        arg5 = arg6;
+    }
+    ret = get_errno(pwrite(arg1, p, arg3, target_offset64(arg4, arg5)));
+    unlock_user(p, arg2, 0);
+
+    return ret;
+}
+
+/* writev(2) */
+static inline abi_long do_bsd_writev(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    int count = arg3;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (vec == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(writev(arg1, vec, count));
+    unlock_iovec(vec, arg2, count, 0);
+
+    return ret;
+}
+
+/* pwritev(2) */
+static inline abi_long do_bsd_pwritev(void *cpu_env, abi_long arg1,
+    abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    int count = arg3;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (vec == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) {
+        return -TARGET_EFAULT;
+    }
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg4 = arg5;
+        arg5 = arg6;
+    }
+    ret = get_errno(pwritev(arg1, vec, count, target_offset64(arg4, arg5)));
+    unlock_iovec(vec, arg2, count, 0);
+
+    return ret;
+}
+
+/* open(2) */
+static inline abi_long do_bsd_open(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(open(path(p), target_to_host_bitmask(arg2, fcntl_flags_tbl),
+                arg3));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* openat(2) */
+static inline abi_long do_bsd_openat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(openat(arg1, path(p),
+                target_to_host_bitmask(arg3, fcntl_flags_tbl), arg4));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* close(2) */
+static inline abi_long do_bsd_close(abi_long arg1)
+{
+
+    return get_errno(close(arg1));
+}
+
+/* closefrom(2) */
+static inline abi_long do_bsd_closefrom(abi_long arg1)
+{
+
+    closefrom(arg1);  /* returns void */
+    return get_errno(0);
+}
+
+/* revoke(2) */
+static inline abi_long do_bsd_revoke(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(revoke(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* creat(2) (obsolete) */
+static inline abi_long do_bsd_creat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(open(path(p), O_CREAT | O_TRUNC | O_WRONLY, arg2));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+
+/* access(2) */
+static inline abi_long do_bsd_access(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(access(path(p), arg2));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* eaccess(2) */
+static inline abi_long do_bsd_eaccess(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(eaccess(path(p), arg2));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* faccessat(2) */
+static inline abi_long do_bsd_faccessat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(faccessat(arg1, p, arg3, arg4)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* chdir(2) */
+static inline abi_long do_bsd_chdir(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chdir(p)); /* XXX  path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchdir(2) */
+static inline abi_long do_bsd_fchdir(abi_long arg1)
+{
+
+    return get_errno(fchdir(arg1));
+}
+
+/* rename(2) */
+static inline abi_long do_bsd_rename(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(rename(p1, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* renameat(2) */
+static inline abi_long do_bsd_renameat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(renameat(arg1, p1, arg3, p2));
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* link(2) */
+static inline abi_long do_bsd_link(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(link(p1, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* linkat(2) */
+static inline abi_long do_bsd_linkat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg2);
+    LOCK_PATH(p2, arg4);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(linkat(arg1, p1, arg3, p2, arg5));
+    }
+    UNLOCK_PATH(p2, arg4);
+    UNLOCK_PATH(p1, arg2);
+
+    return ret;
+}
+
+/* unlink(2) */
+static inline abi_long do_bsd_unlink(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(unlink(p)); /* XXX path(p) */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* unlinkat(2) */
+static inline abi_long do_bsd_unlinkat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(unlinkat(arg1, p, arg3)); /* XXX path(p) */
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* mkdir(2) */
+static inline abi_long do_bsd_mkdir(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(mkdir(p, arg2)); /* XXX path(p) */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+
+/* mkdirat(2) */
+static inline abi_long do_bsd_mkdirat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(mkdirat(arg1, p, arg3));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+
+/* rmdir(2) */
+static inline abi_long do_bsd_rmdir(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(rmdir(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* undocumented __getcwd(char *buf, size_t len)  system call */
+static inline abi_long do_bsd___getcwd(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__getcwd(p, arg2));
+    unlock_user(p, arg1, ret);
+
+    return ret;
+}
+
+/* dup(2) */
+static inline abi_long do_bsd_dup(abi_long arg1)
+{
+
+    return get_errno(dup(arg1));
+}
+
+/* dup2(2) */
+static inline abi_long do_bsd_dup2(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(dup2(arg1, arg2));
+}
+
+/* truncate(2) */
+static inline abi_long do_bsd_truncate(void *cpu_env, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg2 = arg3;
+        arg3 = arg4;
+    }
+    ret = get_errno(truncate(p, target_offset64(arg2, arg3)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* ftruncate(2) */
+static inline abi_long do_bsd_ftruncate(void *cpu_env, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4)
+{
+
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg2 = arg3;
+        arg3 = arg4;
+    }
+    return get_errno(ftruncate(arg1, target_offset64(arg2, arg3)));
+}
+
+/* acct(2) */
+static inline abi_long do_bsd_acct(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    if (arg1 == 0) {
+        ret = get_errno(acct(NULL));
+    } else {
+        LOCK_PATH(p, arg1);
+        ret = get_errno(acct(path(p)));
+        UNLOCK_PATH(p, arg1);
+    }
+    return ret;
+}
+
+/* sync(2) */
+static inline abi_long do_bsd_sync(void)
+{
+
+    sync();
+    return 0;
+}
+
+/* mount(2) */
+static inline abi_long do_bsd_mount(abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        /*
+         * XXX arg4 should be locked, but it isn't clear how to do that
+         * since it's it may be not be a NULL-terminated string.
+         */
+        if (arg4 == 0) {
+            ret = get_errno(mount(p1, p2, arg3, NULL)); /* XXX path(p2)? */
+        } else {
+            ret = get_errno(mount(p1, p2, arg3, g2h(arg4))); /* XXX path(p2)? */
+        }
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* unmount(2) */
+static inline abi_long do_bsd_unmount(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(unmount(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* nmount(2) */
+static inline abi_long do_bsd_nmount(abi_long arg1, abi_long count,
+        abi_long flags)
+{
+    abi_long ret;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (lock_iovec(VERIFY_READ, vec, arg1, count, 1) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(nmount(vec, count, flags));
+    unlock_iovec(vec, arg1, count, 0);
+
+    return ret;
+}
+
+/* symlink(2) */
+static inline abi_long do_bsd_symlink(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(symlink(p1, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* symlinkat(2) */
+static inline abi_long do_bsd_symlinkat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg3);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(symlinkat(p1, arg2, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg3);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* readlink(2) */
+static inline abi_long do_bsd_readlink(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(readlink(path(p1), p2, arg3));
+    }
+    unlock_user(p2, arg2, ret);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* readlinkat(2) */
+static inline abi_long do_bsd_readlinkat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg2);
+    p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(readlinkat(arg1, p1, p2, arg4));
+    }
+    unlock_user(p2, arg3, ret);
+    UNLOCK_PATH(p1, arg2);
+
+    return ret;
+}
+
+/* chmod(2) */
+static inline abi_long do_bsd_chmod(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chmod(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchmod(2) */
+static inline abi_long do_bsd_fchmod(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(fchmod(arg1, arg2));
+}
+
+/* lchmod(2) */
+static inline abi_long do_bsd_lchmod(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lchmod(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchmodat(2) */
+static inline abi_long do_bsd_fchmodat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(fchmodat(arg1, p, arg3, arg4));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* mknod(2) */
+static inline abi_long do_bsd_mknod(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(mknod(p, arg2, arg3)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* mknodat(2) */
+static inline abi_long do_bsd_mknodat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(mknodat(arg1, p, arg3, arg4));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* chown(2) */
+static inline abi_long do_bsd_chown(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chown(p, arg2, arg3)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchown(2) */
+static inline abi_long do_bsd_fchown(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    return get_errno(fchown(arg1, arg2, arg3));
+}
+
+/* lchown(2) */
+static inline abi_long do_bsd_lchown(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lchown(p, arg2, arg3)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchownat(2) */
+static inline abi_long do_bsd_fchownat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(fchownat(arg1, p, arg3, arg4, arg5)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* chflags(2) */
+static inline abi_long do_bsd_chflags(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chflags(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* lchflags(2) */
+static inline abi_long do_bsd_lchflags(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lchflags(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchflags(2) */
+static inline abi_long do_bsd_fchflags(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(fchflags(arg1, arg2));
+}
+
+/* chroot(2) */
+static inline abi_long do_bsd_chroot(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chroot(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* flock(2) */
+static abi_long do_bsd_flock(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(flock(arg1, arg2));
+}
+
+/* mkfifo(2) */
+static inline abi_long do_bsd_mkfifo(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(mkfifo(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* mkfifoat(2) */
+static inline abi_long do_bsd_mkfifoat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(mkfifoat(arg1, p, arg3));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* pathconf(2) */
+static inline abi_long do_bsd_pathconf(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(pathconf(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* lpathconf(2) */
+static inline abi_long do_bsd_lpathconf(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lpathconf(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fpathconf(2) */
+static inline abi_long do_bsd_fpathconf(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(fpathconf(arg1, arg2));
+}
+
+/* undelete(2) */
+static inline abi_long do_bsd_undelete(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(undelete(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* poll(2) */
+static abi_long do_bsd_poll(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    nfds_t i, nfds = arg2;
+    int timeout = arg3;
+    struct pollfd *pfd;
+    struct target_pollfd *target_pfd;
+
+    target_pfd = lock_user(VERIFY_WRITE, arg1,
+            sizeof(struct target_pollfd) * nfds, 1);
+    if (!target_pfd) {
+        return -TARGET_EFAULT;
+    }
+    pfd = alloca(sizeof(struct pollfd) * nfds);
+    for (i = 0; i < nfds; i++) {
+        pfd[i].fd = tswap32(target_pfd[i].fd);
+        pfd[i].events = tswap16(target_pfd[i].events);
+    } ret = get_errno(poll(pfd, nfds, timeout));
+    if (!is_error(ret)) {
+        for (i = 0; i < nfds; i++) {
+            target_pfd[i].revents = tswap16(pfd[i].revents);
+        }
+    }
+    unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
+
+    return ret;
+}
+
+/*
+ * undocumented openbsd_poll(struct pollfd *fds, u_int nfds, int
+ * timeout) system call.
+ */
+static abi_long do_bsd_openbsd_poll(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall openbsd_poll()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* lseek(2) */
+static abi_long do_bsd_lseek(void *cpu_env, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+#if TARGET_ABI_BITS == 32
+    int64_t res;
+
+    /* 32-bit arch's use two 32 registers for 64 bit return value */
+    if (regpairs_aligned(cpu_env) != 0) {
+    	res = lseek(arg1, target_offset64(arg3, arg4), arg5);
+    } else {
+        res = lseek(arg1, target_offset64(arg2, arg3), arg4);
+    }
+    if (res == -1) {
+        ret = get_errno(res);
+    } else {
+        ret = res & 0xFFFFFFFF;
+        set_second_rval(cpu_env, (res >> 32) & 0xFFFFFFFF);
+    }
+#else
+    ret = get_errno(lseek(arg1, arg2, arg3));
+#endif
+    return ret;
+}
+
+/* pipe(2) */
+static abi_long do_bsd_pipe(void *cpu_env, abi_long arg1)
+{
+    abi_long ret;
+    int host_pipe[2];
+    int host_ret = pipe(host_pipe);
+
+    if (host_ret != -1) {
+        set_second_rval(cpu_env, host_pipe[1]);
+        ret = host_pipe[0];
+    } else {
+        ret = get_errno(host_ret);
+    }
+    return ret;
+}
+
+/* swapon(2) */
+static abi_long do_bsd_swapon(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(swapon(path(p)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* swapoff(2) */
+static abi_long do_bsd_swapoff(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(swapoff(path(p)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/*
+ * undocumented freebsd6_pread(int fd, void *buf, size_t nbyte, int pad,
+ * off_t offset) system call.
+ */
+static abi_long do_bsd_freebsd6_pread(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_pread()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_pwrite(int fd, void *buf, size_t nbyte, int pad,
+ * off_t offset) system call.
+ */
+static abi_long do_bsd_freebsd6_pwrite(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_pwrite()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_lseek(int fd, int pad, off_t offset, int whence)
+ * system call.
+ */
+static abi_long do_bsd_freebsd6_lseek(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_lseek()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_truncate(char *path, int pad, off_t offset) system
+ * call.
+ */
+static abi_long do_bsd_freebsd6_truncate(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_truncate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_ftruncate(int fd, int pad, off_t offset) system
+ * call.
+ */
+static abi_long do_bsd_freebsd6_ftruncate(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_ftruncate()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__BSD_FILE_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index a9f5666..e668a67 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -446,6 +446,42 @@ static inline void *lock_user_string(abi_ulong guest_addr)
 #define unlock_user_struct(host_ptr, guest_addr, copy)          \
     unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
 
+#if TARGET_ABI_BITS == 32
+static inline uint64_t
+target_offset64(uint32_t word0, uint32_t word1)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    return ((uint64_t)word0 << 32) | word1;
+#else
+    return ((uint64_t)word1 << 32) | word0;
+#endif
+}
+#else /* TARGET_ABI_BITS != 32 */
+static inline uint64_t
+target_offset64(uint64_t word0, uint64_t word1)
+{
+    return word0;
+}
+#endif /* TARGET_ABI_BITS != 32 */
+
+/* ARM EABI and MIPS expect 64bit types aligned even on pairs of registers */
+#ifdef TARGET_ARM
+static inline int
+regpairs_aligned(void *cpu_env) {
+    return ((((CPUARMState *)cpu_env)->eabi) == 1);
+}
+#elif defined(TARGET_MIPS) && TARGET_ABI_BITS == 32
+static inline int regpairs_aligned(void *cpu_env)
+{
+    return 1;
+}
+#else
+static inline int regpairs_aligned(void *cpu_env)
+{
+    return 0;
+}
+#endif
+
 #if defined(CONFIG_USE_NPTL)
 #include <pthread.h>
 #endif
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index f8a40f0..15780af 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -41,6 +41,7 @@
 static int host_to_target_errno(int err);
 
 /* BSD independent syscall shims */
+#include "bsd-file.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
 
@@ -176,7 +177,6 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                             abi_long arg8)
 {
     abi_long ret;
-    void *p;
 
 #ifdef DEBUG
     gemu_log("freebsd syscall %d\n", num);
@@ -433,38 +433,305 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
 
-    case TARGET_FREEBSD_NR_read:
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-            goto efault;
-        ret = get_errno(read(arg1, p, arg3));
-        unlock_user(p, arg2, ret);
+        /*
+         * File system calls.
+         */
+    case TARGET_FREEBSD_NR_read: /* read(2) */
+        ret = do_bsd_read(arg1, arg2, arg3);
         break;
-    case TARGET_FREEBSD_NR_write:
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            goto efault;
-        ret = get_errno(write(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
+
+    case TARGET_FREEBSD_NR_pread: /* pread(2) */
+        ret = do_bsd_pread(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
-    case TARGET_FREEBSD_NR_writev:
-        {
-            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(writev(arg1, vec, count));
-            unlock_iovec(vec, arg2, count, 0);
-        }
+    case TARGET_FREEBSD_NR_readv: /* readv(2) */
+        ret = do_bsd_read(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_write: /* write(2) */
+        ret = do_bsd_write(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pwrite: /* pwrite(2) */
+        ret = do_bsd_pwrite(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_writev: /* writev(2) */
+        ret = do_bsd_writev(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pwritev: /* pwritev(2) */
+        ret = do_bsd_pwritev(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_open: /* open(2) */
+        ret = do_bsd_open(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_openat: /* openat(2) */
+        ret = do_bsd_openat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_close: /* close(2) */
+        ret = do_bsd_close(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_closefrom: /* closefrom(2) */
+        ret = do_bsd_closefrom(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_revoke: /* revoke(2) */
+        ret = do_bsd_revoke(arg1);
+        break;
+
+#ifdef TARGET_FREEBSD_NR_creat
+    case TARGET_FREEBSD_NR_creat: /* creat(2) (obsolete) */
+        ret = do_bsd_creat(arg1);
+        break;
+#endif
+
+    case TARGET_FREEBSD_NR_access: /* access(2) */
+        ret = do_bsd_access(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_eaccess: /* eaccess(2) */
+        ret = do_bsd_eaccess(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_faccessat: /* faccessat(2) */
+        ret = do_bsd_faccessat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_chdir: /* chdir(2) */
+        ret = do_bsd_chdir(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_fchdir: /* fchdir(2) */
+        ret = do_bsd_fchdir(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_rename: /* rename(2) */
+        ret = do_bsd_rename(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_renameat: /* renameat(2) */
+        ret = do_bsd_renameat(arg1, arg2, arg3, arg4);
         break;
-    case TARGET_FREEBSD_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
-        unlock_user(p, arg1, 0);
+
+    case TARGET_FREEBSD_NR_link: /* link(2) */
+        ret = do_bsd_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_linkat: /* linkat(2) */
+        ret = do_bsd_linkat(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_unlink: /* unlink(2) */
+        ret = do_bsd_unlink(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_unlinkat: /* unlinkat(2) */
+        ret = do_bsd_unlinkat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mkdir: /* mkdir(2) */
+        ret = do_bsd_mkdir(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mkdirat: /* mkdirat(2) */
+        ret = do_bsd_mkdirat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_rmdir: /* rmdir(2) (XXX no rmdirat()?) */
+        ret = do_bsd_rmdir(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___getcwd: /* undocumented __getcwd() */
+        ret = do_bsd___getcwd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_dup: /* dup(2) */
+        ret = do_bsd_dup(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_dup2: /* dup2(2) */
+        ret = do_bsd_dup2(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_truncate: /* truncate(2) */
+        ret = do_bsd_truncate(cpu_env, arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ftruncate: /* ftruncate(2) */
+        ret = do_bsd_ftruncate(cpu_env, arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_acct: /* acct(2) */
+        ret = do_bsd_acct(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sync: /* sync(2) */
+        ret = do_bsd_sync();
+        break;
+
+    case TARGET_FREEBSD_NR_mount: /* mount(2) */
+        ret = do_bsd_mount(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_unmount: /* unmount(2) */
+        ret = do_bsd_unmount(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_nmount: /* nmount(2) */
+        ret = do_bsd_nmount(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_symlink: /* symlink(2) */
+        ret = do_bsd_symlink(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_symlinkat: /* symlinkat(2) */
+        ret = do_bsd_symlinkat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_readlink: /* readlink(2) */
+        ret = do_bsd_readlink(arg1, arg2, arg3);
         break;
+
+    case TARGET_FREEBSD_NR_readlinkat: /* readlinkat(2) */
+        ret = do_bsd_readlinkat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_chmod: /* chmod(2) */
+        ret = do_bsd_chmod(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fchmod: /* fchmod(2) */
+        ret = do_bsd_fchmod(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lchmod: /* lchmod(2) */
+        ret = do_bsd_lchmod(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fchmodat: /* fchmodat(2) */
+        ret = do_bsd_fchmodat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_mknod: /* mknod(2) */
+        ret = do_bsd_mknod(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mknodat: /* mknodat(2) */
+        ret = do_bsd_mknodat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_chown: /* chown(2) */
+        ret = do_bsd_chown(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_fchown: /* fchown(2) */
+        ret = do_bsd_fchown(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_lchown: /* lchown(2) */
+        ret = do_bsd_lchown(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_fchownat: /* fchownat(2) */
+        ret = do_bsd_fchownat(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_chflags: /* chflags(2) */
+        ret = do_bsd_chflags(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lchflags: /* lchflags(2) */
+        ret = do_bsd_lchflags(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fchflags: /* fchflags(2) */
+        ret = do_bsd_fchflags(arg2, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_chroot: /* chroot(2) */
+        ret = do_bsd_chroot(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_flock: /* flock(2) */
+        ret = do_bsd_flock(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mkfifo: /* mkfifo(2) */
+        ret = do_bsd_mkfifo(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mkfifoat: /* mkfifoat(2) */
+        ret = do_bsd_mkfifoat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pathconf: /* pathconf(2) */
+        ret = do_bsd_pathconf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lpathconf: /* lpathconf(2) */
+        ret = do_bsd_lpathconf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fpathconf: /* fpathconf(2) */
+        ret = do_bsd_fpathconf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_undelete: /* undelete(2) */
+        ret = do_bsd_undelete(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_poll: /* poll(2) */
+        ret = do_bsd_poll(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_openbsd_poll:  /* undocumented openbsd_poll() */
+        ret = do_bsd_openbsd_poll(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_lseek: /* lseek(2) */
+        ret = do_bsd_lseek(cpu_env, arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_pipe: /* pipe(2) */
+        ret = do_bsd_pipe(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_swapon: /* swapon(2) */
+        ret = do_bsd_swapon(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_swapoff: /* swapoff(2) */
+        ret = do_bsd_swapoff(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_pread: /* undocumented freebsd6_pread() */
+        ret = do_bsd_freebsd6_pread(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_pwrite: /* undocumented freebsd6_pwrite() */
+        ret = do_bsd_freebsd6_pwrite(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_lseek: /* undocumented freebsd6_lseek() */
+        ret = do_bsd_freebsd6_lseek(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_truncate: /* undocumented */
+        ret = do_bsd_freebsd6_truncate(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_ftruncate: /* undocumented */
+        ret = do_bsd_freebsd6_ftruncate(arg1, arg2, arg3);
+        break;
+
+
+
     case TARGET_FREEBSD_NR_mmap:
         ret = get_errno(target_mmap(arg1, arg2, arg3,
                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
@@ -654,16 +921,12 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                     arg8));
         break;
     }
- fail:
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
     if (do_strace)
         print_freebsd_syscall_ret(num, ret);
     return ret;
- efault:
-    ret = -TARGET_EFAULT;
-    goto fail;
 }
 
 abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
@@ -671,7 +934,6 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
                            abi_long arg5, abi_long arg6)
 {
     abi_long ret;
-    void *p;
 
 #ifdef DEBUG
     gemu_log("netbsd syscall %d\n", num);
@@ -681,34 +943,19 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
 
     switch(num) {
     case TARGET_NETBSD_NR_exit:
-#ifdef TARGET_GPROF
-        _mcleanup();
-#endif
-        gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
-        _exit(arg1);
-        ret = 0; /* avoid warning */
+        ret = do_bsd_exit(cpu_env, arg1);
         break;
+
     case TARGET_NETBSD_NR_read:
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-            goto efault;
-        ret = get_errno(read(arg1, p, arg3));
-        unlock_user(p, arg2, ret);
+        ret = do_bsd_read(arg1, arg2, arg3);
         break;
     case TARGET_NETBSD_NR_write:
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            goto efault;
-        ret = get_errno(write(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
+        ret = do_bsd_write(arg1, arg2, arg3);
         break;
     case TARGET_NETBSD_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
-        unlock_user(p, arg1, 0);
+        ret = do_bsd_open(arg1, arg2, arg3);
         break;
+
     case TARGET_NETBSD_NR_mmap:
         ret = get_errno(target_mmap(arg1, arg2, arg3,
                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
@@ -727,16 +974,12 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
     }
- fail:
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
     if (do_strace)
         print_netbsd_syscall_ret(num, ret);
     return ret;
- efault:
-    ret = -TARGET_EFAULT;
-    goto fail;
 }
 
 abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
@@ -744,7 +987,6 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
                             abi_long arg5, abi_long arg6)
 {
     abi_long ret;
-    void *p;
 
 #ifdef DEBUG
     gemu_log("openbsd syscall %d\n", num);
@@ -754,34 +996,19 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
 
     switch(num) {
     case TARGET_OPENBSD_NR_exit:
-#ifdef TARGET_GPROF
-        _mcleanup();
-#endif
-        gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
-        _exit(arg1);
-        ret = 0; /* avoid warning */
+        ret = do_bsd_exit(cpu_env, arg1);
         break;
+
     case TARGET_OPENBSD_NR_read:
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-            goto efault;
-        ret = get_errno(read(arg1, p, arg3));
-        unlock_user(p, arg2, ret);
+        ret = do_bsd_read(arg1, arg2, arg3);
         break;
     case TARGET_OPENBSD_NR_write:
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            goto efault;
-        ret = get_errno(write(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
+        ret = do_bsd_write(arg1, arg2, arg3);
         break;
     case TARGET_OPENBSD_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
-        unlock_user(p, arg1, 0);
+        ret = do_bsd_open(arg1, arg2, arg3);
         break;
+
     case TARGET_OPENBSD_NR_mmap:
         ret = get_errno(target_mmap(arg1, arg2, arg3,
                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
@@ -800,16 +1027,12 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
     }
- fail:
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
     if (do_strace)
         print_openbsd_syscall_ret(num, ret);
     return ret;
- efault:
-    ret = -TARGET_EFAULT;
-    goto fail;
 }
 
 void syscall_init(void)
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 11/19] bsd-user: add support for stat, directory, and file control related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (30 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 10/19] bsd-user: add support for file system " Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 12/19] bsd-user: add support for memory management " Stacey Son
                   ` (7 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for stat, directory, and file control related
system calls including stat(2), lstat(2), fstat(2), fstatat(2), nstat(), nfstat(),
nlstat(), getfh(2), lgetfh(2), fhopen(2), fhstat(2), fhstatfs(2), statfs(2),
fstatfs(2), getfsstat(2), getdents(2), getdirentries(2), and fcntl(2).

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs     |    1 +
 bsd-user/freebsd/os-stat.c |  234 +++++++++++++++++++++++
 bsd-user/freebsd/os-stat.h |  437 ++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h |    8 +
 bsd-user/netbsd/os-stat.c  |    1 +
 bsd-user/netbsd/os-stat.h  |    1 +
 bsd-user/openbsd/os-stat.c |    1 +
 bsd-user/openbsd/os-stat.h |  176 ++++++++++++++++++
 bsd-user/syscall.c         |   76 ++++++++
 9 files changed, 935 insertions(+), 0 deletions(-)
 create mode 100644 bsd-user/freebsd/os-stat.c
 create mode 100644 bsd-user/freebsd/os-stat.h
 create mode 100644 bsd-user/netbsd/os-stat.c
 create mode 100644 bsd-user/netbsd/os-stat.h
 create mode 100644 bsd-user/openbsd/os-stat.c
 create mode 100644 bsd-user/openbsd/os-stat.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 6a2fc37..ee70866 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,5 +1,6 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
 	        uaccess.o bsd-proc.o \
 			$(HOST_ABI_DIR)/os-proc.o \
+			$(HOST_ABI_DIR)/os-stat.o \
 			$(HOST_ABI_DIR)/os-sys.o \
 			$(HOST_ABI_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/freebsd/os-stat.c b/bsd-user/freebsd/os-stat.c
new file mode 100644
index 0000000..50885d1
--- /dev/null
+++ b/bsd-user/freebsd/os-stat.c
@@ -0,0 +1,234 @@
+/*
+ *  FreeBSD stat related conversion routines
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+/*
+ * stat conversion
+ */
+abi_long h2t_freebsd_stat(abi_ulong target_addr, struct stat *host_st)
+{
+    struct target_freebsd_stat *target_st;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    memset(target_st, 0, sizeof(*target_st));
+    __put_user(host_st->st_dev, &target_st->st_dev);
+    __put_user(host_st->st_ino, &target_st->st_ino);
+    __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_atim.tv_sec, &target_st->st_atim.tv_sec);
+    __put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec);
+    __put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec);
+    __put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec);
+    __put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec);
+    __put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec);
+    __put_user(host_st->st_size, &target_st->st_size);
+    __put_user(host_st->st_blocks, &target_st->st_blocks);
+    __put_user(host_st->st_blksize, &target_st->st_blksize);
+    __put_user(host_st->st_flags, &target_st->st_flags);
+    __put_user(host_st->st_gen, &target_st->st_gen);
+    /* st_lspare not used */
+    __put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec);
+    __put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec);
+    unlock_user_struct(target_st, target_addr, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_nstat(abi_ulong target_addr, struct stat *host_st)
+{
+    struct target_freebsd_nstat *target_st;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    memset(target_st, 0, sizeof(*target_st));
+    __put_user(host_st->st_dev, &target_st->st_dev);
+    __put_user(host_st->st_ino, &target_st->st_ino);
+    __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_atim.tv_sec, &target_st->st_atim.tv_sec);
+    __put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec);
+    __put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec);
+    __put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec);
+    __put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec);
+    __put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec);
+    __put_user(host_st->st_size, &target_st->st_size);
+    __put_user(host_st->st_blocks, &target_st->st_blocks);
+    __put_user(host_st->st_blksize, &target_st->st_blksize);
+    __put_user(host_st->st_flags, &target_st->st_flags);
+    __put_user(host_st->st_gen, &target_st->st_gen);
+    __put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec);
+    __put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec);
+    unlock_user_struct(target_st, target_addr, 1);
+
+    return 0;
+}
+
+/*
+ * file handle conversion
+ */
+abi_long t2h_freebsd_fhandle(fhandle_t *host_fh, abi_ulong target_addr)
+{
+    target_freebsd_fhandle_t *target_fh;
+
+    if (!lock_user_struct(VERIFY_READ, target_fh, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]);
+    __get_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]);
+    __get_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len);
+    /* u_short         fid_data0; */
+    memcpy(host_fh->fh_fid.fid_data, target_fh->fh_fid.fid_data,
+        TARGET_MAXFIDSZ);
+    unlock_user_struct(target_fh, target_addr, 0);
+    return 0;
+}
+
+abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh)
+{
+    target_freebsd_fhandle_t *target_fh;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_fh, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]);
+    __put_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]);
+    __put_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len);
+    /* u_short         fid_data0; */
+    memcpy(target_fh->fh_fid.fid_data, host_fh->fh_fid.fid_data,
+            TARGET_MAXFIDSZ);
+    unlock_user_struct(target_fh, target_addr, 1);
+    return 0;
+}
+
+/*
+ *  file system stat
+ */
+abi_long h2t_freebsd_statfs(abi_ulong target_addr, struct statfs *host_statfs)
+{
+    struct target_freebsd_statfs *target_statfs;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_statfs, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_statfs->f_version, &target_statfs->f_version);
+    __put_user(host_statfs->f_type, &target_statfs->f_type);
+    __put_user(host_statfs->f_flags, &target_statfs->f_flags);
+    __put_user(host_statfs->f_bsize, &target_statfs->f_bsize);
+    __put_user(host_statfs->f_iosize, &target_statfs->f_iosize);
+    __put_user(host_statfs->f_blocks, &target_statfs->f_blocks);
+    __put_user(host_statfs->f_bfree, &target_statfs->f_bfree);
+    __put_user(host_statfs->f_bavail, &target_statfs->f_bavail);
+    __put_user(host_statfs->f_files, &target_statfs->f_files);
+    __put_user(host_statfs->f_ffree, &target_statfs->f_ffree);
+    __put_user(host_statfs->f_syncwrites, &target_statfs->f_syncwrites);
+    __put_user(host_statfs->f_asyncwrites, &target_statfs->f_asyncwrites);
+    __put_user(host_statfs->f_syncreads, &target_statfs->f_syncreads);
+    __put_user(host_statfs->f_asyncreads, &target_statfs->f_asyncreads);
+    /* uint64_t f_spare[10]; */
+    __put_user(host_statfs->f_namemax, &target_statfs->f_namemax);
+    __put_user(host_statfs->f_owner, &target_statfs->f_owner);
+    __put_user(host_statfs->f_fsid.val[0], &target_statfs->f_fsid.val[0]);
+    __put_user(host_statfs->f_fsid.val[1], &target_statfs->f_fsid.val[1]);
+    /* char f_charspace[80]; */
+    strncpy(&target_statfs->f_fstypename[0], host_statfs->f_fstypename,
+        TARGET_MFSNAMELEN);
+    strncpy(&target_statfs->f_mntfromname[0], host_statfs->f_mntfromname,
+        TARGET_MNAMELEN);
+    strncpy(&target_statfs->f_mntonname[0], host_statfs->f_mntonname,
+        TARGET_MNAMELEN);
+    unlock_user_struct(target_statfs, target_addr, 1);
+    return 0;
+}
+
+/*
+ * fcntl cmd conversion
+ */
+abi_long target_to_host_fcntl_cmd(int cmd)
+{
+
+    switch (cmd) {
+    case TARGET_F_DUPFD:
+        return F_DUPFD;
+
+    case TARGET_F_DUP2FD:
+        return F_DUP2FD;
+
+    case TARGET_F_GETFD:
+        return F_GETFD;
+
+    case TARGET_F_SETFD:
+        return F_SETFD;
+
+    case TARGET_F_GETFL:
+        return F_GETFL;
+
+    case TARGET_F_SETFL:
+        return F_SETFL;
+
+    case TARGET_F_GETOWN:
+        return F_GETOWN;
+
+    case TARGET_F_SETOWN:
+        return F_SETOWN;
+
+    case TARGET_F_GETLK:
+        return F_GETLK;
+
+    case TARGET_F_SETLK:
+        return F_SETLK;
+
+    case TARGET_F_SETLKW:
+        return F_SETLKW;
+
+    case TARGET_F_READAHEAD:
+        return F_READAHEAD;
+
+    case TARGET_F_RDAHEAD:
+        return F_RDAHEAD;
+
+#ifdef F_DUPFD_CLOEXEC
+    case TARGET_F_DUPFD_CLOEXEC:
+        return F_DUPFD_CLOEXEC;
+#endif
+
+#ifdef F_DUP2FD_CLOEXEC
+    case TARGET_F_DUP2FD_CLOEXEC:
+        return F_DUP2FD_CLOEXEC;
+#endif
+
+    default:
+        return -TARGET_EINVAL;
+    }
+}
+
diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h
new file mode 100644
index 0000000..ed6bcab
--- /dev/null
+++ b/bsd-user/freebsd/os-stat.h
@@ -0,0 +1,437 @@
+/*
+ *  stat related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_STAT_H_
+#define __FREEBSD_STAT_H_
+
+#include <sys/types.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include "qemu-os.h"
+
+/* undocumented nstat system calls */
+int nstat(const char *path, struct stat *sb);
+int nlstat(const char *path, struct stat *sb);
+int nfstat(int fd, struct stat *sb);
+
+/* stat(2) */
+static inline abi_long do_freebsd_stat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(stat(path(p), &st));
+    UNLOCK_PATH(p, arg1);
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_stat(arg2, &st);
+    }
+    return ret;
+}
+
+/* lstat(2) */
+static inline abi_long do_freebsd_lstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lstat(path(p), &st));
+    UNLOCK_PATH(p, arg1);
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_stat(arg2, &st);
+    }
+    return ret;
+}
+
+/* fstat(2) */
+static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct stat st;
+
+    ret = get_errno(fstat(arg1, &st));
+    if (!is_error(ret))  {
+        ret = h2t_freebsd_stat(arg2, &st);
+    }
+    return ret;
+}
+
+/* fstatat(2) */
+static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(fstatat(arg1, p, &st, arg4));
+    UNLOCK_PATH(p, arg2);
+    if (!is_error(ret) && arg3) {
+        ret = h2t_freebsd_stat(arg3, &st);
+    }
+    return ret;
+}
+
+/* undocummented nstat(char *path, struct nstat *ub) syscall */
+static abi_long do_freebsd_nstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(nstat(path(p), &st));
+    UNLOCK_PATH(p, arg1);
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_nstat(arg2, &st);
+    }
+    return ret;
+}
+
+/* undocummented nfstat(int fd, struct nstat *sb) syscall */
+static abi_long do_freebsd_nfstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct stat st;
+
+    ret = get_errno(nfstat(arg1, &st));
+    if (!is_error(ret))  {
+        ret = h2t_freebsd_nstat(arg2, &st);
+    }
+    return ret;
+}
+
+/* undocummented nlstat(char *path, struct nstat *ub) syscall */
+static abi_long do_freebsd_nlstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(nlstat(path(p), &st));
+    UNLOCK_PATH(p, arg1);
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_nstat(arg2, &st);
+    }
+    return ret;
+}
+
+/* getfh(2) */
+static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    fhandle_t host_fh;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(getfh(path(p), &host_fh));
+    UNLOCK_PATH(p, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+    return h2t_freebsd_fhandle(arg2, &host_fh);
+}
+
+/* lgetfh(2) */
+static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    fhandle_t host_fh;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lgetfh(path(p), &host_fh));
+    UNLOCK_PATH(p, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+    return h2t_freebsd_fhandle(arg2, &host_fh);
+}
+
+/* fhopen(2) */
+static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    fhandle_t host_fh;
+
+    ret = t2h_freebsd_fhandle(&host_fh, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(fhopen(&host_fh, arg2));
+}
+
+/* fhstat(2) */
+static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    fhandle_t host_fh;
+    struct stat host_sb;
+
+    ret = t2h_freebsd_fhandle(&host_fh, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = get_errno(fhstat(&host_fh, &host_sb));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return h2t_freebsd_stat(arg2, &host_sb);
+}
+
+/* fhstatfs(2) */
+static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr,
+        abi_ulong target_stfs_addr)
+{
+    abi_long ret;
+    fhandle_t host_fh;
+    struct statfs host_stfs;
+
+    ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = get_errno(fhstatfs(&host_fh, &host_stfs));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return h2t_freebsd_statfs(target_stfs_addr, &host_stfs);
+}
+
+/* statfs(2) */
+static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct statfs host_stfs;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(statfs(path(p), &host_stfs));
+    UNLOCK_PATH(p, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return h2t_freebsd_statfs(arg2, &host_stfs);
+}
+
+/* fstatfs(2) */
+static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr)
+{
+    abi_long ret;
+    struct statfs host_stfs;
+
+    ret = get_errno(fstatfs(fd, &host_stfs));
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return h2t_freebsd_statfs(target_addr, &host_stfs);
+}
+
+/* getfsstat(2) */
+static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr,
+        abi_long bufsize, abi_long flags)
+{
+    abi_long ret;
+    struct statfs *host_stfs;
+    int count;
+    long host_bufsize;
+
+    count = bufsize / sizeof(struct target_freebsd_statfs);
+
+    /* if user buffer is NULL then return number of mounted FS's */
+    if (target_addr == 0 || count == 0) {
+        return get_errno(getfsstat(NULL, 0, flags));
+    }
+
+    /* XXX check count to be reasonable */
+    host_bufsize = sizeof(struct statfs) * count;
+    host_stfs = alloca(host_bufsize);
+    if (!host_stfs) {
+        return -TARGET_EINVAL;
+    }
+
+    ret = count = get_errno(getfsstat(host_stfs, host_bufsize, flags));
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    while (count--) {
+        if (h2t_freebsd_statfs((target_addr +
+                        (count * sizeof(struct target_freebsd_statfs))),
+                    &host_stfs[count])) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getdents(2) */
+static inline abi_long do_freebsd_getdents(abi_long arg1, abi_ulong arg2,
+        abi_long nbytes)
+{
+    abi_long ret;
+    struct dirent *dirp;
+
+    dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
+    if (dirp == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(getdents(arg1, (char *)dirp, nbytes));
+    if (!is_error(ret)) {
+        struct dirent *de;
+        int len = ret;
+        int reclen;
+
+        de = dirp;
+        while (len > 0) {
+            reclen = de->d_reclen;
+            if (reclen > len) {
+                return -TARGET_EFAULT;
+            }
+            de->d_reclen = tswap16(reclen);
+            de->d_fileno = tswap32(de->d_fileno);
+            len -= reclen;
+        }
+    }
+    return ret;
+}
+
+/* getdirecentries(2) */
+static inline abi_long do_freebsd_getdirentries(abi_long arg1, abi_ulong arg2,
+        abi_long nbytes, abi_ulong arg4)
+{
+    abi_long ret;
+    struct dirent *dirp;
+    long basep;
+
+    dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
+    if (dirp == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(getdirentries(arg1, (char *)dirp, nbytes, &basep));
+    if (!is_error(ret)) {
+        struct dirent *de;
+        int len = ret;
+        int reclen;
+
+        de = dirp;
+        while (len > 0) {
+            reclen = de->d_reclen;
+            if (reclen > len) {
+                return -TARGET_EFAULT;
+            }
+            de->d_reclen = tswap16(reclen);
+            de->d_fileno = tswap32(de->d_fileno);
+            len -= reclen;
+            de = (struct dirent *)((void *)de + reclen);
+        }
+    }
+    unlock_user(dirp, arg2, ret);
+    if (arg4) {
+        if (put_user(basep, arg4, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* fcntl(2) */
+static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    int host_cmd;
+    struct flock fl;
+    struct target_freebsd_flock *target_fl;
+
+    host_cmd = target_to_host_fcntl_cmd(arg2);
+    if (host_cmd < 0) {
+        return host_cmd;
+    }
+    switch (arg2) {
+    case TARGET_F_GETLK:
+        if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(fl.l_type, &target_fl->l_type);
+        __get_user(fl.l_whence, &target_fl->l_whence);
+        __get_user(fl.l_start, &target_fl->l_start);
+        __get_user(fl.l_len, &target_fl->l_len);
+        __get_user(fl.l_pid, &target_fl->l_pid);
+        __get_user(fl.l_sysid, &target_fl->l_sysid);
+        unlock_user_struct(target_fl, arg3, 0);
+        ret = get_errno(fcntl(arg1, host_cmd, &fl));
+        if (!is_error(ret)) {
+            if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) {
+                return -TARGET_EFAULT;
+            }
+            __put_user(fl.l_type, &target_fl->l_type);
+            __put_user(fl.l_whence, &target_fl->l_whence);
+            __put_user(fl.l_start, &target_fl->l_start);
+            __put_user(fl.l_len, &target_fl->l_len);
+            __put_user(fl.l_pid, &target_fl->l_pid);
+            __put_user(fl.l_sysid, &target_fl->l_sysid);
+            unlock_user_struct(target_fl, arg3, 1);
+        }
+        break;
+
+    case TARGET_F_SETLK:
+    case TARGET_F_SETLKW:
+        if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(fl.l_type, &target_fl->l_type);
+        __get_user(fl.l_whence, &target_fl->l_whence);
+        __get_user(fl.l_start, &target_fl->l_start);
+        __get_user(fl.l_len, &target_fl->l_len);
+        __get_user(fl.l_pid, &target_fl->l_pid);
+        __get_user(fl.l_sysid, &target_fl->l_sysid);
+        unlock_user_struct(target_fl, arg3, 0);
+        ret = get_errno(fcntl(arg1, host_cmd, &fl));
+        break;
+
+    case TARGET_F_DUPFD:
+    case TARGET_F_DUP2FD:
+    case TARGET_F_GETOWN:
+    case TARGET_F_SETOWN:
+    case TARGET_F_GETFD:
+    case TARGET_F_SETFD:
+    case TARGET_F_GETFL:
+    case TARGET_F_SETFL:
+    case TARGET_F_READAHEAD:
+    case TARGET_F_RDAHEAD:
+    default:
+        ret = get_errno(fcntl(arg1, host_cmd, arg3));
+        break;
+    }
+    return ret;
+}
+
+#endif /* ! __FREEBSD_STAT_H_ */
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index bde610e..e915246 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -50,4 +50,12 @@ abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
 abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds,
         int n);
 
+/* os-stat.c */
+abi_long h2t_freebsd_stat(abi_ulong target_addr, struct stat *host_st);
+abi_long h2t_freebsd_nstat(abi_ulong target_addr, struct stat *host_st);
+abi_long t2h_freebsd_fhandle(fhandle_t *host_fh, abi_ulong target_addr);
+abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh);
+abi_long h2t_freebsd_statfs(abi_ulong target_addr, struct statfs *host_statfs);
+abi_long target_to_host_fcntl_cmd(int cmd);
+
 #endif /* !_QEMU_OS_H_ */
diff --git a/bsd-user/netbsd/os-stat.c b/bsd-user/netbsd/os-stat.c
new file mode 100644
index 0000000..11ea122
--- /dev/null
+++ b/bsd-user/netbsd/os-stat.c
@@ -0,0 +1 @@
+/* XXX NetBSD stat related helpers */
diff --git a/bsd-user/netbsd/os-stat.h b/bsd-user/netbsd/os-stat.h
new file mode 100644
index 0000000..11ea122
--- /dev/null
+++ b/bsd-user/netbsd/os-stat.h
@@ -0,0 +1 @@
+/* XXX NetBSD stat related helpers */
diff --git a/bsd-user/openbsd/os-stat.c b/bsd-user/openbsd/os-stat.c
new file mode 100644
index 0000000..de4e3f5
--- /dev/null
+++ b/bsd-user/openbsd/os-stat.c
@@ -0,0 +1 @@
+/* XXX OpenBSD stat related helpers */
diff --git a/bsd-user/openbsd/os-stat.h b/bsd-user/openbsd/os-stat.h
new file mode 100644
index 0000000..1d3850d
--- /dev/null
+++ b/bsd-user/openbsd/os-stat.h
@@ -0,0 +1,176 @@
+/*
+ *  OpenBSD stat related system call shims and definitions
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OPENBSD_STAT_H_
+#define __OPENBSD_STAT_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* stat(2) */
+static inline abi_long do_freebsd_stat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall stat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* lstat(2) */
+static inline abi_long do_freebsd_lstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall lstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fstat(2) */
+static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall fstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fstatat(2) */
+static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall fstatat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocummented nstat(char *path, struct nstat *ub) syscall */
+static abi_long do_freebsd_nstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall nstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocummented nfstat(int fd, struct nstat *sb) syscall */
+static abi_long do_freebsd_nfstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall nfstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocummented nlstat(char *path, struct nstat *ub) syscall */
+static abi_long do_freebsd_nlstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall nlstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getfh(2) */
+static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getfh()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* lgetfh(2) */
+static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall lgetfh()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fhopen(2) */
+static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall fhopen()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fhstat(2) */
+static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall fhstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fhstatfs(2) */
+static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr,
+        abi_ulong target_stfs_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall fhstatfs()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* statfs(2) */
+static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall statfs()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fstatfs(2) */
+static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall fstatfs()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getfsstat(2) */
+static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr,
+        abi_long bufsize, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall getfsstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getdents(2) */
+static inline abi_long do_freebsd_getdents(abi_long arg1, abi_ulong arg2,
+        abi_long nbytes)
+{
+
+    qemu_log("qemu: Unsupported syscall getdents()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getdirecentries(2) */
+static inline abi_long do_freebsd_getdirentries(abi_long arg1, abi_ulong arg2,
+        abi_long nbytes, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall getdirecentries()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fcntl(2) */
+static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall fcntl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_STAT_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 15780af..633d638 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -49,6 +49,7 @@ static int host_to_target_errno(int err);
 #include "os-time.h"
 #include "os-proc.h"
 #include "os-signal.h"
+#include "os-stat.h"
 
 /* #define DEBUG */
 
@@ -730,6 +731,81 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = do_bsd_freebsd6_ftruncate(arg1, arg2, arg3);
         break;
 
+        /*
+         * stat system calls
+         */
+    case TARGET_FREEBSD_NR_stat: /* stat(2) */
+        ret = do_freebsd_stat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lstat: /* lstat(2) */
+        ret = do_freebsd_lstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fstat: /* fstat(2) */
+        ret = do_freebsd_fstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fstatat: /* fstatat(2) */
+        ret = do_freebsd_fstatat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_nstat: /* undocumented */
+        ret = do_freebsd_nstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_nfstat: /* undocumented */
+        ret = do_freebsd_nfstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_nlstat: /* undocumented */
+        ret = do_freebsd_nlstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getfh: /* getfh(2) */
+        ret = do_freebsd_getfh(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lgetfh: /* lgetfh(2) */
+        ret = do_freebsd_lgetfh(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fhopen: /* fhopen(2) */
+        ret = do_freebsd_fhopen(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fhstat: /* fhstat(2) */
+        ret = do_freebsd_fhstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fhstatfs: /* fhstatfs(2) */
+        ret = do_freebsd_fhstatfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_statfs: /* statfs(2) */
+        ret = do_freebsd_statfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fstatfs: /* fstatfs(2) */
+        ret = do_freebsd_fstatfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getfsstat: /* getfsstat(2) */
+        ret = do_freebsd_getfsstat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getdents: /* getdents(2) */
+        ret = do_freebsd_getdents(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getdirentries: /* getdirentries(2) */
+        ret = do_freebsd_getdirentries(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_fcntl: /* fcntl(2) */
+        ret = do_freebsd_fcntl(arg1, arg2, arg3);
+        break;
+
 
 
     case TARGET_FREEBSD_NR_mmap:
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 12/19] bsd-user: add support for memory management related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (31 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 11/19] bsd-user: add support for stat, directory, and file control " Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 13/19] bsd-user: add support for socket " Stacey Son
                   ` (6 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for memory management related system calls
including mmap(2), munmap(2), mprotect(2), msync(2), mlock(2), munlock(2),
mlockall(2), munlockall(2), madvise(2), minherit(2), mincore(2), shm_open(2),
shm_unlink(2), shmget(2), shmctl(2), shmat(2), shmdt(2), vadvise(), sbrk(), sstk(),
and freebsd6_mmap().

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs |    2 +-
 bsd-user/bsd-mem.c     |  122 ++++++++++++
 bsd-user/bsd-mem.h     |  393 ++++++++++++++++++++++++++++++++++++++
 bsd-user/mmap.c        |  493 ++++++++++++++++++++++++++++++------------------
 bsd-user/qemu-bsd.h    |   10 +
 bsd-user/qemu.h        |    3 +-
 bsd-user/syscall.c     |  174 ++++++++++-------
 7 files changed, 942 insertions(+), 255 deletions(-)
 create mode 100644 bsd-user/bsd-mem.c
 create mode 100644 bsd-user/bsd-mem.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index ee70866..1a33a6d 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,5 +1,5 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-proc.o \
+	        uaccess.o bsd-mem.o bsd-proc.o \
 			$(HOST_ABI_DIR)/os-proc.o \
 			$(HOST_ABI_DIR)/os-stat.o \
 			$(HOST_ABI_DIR)/os-sys.o \
diff --git a/bsd-user/bsd-mem.c b/bsd-user/bsd-mem.c
new file mode 100644
index 0000000..bfe03aa
--- /dev/null
+++ b/bsd-user/bsd-mem.c
@@ -0,0 +1,122 @@
+/*
+ *  memory management system conversion routines
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+struct bsd_shm_regions bsd_shm_regions[N_BSD_SHM_REGIONS];
+
+abi_ulong bsd_target_brk;
+abi_ulong bsd_target_original_brk;
+
+void target_set_brk(abi_ulong new_brk)
+{
+
+    bsd_target_original_brk = bsd_target_brk = HOST_PAGE_ALIGN(new_brk);
+}
+
+abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
+        abi_ulong target_addr)
+{
+    struct target_ipc_perm *target_ip;
+
+    if (!lock_user_struct(VERIFY_READ, target_ip, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_ip->cuid, &target_ip->cuid);
+    __get_user(host_ip->cgid, &target_ip->cgid);
+    __get_user(host_ip->uid, &target_ip->uid);
+    __get_user(host_ip->gid, &target_ip->gid);
+    __get_user(host_ip->mode, &target_ip->mode);
+    __get_user(host_ip->seq, &target_ip->seq);
+    __get_user(host_ip->key, &target_ip->key);
+    unlock_user_struct(target_ip, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_ipc_perm(abi_ulong target_addr,
+        struct ipc_perm *host_ip)
+{
+    struct target_ipc_perm *target_ip;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ip, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_ip->cuid, &target_ip->cuid);
+    __put_user(host_ip->cgid, &target_ip->cgid);
+    __put_user(host_ip->uid, &target_ip->uid);
+    __put_user(host_ip->gid, &target_ip->gid);
+    __put_user(host_ip->mode, &target_ip->mode);
+    __put_user(host_ip->seq, &target_ip->seq);
+    __put_user(host_ip->key, &target_ip->key);
+    unlock_user_struct(target_ip, target_addr, 1);
+
+    return 0;
+}
+
+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_lpid, &target_sd->shm_lpid);
+    __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    __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);
+    unlock_user_struct(target_sd, target_addr, 0);
+
+    return 0;
+}
+
+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_lpid, &target_sd->shm_lpid);
+    __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    __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);
+    unlock_user_struct(target_sd, target_addr, 1);
+
+    return 0;
+}
+
diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h
new file mode 100644
index 0000000..88c01ec
--- /dev/null
+++ b/bsd-user/bsd-mem.h
@@ -0,0 +1,393 @@
+/*
+ *  memory management system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*--
+ * Copyright (c) 1982, 1986, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BSD_MMAN_H_
+#define _BSD_MMAN_H_
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <fcntl.h>
+
+#include "qemu-bsd.h"
+
+extern struct bsd_shm_regions bsd_shm_regions[];
+extern abi_ulong bsd_target_brk;
+extern abi_ulong bsd_target_original_brk;
+
+/* mmap(2) */
+static inline abi_long do_bsd_mmap(void *cpu_env, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7,
+    abi_long arg8)
+{
+
+    if (regpairs_aligned(cpu_env) != 0) {
+       arg6 = arg7;
+       arg7 = arg8;
+    }
+    return get_errno(target_mmap(arg1, arg2, arg3,
+                target_to_host_bitmask(arg4, mmap_flags_tbl), arg5,
+		target_offset64(arg6, arg7)));
+}
+
+/* munmap(2) */
+static inline abi_long do_bsd_munmap(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(target_munmap(arg1, arg2));
+}
+
+/* mprotect(2) */
+static inline abi_long do_bsd_mprotect(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    return get_errno(target_mprotect(arg1, arg2, arg3));
+}
+
+/* msync(2) */
+static inline abi_long do_bsd_msync(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+
+    return get_errno(msync(g2h(arg1), arg2, arg3));
+}
+
+/* mlock(2) */
+static inline abi_long do_bsd_mlock(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(mlock(g2h(arg1), arg2));
+}
+
+/* munlock(2) */
+static inline abi_long do_bsd_munlock(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(munlock(g2h(arg1), arg2));
+}
+
+/* mlockall(2) */
+static inline abi_long do_bsd_mlockall(abi_long arg1)
+{
+
+    return get_errno(mlockall(arg1));
+}
+
+/* munlockall(2) */
+static inline abi_long do_bsd_munlockall(void)
+{
+
+    return get_errno(munlockall());
+}
+
+/* madvise(2) */
+static inline abi_long do_bsd_madvise(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    /*
+     * A straight passthrough may not be safe because qemu sometimes
+     * turns private file-backed mapping into anonymous mappings. This
+     * will break MADV_DONTNEED.  This is a hint, so ignoring and returing
+     * success is ok.
+     */
+    return get_errno(0);
+}
+
+/* minherit(2) */
+static inline abi_long do_bsd_minherit(abi_long addr, abi_long len,
+        abi_long inherit)
+{
+
+    return get_errno(minherit(g2h(addr), len, inherit));
+}
+
+/* mincore(2) */
+static inline abi_long do_bsd_mincore(abi_ulong target_addr, abi_ulong len,
+        abi_ulong target_vec)
+{
+    abi_long ret;
+    void *p, *a;
+
+    a = lock_user(VERIFY_WRITE, target_addr, len, 0);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+    p = lock_user_string(target_vec);
+    if (p == NULL) {
+        unlock_user(a, target_addr, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(mincore(a, len, p));
+    unlock_user(p, target_vec, ret);
+    unlock_user(a, target_addr, 0);
+
+    return ret;
+}
+
+/* break() XXX this needs some more work. */
+static inline abi_long do_obreak(abi_ulong new_brk)
+{
+    abi_ulong brk_page;
+    abi_long mapped_addr;
+    int new_alloc_size;
+
+    return -TARGET_EINVAL;
+
+    if (!new_brk) {
+        return 0;
+    }
+    if (new_brk < bsd_target_original_brk) {
+        return -TARGET_EINVAL;
+    }
+
+    brk_page = HOST_PAGE_ALIGN(bsd_target_brk);
+
+    /* If the new brk is less than this, set it and we're done... */
+    if (new_brk < brk_page) {
+        bsd_target_brk = new_brk;
+        return 0;
+    }
+
+    /* We need to allocate more memory after the brk... */
+    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
+    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
+                PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0));
+
+    if (!is_error(mapped_addr)) {
+        bsd_target_brk = new_brk;
+    } else {
+        return mapped_addr;
+    }
+
+    return 0;
+}
+
+/* shm_open(2) */
+static inline abi_long do_bsd_shm_open(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+    int ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(shm_open(path(p),
+                target_to_host_bitmask(arg2, fcntl_flags_tbl), arg3));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* shm_unlink(2) */
+static inline abi_long do_bsd_shm_unlink(abi_ulong arg1)
+{
+    int ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(shm_unlink(p)); /* XXX path(p)? */
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* shmget(2) */
+static inline abi_long do_bsd_shmget(abi_long arg1, abi_ulong arg2,
+        abi_long arg3)
+{
+
+    return get_errno(shmget(arg1, arg2, arg3));
+}
+
+/* shmctl(2) */
+static inline abi_long do_bsd_shmctl(abi_long shmid, abi_long cmd,
+        abi_ulong buff)
+{
+    struct shmid_ds dsarg;
+    abi_long ret = -TARGET_EINVAL;
+
+    cmd &= 0xff;
+
+    switch (cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+        if (target_to_host_shmid_ds(&dsarg, buff)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(shmctl(shmid, cmd, &dsarg));
+        if (host_to_target_shmid_ds(buff, &dsarg)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    case IPC_RMID:
+        ret = get_errno(shmctl(shmid, cmd, NULL));
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+/* shmat(2) */
+static inline abi_long do_bsd_shmat(int shmid, abi_ulong shmaddr, int shmflg)
+{
+    abi_ulong raddr;
+    abi_long ret;
+    void *host_raddr;
+    struct shmid_ds shm_info;
+    int i;
+
+    /* 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 the length */
+        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_BSD_SHM_REGIONS; i++) {
+        if (bsd_shm_regions[i].start == 0) {
+            bsd_shm_regions[i].start = raddr;
+            bsd_shm_regions[i].size = shm_info.shm_segsz;
+            break;
+        }
+    }
+
+    mmap_unlock();
+    return raddr;
+}
+
+/* shmdt(2) */
+static inline abi_long do_bsd_shmdt(abi_ulong shmaddr)
+{
+    int i;
+
+    for (i = 0; i < N_BSD_SHM_REGIONS; ++i) {
+        if (bsd_shm_regions[i].start == shmaddr) {
+            bsd_shm_regions[i].start = 0;
+            page_set_flags(shmaddr,
+                shmaddr + bsd_shm_regions[i].size, 0);
+            break;
+        }
+    }
+
+    return get_errno(shmdt(g2h(shmaddr)));
+}
+
+
+static inline abi_long do_bsd_vadvise(void)
+{
+    /* See sys_ovadvise() in vm_unix.c */
+    qemu_log("qemu: Unsupported syscall vadvise()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_bsd_sbrk(void)
+{
+    /* see sys_sbrk() in vm_mmap.c */
+    qemu_log("qemu: Unsupported syscall sbrk()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_bsd_sstk(void)
+{
+    /* see sys_sstk() in vm_mmap.c */
+    qemu_log("qemu: Unsupported syscall sstk()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_mmap(caddr_t addr, size_t len, int prot, int
+ * flags, int fd, int pad, off_t pos) system call.
+ */
+static inline abi_long do_bsd_freebsd6_mmap(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6,
+        abi_long arg7)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_mmap()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !_BSD_MMAN_H_ */
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index aae8ea1..fc7bc5c 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -1,4 +1,4 @@
-/*
+/**
  *  mmap support for qemu
  *
  *  Copyright (c) 2003 - 2008 Fabrice Bellard
@@ -26,44 +26,9 @@
 
 #include "qemu.h"
 #include "qemu-common.h"
-#include "bsd-mman.h"
-
-//#define DEBUG_MMAP
-
-#if defined(CONFIG_USE_NPTL)
-pthread_mutex_t mmap_mutex;
-static int __thread mmap_lock_count;
-
-void mmap_lock(void)
-{
-    if (mmap_lock_count++ == 0) {
-        pthread_mutex_lock(&mmap_mutex);
-    }
-}
-
-void mmap_unlock(void)
-{
-    if (--mmap_lock_count == 0) {
-        pthread_mutex_unlock(&mmap_mutex);
-    }
-}
 
-/* Grab lock to make sure things are in a consistent state after fork().  */
-void mmap_fork_start(void)
-{
-    if (mmap_lock_count)
-        abort();
-    pthread_mutex_lock(&mmap_mutex);
-}
+// #define DEBUG_MMAP
 
-void mmap_fork_end(int child)
-{
-    if (child)
-        pthread_mutex_init(&mmap_mutex, NULL);
-    else
-        pthread_mutex_unlock(&mmap_mutex);
-}
-#else
 /* We aren't threadsafe to start with, so no need to worry about locking.  */
 void mmap_lock(void)
 {
@@ -72,67 +37,6 @@ void mmap_lock(void)
 void mmap_unlock(void)
 {
 }
-#endif
-
-static void *bsd_vmalloc(size_t size)
-{
-    void *p;
-    mmap_lock();
-    /* Use map and mark the pages as used.  */
-    p = mmap(NULL, size, PROT_READ | PROT_WRITE,
-             MAP_PRIVATE | MAP_ANON, -1, 0);
-
-    if (h2g_valid(p)) {
-        /* Allocated region overlaps guest address space.
-           This may recurse.  */
-        abi_ulong addr = h2g(p);
-        page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size),
-                       PAGE_RESERVED);
-    }
-
-    mmap_unlock();
-    return p;
-}
-
-void *g_malloc(size_t size)
-{
-    char * p;
-    size += 16;
-    p = bsd_vmalloc(size);
-    *(size_t *)p = size;
-    return p + 16;
-}
-
-/* We use map, which is always zero initialized.  */
-void * g_malloc0(size_t size)
-{
-    return g_malloc(size);
-}
-
-void g_free(void *ptr)
-{
-    /* FIXME: We should unmark the reserved pages here.  However this gets
-       complicated when one target page spans multiple host pages, so we
-       don't bother.  */
-    size_t *p;
-    p = (size_t *)((char *)ptr - 16);
-    munmap(p, *p);
-}
-
-void *g_realloc(void *ptr, size_t size)
-{
-    size_t old_size, copy;
-    void *new_ptr;
-
-    if (!ptr)
-        return g_malloc(size);
-    old_size = *(size_t *)((char *)ptr - 16);
-    copy = old_size < size ? old_size : size;
-    new_ptr = g_malloc(size);
-    memcpy(new_ptr, ptr, copy);
-    g_free(ptr);
-    return new_ptr;
-}
 
 /* NOTE: all the constants are the HOST ones, but addresses are target. */
 int target_mprotect(abi_ulong start, abi_ulong len, int prot)
@@ -164,11 +68,11 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
     if (start > host_start) {
         /* handle host page containing start */
         prot1 = prot;
-        for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
+        for (addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
             prot1 |= page_get_flags(addr);
         }
         if (host_end == host_start + qemu_host_page_size) {
-            for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+            for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
                 prot1 |= page_get_flags(addr);
             }
             end = host_end;
@@ -180,7 +84,7 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
     }
     if (end < host_end) {
         prot1 = prot;
-        for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+        for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
             prot1 |= page_get_flags(addr);
         }
         ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size,
@@ -218,7 +122,7 @@ static int mmap_frag(abi_ulong real_start,
 
     /* get the protection of the target pages outside the mapping */
     prot1 = 0;
-    for(addr = real_start; addr < real_end; addr++) {
+    for (addr = real_start; addr < real_end; addr++) {
         if (addr < start || addr >= end)
             prot1 |= page_get_flags(addr);
     }
@@ -246,7 +150,8 @@ static int mmap_frag(abi_ulong real_start,
             mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
 
         /* read the corresponding file data */
-        pread(fd, g2h(start), end - start, offset);
+        if (pread(fd, g2h(start), end - start, offset) == -1)
+	    return -1;
 
         /* put final protection */
         if (prot_new != (prot1 | PROT_WRITE))
@@ -260,69 +165,184 @@ static int mmap_frag(abi_ulong real_start,
     return 0;
 }
 
-#if defined(__CYGWIN__)
+#if HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
+# define TASK_UNMAPPED_BASE  (1ul << 38)
+#elif defined(__CYGWIN__)
 /* Cygwin doesn't have a whole lot of address space.  */
-static abi_ulong mmap_next_start = 0x18000000;
+# define TASK_UNMAPPED_BASE  0x18000000
 #else
-static abi_ulong mmap_next_start = 0x40000000;
+# define TASK_UNMAPPED_BASE  0x40000000
 #endif
+abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
 
 unsigned long last_brk;
 
-/* find a free memory area of size 'size'. The search starts at
-   'start'. If 'start' == 0, then a default start address is used.
-   Return -1 if error.
-*/
-/* page_init() marks pages used by the host as reserved to be sure not
-   to use them. */
-static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
+#ifdef CONFIG_USE_GUEST_BASE
+/* Subroutine of mmap_find_vma, used when we have pre-allocated a chunk
+   of guest address space.  */
+static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
 {
-    abi_ulong addr, addr1, addr_start;
+    abi_ulong addr;
+    abi_ulong end_addr;
     int prot;
-    unsigned long new_brk;
-
-    new_brk = (unsigned long)sbrk(0);
-    if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) {
-        /* This is a hack to catch the host allocating memory with brk().
-           If it uses mmap then we loose.
-           FIXME: We really want to avoid the host allocating memory in
-           the first place, and maybe leave some slack to avoid switching
-           to mmap.  */
-        page_set_flags(last_brk & TARGET_PAGE_MASK,
-                       TARGET_PAGE_ALIGN(new_brk),
-                       PAGE_RESERVED);
+    int looped = 0;
+
+    if (size > RESERVED_VA) {
+        return (abi_ulong)-1;
     }
-    last_brk = new_brk;
 
     size = HOST_PAGE_ALIGN(size);
-    start = start & qemu_host_page_mask;
-    addr = start;
-    if (addr == 0)
-        addr = mmap_next_start;
-    addr_start = addr;
-    for(;;) {
-        prot = 0;
-        for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
-            prot |= page_get_flags(addr1);
+    end_addr = start + size;
+    if (end_addr > RESERVED_VA) {
+        end_addr = RESERVED_VA;
+    }
+    addr = end_addr - qemu_host_page_size;
+
+    while (1) {
+        if (addr > end_addr) {
+            if (looped) {
+                return (abi_ulong)-1;
+            }
+            end_addr = RESERVED_VA;
+            addr = end_addr - qemu_host_page_size;
+            looped = 1;
+            continue;
+        }
+        prot = page_get_flags(addr);
+        if (prot) {
+            end_addr = addr;
         }
-        if (prot == 0)
+        if (addr + size == end_addr) {
             break;
-        addr += qemu_host_page_size;
-        /* we found nothing */
-        if (addr == addr_start)
-            return (abi_ulong)-1;
+        }
+        addr -= qemu_host_page_size;
     }
-    if (start == 0)
-        mmap_next_start = addr + size;
+
+    if (start == mmap_next_start) {
+        mmap_next_start = addr;
+    }
+
     return addr;
 }
+#endif
+
+/*
+ * Find and reserve a free memory area of size 'size'. The search
+ * starts at 'start'.
+ * It must be called with mmap_lock() held.
+ * Return -1 if error.
+ */
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
+{
+    void *ptr, *prev;
+    abi_ulong addr;
+    int wrapped, repeat;
+
+    /* If 'start' == 0, then a default start address is used. */
+    if (start == 0) {
+        start = mmap_next_start;
+    } else {
+        start &= qemu_host_page_mask;
+    }
+
+    size = HOST_PAGE_ALIGN(size);
+
+#ifdef CONFIG_USE_GUEST_BASE
+    if (RESERVED_VA) {
+        return mmap_find_vma_reserved(start, size);
+    }
+#endif
+
+    addr = start;
+    wrapped = repeat = 0;
+    prev = 0;
+
+    for (;; prev = ptr) {
+        /*
+         * Reserve needed memory area to avoid a race.
+         * It should be discarded using:
+         *  - mmap() with MAP_FIXED flag
+         *  - mremap() with MREMAP_FIXED flag
+         *  - shmat() with SHM_REMAP flag
+         */
+        ptr = mmap(g2h(addr), size, PROT_NONE,
+                   MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
+
+        /* ENOMEM, if host address space has no memory */
+        if (ptr == MAP_FAILED) {
+            return (abi_ulong)-1;
+        }
+
+        /* Count the number of sequential returns of the same address.
+           This is used to modify the search algorithm below.  */
+        repeat = (ptr == prev ? repeat + 1 : 0);
+
+        if (h2g_valid(ptr + size - 1)) {
+            addr = h2g(ptr);
+
+            if ((addr & ~TARGET_PAGE_MASK) == 0) {
+                /* Success.  */
+                if (start == mmap_next_start && addr >= TASK_UNMAPPED_BASE) {
+                    mmap_next_start = addr + size;
+                }
+                return addr;
+            }
+
+            /* The address is not properly aligned for the target.  */
+            switch (repeat) {
+            case 0:
+                /* Assume the result that the kernel gave us is the
+                   first with enough free space, so start again at the
+                   next higher target page.  */
+                addr = TARGET_PAGE_ALIGN(addr);
+                break;
+            case 1:
+                /* Sometimes the kernel decides to perform the allocation
+                   at the top end of memory instead.  */
+                addr &= TARGET_PAGE_MASK;
+                break;
+            case 2:
+                /* Start over at low memory.  */
+                addr = 0;
+                break;
+            default:
+                /* Fail.  This unaligned block must the last.  */
+                addr = -1;
+                break;
+            }
+        } else {
+            /* Since the result the kernel gave didn't fit, start
+               again at low memory.  If any repetition, fail.  */
+            addr = (repeat ? -1 : 0);
+        }
+
+        /* Unmap and try again.  */
+        munmap(ptr, size);
+
+        /* ENOMEM if we checked the whole of the target address space.  */
+        if (addr == (abi_ulong)-1) {
+            return (abi_ulong)-1;
+        } else if (addr == 0) {
+            if (wrapped) {
+                return (abi_ulong)-1;
+            }
+            wrapped = 1;
+            /* Don't actually use 0 when wrapping, instead indicate
+               that we'd truly like an allocation in low memory.  */
+            addr = (mmap_min_addr > TARGET_PAGE_SIZE
+                     ? TARGET_PAGE_ALIGN(mmap_min_addr)
+                     : TARGET_PAGE_SIZE);
+        } else if (wrapped && addr >= start) {
+            return (abi_ulong)-1;
+        }
+    }
+}
 
 /* NOTE: all the constants are the HOST ones */
 abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
-                     int flags, int fd, abi_ulong offset)
+                     int flags, int fd, off_t offset)
 {
     abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
-    unsigned long host_start;
 
     mmap_lock();
 #ifdef DEBUG_MMAP
@@ -337,21 +357,30 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
             printf("MAP_FIXED ");
         if (flags & MAP_ANON)
             printf("MAP_ANON ");
-        switch(flags & TARGET_BSD_MAP_FLAGMASK) {
-        case MAP_PRIVATE:
-            printf("MAP_PRIVATE ");
-            break;
-        case MAP_SHARED:
-            printf("MAP_SHARED ");
-            break;
-        default:
-            printf("[MAP_FLAGMASK=0x%x] ", flags & TARGET_BSD_MAP_FLAGMASK);
-            break;
-        }
-        printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset);
+	if (flags & MAP_PRIVATE)
+	    printf("MAP_PRIVATE ");
+	if (flags & MAP_SHARED)
+	    printf("MAP_SHARED ");
+	if (flags & MAP_NOCORE)
+	    printf("MAP_NOCORE ");
+#ifdef MAP_STACK
+	if (flags & MAP_STACK)
+	    printf("MAP_STACK ");
+#endif
+        printf("fd=%d offset=0x%llx\n", fd, offset);
     }
 #endif
 
+#ifdef MAP_STACK
+    if (flags & MAP_STACK) {
+        if ((fd != -1) || ((prot & (PROT_READ | PROT_WRITE)) !=
+                    (PROT_READ | PROT_WRITE))) {
+            errno = EINVAL;
+            goto fail;
+        }
+    }
+#endif /* MAP_STACK */
+
     if (offset & ~TARGET_PAGE_MASK) {
         errno = EINVAL;
         goto fail;
@@ -361,34 +390,78 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
     if (len == 0)
         goto the_end;
     real_start = start & qemu_host_page_mask;
+    host_offset = offset & qemu_host_page_mask;
 
+    /* If the user is asking for the kernel to find a location, do that
+       before we truncate the length for mapping files below.  */
     if (!(flags & MAP_FIXED)) {
-        abi_ulong mmap_start;
-        void *p;
-        host_offset = offset & qemu_host_page_mask;
         host_len = len + offset - host_offset;
         host_len = HOST_PAGE_ALIGN(host_len);
-        mmap_start = mmap_find_vma(real_start, host_len);
-        if (mmap_start == (abi_ulong)-1) {
+        start = mmap_find_vma(real_start, host_len);
+        if (start == (abi_ulong)-1) {
             errno = ENOMEM;
             goto fail;
         }
+    }
+
+    /* When mapping files into a memory area larger than the file, accesses
+       to pages beyond the file size will cause a SIGBUS.
+
+       For example, if mmaping a file of 100 bytes on a host with 4K pages
+       emulating a target with 8K pages, the target expects to be able to
+       access the first 8K. But the host will trap us on any access beyond
+       4K.
+
+       When emulating a target with a larger page-size than the hosts, we
+       may need to truncate file maps at EOF and add extra anonymous pages
+       up to the targets page boundary.  */
+
+    if ((qemu_real_host_page_size < TARGET_PAGE_SIZE)
+        && !(flags & MAP_ANONYMOUS)) {
+       struct stat sb;
+
+       if (fstat (fd, &sb) == -1)
+           goto fail;
+
+       /* Are we trying to create a map beyond EOF?.  */
+       if (offset + len > sb.st_size) {
+           /* If so, truncate the file map at eof aligned with
+              the hosts real pagesize. Additional anonymous maps
+              will be created beyond EOF.  */
+           len = (sb.st_size - offset);
+           len += qemu_real_host_page_size - 1;
+           len &= ~(qemu_real_host_page_size - 1);
+       }
+    }
+
+    if (!(flags & MAP_FIXED)) {
+        unsigned long host_start;
+        void *p;
+
+        host_len = len + offset - host_offset;
+        host_len = HOST_PAGE_ALIGN(host_len);
+
         /* Note: we prefer to control the mapping address. It is
            especially important if qemu_host_page_size >
            qemu_real_host_page_size */
-        p = mmap(g2h(mmap_start),
-                 host_len, prot, flags | MAP_FIXED, fd, host_offset);
-        if (p == MAP_FAILED)
+        p = mmap(g2h(start), host_len, prot,
+                 flags | MAP_FIXED | MAP_ANON, -1, 0);
+        if (p == MAP_FAILED) {
             goto fail;
+	}
         /* update start so that it points to the file position at 'offset' */
         host_start = (unsigned long)p;
-        if (!(flags & MAP_ANON))
+        if (!(flags & MAP_ANON)) {
+            p = mmap(g2h(start), len, prot,
+                     flags | MAP_FIXED, fd, host_offset);
+            if (p == MAP_FAILED) {
+                munmap(g2h(start), host_len);
+                goto fail;
+            }
             host_start += offset - host_offset;
+        }
         start = h2g(host_start);
     } else {
-        int flg;
-        target_ulong addr;
-
         if (start & ~TARGET_PAGE_MASK) {
             errno = EINVAL;
             goto fail;
@@ -396,12 +469,14 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
         end = start + len;
         real_end = HOST_PAGE_ALIGN(end);
 
-        for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) {
-            flg = page_get_flags(addr);
-            if (flg & PAGE_RESERVED) {
-                errno = ENXIO;
-                goto fail;
-            }
+        /*
+         * Test if requested memory area fits target address space
+         * It can fail only on 64-bit host with 32-bit target.
+         * On any other target/host host mmap() handles this error correctly.
+         */
+        if ((unsigned long)start + len - 1 > (abi_ulong) -1) {
+            errno = EINVAL;
+            goto fail;
         }
 
         /* worst case: we cannot map the file because the offset is not
@@ -410,8 +485,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
             (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
             /* msync() won't work here, so we return an error if write is
                possible while it is a shared mapping */
-            if ((flags & TARGET_BSD_MAP_FLAGMASK) == MAP_SHARED &&
-                (prot & PROT_WRITE)) {
+            if ((flags & MAP_SHARED) && (prot & PROT_WRITE)) {
                 errno = EINVAL;
                 goto fail;
             }
@@ -420,7 +494,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
                                   -1, 0);
             if (retaddr == -1)
                 goto fail;
-            pread(fd, g2h(start), len, offset);
+            if (pread(fd, g2h(start), len, offset) == -1)
+                goto fail;
             if (!(prot & PROT_WRITE)) {
                 ret = target_mprotect(start, len, prot);
                 if (ret != 0) {
@@ -480,6 +555,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
     page_dump(stdout);
     printf("\n");
 #endif
+    tb_invalidate_phys_range(start, start + len, 0);
     mmap_unlock();
     return start;
 fail:
@@ -487,13 +563,56 @@ fail:
     return -1;
 }
 
+static void mmap_reserve(abi_ulong start, abi_ulong size)
+{
+    abi_ulong real_start;
+    abi_ulong real_end;
+    abi_ulong addr;
+    abi_ulong end;
+    int prot;
+
+    real_start = start & qemu_host_page_mask;
+    real_end = HOST_PAGE_ALIGN(start + size);
+    end = start + size;
+    if (start > real_start) {
+        /* handle host page containing start */
+        prot = 0;
+        for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
+            prot |= page_get_flags(addr);
+        }
+        if (real_end == real_start + qemu_host_page_size) {
+            for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+                prot |= page_get_flags(addr);
+            }
+            end = real_end;
+        }
+        if (prot != 0)
+            real_start += qemu_host_page_size;
+    }
+    if (end < real_end) {
+        prot = 0;
+        for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+            prot |= page_get_flags(addr);
+        }
+        if (prot != 0)
+            real_end -= qemu_host_page_size;
+    }
+    if (real_start != real_end) {
+        mmap(g2h(real_start), real_end - real_start, PROT_NONE,
+                 MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
+                 -1, 0);
+    }
+}
+
 int target_munmap(abi_ulong start, abi_ulong len)
 {
     abi_ulong end, real_start, real_end, addr;
     int prot, ret;
 
 #ifdef DEBUG_MMAP
-    printf("munmap: start=0x%lx len=0x%lx\n", start, len);
+    printf("munmap: start=0x" TARGET_ABI_FMT_lx " len=0x"
+           TARGET_ABI_FMT_lx "\n",
+           start, len);
 #endif
     if (start & ~TARGET_PAGE_MASK)
         return -EINVAL;
@@ -508,11 +627,11 @@ int target_munmap(abi_ulong start, abi_ulong len)
     if (start > real_start) {
         /* handle host page containing start */
         prot = 0;
-        for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
+        for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
             prot |= page_get_flags(addr);
         }
         if (real_end == real_start + qemu_host_page_size) {
-            for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+            for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
                 prot |= page_get_flags(addr);
             }
             end = real_end;
@@ -522,7 +641,7 @@ int target_munmap(abi_ulong start, abi_ulong len)
     }
     if (end < real_end) {
         prot = 0;
-        for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+        for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
             prot |= page_get_flags(addr);
         }
         if (prot != 0)
@@ -532,11 +651,17 @@ int target_munmap(abi_ulong start, abi_ulong len)
     ret = 0;
     /* unmap what we can */
     if (real_start < real_end) {
-        ret = munmap(g2h(real_start), real_end - real_start);
+        if (RESERVED_VA) {
+            mmap_reserve(real_start, real_end - real_start);
+        } else {
+            ret = munmap(g2h(real_start), real_end - real_start);
+        }
     }
 
-    if (ret == 0)
+    if (ret == 0) {
         page_set_flags(start, start + len, 0);
+        tb_invalidate_phys_range(start, start + len, 0);
+    }
     mmap_unlock();
     return ret;
 }
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
index 590c36b..f562aad 100644
--- a/bsd-user/qemu-bsd.h
+++ b/bsd-user/qemu-bsd.h
@@ -32,6 +32,16 @@
 #include <sys/wait.h>
 #include <netinet/in.h>
 
+/* bsd-mem.c */
+abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
+        abi_ulong target_addr);
+abi_long host_to_target_ipc_perm(abi_ulong target_addr,
+        struct ipc_perm *host_ip);
+abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
+        abi_ulong target_addr);
+abi_long host_to_target_shmid_ds(abi_ulong target_addr,
+        struct shmid_ds *host_sd);
+
 /* bsd-proc.c */
 int target_to_host_resource(int code);
 rlim_t target_to_host_rlim(abi_ulong target_rlim);
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index e668a67..613a89e 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -219,7 +219,7 @@ void QEMU_NORETURN force_sig(int target_sig);
 /* mmap.c */
 int target_mprotect(abi_ulong start, abi_ulong len, int prot);
 abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
-                     int flags, int fd, abi_ulong offset);
+                     int flags, int fd, off_t offset);
 int target_munmap(abi_ulong start, abi_ulong len);
 abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
                        abi_ulong new_size, unsigned long flags,
@@ -228,6 +228,7 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
 extern unsigned long last_brk;
 void mmap_lock(void);
 void mmap_unlock(void);
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
 void cpu_list_lock(void);
 void cpu_list_unlock(void);
 #if defined(CONFIG_USE_NPTL)
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 633d638..e3967fa 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -17,22 +17,16 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
-#include <stdlib.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdarg.h>
 #include <string.h>
 #include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <time.h>
-#include <limits.h>
 #include <sys/types.h>
-#include <sys/mman.h>
 #include <sys/syscall.h>
 #include <sys/param.h>
 #include <sys/sysctl.h>
-#include <utime.h>
 
 #include "qemu.h"
 #include "qemu-common.h"
@@ -42,6 +36,7 @@ static int host_to_target_errno(int err);
 
 /* BSD independent syscall shims */
 #include "bsd-file.h"
+#include "bsd-mem.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
 
@@ -53,19 +48,18 @@ static int host_to_target_errno(int err);
 
 /* #define DEBUG */
 
-static abi_ulong target_brk;
-static abi_ulong target_original_brk;
-
 /*
  * errno conversion.
  */
 abi_long get_errno(abi_long ret)
 {
-    if (ret == -1)
+
+    if (ret == -1) {
         /* XXX need to translate host -> target errnos here */
         return -(errno);
-    else
+    } else {
         return ret;
+    }
 }
 
 static int host_to_target_errno(int err)
@@ -76,46 +70,8 @@ static int host_to_target_errno(int err)
 
 int is_error(abi_long ret)
 {
-    return (abi_ulong)ret >= (abi_ulong)(-4096);
-}
 
-void target_set_brk(abi_ulong new_brk)
-{
-    target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
-}
-
-/* do_obreak() must return target errnos. */
-static abi_long do_obreak(abi_ulong new_brk)
-{
-    abi_ulong brk_page;
-    abi_long mapped_addr;
-    int new_alloc_size;
-
-    if (!new_brk)
-        return 0;
-    if (new_brk < target_original_brk)
-        return -TARGET_EINVAL;
-
-    brk_page = HOST_PAGE_ALIGN(target_brk);
-
-    /* If the new brk is less than this, set it and we're done... */
-    if (new_brk < brk_page) {
-        target_brk = new_brk;
-        return 0;
-    }
-
-    /* We need to allocate more memory after the brk... */
-    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
-    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
-                                        PROT_READ|PROT_WRITE,
-                                        MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0));
-
-    if (!is_error(mapped_addr))
-        target_brk = new_brk;
-    else
-        return mapped_addr;
-
-    return 0;
+    return (abi_ulong)ret >= (abi_ulong)(-4096);
 }
 
 /* FIXME
@@ -169,6 +125,13 @@ static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
     return 0;
 }
 
+
+/* stub for arm semihosting support */
+abi_long do_brk(abi_ulong new_brk)
+{
+    return do_obreak(new_brk);
+}
+
 /* 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>. */
@@ -340,6 +303,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_FREEBSD_NR_getloginclass: /* getloginclass(2) */
         ret = do_freebsd_getloginclass(arg1, arg2);
         break;
+
 #if 0
     case TARGET_FREEBSD_NR_pdwait4: /* pdwait4(2) */
         ret = do_freebsd_pdwait4(arg1, arg2, arg3, arg4);
@@ -417,6 +381,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_FREEBSD_NR_auditctl: /* auditctl(2) */
         ret = do_freebsd_auditctl(arg1);
         break;
+
     case TARGET_FREEBSD_NR_utrace: /* utrace(2) */
         ret = do_bsd_utrace(arg1, arg2);
         break;
@@ -434,6 +399,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
 
+
         /*
          * File system calls.
          */
@@ -807,20 +773,95 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
 
+        /*
+         * Memory management system calls.
+         */
+    case TARGET_FREEBSD_NR_mmap: /* mmap(2) */
+        ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+           arg8);
+        break;
+
+    case TARGET_FREEBSD_NR_munmap: /* munmap(2) */
+        ret = do_bsd_munmap(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mprotect: /* mprotect(2) */
+        ret = do_bsd_mprotect(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_msync: /* msync(2) */
+        ret = do_bsd_msync(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mlock: /* mlock(2) */
+        ret = do_bsd_mlock(arg1, arg2);
+        break;
 
-    case TARGET_FREEBSD_NR_mmap:
-        ret = get_errno(target_mmap(arg1, arg2, arg3,
-                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
-                                    arg5,
-                                    arg6));
+    case TARGET_FREEBSD_NR_munlock: /* munlock(2) */
+        ret = do_bsd_munlock(arg1, arg2);
         break;
-    case TARGET_FREEBSD_NR_mprotect:
-        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+
+    case TARGET_FREEBSD_NR_mlockall: /* mlockall(2) */
+        ret = do_bsd_mlockall(arg1);
         break;
-    case TARGET_FREEBSD_NR_break:
-        ret = do_obreak(arg1);
+
+    case TARGET_FREEBSD_NR_munlockall: /* munlockall(2) */
+        ret = do_bsd_munlockall();
+        break;
+
+    case TARGET_FREEBSD_NR_madvise: /* madvise(2) */
+        ret = do_bsd_madvise(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_minherit: /* minherit(2) */
+        ret = do_bsd_minherit(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mincore: /* mincore(2) */
+        ret = do_bsd_mincore(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_shm_open: /* shm_open(2) */
+        ret = do_bsd_shm_open(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_shm_unlink: /* shm_unlink(2) */
+        ret = do_bsd_shm_unlink(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_shmget: /* shmget(2) */
+        ret = do_bsd_shmget(arg1, arg2, arg3);
         break;
 
+    case TARGET_FREEBSD_NR_shmctl: /* shmctl(2) */
+        ret = do_bsd_shmctl(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_shmat: /* shmat(2) */
+        ret = do_bsd_shmat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_shmdt: /* shmdt(2) */
+        ret = do_bsd_shmdt(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_vadvise:
+        ret = do_bsd_vadvise();
+        break;
+
+    case TARGET_FREEBSD_NR_sbrk:
+        ret = do_bsd_sbrk();
+        break;
+
+    case TARGET_FREEBSD_NR_sstk:
+        ret = do_bsd_sstk();
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_mmap: /* undocumented */
+        ret = do_bsd_freebsd6_mmap(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+        break;
+
+
         /*
          * time related system calls.
          */
@@ -997,6 +1038,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                     arg8));
         break;
     }
+
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
@@ -1033,13 +1075,10 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_NETBSD_NR_mmap:
-        ret = get_errno(target_mmap(arg1, arg2, arg3,
-                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
-                                    arg5,
-                                    arg6));
+        ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
         break;
     case TARGET_NETBSD_NR_mprotect:
-        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+        ret = do_bsd_mprotect(arg1, arg2, arg3);
         break;
 
     case TARGET_NETBSD_NR_syscall:
@@ -1086,13 +1125,10 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_OPENBSD_NR_mmap:
-        ret = get_errno(target_mmap(arg1, arg2, arg3,
-                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
-                                    arg5,
-                                    arg6));
+        ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
         break;
     case TARGET_OPENBSD_NR_mprotect:
-        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+        ret = do_bsd_mprotect(arg1, arg2, arg3);
         break;
 
     case TARGET_OPENBSD_NR_syscall:
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 13/19] bsd-user: add support for socket related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (32 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 12/19] bsd-user: add support for memory management " Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 14/19] bsd-user: add support for thread " Stacey Son
                   ` (5 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for socket related system calls including
accept(2), bind(2), connect(2), getpeername(2), getsockname(2), getsockopt(2),
setsockopt(2), listen(2), recvfrom(2), recvmsg(2), sendmsg(2), sendto(2),
socket(2), socketpair(2), shutdown(2), setfib(2), sctp_peeloff(2),
sctp_generic_sendmsg(2), sctp_generic_recvmsg(2), sendfile(2), and
freebsd4_sendfile(2).

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs       |    4 +-
 bsd-user/bsd-socket.c        |  108 +++++++++
 bsd-user/bsd-socket.h        |  266 ++++++++++++++++++++
 bsd-user/freebsd/os-socket.c |  149 ++++++++++++
 bsd-user/freebsd/os-socket.h |  548 ++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h   |    6 +
 bsd-user/netbsd/os-socket.c  |    1 +
 bsd-user/netbsd/os-socket.h  |   98 ++++++++
 bsd-user/openbsd/os-socket.c |    1 +
 bsd-user/openbsd/os-socket.h |   98 ++++++++
 bsd-user/qemu-bsd.h          |    8 +
 bsd-user/syscall.c           |   93 +++++++
 12 files changed, 1378 insertions(+), 2 deletions(-)
 create mode 100644 bsd-user/bsd-socket.c
 create mode 100644 bsd-user/bsd-socket.h
 create mode 100644 bsd-user/freebsd/os-socket.c
 create mode 100644 bsd-user/freebsd/os-socket.h
 create mode 100644 bsd-user/netbsd/os-socket.c
 create mode 100644 bsd-user/netbsd/os-socket.h
 create mode 100644 bsd-user/openbsd/os-socket.c
 create mode 100644 bsd-user/openbsd/os-socket.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 1a33a6d..9869837 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,6 +1,6 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-mem.o bsd-proc.o \
+	        uaccess.o bsd-mem.o bsd-proc.o bsd-socket.o \
 			$(HOST_ABI_DIR)/os-proc.o \
-			$(HOST_ABI_DIR)/os-stat.o \
+			$(HOST_ABI_DIR)/os-socket.o $(HOST_ABI_DIR)/os-stat.o \
 			$(HOST_ABI_DIR)/os-sys.o \
 			$(HOST_ABI_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/bsd-socket.c b/bsd-user/bsd-socket.c
new file mode 100644
index 0000000..c1a3b49
--- /dev/null
+++ b/bsd-user/bsd-socket.c
@@ -0,0 +1,108 @@
+/*
+ *  BSD socket system call related helpers
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+/*
+ * socket conversion
+ */
+abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr,
+        socklen_t len)
+{
+    const socklen_t unix_maxlen = sizeof(struct sockaddr_un);
+    sa_family_t sa_family;
+    struct target_sockaddr *target_saddr;
+
+    target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
+    if (target_saddr == 0) {
+        return -TARGET_EFAULT;
+    }
+
+    sa_family = 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 will
+     * fix that here if needed.
+     */
+    if (target_saddr->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;
+        }
+    }
+
+    memcpy(addr, target_saddr, len);
+    addr->sa_family = sa_family;        /* type uint8_t */
+    addr->sa_len = target_saddr->sa_len;    /* type uint8_t */
+    unlock_user(target_saddr, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
+        socklen_t len)
+{
+    struct target_sockaddr *target_saddr;
+
+    target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
+    if (target_saddr == 0) {
+        return -TARGET_EFAULT;
+    }
+    memcpy(target_saddr, addr, len);
+    target_saddr->sa_family = addr->sa_family;  /* type uint8_t */
+    target_saddr->sa_len = addr->sa_len;        /* type uint8_t */
+    unlock_user(target_saddr, target_addr, len);
+
+    return 0;
+}
+
+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 == 0) {
+        return -TARGET_EFAULT;
+    }
+    mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
+    mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
+    if (len == sizeof(struct target_ip_mreqn)) {
+        mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
+    }
+    unlock_user(target_smreqn, target_addr, 0);
+
+    return 0;
+}
+
diff --git a/bsd-user/bsd-socket.h b/bsd-user/bsd-socket.h
new file mode 100644
index 0000000..f5d1ac8
--- /dev/null
+++ b/bsd-user/bsd-socket.h
@@ -0,0 +1,266 @@
+/*
+ *  socket related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __BSD_SOCKET_H_
+#define __BSD_SOCKET_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu-bsd.h"
+
+/* bind(2) */
+static inline abi_long do_bsd_bind(int sockfd, abi_ulong target_addr,
+        socklen_t addrlen)
+{
+    abi_long ret;
+    void *addr;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+
+    addr = alloca(addrlen + 1);
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(bind(sockfd, addr, addrlen));
+}
+
+/* connect(2) */
+static inline abi_long do_bsd_connect(int sockfd, abi_ulong target_addr,
+        socklen_t addrlen)
+{
+    abi_long ret;
+    void *addr;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    addr = alloca(addrlen);
+
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(connect(sockfd, addr, addrlen));
+}
+
+/* accept(2) */
+static inline abi_long do_bsd_accept(int fd, abi_ulong target_addr,
+        abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (target_addr == 0) {
+        return get_errno(accept(fd, NULL, NULL));
+    }
+    /* return EINVAL if addrlen pointer is invalid */
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EINVAL;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EINVAL;
+    }
+    addr = alloca(addrlen);
+
+    ret = get_errno(accept(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getpeername(2) */
+static inline abi_long do_bsd_getpeername(int fd, abi_ulong target_addr,
+        abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EFAULT;
+    }
+    addr = alloca(addrlen);
+    ret = get_errno(getpeername(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getsockname(2) */
+static inline abi_long do_bsd_getsockname(int fd, abi_ulong target_addr,
+        abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EFAULT;
+    }
+    addr = alloca(addrlen);
+
+    ret = get_errno(getsockname(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* socketpair(2) */
+static inline abi_long do_bsd_socketpair(int domain, int type, int protocol,
+        abi_ulong target_tab_addr)
+{
+    int tab[2];
+    abi_long ret;
+
+    ret = get_errno(socketpair(domain, type, protocol, tab));
+    if (!is_error(ret)) {
+        if (put_user_s32(tab[0], target_tab_addr) ||
+                put_user_s32(tab[1], target_tab_addr + sizeof(tab[0]))) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* sendto(2) */
+static inline abi_long do_bsd_sendto(int fd, abi_ulong msg, size_t len,
+        int flags, abi_ulong target_addr, socklen_t addrlen)
+{
+    struct sockaddr *saddr;
+    void *host_msg;
+    abi_long ret;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    host_msg = lock_user(VERIFY_READ, msg, len, 1);
+    if (!host_msg) {
+        return -TARGET_EFAULT;
+    }
+    if (target_addr) {
+        saddr = alloca(addrlen);
+        ret = target_to_host_sockaddr(saddr, target_addr, addrlen);
+        if (is_error(ret)) {
+            unlock_user(host_msg, msg, 0);
+            return ret;
+        }
+        ret = get_errno(sendto(fd, host_msg, len, flags, saddr, addrlen));
+    } else {
+        ret = get_errno(send(fd, host_msg, len, flags));
+    }
+    unlock_user(host_msg, msg, 0);
+    return ret;
+}
+
+/* recvfrom(2) */
+static inline abi_long do_bsd_recvfrom(int fd, abi_ulong msg, size_t len,
+        int flags, abi_ulong target_addr, abi_ulong target_addrlen)
+{
+    socklen_t addrlen;
+    struct sockaddr *saddr;
+    void *host_msg;
+    abi_long ret;
+
+    host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
+    if (!host_msg) {
+        return -TARGET_EFAULT;
+    }
+    if (target_addr) {
+        if (get_user_u32(addrlen, target_addrlen)) {
+            ret = -TARGET_EFAULT;
+            goto fail;
+        }
+        if ((int)addrlen < 0) {
+            ret = -TARGET_EINVAL;
+            goto fail;
+        }
+        saddr = alloca(addrlen);
+        ret = get_errno(recvfrom(fd, host_msg, len, flags, saddr, &addrlen));
+    } else {
+        saddr = NULL; /* To keep compiler quiet.  */
+        ret = get_errno(qemu_recv(fd, host_msg, len, flags));
+    }
+    if (!is_error(ret)) {
+        if (target_addr) {
+            host_to_target_sockaddr(target_addr, saddr, addrlen);
+            if (put_user_u32(addrlen, target_addrlen)) {
+                ret = -TARGET_EFAULT;
+                goto fail;
+            }
+        }
+        unlock_user(host_msg, msg, len);
+    } else {
+fail:
+        unlock_user(host_msg, msg, 0);
+    }
+    return ret;
+}
+
+/* socket(2) */
+static inline abi_long do_bsd_socket(abi_long domain, abi_long type,
+        abi_long protocol)
+{
+
+    return get_errno(socket(domain, type, protocol));
+}
+
+/* shutdown(2) */
+static inline abi_long do_bsd_shutdown(abi_long s, abi_long how)
+{
+
+    return get_errno(shutdown(s, how));
+}
+
+#endif /* !__BSD_SOCKET_H_ */
diff --git a/bsd-user/freebsd/os-socket.c b/bsd-user/freebsd/os-socket.c
new file mode 100644
index 0000000..949af28
--- /dev/null
+++ b/bsd-user/freebsd/os-socket.c
@@ -0,0 +1,149 @@
+/*
+ *  FreeBSD socket related system call helpers
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+abi_long t2h_freebsd_cmsg(struct msghdr *msgh,
+        struct target_msghdr *target_msgh)
+{
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
+    abi_long msg_controllen;
+    abi_ulong target_cmsg_addr;
+    struct target_cmsghdr *target_cmsg;
+    socklen_t space = 0;
+
+
+    msg_controllen = tswapal(target_msgh->msg_controllen);
+    if (msg_controllen < sizeof(struct target_cmsghdr)) {
+        goto the_end;
+    }
+    target_cmsg_addr = tswapal(target_msgh->msg_control);
+    target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
+    if (target_cmsg == 0) {
+        return -TARGET_EFAULT;
+    }
+    while (cmsg && target_cmsg) {
+        void *data = CMSG_DATA(cmsg);
+        void *target_data = TARGET_CMSG_DATA(target_cmsg);
+        int len = tswapal(target_cmsg->cmsg_len) -
+            TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr));
+        space += CMSG_SPACE(len);
+        if (space > msgh->msg_controllen) {
+            space -= CMSG_SPACE(len);
+            gemu_log("Host cmsg overflow\n");
+            break;
+        }
+        cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
+        cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
+        cmsg->cmsg_len = CMSG_LEN(len);
+
+        if (cmsg->cmsg_level != TARGET_SOL_SOCKET ||
+            cmsg->cmsg_type != SCM_RIGHTS) {
+            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);
+    }
+    unlock_user(target_cmsg, target_cmsg_addr, 0);
+
+the_end:
+    msgh->msg_controllen = space;
+    return 0;
+}
+
+abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh,
+        struct msghdr *msgh)
+{
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
+    abi_long msg_controllen;
+    abi_ulong target_cmsg_addr;
+    struct target_cmsghdr *target_cmsg;
+    socklen_t space = 0;
+
+    msg_controllen = tswapal(target_msgh->msg_controllen);
+    if (msg_controllen < sizeof(struct target_cmsghdr)) {
+        goto the_end;
+    }
+    target_cmsg_addr = tswapal(target_msgh->msg_control);
+    target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr,
+        msg_controllen, 0);
+    if (target_cmsg == 0) {
+        return -TARGET_EFAULT;
+    }
+    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);
+        if (space > msg_controllen) {
+            space -= TARGET_CMSG_SPACE(len);
+            gemu_log("Target cmsg overflow\n");
+            break;
+        }
+        target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
+        target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
+        target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
+        if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
+            (cmsg->cmsg_type == SCM_RIGHTS)) {
+            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]);
+            }
+        } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
+            (cmsg->cmsg_type == SO_TIMESTAMP) &&
+            (len == sizeof(struct timeval))) {
+            /* copy struct timeval to target */
+            struct timeval *tv = (struct timeval *)data;
+            struct target_freebsd_timeval *target_tv =
+                (struct target_freebsd_timeval *)target_data;
+            __put_user(tv->tv_sec, &target_tv->tv_sec);
+            __put_user(tv->tv_usec, &target_tv->tv_usec);
+        } else {
+            gemu_log("Unsupported ancillary data: %d/%d\n",
+                cmsg->cmsg_level, cmsg->cmsg_type);
+            memcpy(target_data, data, len);
+        }
+        cmsg = CMSG_NXTHDR(msgh, cmsg);
+        target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
+    }
+    unlock_user(target_cmsg, target_cmsg_addr, space);
+
+the_end:
+    target_msgh->msg_controllen = tswapal(space);
+    return 0;
+}
+
diff --git a/bsd-user/freebsd/os-socket.h b/bsd-user/freebsd/os-socket.h
new file mode 100644
index 0000000..9339ffb
--- /dev/null
+++ b/bsd-user/freebsd/os-socket.h
@@ -0,0 +1,548 @@
+/*
+ *  FreeBSD socket related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __FREEBSD_SOCKET_H_
+#define __FREEBSD_SOCKET_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu-os.h"
+
+/* sendmsg(2) */
+static inline abi_long do_freebsd_sendmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+    abi_long ret;
+    struct target_msghdr *msgp;
+    struct msghdr msg;
+    int count;
+    struct iovec *vec;
+    abi_ulong target_vec;
+
+    if (!lock_user_struct(VERIFY_READ, msgp, target_msg, 1)) {
+        return -TARGET_EFAULT;
+    }
+    if (msgp->msg_name) {
+        msg.msg_namelen = tswap32(msgp->msg_namelen);
+        msg.msg_name = alloca(msg.msg_namelen);
+        ret = target_to_host_sockaddr(msg.msg_name,
+            tswapal(msgp->msg_name), msg.msg_namelen);
+
+        if (is_error(ret)) {
+            unlock_user_struct(msgp, target_msg, 0);
+            return ret;
+        }
+    } else {
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+    }
+    msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
+    msg.msg_control = alloca(msg.msg_controllen);
+    msg.msg_flags = tswap32(msgp->msg_flags);
+
+    count = tswapal(msgp->msg_iovlen);
+    vec = alloca(count * sizeof(struct iovec));
+    target_vec = tswapal(msgp->msg_iov);
+    lock_iovec(VERIFY_READ, vec, target_vec, count, 1);
+    msg.msg_iovlen = count;
+    msg.msg_iov = vec;
+
+    ret = t2h_freebsd_cmsg(&msg, msgp);
+    if (!is_error(ret)) {
+        ret = get_errno(sendmsg(fd, &msg, flags));
+    }
+    unlock_iovec(vec, target_vec, count, 0);
+    unlock_user_struct(msgp, target_msg, 0);
+    return ret;
+}
+
+/* recvmsg(2) */
+static inline abi_long do_freebsd_recvmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+    abi_long ret, len;
+    struct target_msghdr *msgp;
+    struct msghdr msg;
+    int count;
+    struct iovec *vec;
+    abi_ulong target_vec;
+
+    if (!lock_user_struct(VERIFY_WRITE, msgp, target_msg, 0)) {
+        return -TARGET_EFAULT;
+    }
+    if (msgp->msg_name) {
+        msg.msg_namelen = tswap32(msgp->msg_namelen);
+        msg.msg_name = alloca(msg.msg_namelen);
+        ret = target_to_host_sockaddr(msg.msg_name,
+            tswapal(msgp->msg_name), msg.msg_namelen);
+
+        if (is_error(ret)) {
+            unlock_user_struct(msgp, target_msg, 1);
+            return ret;
+        }
+    } else {
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+    }
+    msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
+    msg.msg_control = alloca(msg.msg_controllen);
+    msg.msg_flags = tswap32(msgp->msg_flags);
+
+    count = tswapal(msgp->msg_iovlen);
+    vec = alloca(count * sizeof(struct iovec));
+    target_vec = tswapal(msgp->msg_iov);
+    lock_iovec(VERIFY_WRITE, vec, target_vec, count, 0);
+    msg.msg_iovlen = count;
+    msg.msg_iov = vec;
+
+    ret = get_errno(recvmsg(fd, &msg, flags));
+    if (!is_error(ret)) {
+        len = ret;
+        ret = h2t_freebsd_cmsg(msgp, &msg);
+        if (!is_error(ret)) {
+            msgp->msg_namelen = tswap32(msg.msg_namelen);
+            if (msg.msg_name != NULL) {
+                ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
+                        msg.msg_name, msg.msg_namelen);
+                if (is_error(ret)) {
+                    goto out;
+                }
+            }
+        }
+        ret = len;
+    }
+out:
+    unlock_iovec(vec, target_vec, count, 1);
+    unlock_user_struct(msgp, target_msg, 1);
+    return ret;
+}
+
+/* setsockopt(2) */
+static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, socklen_t optlen)
+{
+    abi_long ret;
+    int val;
+    struct ip_mreqn *ip_mreq;
+
+    switch (level) {
+    case IPPROTO_TCP:
+        /* TCP options all take an 'int' value. */
+        if (optlen < sizeof(uint32_t)) {
+            return -TARGET_EINVAL;
+        }
+        if (get_user_u32(val, optval_addr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
+        break;
+
+    case IPPROTO_IP:
+        switch (optname) {
+        case IP_HDRINCL:/* int; header is included with data */
+        case IP_TOS:    /* int; IP type of service and preced. */
+        case IP_TTL:    /* int; IP time to live */
+        case IP_RECVOPTS: /* bool; receive all IP opts w/dgram */
+        case IP_RECVRETOPTS: /* bool; receive IP opts for response */
+        case IP_RECVDSTADDR: /* bool; receive IP dst addr w/dgram */
+        case IP_MULTICAST_IF:/* u_char; set/get IP multicast i/f  */
+        case IP_MULTICAST_TTL:/* u_char; set/get IP multicast ttl */
+        case IP_MULTICAST_LOOP:/*u_char;set/get IP multicast loopback */
+        case IP_PORTRANGE: /* int; range to choose for unspec port */
+        case IP_RECVIF: /* bool; receive reception if w/dgram */
+        case IP_IPSEC_POLICY:   /* int; set/get security policy */
+        case IP_FAITH:  /* bool; accept FAITH'ed connections */
+        case IP_RECVTTL: /* bool; receive reception TTL w/dgram */
+            val = 0;
+            if (optlen >= sizeof(uint32_t)) {
+                if (get_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            } else if (optlen >= 1) {
+                if (get_user_u8(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            }
+            ret = get_errno(setsockopt(sockfd, level, optname, &val,
+                        sizeof(val)));
+            break;
+
+        case IP_ADD_MEMBERSHIP: /*ip_mreq; add an IP group membership */
+        case IP_DROP_MEMBERSHIP:/*ip_mreq; drop an IP group 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;
+
+        default:
+            goto unimplemented;
+        }
+        break;
+
+    case TARGET_SOL_SOCKET:
+        switch (optname) {
+        /* Options with 'int' argument.  */
+        case TARGET_SO_DEBUG:
+            optname = SO_DEBUG;
+            break;
+
+        case TARGET_SO_REUSEADDR:
+            optname = SO_REUSEADDR;
+            break;
+
+        case TARGET_SO_REUSEPORT:
+            optname = SO_REUSEADDR;
+            break;
+
+        case TARGET_SO_KEEPALIVE:
+            optname = SO_KEEPALIVE;
+            break;
+
+        case TARGET_SO_DONTROUTE:
+            optname = SO_DONTROUTE;
+            break;
+
+        case TARGET_SO_LINGER:
+            optname = SO_LINGER;
+            break;
+
+        case TARGET_SO_BROADCAST:
+            optname = SO_BROADCAST;
+            break;
+
+        case TARGET_SO_OOBINLINE:
+            optname = SO_OOBINLINE;
+            break;
+
+        case TARGET_SO_SNDBUF:
+            optname = SO_SNDBUF;
+            break;
+
+        case TARGET_SO_RCVBUF:
+            optname = SO_RCVBUF;
+            break;
+
+        case TARGET_SO_SNDLOWAT:
+            optname = SO_RCVLOWAT;
+            break;
+
+        case TARGET_SO_RCVLOWAT:
+            optname = SO_RCVLOWAT;
+            break;
+
+        case TARGET_SO_SNDTIMEO:
+            optname = SO_SNDTIMEO;
+            break;
+
+        case TARGET_SO_RCVTIMEO:
+            optname = SO_RCVTIMEO;
+            break;
+
+        case TARGET_SO_ACCEPTFILTER:
+            goto unimplemented;
+
+        case TARGET_SO_NOSIGPIPE:
+            optname = SO_NOSIGPIPE;
+            break;
+
+        case TARGET_SO_TIMESTAMP:
+            optname = SO_TIMESTAMP;
+            break;
+
+        case TARGET_SO_BINTIME:
+            optname = SO_BINTIME;
+            break;
+
+        case TARGET_SO_ERROR:
+            optname = SO_ERROR;
+            break;
+
+        case TARGET_SO_SETFIB:
+            optname = SO_ERROR;
+            break;
+
+#ifdef SO_USER_COOKIE
+        case TARGET_SO_USER_COOKIE:
+            optname = SO_USER_COOKIE;
+            break;
+#endif
+        default:
+            goto unimplemented;
+        }
+        if (optlen < sizeof(uint32_t)) {
+            return -TARGET_EINVAL;
+        }
+        if (get_user_u32(val, optval_addr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val,
+                    sizeof(val)));
+        break;
+    default:
+unimplemented:
+    gemu_log("Unsupported setsockopt level=%d optname=%d\n",
+        level, optname);
+    ret = -TARGET_ENOPROTOOPT;
+    }
+
+    return ret;
+}
+
+/* getsockopt(2) */
+static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, abi_ulong optlen)
+{
+    abi_long ret;
+    int len, val;
+    socklen_t lv;
+
+    switch (level) {
+    case TARGET_SOL_SOCKET:
+        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_ACCEPTFILTER:
+            goto unimplemented;
+
+        /* 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_REUSEPORT:
+            optname = SO_REUSEPORT;
+            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_TIMESTAMP:
+            optname = SO_TIMESTAMP;
+            goto int_case;
+
+        case TARGET_SO_RCVLOWAT:
+            optname = SO_RCVLOWAT;
+            goto int_case;
+
+        case TARGET_SO_LISTENINCQLEN:
+            optname = SO_LISTENINCQLEN;
+            goto int_case;
+
+        default:
+int_case:
+            if (get_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            if (len < 0) {
+                return -TARGET_EINVAL;
+            }
+            lv = sizeof(lv);
+            ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len > lv) {
+                len = lv;
+            }
+            if (len == 4) {
+                if (put_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            } else {
+                if (put_user_u8(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            }
+            if (put_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            break;
+
+        }
+        break;
+
+    case IPPROTO_TCP:
+        /* TCP options all take an 'int' value. */
+        goto int_case;
+
+    case IPPROTO_IP:
+        switch (optname) {
+        case IP_HDRINCL:
+        case IP_TOS:
+        case IP_TTL:
+        case IP_RECVOPTS:
+        case IP_RECVRETOPTS:
+        case IP_RECVDSTADDR:
+
+        case IP_RETOPTS:
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 && defined(IP_RECVTOS)
+        case IP_RECVTOS:
+#endif
+        case IP_MULTICAST_TTL:
+        case IP_MULTICAST_LOOP:
+        case IP_PORTRANGE:
+        case IP_IPSEC_POLICY:
+        case IP_FAITH:
+        case IP_ONESBCAST:
+        case IP_BINDANY:
+            if (get_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            if (len < 0) {
+                return -TARGET_EINVAL;
+            }
+            lv = sizeof(lv);
+            ret = get_errno(getsockopt(sockfd, level, optname,
+                &val, &lv));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len < sizeof(int) && len > 0 && val >= 0 &&
+                val < 255) {
+                len = 1;
+                if (put_user_u32(len, optlen) ||
+                        put_user_u8(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            } else {
+                if (len > sizeof(int)) {
+                    len = sizeof(int);
+                }
+                if (put_user_u32(len, optlen) ||
+                        put_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            }
+            break;
+
+        default:
+            goto unimplemented;
+        }
+        break;
+
+    default:
+unimplemented:
+        gemu_log("getsockopt level=%d optname=%d not yet supported\n",
+            level, optname);
+        ret = -TARGET_EOPNOTSUPP;
+        break;
+    }
+    return ret;
+}
+
+/* setfib(2) */
+static inline abi_long do_freebsd_setfib(abi_long fib)
+{
+
+    return get_errno(setfib(fib));
+}
+
+/* sctp_peeloff(2) */
+static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_peeloff()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_sendmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s,
+        abi_ulong target_msg, abi_long msglen, abi_ulong target_to,
+        abi_ulong len, abi_ulong target_sinfo, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_recvmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s,
+        abi_ulong target_iov, abi_long iovlen, abi_ulong target_from,
+        abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* freebsd4_sendfile(2) */
+static inline abi_long do_freebsd_freebsd4_sendfile(abi_long fd, abi_long s,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong nbytes, abi_ulong target_hdtr,
+        abi_ulong target_sbytes, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd4_sendfile()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sendfile(2) */
+static inline abi_long do_freebsd_sendfile(abi_long fd, abi_long s,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong nbytes, abi_ulong target_hdtr,
+        abi_ulong target_sbytes, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sendfile()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__FREEBSD_SOCKET_H_ */
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index e915246..90d8eb4 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -50,6 +50,12 @@ abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
 abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds,
         int n);
 
+/* os-socket.c */
+abi_long t2h_freebsd_cmsg(struct msghdr *msgh,
+                struct target_msghdr *target_msgh);
+abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh,
+                struct msghdr *msgh);
+
 /* os-stat.c */
 abi_long h2t_freebsd_stat(abi_ulong target_addr, struct stat *host_st);
 abi_long h2t_freebsd_nstat(abi_ulong target_addr, struct stat *host_st);
diff --git a/bsd-user/netbsd/os-socket.c b/bsd-user/netbsd/os-socket.c
new file mode 100644
index 0000000..d983c34
--- /dev/null
+++ b/bsd-user/netbsd/os-socket.c
@@ -0,0 +1 @@
+/* XXX NetBSD socket related helpers */
diff --git a/bsd-user/netbsd/os-socket.h b/bsd-user/netbsd/os-socket.h
new file mode 100644
index 0000000..a49c41d
--- /dev/null
+++ b/bsd-user/netbsd/os-socket.h
@@ -0,0 +1,98 @@
+/*
+ *  NetBSD socket related system call shims
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __NETBSD_SOCKET_H_
+#define __NETBSD_SOCKET_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* sendmsg(2) */
+static inline abi_long do_freebsd_sendmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* recvmsg(2) */
+static inline abi_long do_freebsd_recvmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setsockopt(2) */
+static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, socklen_t optlen)
+{
+
+    qemu_log("qemu: Unsupported syscall setsockopt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getsockopt(2) */
+static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, abi_ulong optlen)
+{
+
+    qemu_log("qemu: Unsupported syscall getsockopt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setfib(2) */
+static inline abi_long do_freebsd_setfib(abi_long fib)
+{
+
+    qemu_log("qemu: Unsupported syscall setfib()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_peeloff(2) */
+static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_peeloff()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_sendmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s,
+        abi_ulong target_msg, abi_long msglen, abi_ulong target_to,
+        abi_ulong len, abi_ulong target_sinfo, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_recvmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s,
+        abi_ulong target_iov, abi_long iovlen, abi_ulong target_from,
+        abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__NETBSD_SOCKET_H_ */
diff --git a/bsd-user/openbsd/os-socket.c b/bsd-user/openbsd/os-socket.c
new file mode 100644
index 0000000..183002d
--- /dev/null
+++ b/bsd-user/openbsd/os-socket.c
@@ -0,0 +1 @@
+/* XXX OpenBSD socket related helpers */
diff --git a/bsd-user/openbsd/os-socket.h b/bsd-user/openbsd/os-socket.h
new file mode 100644
index 0000000..b8b1e99
--- /dev/null
+++ b/bsd-user/openbsd/os-socket.h
@@ -0,0 +1,98 @@
+/*
+ *  OpenBSD socket related system call shims
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __OPENBSD_SOCKET_H_
+#define __OPENBSD_SOCKET_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* sendmsg(2) */
+static inline abi_long do_freebsd_sendmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* recvmsg(2) */
+static inline abi_long do_freebsd_recvmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setsockopt(2) */
+static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, socklen_t optlen)
+{
+
+    qemu_log("qemu: Unsupported syscall setsockopt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getsockopt(2) */
+static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, abi_ulong optlen)
+{
+
+    qemu_log("qemu: Unsupported syscall getsockopt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setfib(2) */
+static inline abi_long do_freebsd_setfib(abi_long fib)
+{
+
+    qemu_log("qemu: Unsupported syscall setfib()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_peeloff(2) */
+static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_peeloff()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_sendmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s,
+        abi_ulong target_msg, abi_long msglen, abi_ulong target_to,
+        abi_ulong len, abi_ulong target_sinfo, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_recvmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s,
+        abi_ulong target_iov, abi_long iovlen, abi_ulong target_from,
+        abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__OPENBSD_SOCKET_H_ */
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
index f562aad..09b99ef 100644
--- a/bsd-user/qemu-bsd.h
+++ b/bsd-user/qemu-bsd.h
@@ -50,4 +50,12 @@ abi_long host_to_target_rusage(abi_ulong target_addr,
         const struct rusage *rusage);
 int host_to_target_waitstatus(int status);
 
+/* bsd-socket.c */
+abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr,
+        socklen_t len);
+abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
+        socklen_t len);
+abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr,
+        socklen_t len);
+
 #endif /* !_QEMU_BSD_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index e3967fa..286c71e 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -39,11 +39,13 @@ static int host_to_target_errno(int err);
 #include "bsd-mem.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
+#include "bsd-socket.h"
 
 /* *BSD dependent syscall shims */
 #include "os-time.h"
 #include "os-proc.h"
 #include "os-signal.h"
+#include "os-socket.h"
 #include "os-stat.h"
 
 /* #define DEBUG */
@@ -1017,6 +1019,97 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * socket related system calls
+         */
+    case TARGET_FREEBSD_NR_accept: /* accept(2) */
+        ret = do_bsd_accept(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_bind: /* bind(2) */
+        ret = do_bsd_bind(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_connect: /* connect(2) */
+        ret = do_bsd_connect(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getpeername: /* getpeername(2) */
+        ret = do_bsd_getpeername(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getsockname: /* getsockname(2) */
+        ret = do_bsd_getsockname(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getsockopt: /* getsockopt(2) */
+        ret = do_bsd_getsockopt(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_setsockopt: /* setsockopt(2) */
+        ret = do_bsd_setsockopt(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_listen: /* listen(2) */
+        ret = get_errno(listen(arg1, arg2));
+        break;
+
+    case TARGET_FREEBSD_NR_recvfrom: /* recvfrom(2) */
+        ret = do_bsd_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_recvmsg: /* recvmsg(2) */
+        ret = do_freebsd_recvmsg(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sendmsg: /* sendmsg(2) */
+        ret = do_freebsd_sendmsg(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sendto: /* sendto(2) */
+        ret = do_bsd_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_socket: /* socket(2) */
+        ret = do_bsd_socket(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_socketpair: /* socketpair(2) */
+        ret = do_bsd_socketpair(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_shutdown: /* shutdown(2) */
+        ret = do_bsd_shutdown(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setfib: /* setfib(2) */
+        ret = do_freebsd_setfib(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sctp_peeloff: /* sctp_peeloff(2) */
+        ret = do_freebsd_sctp_peeloff(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sctp_generic_sendmsg: /* sctp_generic_sendmsg(2) */
+        ret = do_freebsd_sctp_generic_sendmsg(arg1, arg2, arg2, arg4, arg5,
+                arg6, arg7);
+        break;
+
+    case TARGET_FREEBSD_NR_sctp_generic_recvmsg: /* sctp_generic_recvmsg(2) */
+        ret = do_freebsd_sctp_generic_recvmsg(arg1, arg2, arg2, arg4, arg5,
+                arg6, arg7);
+        break;
+
+    case TARGET_FREEBSD_NR_sendfile: /* sendfile(2) */
+        ret = do_freebsd_sendfile(arg1, arg2, arg2, arg4, arg5, arg6, arg7,
+                arg8);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd4_sendfile: /* freebsd4_sendfile(2) */
+        ret = do_freebsd_freebsd4_sendfile(arg1, arg2, arg2, arg4, arg5,
+                arg6, arg7, arg8);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 14/19] bsd-user: add support for thread related system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (33 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 13/19] bsd-user: add support for socket " Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-27 11:28   ` Paolo Bonzini
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 15/19] bsd-user: add support for the ioctl system call Stacey Son
                   ` (4 subsequent siblings)
  39 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for thread related system calls including
thr_create(), thr_new(), thr_set_name(), thr_self(), thr_suspend(),
thr_wake(), thr_kill(), thr_kill2(), rtprio_thread(2), getcontext(2),
setcontext(2), swapcontext(2), _umtx_lock(), _umtx_unlock(), and
_umtx_op().

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs       |    2 +-
 bsd-user/freebsd/os-thread.c | 1001 ++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-thread.h |  511 +++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h   |    6 +
 bsd-user/mmap.c              |   26 +-
 bsd-user/netbsd/os-thread.c  |    1 +
 bsd-user/netbsd/os-thread.h  |  133 ++++++
 bsd-user/openbsd/os-thread.c |    1 +
 bsd-user/openbsd/os-thread.h |  133 ++++++
 bsd-user/qemu.h              |   59 +++-
 bsd-user/syscall.c           |   71 +++-
 bsd-user/syscall_defs.h      |    6 +-
 include/qemu/tls.h           |    2 +-
 13 files changed, 1934 insertions(+), 18 deletions(-)
 create mode 100644 bsd-user/freebsd/os-thread.c
 create mode 100644 bsd-user/freebsd/os-thread.h
 create mode 100644 bsd-user/netbsd/os-thread.c
 create mode 100644 bsd-user/netbsd/os-thread.h
 create mode 100644 bsd-user/openbsd/os-thread.c
 create mode 100644 bsd-user/openbsd/os-thread.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 9869837..b691ffc 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -2,5 +2,5 @@ obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
 	        uaccess.o bsd-mem.o bsd-proc.o bsd-socket.o \
 			$(HOST_ABI_DIR)/os-proc.o \
 			$(HOST_ABI_DIR)/os-socket.o $(HOST_ABI_DIR)/os-stat.o \
-			$(HOST_ABI_DIR)/os-sys.o \
+			$(HOST_ABI_DIR)/os-sys.o $(HOST_ABI_DIR)/os-thread.o \
 			$(HOST_ABI_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/freebsd/os-thread.c b/bsd-user/freebsd/os-thread.c
new file mode 100644
index 0000000..6bf2a9f
--- /dev/null
+++ b/bsd-user/freebsd/os-thread.c
@@ -0,0 +1,1001 @@
+/*
+ *  FreeBSD thr emulation support code
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/mman.h>
+#include <sys/thr.h>
+#include <sys/umtx.h>
+#include <sys/rtprio.h>
+
+#include <machine/atomic.h>
+
+#include <time.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+#include "target_arch_cpu.h"
+#include "target_arch_thread.h"
+
+// #define DEBUG_UMTX(...)   fprintf(stderr, __VA_ARGS__)
+#define DEBUG_UMTX(...)
+
+#define NEW_STACK_SIZE  0x40000
+
+/* sys/_umtx.h */
+struct target_umtx {
+    abi_ulong   u_owner;    /* Owner of the mutex. */
+};
+
+struct target_umutex {
+    uint32_t    m_owner;    /* Owner of the mutex */
+    uint32_t    m_flags;    /* Flags of the mutex */
+    uint32_t    m_ceiling[2];   /* Priority protect ceiling */
+    uint32_t    m_spare[4];
+};
+
+struct target_ucond {
+    uint32_t    c_has_waiters;  /* Has waiters in kernel */
+    uint32_t    c_flags;    /* Flags of the condition variable */
+    uint32_t    c_clockid;  /* Clock id */
+    uint32_t    c_spare[1];
+};
+
+struct target_urwlock {
+    uint32_t    rw_state;
+    uint32_t    rw_flags;
+    uint32_t    rw_blocked_readers;
+    uint32_t    rw_blocked_writers;
+    uint32_t    rw_spare[4];
+};
+
+struct target__usem {
+    uint32_t    _has_waiters;
+    uint32_t    _count;
+    uint32_t    _flags;
+};
+
+static pthread_mutex_t new_thread_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t *new_freebsd_thread_lock_ptr = &new_thread_lock;
+
+static pthread_mutex_t umtx_wait_lck = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t umtx_wait_cv = PTHREAD_COND_INITIALIZER;
+static abi_ulong umtx_wait_addr;
+
+static void rtp_to_schedparam(const struct rtprio *rtp, int *policy,
+        struct sched_param *param)
+{
+
+    switch (rtp->type) {
+    case RTP_PRIO_REALTIME:
+        *policy = SCHED_RR;
+        param->sched_priority = RTP_PRIO_MAX - rtp->prio;
+        break;
+
+    case RTP_PRIO_FIFO:
+        *policy = SCHED_FIFO;
+        param->sched_priority = RTP_PRIO_MAX - rtp->prio;
+        break;
+
+    default:
+        *policy = SCHED_OTHER;
+        param->sched_priority = 0;
+        break;
+    }
+}
+
+void *new_freebsd_thread_start(void *arg)
+{
+    new_freebsd_thread_info_t *info = arg;
+    CPUArchState *env;
+    CPUState *cpu;
+    // TaskState *ts;
+    long tid;
+
+    env = info->env;
+    cpu = ENV_GET_CPU(env);
+    thread_cpu = cpu;
+
+    // ts = (TaskState *)env->opaque;
+    (void)thr_self(&tid);
+    cpu->host_tid = tid;
+    // ts->ts_tid = tid;
+
+    /* copy out the TID info */
+    if (info->param.child_tid) {
+        put_user(tid, info->param.child_tid, abi_long);
+    }
+    if (info->param.parent_tid) {
+        put_user(info->parent_tid, info->param.parent_tid, abi_long);
+    }
+
+    /* Set arch dependent registers to start thread. */
+    target_thread_set_upcall(env, info->param.start_func, info->param.arg,
+        info->param.stack_base, info->param.stack_size);
+
+    /* 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 finished initializing the TLS state. */
+    pthread_mutex_lock(new_freebsd_thread_lock_ptr);
+    pthread_mutex_unlock(new_freebsd_thread_lock_ptr);
+
+    cpu_loop(env);
+    /* never exits */
+
+    return NULL;
+}
+
+/*
+ * FreeBSD user mutex (_umtx) emulation
+ */
+static int tcmpset_al(abi_ulong *addr, abi_ulong a, abi_ulong b)
+{
+    abi_ulong current = tswapal(a);
+    abi_ulong new = tswapal(b);
+
+#ifdef TARGET_ABI32
+    return atomic_cmpset_acq_32(addr, current, new);
+#else
+    return atomic_cmpset_acq_64(addr, current, new);
+#endif
+}
+
+static int tcmpset_32(uint32_t *addr, uint32_t a, uint32_t b)
+{
+    uint32_t current = tswap32(a);
+    uint32_t new = tswap32(b);
+
+    return atomic_cmpset_acq_32(addr, current, new);
+}
+
+abi_long freebsd_umtx_wait_uint(abi_ulong obj, uint32_t val,
+        struct timespec *timeout)
+{
+
+    DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x, NULL, %p)\n",
+            __func__, g2h(obj), UMTX_OP_WAIT_UINT, val, timeout);
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_WAIT_UINT, val, NULL, timeout));
+}
+
+abi_long freebsd_umtx_wait_uint_private(abi_ulong obj, uint32_t val,
+        struct timespec *timeout)
+{
+
+    DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x, NULL, %p)\n",
+            __func__, g2h(obj), UMTX_OP_WAIT_UINT_PRIVATE, val, timeout);
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_WAIT_UINT_PRIVATE, val, NULL,
+                timeout));
+}
+
+abi_long freebsd_umtx_wake_private(abi_ulong obj, uint32_t val)
+{
+
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(obj), UMTX_OP_WAKE_PRIVATE, val);
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_WAKE_PRIVATE, val, NULL, NULL));
+}
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#if defined(UMTX_OP_NWAKE_PRIVATE)
+abi_long freebsd_umtx_nwake_private(abi_ulong obj, uint32_t val)
+{
+
+    DEBUG_UMTX("<NWAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(obj), UMTX_OP_NWAKE_PRIVATE, val);
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_NWAKE_PRIVATE, val, NULL,
+                NULL));
+}
+#endif /* UMTX_OP_NWAKE_PRIVATE */
+
+#if defined(UMTX_OP_MUTEX_WAKE2)
+abi_long freebsd_umtx_mutex_wake2(abi_ulong target_addr,
+        __unused uint32_t flags)
+{
+    abi_long ret = 0;
+
+    pthread_mutex_lock(&umtx_wait_lck);
+    DEBUG_UMTX("<WAKE2 CV> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(target_addr), UMTX_OP_MUTEX_WAKE2, flags);
+    umtx_wait_addr = target_addr;
+    ret = get_errno(pthread_cond_broadcast(&umtx_wait_cv));
+    pthread_mutex_unlock(&umtx_wait_lck);
+
+    return ret;
+}
+#endif /* UMTX_OP_MUTEX_WAKE2 */
+
+abi_long freebsd_umtx_sem_wait(abi_ulong obj, struct timespec *timeout)
+{
+
+    /* XXX Assumes struct _usem is opauque to the user */
+    if (!access_ok(VERIFY_WRITE, obj, sizeof(struct target__usem))) {
+        return -TARGET_EFAULT;
+    }
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_SEM_WAIT, 0, NULL, timeout));
+}
+
+abi_long freebsd_umtx_sem_wake(abi_ulong obj, uint32_t val)
+{
+
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_SEM_WAKE, val, NULL, NULL));
+}
+#endif
+
+abi_long t2h_freebsd_rtprio(struct rtprio *host_rtp, abi_ulong target_addr)
+{
+    struct target_freebsd_rtprio *target_rtp;
+
+    if (!lock_user_struct(VERIFY_READ, target_rtp, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_rtp->type, &target_rtp->type);
+    __get_user(host_rtp->prio, &target_rtp->prio);
+    unlock_user_struct(target_rtp, target_addr, 0);
+    return 0;
+}
+
+abi_long h2t_freebsd_rtprio(abi_ulong target_addr, struct rtprio *host_rtp)
+{
+    struct target_freebsd_rtprio *target_rtp;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_rtp, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_rtp->type, &target_rtp->type);
+    __put_user(host_rtp->prio, &target_rtp->prio);
+    unlock_user_struct(target_rtp, target_addr, 1);
+    return 0;
+}
+
+abi_long freebsd_lock_umtx(abi_ulong target_addr, abi_long id,
+        struct timespec *timeout)
+{
+    abi_long ret;
+    abi_long owner;
+
+    /*
+     * XXX Note that memory at umtx_addr can change and so we need to be
+     * careful and check for faults.
+     */
+    for (;;) {
+        struct target_umtx *target_umtx;
+
+        if (!lock_user_struct(VERIFY_WRITE, target_umtx, target_addr, 0)) {
+            return -TARGET_EFAULT;
+        }
+        /* Check the simple uncontested case. */
+        if (tcmpset_al(&target_umtx->u_owner,
+                TARGET_UMTX_UNOWNED, id)) {
+            unlock_user_struct(target_umtx, target_addr, 1);
+            return 0;
+        }
+        /* Check to see if the lock is contested but free. */
+        __get_user(owner, &target_umtx->u_owner);
+
+        if (TARGET_UMTX_CONTESTED == owner) {
+            if (tcmpset_al(&target_umtx->u_owner, TARGET_UMTX_CONTESTED,
+                        id | TARGET_UMTX_CONTESTED)) {
+                unlock_user_struct(target_umtx, target_addr, 1);
+                return 0;
+            }
+            /* We failed because it changed on us, restart. */
+            unlock_user_struct(target_umtx, target_addr, 1);
+            continue;
+        }
+
+        /* Set the contested bit and sleep. */
+        do {
+            __get_user(owner, &target_umtx->u_owner);
+            if (owner & TARGET_UMTX_CONTESTED) {
+                break;
+            }
+        } while (!tcmpset_al(&target_umtx->u_owner, owner,
+                    owner | TARGET_UMTX_CONTESTED));
+
+        __get_user(owner, &target_umtx->u_owner);
+        unlock_user_struct(target_umtx, target_addr, 1);
+
+        /* Byte swap, if needed, to match what is stored in user mem. */
+        owner = tswapal(owner);
+        DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%llx, NULL, NULL)\n",
+                __func__, g2h(target_addr), UMTX_OP_WAIT, (long long)owner);
+#ifdef TARGET_ABI32
+        ret = get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAIT_UINT, owner,
+            NULL, timeout));
+#else
+        ret = get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAIT, owner,
+            NULL, timeout));
+#endif
+        if (is_error(ret)) {
+            return ret;
+        }
+    }
+}
+
+abi_long freebsd_unlock_umtx(abi_ulong target_addr, abi_long id)
+{
+    abi_ulong owner;
+    struct target_umtx *target_umtx;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_umtx, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(owner, &target_umtx->u_owner);
+    if ((owner & ~TARGET_UMTX_CONTESTED) != id) {
+        unlock_user_struct(target_umtx, target_addr, 1);
+        return -TARGET_EPERM;
+    }
+    /* Check the simple uncontested case. */
+    if ((owner & ~TARGET_UMTX_CONTESTED) == 0) {
+        if (tcmpset_al(&target_umtx->u_owner, owner,
+            TARGET_UMTX_UNOWNED)) {
+            unlock_user_struct(target_umtx, target_addr, 1);
+            return 0;
+        }
+    }
+    /* This is a contested lock. Unlock it. */
+    __put_user(TARGET_UMTX_UNOWNED, &target_umtx->u_owner);
+    unlock_user_struct(target_umtx, target_addr, 1);
+
+    /* Wake up all those contesting it. */
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(target_addr), UMTX_OP_WAKE, 0);
+    _umtx_op(g2h(target_addr), UMTX_OP_WAKE, 0, 0, 0);
+
+    return 0;
+}
+
+abi_long freebsd_umtx_wait(abi_ulong targ_addr, abi_ulong id,
+        struct timespec *ts)
+{
+
+    /* We want to check the user memory but not lock it.  We might sleep. */
+    if (!access_ok(VERIFY_READ, targ_addr, sizeof(abi_ulong))) {
+        return -TARGET_EFAULT;
+    }
+
+    DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%llx, NULL, NULL)\n",
+            __func__, g2h(targ_addr), UMTX_OP_WAIT, (long long)id);
+#ifdef TARGET_ABI32
+    return get_errno(_umtx_op(g2h(targ_addr), UMTX_OP_WAIT_UINT, id, NULL, ts));
+#else
+    return get_errno(_umtx_op(g2h(targ_addr), UMTX_OP_WAIT, id, NULL, ts));
+#endif
+}
+
+abi_long freebsd_umtx_wake(abi_ulong target_addr, uint32_t n_wake)
+{
+
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(target_addr), UMTX_OP_WAKE, n_wake);
+    return get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAKE, n_wake, NULL, 0));
+}
+
+abi_long freebsd_umtx_mutex_wake(abi_ulong obj, abi_long val)
+{
+
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%llx, NULL, NULL)\n",
+            __func__, g2h(obj), UMTX_OP_WAKE, (long long)val);
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_MUTEX_WAKE, val, NULL, NULL));
+}
+
+abi_long freebsd_lock_umutex(abi_ulong target_addr, uint32_t id,
+        struct timespec *ts, int mode)
+{
+    uint32_t owner, flags;
+    int ret = 0;
+
+    for (;;) {
+        struct target_umutex *target_umutex;
+
+        pthread_mutex_lock(&umtx_wait_lck);
+
+        if (!lock_user_struct(VERIFY_WRITE, target_umutex, target_addr, 0)) {
+            pthread_mutex_unlock(&umtx_wait_lck);
+            return -TARGET_EFAULT;
+        }
+
+        __get_user(owner, &target_umutex->m_owner);
+
+        if (TARGET_UMUTEX_WAIT == mode) {
+            if (TARGET_UMUTEX_UNOWNED == owner ||
+                    TARGET_UMUTEX_CONTESTED == owner) {
+                unlock_user_struct(target_umutex, target_addr, 1);
+                pthread_mutex_unlock(&umtx_wait_lck);
+                return 0;
+            }
+        } else {
+            if (tcmpset_32(&target_umutex->m_owner, TARGET_UMUTEX_UNOWNED,
+                        id)) {
+                /* The acquired succeeded. */
+                unlock_user_struct(target_umutex, target_addr, 1);
+                pthread_mutex_unlock(&umtx_wait_lck);
+                return 0;
+            }
+
+            /* If no one owns it but it is contested try to acquire it. */
+            if (TARGET_UMUTEX_CONTESTED == owner) {
+                if (tcmpset_32(&target_umutex->m_owner, TARGET_UMUTEX_CONTESTED,
+                            id | TARGET_UMUTEX_CONTESTED)) {
+                    unlock_user_struct(target_umutex, target_addr, 1);
+                    pthread_mutex_unlock(&umtx_wait_lck);
+                    return 0;
+                }
+                /* The lock changed so restart. */
+                unlock_user_struct(target_umutex, target_addr, 1);
+                pthread_mutex_unlock(&umtx_wait_lck);
+                continue;
+            }
+        }
+
+        __get_user(flags, &target_umutex->m_flags);
+        if ((flags & TARGET_UMUTEX_ERROR_CHECK) != 0 &&
+                (owner & ~TARGET_UMUTEX_CONTESTED) == id) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            pthread_mutex_unlock(&umtx_wait_lck);
+            return -TARGET_EDEADLK;
+        }
+
+        if (TARGET_UMUTEX_TRY == mode) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            pthread_mutex_unlock(&umtx_wait_lck);
+            return -TARGET_EBUSY;
+        }
+
+        /*
+         * If we caught a signal, we have retried and now
+         * exit immediately.
+         */
+        if (is_error(ret)) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            pthread_mutex_unlock(&umtx_wait_lck);
+            return ret;
+        }
+
+        /* Set the contested bit and sleep. */
+        if (!tcmpset_32(&target_umutex->m_owner, owner,
+                    owner | TARGET_UMUTEX_CONTESTED)) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            pthread_mutex_unlock(&umtx_wait_lck);
+            continue;
+        }
+
+        DEBUG_UMTX("<WAIT CV> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+                __func__, g2h(target_addr), UMTX_OP_WAIT_UINT,
+                tswap32(target_umutex->m_owner));
+        unlock_user_struct(target_umutex, target_addr, 1);
+
+again:
+        if (ts == NULL) {
+            ret = get_errno(pthread_cond_wait(&umtx_wait_cv,
+                        &umtx_wait_lck));
+        } else {
+            ret = get_errno(pthread_cond_timedwait(&umtx_wait_cv,
+                        &umtx_wait_lck, ts));
+        }
+        if (ret != 0) {
+            pthread_mutex_unlock(&umtx_wait_lck);
+            break;
+        }
+        if (target_addr != umtx_wait_addr) {
+            goto again;
+        }
+        pthread_mutex_unlock(&umtx_wait_lck);
+    }
+
+    return ret;
+}
+
+abi_long freebsd_unlock_umutex(abi_ulong target_addr, uint32_t id)
+{
+    struct target_umutex *target_umutex;
+    uint32_t owner;
+
+
+    if (!lock_user_struct(VERIFY_WRITE, target_umutex, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    /* Make sure we own this mutex. */
+    __get_user(owner, &target_umutex->m_owner);
+    if ((owner & ~TARGET_UMUTEX_CONTESTED) != id) {
+        unlock_user_struct(target_umutex, target_addr, 1);
+        return -TARGET_EPERM;
+    }
+    if ((owner & TARGET_UMUTEX_CONTESTED) == 0) {
+        if (tcmpset_32(&target_umutex->m_owner, owner, TARGET_UMTX_UNOWNED)) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            return 0;
+        }
+    }
+    /* This is a contested lock. Unlock it. */
+    __put_user(TARGET_UMUTEX_UNOWNED, &target_umutex->m_owner);
+    unlock_user_struct(target_umutex, target_addr, 1);
+
+    /* And wake up all those contesting it. */
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(target_addr), UMTX_OP_WAKE, 0);
+    return get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAKE, 0, 0, 0));
+}
+
+/*
+ * _cv_mutex is keeps other threads from doing a signal or broadcast until
+ * the thread is actually asleep and ready.  This is a global mutex for all
+ * condition vars so I am sure performance may be a problem if there are lots
+ * of CVs.
+ */
+static struct umutex _cv_mutex = { 0, 0, { 0, 0 }, { 0, 0, 0, 0 } };
+
+
+/*
+ * wflags CVWAIT_CHECK_UNPARKING, CVWAIT_ABSTIME, CVWAIT_CLOCKID
+ */
+abi_long freebsd_cv_wait(abi_ulong target_ucond_addr,
+        abi_ulong target_umtx_addr, struct timespec *ts, int wflags)
+{
+    abi_long ret;
+    long tid;
+
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+                sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* Check the clock ID if needed. */
+    if ((wflags & TARGET_CVWAIT_CLOCKID) != 0) {
+        struct target_ucond *target_ucond;
+        uint32_t clockid;
+
+        if (!lock_user_struct(VERIFY_WRITE, target_ucond, target_ucond_addr,
+                    0)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(clockid, &target_ucond->c_clockid);
+        unlock_user_struct(target_ucond, target_ucond_addr, 1);
+        if (clockid >= CLOCK_THREAD_CPUTIME_ID) {
+            /* Only HW clock id will work. */
+            return -TARGET_EINVAL;
+        }
+    }
+
+    thr_self(&tid);
+
+    /* Lock the _cv_mutex so we can safely unlock the user mutex */
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
+
+    /* unlock the user mutex */
+    ret = freebsd_unlock_umutex(target_umtx_addr, tid);
+    if (is_error(ret)) {
+        _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+        return ret;
+    }
+
+    /* UMTX_OP_CV_WAIT unlocks _cv_mutex */
+    DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x, %p, NULL)\n",
+            __func__, g2h(target_ucond_addr), UMTX_OP_CV_WAIT, wflags,
+            &_cv_mutex);
+    ret = get_errno(_umtx_op(g2h(target_ucond_addr), UMTX_OP_CV_WAIT, wflags,
+                &_cv_mutex, ts));
+
+    return ret;
+}
+
+abi_long freebsd_cv_signal(abi_ulong target_ucond_addr)
+{
+    abi_long ret;
+
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+                sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* Lock the _cv_mutex to prevent a race in do_cv_wait(). */
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(target_ucond_addr), UMTX_OP_CV_SIGNAL, 0);
+    ret = get_errno(_umtx_op(g2h(target_ucond_addr), UMTX_OP_CV_SIGNAL, 0,
+        NULL, NULL));
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+
+    return ret;
+}
+
+abi_long freebsd_cv_broadcast(abi_ulong target_ucond_addr)
+{
+    int ret;
+
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+                sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* Lock the _cv_mutex to prevent a race in do_cv_wait(). */
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(target_ucond_addr), UMTX_OP_CV_BROADCAST, 0);
+    ret = get_errno(_umtx_op(g2h(target_ucond_addr), UMTX_OP_CV_BROADCAST, 0,
+                NULL, NULL));
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+
+    return ret;
+}
+
+abi_long freebsd_rw_rdlock(abi_ulong target_addr, long fflag,
+        struct timespec *ts)
+{
+    struct target_urwlock *target_urwlock;
+    uint32_t flags, wrflags;
+    uint32_t state;
+    uint32_t blocked_readers;
+    abi_long ret;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    __get_user(flags, &target_urwlock->rw_flags);
+    wrflags = TARGET_URWLOCK_WRITE_OWNER;
+    if (!(fflag & TARGET_URWLOCK_PREFER_READER) &&
+            !(flags & TARGET_URWLOCK_PREFER_READER)) {
+        wrflags |= TARGET_URWLOCK_WRITE_WAITERS;
+    }
+    for (;;) {
+        __get_user(state, &target_urwlock->rw_state);
+        /* try to lock it */
+        while (!(state & wrflags)) {
+            if (TARGET_URWLOCK_READER_COUNT(state) ==
+                TARGET_URWLOCK_MAX_READERS) {
+                unlock_user_struct(target_urwlock,
+                    target_addr, 1);
+                return -TARGET_EAGAIN;
+            }
+            if (tcmpset_32(&target_urwlock->rw_state, state,
+                (state + 1))) {
+                /* The acquired succeeded. */
+                unlock_user_struct(target_urwlock,
+                    target_addr, 1);
+                return 0;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+        /* set read contention bit */
+        if (!tcmpset_32(&target_urwlock->rw_state, state,
+            state | TARGET_URWLOCK_READ_WAITERS)) {
+            /* The state has changed.  Start over. */
+            continue;
+        }
+
+        /* contention bit is set, increase read waiter count */
+        __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_readers,
+                    blocked_readers, blocked_readers + 1)) {
+            __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        }
+
+        while (state & wrflags) {
+            /* sleep/wait */
+            unlock_user_struct(target_urwlock, target_addr, 1);
+            DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x (0x%x), NULL, NULL)\n",
+                    __func__, &target_urwlock->rw_state,
+                    UMTX_OP_WAIT_UINT, tswap32(state),
+                    target_urwlock->rw_state);
+            ret = get_errno(_umtx_op(&target_urwlock->rw_state,
+                        UMTX_OP_WAIT_UINT, tswap32(state), NULL, ts));
+            if (is_error(ret)) {
+                return ret;
+            }
+            if (!lock_user_struct(VERIFY_WRITE, target_urwlock,
+                        target_addr, 0)) {
+                return -TARGET_EFAULT;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        /* decrease read waiter count */
+        __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_readers,
+                    blocked_readers, (blocked_readers - 1))) {
+            __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        }
+        if (blocked_readers == 1) {
+            /* clear read contention bit */
+            __get_user(state, &target_urwlock->rw_state);
+            while (!tcmpset_32(&target_urwlock->rw_state, state,
+                state & ~TARGET_URWLOCK_READ_WAITERS)) {
+                __get_user(state, &target_urwlock->rw_state);
+            }
+        }
+    }
+}
+
+abi_long freebsd_rw_wrlock(abi_ulong target_addr, long fflag,
+        struct timespec *ts)
+{
+    struct target_urwlock *target_urwlock;
+    uint32_t blocked_readers, blocked_writers;
+    uint32_t state;
+    abi_long ret;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    blocked_readers = 0;
+    for (;;) {
+        __get_user(state, &target_urwlock->rw_state);
+        while (!(state & TARGET_URWLOCK_WRITE_OWNER) &&
+            TARGET_URWLOCK_READER_COUNT(state) == 0) {
+            if (tcmpset_32(&target_urwlock->rw_state, state,
+                        state | TARGET_URWLOCK_WRITE_OWNER)) {
+                unlock_user_struct(target_urwlock, target_addr, 1);
+                return 0;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        if (!(state & (TARGET_URWLOCK_WRITE_OWNER |
+                        TARGET_URWLOCK_WRITE_WAITERS)) &&
+                blocked_readers != 0) {
+            DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+                __func__, &target_urwlock->rw_state, UMTX_OP_WAKE,
+                tswap32(state));
+            ret = get_errno(_umtx_op(&target_urwlock->rw_state,
+                UMTX_OP_WAKE, INT_MAX, NULL, NULL));
+            return ret;
+        }
+        /* re-read the state */
+        __get_user(state, &target_urwlock->rw_state);
+
+        /* and set TARGET_URWLOCK_WRITE_WAITERS */
+        while (((state & TARGET_URWLOCK_WRITE_OWNER) ||
+                    TARGET_URWLOCK_READER_COUNT(state) != 0) &&
+                (state & TARGET_URWLOCK_WRITE_WAITERS) == 0) {
+            if (tcmpset_32(&target_urwlock->rw_state, state,
+                        state | TARGET_URWLOCK_WRITE_WAITERS)) {
+                break;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        /* contention bit is set, increase write waiter count */
+        __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_writers,
+                    blocked_writers, blocked_writers + 1)) {
+            __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        }
+
+        /* sleep */
+        while ((state & TARGET_URWLOCK_WRITE_OWNER) ||
+                (TARGET_URWLOCK_READER_COUNT(state) != 0)) {
+            unlock_user_struct(target_urwlock, target_addr, 1);
+            DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x(0x%x), NULL, NULL)\n",
+                    __func__, &target_urwlock->rw_blocked_writers,
+                    UMTX_OP_WAIT_UINT, tswap32(state),
+                    target_urwlock->rw_state);
+            ret = get_errno(_umtx_op(&target_urwlock->rw_state,
+                        UMTX_OP_WAIT_UINT, tswap32(state), NULL, ts));
+            if (is_error(ret)) {
+                return ret;
+            }
+            if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr,
+                        0)) {
+                return -TARGET_EFAULT;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        /* decrease the write waiter count */
+        __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_writers,
+                    blocked_writers, (blocked_writers - 1))) {
+            __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        }
+        if (blocked_writers == 1) {
+            /* clear write contention bit */
+            __get_user(state, &target_urwlock->rw_state);
+            while (!tcmpset_32(&target_urwlock->rw_state, state,
+                        state & ~TARGET_URWLOCK_WRITE_WAITERS)) {
+                __get_user(state, &target_urwlock->rw_state);
+            }
+            __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        } else {
+            blocked_readers = 0;
+        }
+    }
+}
+
+abi_long freebsd_rw_unlock(abi_ulong target_addr)
+{
+    struct target_urwlock *target_urwlock;
+    uint32_t flags, state, count = 0;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    __get_user(flags, &target_urwlock->rw_flags);
+    __get_user(state, &target_urwlock->rw_state);
+
+    if (state & TARGET_URWLOCK_WRITE_OWNER) {
+        for (;;) {
+            if (!tcmpset_32(&target_urwlock->rw_state, state,
+                state & ~TARGET_URWLOCK_WRITE_OWNER)) {
+                __get_user(state, &target_urwlock->rw_state);
+                if (!(state & TARGET_URWLOCK_WRITE_OWNER)) {
+                    unlock_user_struct(target_urwlock,
+                        target_addr, 1);
+                    return -TARGET_EPERM;
+                }
+            } else {
+                break;
+            }
+        }
+    } else if (TARGET_URWLOCK_READER_COUNT(state) != 0) {
+        /* decrement reader count */
+        for (;;) {
+            if (!tcmpset_32(&target_urwlock->rw_state, state, (state  - 1))) {
+                if (TARGET_URWLOCK_READER_COUNT(state) == 0) {
+                    unlock_user_struct(target_urwlock,
+                        target_addr, 1);
+                        return -TARGET_EPERM;
+                 }
+            } else {
+                break;
+            }
+        }
+    } else {
+        unlock_user_struct(target_urwlock, target_addr, 1);
+        return -TARGET_EPERM;
+    }
+
+    if (!(flags & TARGET_URWLOCK_PREFER_READER)) {
+        if (state & TARGET_URWLOCK_WRITE_WAITERS) {
+            count = 1;
+        } else if (state & TARGET_URWLOCK_READ_WAITERS) {
+            count = INT_MAX;
+        }
+    } else {
+        if (state & TARGET_URWLOCK_READ_WAITERS) {
+            count = INT_MAX;
+        } else if (state & TARGET_URWLOCK_WRITE_WAITERS) {
+            count = 1;
+        }
+    }
+
+    unlock_user_struct(target_urwlock, target_addr, 1);
+    if (count != 0) {
+        DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+                __func__, &target_urwlock->rw_state, UMTX_OP_WAKE, count);
+        return get_errno(_umtx_op(&target_urwlock->rw_state, UMTX_OP_WAKE,
+                    count, NULL, NULL));
+    } else {
+        return 0;
+    }
+}
+
+abi_long do_freebsd_thr_new(CPUArchState *env,
+        abi_ulong target_param_addr, int32_t param_size)
+{
+    new_freebsd_thread_info_t info;
+    pthread_attr_t attr;
+    TaskState *ts;
+    CPUArchState *new_env;
+    struct target_freebsd_thr_param *target_param;
+    abi_ulong target_rtp_addr;
+    struct target_freebsd_rtprio *target_rtp;
+    struct rtprio *rtp_ptr, rtp;
+    TaskState *parent_ts = (TaskState *)env->opaque;
+    sigset_t sigmask;
+    struct sched_param sched_param;
+    int sched_policy;
+    int ret = 0;
+
+    memset(&info, 0, sizeof(info));
+
+    if (!lock_user_struct(VERIFY_READ, target_param, target_param_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    info.param.start_func = tswapal(target_param->start_func);
+    info.param.arg = tswapal(target_param->arg);
+    info.param.stack_base = tswapal(target_param->stack_base);
+    info.param.stack_size = tswapal(target_param->stack_size);
+    info.param.tls_base = tswapal(target_param->tls_base);
+    info.param.tls_size = tswapal(target_param->tls_size);
+    info.param.child_tid = tswapal(target_param->child_tid);
+    info.param.parent_tid = tswapal(target_param->parent_tid);
+    info.param.flags = tswap32(target_param->flags);
+    target_rtp_addr = info.param.rtp = tswapal(target_param->rtp);
+    unlock_user(target_param, target_param_addr, 0);
+
+    thr_self(&info.parent_tid);
+
+    if (target_rtp_addr) {
+        if (!lock_user_struct(VERIFY_READ, target_rtp, target_rtp_addr, 1)) {
+            return -TARGET_EFAULT;
+        }
+        rtp.type = tswap16(target_rtp->type);
+        rtp.prio = tswap16(target_rtp->prio);
+        unlock_user(target_rtp, target_rtp_addr, 0);
+        rtp_ptr = &rtp;
+    } else {
+        rtp_ptr = NULL;
+    }
+
+    /* Create a new CPU instance. */
+    ts = g_malloc0(sizeof(TaskState));
+    init_task_state(ts);
+    new_env = cpu_copy(env);
+    //target_cpu_reset(new_env); /* XXX called in cpu_copy()? */
+
+    /* init regs that differ from the parent thread. */
+    target_cpu_clone_regs(new_env, info.param.stack_base);
+    new_env->opaque = ts;
+    ts->bprm = parent_ts->bprm;
+    ts->info = parent_ts->info;
+
+    target_cpu_set_tls(new_env, info.param.tls_base);
+
+    /* Grab a mutex so that thread setup appears atomic. */
+    pthread_mutex_lock(new_freebsd_thread_lock_ptr);
+
+    pthread_mutex_init(&info.mutex, NULL);
+    pthread_mutex_lock(&info.mutex);
+    pthread_cond_init(&info.cond, NULL);
+    info.env = new_env;
+
+    /* XXX check return values... */
+    pthread_attr_init(&attr);
+    pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    if (rtp_ptr) {
+        rtp_to_schedparam(&rtp, &sched_policy, &sched_param);
+        pthread_attr_setschedpolicy(&attr, sched_policy);
+        pthread_attr_setschedparam(&attr, &sched_param);
+    }
+
+    /*
+     * 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, new_freebsd_thread_start, &info);
+    /* XXX Free new CPU state if thread creation fails. */
+
+    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);
+    } else {
+        /* Creation of new thread failed. */
+        ret = -host_to_target_errno(errno);
+    }
+
+    pthread_mutex_unlock(&info.mutex);
+    pthread_cond_destroy(&info.cond);
+    pthread_mutex_destroy(&info.mutex);
+    pthread_mutex_unlock(new_freebsd_thread_lock_ptr);
+
+    return ret;
+}
diff --git a/bsd-user/freebsd/os-thread.h b/bsd-user/freebsd/os-thread.h
new file mode 100644
index 0000000..5e24852
--- /dev/null
+++ b/bsd-user/freebsd/os-thread.h
@@ -0,0 +1,511 @@
+/*
+ *  FreeBSD thread and user mutex related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __FREEBSD_OS_THREAD_H_
+#define __FREEBSD_OS_THREAD_H_
+
+#include <sys/thr.h>
+#include <sys/rtprio.h>
+#include <sys/umtx.h>
+
+#include "qemu-os.h"
+
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong target_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_self(abi_ulong target_id)
+{
+    abi_long ret;
+    long tid;
+
+    ret = get_errno(thr_self(&tid));
+    if (!is_error(ret)) {
+        if (put_user_sal(tid, target_id)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+static abi_long do_freebsd_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr)
+{
+    CPUState *cpu = ENV_GET_CPU(cpu_env);
+    TaskState *ts;
+
+    /*
+     * XXX This probably breaks if a signal arrives.
+     * We should disable signals.
+     */
+    cpu_list_lock();
+    /* Remove the CPU from the list. */
+    QTAILQ_REMOVE(&cpus, cpu, node);
+    cpu_list_unlock();
+    if (tid_addr) {
+        /* Signal target userland that it can free the stack. */
+        if (!put_user_sal(1, tid_addr)) {
+            freebsd_umtx_wake(tid_addr, INT_MAX);
+        }
+    }
+    thread_cpu = NULL;
+    object_unref(OBJECT(ENV_GET_CPU(cpu_env)));
+    ts = ((CPUArchState *)cpu_env)->opaque;
+    g_free(ts);
+    pthread_exit(NULL);
+    /* Doesn't return */
+    return 0;
+}
+
+static abi_long do_freebsd_thr_kill(long id, int sig)
+{
+
+    return get_errno(thr_kill(id, sig));
+}
+
+static abi_long do_freebsd_thr_kill2(pid_t pid, long id, int sig)
+{
+
+    return get_errno(thr_kill2(pid, id, sig));
+}
+
+static abi_long do_freebsd_thr_suspend(abi_ulong target_ts)
+{
+    abi_long ret;
+    struct timespec ts;
+
+    if (target_ts != 0) {
+        if (t2h_freebsd_timespec(&ts, target_ts)) {
+            return -TARGET_EFAULT;
+        }
+        ret = thr_suspend(&ts);
+    } else {
+        ret = thr_suspend(NULL);
+    }
+    return ret;
+}
+
+static abi_long do_freebsd_thr_wake(long tid)
+{
+
+    return get_errno(thr_wake(tid));
+}
+
+static abi_long do_freebsd_thr_set_name(long tid, abi_ulong target_name)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(target_name);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = thr_set_name(tid, p);
+    unlock_user(p, target_name, 0);
+
+    return ret;
+}
+
+static abi_long do_freebsd_rtprio_thread(int function, lwpid_t lwpid,
+        abi_ulong target_addr)
+{
+    int ret;
+    struct rtprio rtp;
+
+    ret = t2h_freebsd_rtprio(&rtp, target_addr);
+    if (!is_error(ret)) {
+        ret = get_errno(rtprio_thread(function, lwpid, &rtp));
+    }
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_rtprio(target_addr, &rtp);
+    }
+    return ret;
+}
+
+static abi_long do_freebsd_getcontext(void *cpu_env, abi_ulong arg1)
+{
+    abi_long ret;
+    target_ucontext_t *ucp;
+    sigset_t sigmask;
+
+    if (arg1 == 0) {
+        return -TARGET_EINVAL;
+    }
+    ret = get_errno(sigprocmask(0, NULL, &sigmask));
+    if (!is_error(ret)) {
+        ucp = lock_user(VERIFY_WRITE, arg1, sizeof(target_ucontext_t), 0);
+        if (ucp == 0) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_mcontext(cpu_env, &ucp->uc_mcontext, TARGET_MC_GET_CLEAR_RET);
+        host_to_target_sigset(&ucp->uc_sigmask, &sigmask);
+        memset(ucp->__spare__, 0, sizeof(ucp->__spare__));
+        unlock_user(ucp, arg1, sizeof(target_ucontext_t));
+    }
+    return ret;
+}
+
+static abi_long do_freebsd_setcontext(void *cpu_env, abi_ulong arg1)
+{
+    abi_long ret;
+    target_ucontext_t *ucp;
+    sigset_t sigmask;
+    if (arg1 == 0) {
+        return -TARGET_EINVAL;
+    }
+    ucp = lock_user(VERIFY_READ, arg1, sizeof(target_ucontext_t), 1);
+    if (ucp == 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = set_mcontext(cpu_env, &ucp->uc_mcontext, 0);
+    target_to_host_sigset(&sigmask, &ucp->uc_sigmask);
+    unlock_user(ucp, arg1, sizeof(target_ucontext_t));
+    if (!is_error(ret)) {
+        (void)sigprocmask(SIG_SETMASK, &sigmask, NULL);
+    }
+    return ret;
+}
+
+/* swapcontext(2) */
+static abi_long do_freebsd_swapcontext(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+    abi_long ret;
+    target_ucontext_t *ucp;
+    sigset_t sigmask;
+
+    if (arg1 == 0 || arg2 == 0) {
+        return -TARGET_EINVAL;
+    }
+    /* Save current context in arg1. */
+    ret = get_errno(sigprocmask(0, NULL,  &sigmask));
+    if (!is_error(ret)) {
+        ucp = lock_user(VERIFY_WRITE, arg1, sizeof(target_ucontext_t), 0);
+        if (ucp == 0) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_mcontext(cpu_env, &ucp->uc_mcontext, TARGET_MC_GET_CLEAR_RET);
+        host_to_target_sigset(&ucp->uc_sigmask, &sigmask);
+        memset(ucp->__spare__, 0, sizeof(ucp->__spare__));
+        unlock_user(ucp, arg1, sizeof(target_ucontext_t));
+    }
+    if (is_error(ret)) {
+            return ret;
+    }
+
+    /* Restore the context in arg2 to the current context. */
+    ucp = lock_user(VERIFY_READ, arg2, sizeof(target_ucontext_t), 1);
+    if (ucp == 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = set_mcontext(cpu_env, &ucp->uc_mcontext, 0);
+    target_to_host_sigset(&sigmask, &ucp->uc_sigmask);
+    unlock_user(ucp, arg2, sizeof(target_ucontext_t));
+    if (!is_error(ret)) {
+        (void)sigprocmask(SIG_SETMASK, &sigmask, NULL);
+    }
+    return ret;
+}
+
+
+/* undocumented _umtx_lock() */
+static inline abi_long do_freebsd__umtx_lock(abi_ulong target_addr)
+{
+    abi_long ret;
+    long tid;
+
+    ret = get_errno(thr_self(&tid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return freebsd_lock_umtx(target_addr, tid, NULL);
+}
+
+/* undocumented _umtx_unlock() */
+static inline abi_long do_freebsd__umtx_unlock(abi_ulong target_addr)
+{
+    abi_long ret;
+    long tid;
+
+    ret = get_errno(thr_self(&tid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return freebsd_unlock_umtx(target_addr, tid);
+}
+
+/* undocumented _umtx_op(void *obj, int op, u_long val, void *uaddr,
+                           void *target_ts); */
+static inline abi_long do_freebsd__umtx_op(abi_ulong obj, int op, abi_ulong val,
+        abi_ulong uaddr, abi_ulong target_ts)
+{
+    abi_long ret;
+    struct timespec ts;
+    long tid;
+
+    switch (op) {
+    case TARGET_UMTX_OP_LOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_lock_umtx(obj, tid, &ts);
+        } else {
+            ret = freebsd_lock_umtx(obj, tid, NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_UNLOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = freebsd_unlock_umtx(obj, tid);
+        break;
+
+    case TARGET_UMTX_OP_WAIT:
+        /* args: obj *, val, ts * */
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_wait(obj, tswapal(val), &ts);
+        } else {
+            ret = freebsd_umtx_wait(obj, tswapal(val), NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_WAKE:
+        /* args: obj *, nr_wakeup */
+        ret = freebsd_umtx_wake(obj, val);
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_LOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        if (target_ts) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_lock_umutex(obj, tid, &ts, 0);
+        } else {
+            ret = freebsd_lock_umutex(obj, tid, NULL, 0);
+        }
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_UNLOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = freebsd_unlock_umutex(obj, tid);
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_TRYLOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = freebsd_lock_umutex(obj, tid, NULL, TARGET_UMUTEX_TRY);
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_WAIT:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_lock_umutex(obj, tid, &ts, TARGET_UMUTEX_WAIT);
+        } else {
+            ret = freebsd_lock_umutex(obj, tid, NULL, TARGET_UMUTEX_WAIT);
+        }
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_WAKE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_mutex_wake(obj, val);
+        break;
+
+    case TARGET_UMTX_OP_SET_CEILING:
+        ret = 0; /* XXX quietly ignore these things for now */
+        break;
+
+    case TARGET_UMTX_OP_CV_WAIT:
+        /*
+         * Initialization of the struct conv is done by
+         * bzero'ing everything in userland.
+         */
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_cv_wait(obj, uaddr, &ts, val);
+        } else {
+            ret = freebsd_cv_wait(obj, uaddr, NULL, val);
+        }
+        break;
+
+    case TARGET_UMTX_OP_CV_SIGNAL:
+        /*
+         * XXX
+         * User code may check if c_has_waiters is zero.  Other
+         * than that it is assume that user code doesn't do
+         * much with the struct conv fields and is pretty
+         * much opauque to userland.
+         */
+        ret = freebsd_cv_signal(obj);
+        break;
+
+    case TARGET_UMTX_OP_CV_BROADCAST:
+        /*
+         * XXX
+         * User code may check if c_has_waiters is zero.  Other
+         * than that it is assume that user code doesn't do
+         * much with the struct conv fields and is pretty
+         * much opauque to userland.
+         */
+        ret = freebsd_cv_broadcast(obj);
+        break;
+
+    case TARGET_UMTX_OP_WAIT_UINT:
+        if (!access_ok(VERIFY_READ, obj, sizeof(abi_ulong))) {
+            return -TARGET_EFAULT;
+        }
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_wait_uint(obj, tswap32((uint32_t)val), &ts);
+        } else {
+            ret = freebsd_umtx_wait_uint(obj, tswap32((uint32_t)val), NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_WAIT_UINT_PRIVATE:
+        if (!access_ok(VERIFY_READ, obj, sizeof(abi_ulong))) {
+            return -TARGET_EFAULT;
+        }
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_wait_uint_private(obj, tswap32((uint32_t)val),
+                    &ts);
+        } else {
+            ret = freebsd_umtx_wait_uint_private(obj, tswap32((uint32_t)val),
+                    NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_WAKE_PRIVATE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_wake_private(obj, val);
+        break;
+
+    case TARGET_UMTX_OP_RW_RDLOCK:
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_rw_rdlock(obj, val, &ts);
+        } else {
+            ret = freebsd_rw_rdlock(obj, val, NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_RW_WRLOCK:
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_rw_wrlock(obj, val, &ts);
+        } else {
+            ret = freebsd_rw_wrlock(obj, val, NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_RW_UNLOCK:
+        ret = freebsd_rw_unlock(obj);
+        break;
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#ifdef UMTX_OP_MUTEX_WAKE2
+    case TARGET_UMTX_OP_MUTEX_WAKE2:
+        ret = freebsd_umtx_mutex_wake2(obj, val);
+        break;
+#endif /* UMTX_OP_MUTEX_WAKE2 */
+
+#ifdef UMTX_OP_NWAKE_PRIVATE
+    case TARGET_UMTX_OP_NWAKE_PRIVATE:
+        {
+            int i;
+            abi_ulong *uaddr;
+            uint32_t imax = tswap32(INT_MAX);
+
+            if (!access_ok(VERIFY_READ, obj, val * sizeof(uint32_t))) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_nwake_private(obj, val);
+
+            uaddr = (abi_ulong *)g2h(obj);
+            ret = 0;
+            for (i = 0; i < (int32_t)val; i++) {
+                ret = freebsd_umtx_wake_private(tswapal(uaddr[i]), imax);
+                if (is_error(ret)) {
+                    break;
+                }
+            }
+        }
+        break;
+#endif /* UMTX_OP_NWAKE_PRIVATE */
+
+    case TARGET_UMTX_OP_SEM_WAIT:
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_sem_wait(obj, &ts);
+        } else {
+            ret = freebsd_umtx_sem_wait(obj, NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_SEM_WAKE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_sem_wake(obj, val);
+        break;
+#endif
+    default:
+        return -TARGET_EINVAL;
+    }
+    return ret;
+}
+
+#endif /* !__FREEBSD_OS_THREAD_H_ */
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index 90d8eb4..b5510dc 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -64,4 +64,10 @@ abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh);
 abi_long h2t_freebsd_statfs(abi_ulong target_addr, struct statfs *host_statfs);
 abi_long target_to_host_fcntl_cmd(int cmd);
 
+/* os-thread.c */
+abi_long t2h_freebsd_rtprio(struct rtprio *host_rtp, abi_ulong target_addr);
+abi_long h2t_freebsd_rtprio(abi_ulong target_addr, struct rtprio *host_rtp);
+abi_long do_freebsd_thr_new(CPUArchState *env, abi_ulong target_param_addr,
+        int32_t param_size);
+
 #endif /* !_QEMU_OS_H_ */
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index fc7bc5c..31f2f99 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -29,13 +29,37 @@
 
 // #define DEBUG_MMAP
 
-/* We aren't threadsafe to start with, so no need to worry about locking.  */
+pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
+static __thread int mmap_lock_count;
+
 void mmap_lock(void)
 {
+    if (mmap_lock_count++ == 0) {
+        pthread_mutex_lock(&mmap_mutex);
+    }
 }
 
 void mmap_unlock(void)
 {
+    if (--mmap_lock_count == 0) {
+        pthread_mutex_unlock(&mmap_mutex);
+    }
+}
+
+/* Grab lock to make sure things are in a consistent state after fork().  */
+void mmap_fork_start(void)
+{
+    if (mmap_lock_count)
+        abort();
+    pthread_mutex_lock(&mmap_mutex);
+}
+
+void mmap_fork_end(int child)
+{
+    if (child)
+        pthread_mutex_init(&mmap_mutex, NULL);
+    else
+        pthread_mutex_unlock(&mmap_mutex);
 }
 
 /* NOTE: all the constants are the HOST ones, but addresses are target. */
diff --git a/bsd-user/netbsd/os-thread.c b/bsd-user/netbsd/os-thread.c
new file mode 100644
index 0000000..a4af765
--- /dev/null
+++ b/bsd-user/netbsd/os-thread.c
@@ -0,0 +1 @@
+/* XXX NetBSD thread related helpers */
diff --git a/bsd-user/netbsd/os-thread.h b/bsd-user/netbsd/os-thread.h
new file mode 100644
index 0000000..073b0a0
--- /dev/null
+++ b/bsd-user/netbsd/os-thread.h
@@ -0,0 +1,133 @@
+#ifndef __NETBSD_OS_THREAD_H_
+#define __NETBSD_OS_THREAD_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need to
+ * be emulated.
+ */
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong target_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong thread_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_new(CPUArchState *env,
+        abi_ulong target_param_addr, int32_t param_size)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_self(abi_ulong target_id)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_self()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_exit()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_kill(long id, int sig)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_kill()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_kill2(pid_t pid, long id, int sig)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_kill2()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_suspend(abi_ulong target_ts)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_suspend()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_wake(long tid)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_wake()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_set_name(long tid, abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_set_name()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_rtprio_thread(int function, lwpid_t lwpid,
+        abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall rtprio_thread()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_getcontext(void *cpu_env, abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_setcontext(void *cpu_env, abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_swapcontext(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall swapcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_lock(abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_lock()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_unlock(abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_unlock()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_op(abi_ulong obj, int op, abi_ulong val,
+        abi_ulong uaddr, abi_ulong target_ts)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_op()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __NETBSD_OS_THREAD_H_ */
diff --git a/bsd-user/openbsd/os-thread.c b/bsd-user/openbsd/os-thread.c
new file mode 100644
index 0000000..d125281
--- /dev/null
+++ b/bsd-user/openbsd/os-thread.c
@@ -0,0 +1 @@
+/* XXX OpenBSD thread related helpers */
diff --git a/bsd-user/openbsd/os-thread.h b/bsd-user/openbsd/os-thread.h
new file mode 100644
index 0000000..962a769
--- /dev/null
+++ b/bsd-user/openbsd/os-thread.h
@@ -0,0 +1,133 @@
+#ifndef __OPENBSD_OS_THREAD_H_
+#define __OPENBSD_OS_THREAD_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need to
+ * be emulated.
+ */
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong target_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong thread_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_new(CPUArchState *env,
+        abi_ulong target_param_addr, int32_t param_size)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_self(abi_ulong target_id)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_self()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_exit()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_kill(long id, int sig)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_kill()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_kill2(pid_t pid, long id, int sig)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_kill2()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_suspend(abi_ulong target_ts)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_suspend()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_wake(long tid)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_wake()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_set_name(long tid, abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_set_name()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_rtprio_thread(int function, lwpid_t lwpid,
+        abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall rtprio_thread()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_getcontext(void *cpu_env, abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_setcontext(void *cpu_env, abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_swapcontext(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall swapcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_lock(abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_lock()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_unlock(abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_unlock()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_op(abi_ulong obj, int op, abi_ulong val,
+        abi_ulong uaddr, abi_ulong target_ts)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_op()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_OS_THREAD_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 613a89e..4b2add2 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -42,11 +42,7 @@ extern enum BSDType bsd_type;
 #include "target_os_signal.h"
 #include "exec/gdbstub.h"
 
-#if defined(CONFIG_USE_NPTL)
 #define THREAD __thread
-#else
-#define THREAD
-#endif
 
 /* This struct is used to hold certain information about the image.
  * Basically, it replicates in user space what would be certain
@@ -67,6 +63,8 @@ struct image_info {
     abi_ulong entry;
     abi_ulong code_offset;
     abi_ulong data_offset;
+    abi_ulong arg_start;
+    abi_ulong arg_end;
     int       personality;
 };
 
@@ -89,6 +87,15 @@ struct emulated_sigtable {
 typedef struct TaskState {
     struct TaskState *next;
     int used; /* non zero if used */
+#ifdef TARGET_ARM
+    int swi_errno;
+#endif
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
+    /* Extra fields for semihosted binaries. */
+    uint32_t heap_base;
+    uint32_t heap_limit;
+    uint32_t stack_base;
+#endif
     struct image_info *info;
     struct bsd_binprm *bprm;
 
@@ -231,10 +238,8 @@ void mmap_unlock(void);
 abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
 void cpu_list_lock(void);
 void cpu_list_unlock(void);
-#if defined(CONFIG_USE_NPTL)
 void mmap_fork_start(void);
 void mmap_fork_end(int child);
-#endif
 
 /* main.c */
 extern unsigned long target_maxtsiz;
@@ -244,10 +249,15 @@ extern unsigned long target_dflssiz;
 extern unsigned long target_maxssiz;
 extern unsigned long target_sgrowsiz;
 extern char qemu_proc_pathname[];
+void start_exclusive(void);
+void end_exclusive(void);
+void cpu_exec_start(CPUState *cpu);
+void cpu_exec_end(CPUState *cpu);
 
 /* syscall.c */
 abi_long get_errno(abi_long ret);
 int is_error(abi_long ret);
+int host_to_target_errno(int err);
 
 /* os-proc.c */
 abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
@@ -258,6 +268,41 @@ abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
         abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen);
 abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2);
 
+/* os-thread.c */
+extern pthread_mutex_t *new_freebsd_thread_lock_ptr;
+void *new_freebsd_thread_start(void *arg);
+abi_long freebsd_lock_umtx(abi_ulong target_addr, abi_long tid,
+        struct timespec *timeout);
+abi_long freebsd_unlock_umtx(abi_ulong target_addr, abi_long id);
+abi_long freebsd_umtx_wait(abi_ulong targ_addr, abi_ulong id,
+        struct timespec *ts);
+abi_long freebsd_umtx_wake(abi_ulong target_addr, uint32_t n_wake);
+abi_long freebsd_umtx_mutex_wake(abi_ulong target_addr, abi_long val);
+abi_long freebsd_umtx_wait_uint(abi_ulong obj, uint32_t val,
+                struct timespec *timeout);
+abi_long freebsd_umtx_wait_uint_private(abi_ulong obj, uint32_t val,
+                struct timespec *timeout);
+abi_long freebsd_umtx_wake_private(abi_ulong obj, uint32_t val);
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+abi_long freebsd_umtx_nwake_private(abi_ulong obj, uint32_t val);
+abi_long freebsd_umtx_mutex_wake2(abi_ulong obj, uint32_t val);
+abi_long freebsd_umtx_sem_wait(abi_ulong obj, struct timespec *timeout);
+abi_long freebsd_umtx_sem_wake(abi_ulong obj, uint32_t val);
+#endif
+abi_long freebsd_lock_umutex(abi_ulong target_addr, uint32_t id,
+        struct timespec *ts, int mode);
+abi_long freebsd_unlock_umutex(abi_ulong target_addr, uint32_t id);
+abi_long freebsd_cv_wait(abi_ulong target_ucond_addr,
+                abi_ulong target_umtx_addr, struct timespec *ts, int wflags);
+abi_long freebsd_cv_signal(abi_ulong target_ucond_addr);
+abi_long freebsd_cv_broadcast(abi_ulong target_ucond_addr);
+abi_long freebsd_rw_rdlock(abi_ulong target_addr, long fflag,
+        struct timespec *ts);
+abi_long freebsd_rw_wrlock(abi_ulong target_addr, long fflag,
+        struct timespec *ts);
+abi_long freebsd_rw_unlock(abi_ulong target_addr);
+
+
 /* user access */
 
 #define VERIFY_READ 0
@@ -483,8 +528,6 @@ static inline int regpairs_aligned(void *cpu_env)
 }
 #endif
 
-#if defined(CONFIG_USE_NPTL)
 #include <pthread.h>
-#endif
 
 #endif /* QEMU_H */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 286c71e..0a851fe 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -32,7 +32,6 @@
 #include "qemu-common.h"
 
 #define target_to_host_bitmask(x, tbl) (x)
-static int host_to_target_errno(int err);
 
 /* BSD independent syscall shims */
 #include "bsd-file.h"
@@ -47,6 +46,7 @@ static int host_to_target_errno(int err);
 #include "os-signal.h"
 #include "os-socket.h"
 #include "os-stat.h"
+#include "os-thread.h"
 
 /* #define DEBUG */
 
@@ -64,7 +64,7 @@ abi_long get_errno(abi_long ret)
     }
 }
 
-static int host_to_target_errno(int err)
+int host_to_target_errno(int err)
 {
     /* XXX need to translate host errnos here */
     return err;
@@ -1110,6 +1110,73 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * thread system calls
+         */
+    case TARGET_FREEBSD_NR_thr_create: /* thr_create(2) */
+        ret = do_freebsd_thr_create(cpu_env, arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_new: /* thr_new(2) */
+        ret = do_freebsd_thr_new(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_set_name: /* thr_set_name(2) */
+        ret = do_freebsd_thr_set_name(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_self: /* thr_self(2) */
+        ret = do_freebsd_thr_self(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_suspend: /* thr_suspend(2) */
+        ret = do_freebsd_thr_suspend(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_wake: /* thr_wake(2) */
+        ret = do_freebsd_thr_wake(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_kill: /* thr_kill(2) */
+        ret = do_freebsd_thr_kill(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_kill2: /* thr_kill2(2) */
+        ret = do_freebsd_thr_kill2(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_exit: /* thr_exit(2) */
+        ret = do_freebsd_thr_exit(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_rtprio_thread: /* rtprio_thread(2) */
+        ret = do_freebsd_rtprio_thread(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getcontext: /* getcontext(2) */
+        ret = do_freebsd_getcontext(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setcontext: /* setcontext(2) */
+        ret = do_freebsd_setcontext(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_swapcontext: /* swapcontext(2) */
+        ret = do_freebsd_swapcontext(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR__umtx_lock: /* undocumented */
+        ret = do_freebsd__umtx_lock(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR__umtx_unlock: /* undocumented */
+        ret = do_freebsd__umtx_unlock(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR__umtx_op: /* undocumented */
+        ret = do_freebsd__umtx_op(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 4646fb1..340ee6e 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -642,11 +642,7 @@ typedef struct {
 
 #define TARGET_UMTX_UNOWNED                 0x0
 #define TARGET_UMUTEX_UNOWNED               0x0
-#if TARGET_ABI_BITS == 32
-# define TARGET_UMTX_CONTESTED              0x80000000
-#else
-# define TARGET_UMTX_CONTESTED              0x8000000000000000LL
-#endif /* ! TARGET_ABI_BITS == 32 */
+#define TARGET_UMTX_CONTESTED               (abi_ulong)(-1)
 #define TARGET_UMUTEX_CONTESTED             0x80000000U
 
 /* flags for umutex */
diff --git a/include/qemu/tls.h b/include/qemu/tls.h
index b92ea9d..ae7d79d 100644
--- a/include/qemu/tls.h
+++ b/include/qemu/tls.h
@@ -38,7 +38,7 @@
  * TODO: proper implementations via Win32 .tls sections and
  * POSIX pthread_getspecific.
  */
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
 #define DECLARE_TLS(type, x) extern DEFINE_TLS(type, x)
 #define DEFINE_TLS(type, x)  __thread __typeof__(type) tls__##x
 #define tls_var(x)           tls__##x
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 15/19] bsd-user: add support for the ioctl system call
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (34 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 14/19] bsd-user: add support for thread " Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 16/19] bsd-user: add support for extended attribute and ACL related syscalls Stacey Son
                   ` (3 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support for the ioctl system call.  This uses the
generic thunking code to convert data between the host and target CPU.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 Makefile.target                    |    2 +-
 bsd-user/Makefile.objs             |    2 +-
 bsd-user/bsd-ioctl.c               |  448 ++++++++++++++++++++++++++++++++++++
 bsd-user/bsd-ioctl.h               |   27 +++
 bsd-user/freebsd/os-ioctl-cmds.h   |   47 ++++
 bsd-user/freebsd/os-ioctl-filio.h  |   45 ++++
 bsd-user/freebsd/os-ioctl-ioccom.h |   54 +++++
 bsd-user/freebsd/os-ioctl-ttycom.h |  257 +++++++++++++++++++++
 bsd-user/freebsd/os-ioctl-types.h  |    7 +
 bsd-user/netbsd/os-ioctl-cmds.h    |   48 ++++
 bsd-user/netbsd/os-ioctl-filio.h   |   29 +++
 bsd-user/netbsd/os-ioctl-ioccom.h  |   38 +++
 bsd-user/netbsd/os-ioctl-ttycom.h  |  240 +++++++++++++++++++
 bsd-user/netbsd/os-ioctl-types.h   |    7 +
 bsd-user/openbsd/os-ioctl-cmds.h   |   48 ++++
 bsd-user/openbsd/os-ioctl-filio.h  |   29 +++
 bsd-user/openbsd/os-ioctl-ioccom.h |   38 +++
 bsd-user/openbsd/os-ioctl-ttycom.h |  240 +++++++++++++++++++
 bsd-user/openbsd/os-ioctl-types.h  |    7 +
 bsd-user/qemu.h                    |    1 +
 bsd-user/syscall.c                 |   27 ++-
 21 files changed, 1632 insertions(+), 9 deletions(-)
 create mode 100644 bsd-user/bsd-ioctl.c
 create mode 100644 bsd-user/bsd-ioctl.h
 create mode 100644 bsd-user/freebsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/freebsd/os-ioctl-filio.h
 create mode 100644 bsd-user/freebsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/freebsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/freebsd/os-ioctl-types.h
 create mode 100644 bsd-user/netbsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/netbsd/os-ioctl-filio.h
 create mode 100644 bsd-user/netbsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/netbsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/netbsd/os-ioctl-types.h
 create mode 100644 bsd-user/openbsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/openbsd/os-ioctl-filio.h
 create mode 100644 bsd-user/openbsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/openbsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/openbsd/os-ioctl-types.h

diff --git a/Makefile.target b/Makefile.target
index 82ae8cb..2ef9612 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -103,7 +103,7 @@ QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR) \
 			 -I$(SRC_PATH)/bsd-user/$(HOST_ABI_DIR)
 
 obj-y += bsd-user/
-obj-y += gdbstub.o user-exec.o
+obj-y += gdbstub.o thunk.o user-exec.o
 
 endif #CONFIG_BSD_USER
 
diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index b691ffc..242e6f4 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,5 +1,5 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-mem.o bsd-proc.o bsd-socket.o \
+	        uaccess.o bsd-ioctl.o bsd-mem.o bsd-proc.o bsd-socket.o \
 			$(HOST_ABI_DIR)/os-proc.o \
 			$(HOST_ABI_DIR)/os-socket.o $(HOST_ABI_DIR)/os-stat.o \
 			$(HOST_ABI_DIR)/os-sys.o $(HOST_ABI_DIR)/os-thread.o \
diff --git a/bsd-user/bsd-ioctl.c b/bsd-user/bsd-ioctl.c
new file mode 100644
index 0000000..95505a4
--- /dev/null
+++ b/bsd-user/bsd-ioctl.c
@@ -0,0 +1,448 @@
+/*
+ *  BSD ioctl(2) emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#include <sys/_termios.h>
+#else
+#include <sys/termios.h>
+#endif
+#include <sys/ttycom.h>
+#include <sys/filio.h>
+
+#include "qemu.h"
+#include "qemu-common.h"
+
+#include "bsd-ioctl.h"
+#include "os-ioctl-filio.h"
+#include "os-ioctl-ttycom.h"
+
+static const bitmask_transtbl iflag_tbl[] = {
+    { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
+    { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
+    { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
+    { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
+    { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
+    { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
+    { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
+    { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
+    { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
+    { TARGET_IXON, TARGET_IXON, IXON, IXON },
+    { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
+#ifdef IXANY
+    { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
+#endif
+#ifdef IMAXBEL
+    { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
+#endif
+    { 0, 0, 0, 0 }
+};
+
+static const bitmask_transtbl oflag_tbl[] = {
+    { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
+#ifdef ONLCR
+    { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
+#endif
+#ifdef TABDLY
+    { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
+    { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
+#endif
+#ifdef ONOEOT
+    { TARGET_ONOEOT, TARGET_ONOEOT, ONOEOT, ONOEOT },
+#endif
+#ifdef OCRNL
+    { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
+#endif
+#ifdef ONOCR
+    { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
+#endif
+#ifdef ONLRET
+    { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
+#endif
+    { 0, 0, 0, 0 }
+};
+
+static const bitmask_transtbl cflag_tbl[] = {
+#ifdef CIGNORE
+    { TARGET_CIGNORE, TARGET_CIGNORE, CIGNORE, CIGNORE },
+#endif
+    { 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 },
+#ifdef CCTS_OFLOW
+    { TARGET_CCTS_OFLOW, TARGET_CCTS_OFLOW, CCTS_OFLOW, CCTS_OFLOW },
+#endif
+#ifdef CRTSCTS
+    { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
+#endif
+#ifdef CRTS_IFLOW
+    { TARGET_CRTS_IFLOW, TARGET_CRTS_IFLOW, CRTS_IFLOW, CRTS_IFLOW },
+#endif
+#ifdef CDTS_IFLOW
+    { TARGET_CDTR_IFLOW, TARGET_CDTR_IFLOW, CDTR_IFLOW, CDTR_IFLOW },
+#endif
+#ifdef CDSR_OFLOW
+    { TARGET_CDSR_OFLOW, TARGET_CDSR_OFLOW, CDSR_OFLOW, CDSR_OFLOW },
+#endif
+#ifdef CCAR_OFLOW
+    { TARGET_CCAR_OFLOW, TARGET_CCAR_OFLOW, CCAR_OFLOW, CCAR_OFLOW },
+#endif
+    { 0, 0, 0, 0 }
+};
+
+static const bitmask_transtbl lflag_tbl[] = {
+#ifdef ECHOKE
+    { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
+#endif
+    { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
+    { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
+    { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
+    { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
+#ifdef ECHOPRT
+    { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
+#endif
+#ifdef ECHOCTL
+    { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
+#endif
+    { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
+    { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
+#ifdef ALTWERASE
+    { TARGET_ALTWERASE, TARGET_ALTWERASE, ALTWERASE, ALTWERASE },
+#endif
+    { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
+    { TARGET_EXTPROC, TARGET_EXTPROC, EXTPROC, EXTPROC },
+    { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
+#ifdef FLUSHO
+    { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
+#endif
+#ifdef NOKERNINFO
+    { TARGET_NOKERNINFO, TARGET_NOKERNINFO, NOKERNINFO, NOKERNINFO },
+#endif
+#ifdef PENDIN
+    { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
+#endif
+    { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
+    { 0, 0, 0, 0 }
+};
+
+static void target_to_host_termios(void *dst, const void *src)
+{
+    struct termios *host = dst;
+    const struct target_termios *target = src;
+
+    host->c_iflag = target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
+    host->c_oflag = target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
+    host->c_cflag = target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
+    host->c_lflag = target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
+
+    memset(host->c_cc, 0, sizeof(host->c_cc));
+    host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
+    host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
+#ifdef VEOL2
+    host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
+#endif
+    host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
+#ifdef VWERASE
+    host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
+#endif
+    host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
+#ifdef VREPRINT
+    host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
+#endif
+#ifdef VERASE2
+    host->c_cc[VERASE2] = target->c_cc[TARGET_VERASE2];
+#endif
+    host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
+    host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
+    host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
+#ifdef VDSUSP
+    host->c_cc[VDSUSP] = target->c_cc[TARGET_VDSUSP];
+#endif
+    host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
+    host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
+#ifdef VLNEXT
+    host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
+#endif
+#ifdef VDISCARD
+    host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
+#endif
+    host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
+    host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
+#ifdef VSTATUS
+    host->c_cc[VSTATUS] = target->c_cc[TARGET_VSTATUS];
+#endif
+
+    host->c_ispeed = tswap32(target->c_ispeed);
+    host->c_ospeed = tswap32(target->c_ospeed);
+}
+
+static void host_to_target_termios(void *dst, const void *src)
+{
+    struct target_termios *target = dst;
+    const struct termios *host = src;
+
+    target->c_iflag = tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
+    target->c_oflag = tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
+    target->c_cflag = tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
+    target->c_lflag = tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
+
+    memset(target->c_cc, 0, sizeof(target->c_cc));
+    target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
+    target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
+#ifdef VEOL2
+    target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
+#endif
+    target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
+#ifdef VWERASE
+    target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
+#endif
+    target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
+#ifdef VREPRINT
+    target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
+#endif
+#ifdef VERASE2
+    target->c_cc[TARGET_VERASE2] = host->c_cc[VERASE2];
+#endif
+    target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
+    target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
+    target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
+#ifdef VDSUSP
+    target->c_cc[TARGET_VDSUSP] = host->c_cc[VDSUSP];
+#endif
+    target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
+    target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
+#ifdef VLNEXT
+    target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
+#endif
+#ifdef VDISCARD
+    target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
+#endif
+    target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
+    target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
+#ifdef VSTATUS
+    target->c_cc[TARGET_VSTATUS] = host->c_cc[VSTATUS];
+#endif
+
+    target->c_ispeed = tswap32(host->c_ispeed);
+    target->c_ospeed = tswap32(host->c_ospeed);
+}
+
+static const StructEntry struct_termios_def = {
+    .convert = { host_to_target_termios, target_to_host_termios },
+    .size = { sizeof(struct target_termios), sizeof(struct termios) },
+    .align = { __alignof__(struct target_termios),
+        __alignof__(struct termios) },
+};
+
+
+/* ioctl structure type definitions */
+#define STRUCT(name, ...) STRUCT_ ## name,
+#define STRUCT_SPECIAL(name) STRUCT_ ## name,
+enum {
+#include "os-ioctl-types.h"
+};
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+#define STRUCT(name, ...) \
+    static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
+#define STRUCT_SPECIAL(name)
+#include "os-ioctl-types.h"
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+
+struct IOCTLEntry;
+
+typedef abi_long do_ioctl_fn(const struct IOCTLEntry *ie, uint8_t *buf_temp,
+                int fd, abi_long cmd, abi_long arg);
+
+struct IOCTLEntry {
+    unsigned int target_cmd;
+    unsigned int host_cmd;
+    const char *name;
+    int access;
+    do_ioctl_fn *do_ioctl;
+    const argtype arg_type[5];
+};
+typedef struct IOCTLEntry IOCTLEntry;
+
+#define MAX_STRUCT_SIZE 4096
+
+static IOCTLEntry ioctl_entries[] = {
+#define IOC_    0x0000
+#define IOC_R   0x0001
+#define IOC_W   0x0002
+#define IOC_RW  (IOC_R | IOC_W)
+#define IOCTL(cmd, access, ...) \
+    { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
+#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
+    { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
+#include "os-ioctl-cmds.h"
+    { 0, 0 },
+};
+
+abi_long do_bsd_ioctl(int fd, abi_long cmd, abi_long arg)
+{
+    const IOCTLEntry *ie;
+    const argtype *arg_type;
+    abi_long ret;
+    uint8_t buf_temp[MAX_STRUCT_SIZE];
+    int target_size;
+    void *argptr;
+
+    ie = ioctl_entries;
+    for (;;) {
+        if (ie->target_cmd == 0) {
+            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
+            return -TARGET_ENOSYS;
+        }
+        if (ie->target_cmd == cmd) {
+            break;
+        }
+        ie++;
+    }
+    arg_type = ie->arg_type;
+#if defined(DEBUG)
+    gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
+#endif
+    if (ie->do_ioctl) {
+        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
+    }
+
+    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 argument */
+        ret = get_errno(ioctl(fd, ie->host_cmd, arg));
+        break;
+
+    case TYPE_PTR:
+        arg_type++;
+        target_size = thunk_type_size(arg_type, 0);
+        switch (ie->access) {
+        case IOC_R:
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            if (!is_error(ret)) {
+                argptr = lock_user(VERIFY_WRITE, arg,
+                    target_size, 0);
+                if (!argptr) {
+                    return -TARGET_EFAULT;
+                }
+                thunk_convert(argptr, buf_temp, arg_type,
+                    THUNK_TARGET);
+                unlock_user(argptr, arg, target_size);
+            }
+            break;
+
+        case IOC_W:
+            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);
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            break;
+
+        case IOC_RW:
+            /* fallthrough */
+        default:
+            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);
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            if (!is_error(ret)) {
+                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+                if (!argptr) {
+                    return -TARGET_EFAULT;
+                }
+                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+                unlock_user(argptr, arg, target_size);
+            }
+            break;
+        }
+        break;
+
+    default:
+        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
+            (long)cmd, arg_type[0]);
+        ret = -TARGET_ENOSYS;
+        break;
+    }
+    return ret;
+}
+
+void init_bsd_ioctl(void)
+{
+    IOCTLEntry *ie;
+    const argtype *arg_type;
+    int size;
+
+#define STRUCT(name, ...) \
+ thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
+#define STRUCT_SPECIAL(name) \
+ thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
+#include "os-ioctl-types.h"
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+    /*
+     * Patch the ioctl size if necessary using the fact that no
+     * ioctl has all the bits at '1' in the size field
+     * (IOCPARM_MAX - 1).
+     */
+    ie = ioctl_entries;
+    while (ie->target_cmd != 0) {
+        if (((ie->target_cmd >> TARGET_IOCPARM_SHIFT) &
+                    TARGET_IOCPARM_MASK) == TARGET_IOCPARM_MASK) {
+            arg_type = ie->arg_type;
+            if (arg_type[0] != TYPE_PTR) {
+                fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
+                        ie->target_cmd);
+                exit(1);
+            }
+            arg_type++;
+            size = thunk_type_size(arg_type, 0);
+            ie->target_cmd = (ie->target_cmd &
+                    ~(TARGET_IOCPARM_MASK << TARGET_IOCPARM_SHIFT)) |
+                (size << TARGET_IOCPARM_SHIFT);
+        }
+        ie++;
+    }
+
+}
+
diff --git a/bsd-user/bsd-ioctl.h b/bsd-user/bsd-ioctl.h
new file mode 100644
index 0000000..b593c88
--- /dev/null
+++ b/bsd-user/bsd-ioctl.h
@@ -0,0 +1,27 @@
+/*
+ *  ioctl system call definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_IOCTL_H_
+#define __BSD_IOCTL_H_
+
+abi_long do_bsd_ioctl(int fd, abi_long cmd, abi_long arg);
+void init_bsd_ioctl(void);
+
+#endif /* !__BSD_IOCTL_H_ */
+
diff --git a/bsd-user/freebsd/os-ioctl-cmds.h b/bsd-user/freebsd/os-ioctl-cmds.h
new file mode 100644
index 0000000..85d3c41
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-cmds.h
@@ -0,0 +1,47 @@
+
+/* sys/ttycom.h tty(4) */
+IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCCBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCSDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCCDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR))
+IOCTL(TIOCNOTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCSTOP, IOC_, TYPE_NULL)
+IOCTL(TIOCSTART, IOC_, TYPE_NULL)
+IOCTL(TIOCSCTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCDRAIN, IOC_, TYPE_NULL)
+IOCTL(TIOCEXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCNXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
+
+/* sys/filio.h */
+IOCTL(FIOCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODTYPE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOGETLBA, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODGNAME, IOC_R, MK_PTR(STRUCT_fiodgname_arg))
+IOCTL(FIONWRITE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONSPACE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOSEEKDATA, IOC_RW, MK_PTR(TYPE_ULONG))
+IOCTL(FIOSEEKHOLE, IOC_RW, MK_PTR(TYPE_ULONG))
diff --git a/bsd-user/freebsd/os-ioctl-filio.h b/bsd-user/freebsd/os-ioctl-filio.h
new file mode 100644
index 0000000..7e1aae9
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-filio.h
@@ -0,0 +1,45 @@
+/*
+ *  FreeBSD filio definitions for ioctl(2) emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _IOCTL_FILIO_H_
+#define _IOCTL_FILIO_H_
+
+/* see sys/filio.h */
+#define TARGET_FIOCLEX      TARGET_IO('f', 1)
+#define TARGET_FIONCLEX     TARGET_IO('f', 2)
+#define TARGET_FIONREAD     TARGET_IOR('f', 127, int)
+#define TARGET_FIONBIO      TARGET_IOW('f', 126, int)
+#define TARGET_FIOASYNC     TARGET_IOW('f', 125, int)
+#define TARGET_FIOSETOWN    TARGET_IOW('f', 124, int)
+#define TARGET_FIOGETOWN    TARGET_IOR('f', 123, int)
+#define TARGET_FIODTYPE     TARGET_IOR('f', 122, int)
+#define TARGET_FIOGETLBA    TARGET_IOR('f', 121, int)
+
+struct target_fiodgname_arg {
+    int32_t     len;
+    abi_ulong   buf;
+};
+
+#define TARGET_FIODGNAME    TARGET_IOW('f', 120,    \
+                struct target_fiodgname_arg)
+#define TARGET_FIONWRITE    TARGET_IOR('f', 119, int)
+#define TARGET_FIONSPACE    TARGET_IOR('f', 118, int)
+#define TARGET_FIOSEEKDATA  TARGET_IOWR('f', 97, off_t)
+#define TARGET_FIOSEEKHOLE  TARGET_IOWR('f', 98, off_t)
+
+#endif /* !_IOCTL_FILIO_H_ */
diff --git a/bsd-user/freebsd/os-ioctl-ioccom.h b/bsd-user/freebsd/os-ioctl-ioccom.h
new file mode 100644
index 0000000..fb9456f
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-ioccom.h
@@ -0,0 +1,54 @@
+/*
+ *  FreeBSD ioccom definitions for ioctl(2) emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _IOCTL_IOCCOM_H_
+#define _IOCTL_IOCCOM_H_
+/*
+ * Ioctl's have the command encoded in the lower word, and the size of
+ * any in or out parameters in the upper word.  The high 3 bits of the
+ * upper word are used to encode the in/out status of the parameter.
+ */
+/* number of bits for ioctl size */
+#define TARGET_IOCPARM_SHIFT    13
+
+/* parameter length mask */
+#define TARGET_IOCPARM_MASK ((1 << TARGET_IOCPARM_SHIFT) - 1)
+
+#define TARGET_IOCPARM_LEN(x)   (((x) >> 16) & TARGET_IOCPARM_MASK)
+#define TARGET_IOCBASECMD(x)    ((x) & ~(TARGET_IOCPARM_MASK << 16))
+#define TARGET_IOCGROUP(x)  (((x) >> 8) & 0xff)
+
+#define TARGET_IOCPARM_MAX  (1 << TARGET_IOCPARM_SHIFT) /* max size of ioctl */
+#define TARGET_IOC_VOID     0x20000000  /* no parameters */
+#define TARGET_IOC_OUT      0x40000000  /* copy out parameters */
+#define TARGET_IOC_IN       0x80000000  /* copy in parameters */
+#define TARGET_IOC_INOUT    (TARGET_IOC_IN|TARGET_IOC_OUT)
+#define TARGET_IOC_DIRMASK  (TARGET_IOC_VOID|TARGET_IOC_OUT|TARGET_IOC_IN)
+
+#define TARGET_IOC(inout, group, num, len) ((abi_ulong) \
+    ((inout) | (((len) & TARGET_IOCPARM_MASK) << 16) | ((group) << 8) \
+     | (num)))
+#define TARGET_IO(g, n)       TARGET_IOC(IOC_VOID,    (g), (n), 0)
+#define TARGET_IOWINT(g, n)   TARGET_IOC(IOC_VOID,    (g), (n), sizeof(int))
+#define TARGET_IOR(g, n, t)   TARGET_IOC(IOC_OUT, (g), (n), sizeof(t))
+#define TARGET_IOW(g, n, t)   TARGET_IOC(IOC_IN,  (g), (n), sizeof(t))
+/* this should be _IORW, but stdio got there first */
+#define TARGET_IOWR(g, n, t)  TARGET_IOC(IOC_INOUT,   (g), (n), sizeof(t))
+
+#endif /* !_IOCTL_IOCCOM_H_ */
diff --git a/bsd-user/freebsd/os-ioctl-ttycom.h b/bsd-user/freebsd/os-ioctl-ttycom.h
new file mode 100644
index 0000000..b60db25
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-ttycom.h
@@ -0,0 +1,257 @@
+/*
+ *  FreeBSD ttycom definitions for ioctl(2) emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _IOCTL_TTYCOM_H_
+#define _IOCTL_TTYCOM_H_
+
+#include "os-ioctl-ioccom.h"
+
+/* From sys/ttycom.h and sys/_termios.h */
+
+#define TARGET_VEOF     0   /* ICANON */
+#define TARGET_VEOL     1   /* ICANON */
+#define TARGET_VEOL2    2   /* ICANON together with IEXTEN */
+#define TARGET_VERASE   3   /* ICANON */
+#define TARGET_VWERASE  4   /* ICANON together with IEXTEN */
+#define TARGET_VKILL    5   /* ICANON */
+#define TARGET_VREPRINT 6   /* ICANON together with IEXTEN */
+#define TARGET_VERASE2  7   /* ICANON */
+#define TARGET_VINTR    8   /* ISIG */
+#define TARGET_VQUIT    9   /* ISIG */
+#define TARGET_VSUSP    10  /* ISIG */
+#define TARGET_VDSUSP   11  /* ISIG together with IEXTEN */
+#define TARGET_VSTART   12  /* IXON, IXOFF */
+#define TARGET_VSTOP    13  /* IXON, IXOFF */
+#define TARGET_VLNEXT   14  /* IEXTEN */
+#define TARGET_VDISCARD 15  /* IEXTEN */
+#define TARGET_VMIN     16  /* !ICANON */
+#define TARGET_VTIME    17  /* !ICANON */
+#define TARGET_VSTATUS  18  /* ICANON together with IEXTEN */
+/*                      19         spare 2 */
+#define TARGET_NCCS     20
+
+/*
+ * Input flags - software input processing
+ */
+#define TARGET_IGNBRK   0x00000001  /* ignore BREAK condition */
+#define TARGET_BRKINT   0x00000002  /* map BREAK to SIGINTR */
+#define TARGET_IGNPAR   0x00000004  /* ignore (discard) parity errors */
+#define TARGET_PARMRK   0x00000008  /* mark parity and framing errors */
+#define TARGET_INPCK    0x00000010  /* enable checking of parity errors */
+#define TARGET_ISTRIP   0x00000020  /* strip 8th bit off chars */
+#define TARGET_INLCR    0x00000040  /* map NL into CR */
+#define TARGET_IGNCR    0x00000080  /* ignore CR */
+#define TARGET_ICRNL    0x00000100  /* map CR to NL (ala CRMOD) */
+#define TARGET_IXON     0x00000200  /* enable output flow control */
+#define TARGET_IXOFF    0x00000400  /* enable input flow control */
+#define TARGET_IXANY    0x00000800  /* any char will restart after stop */
+#define TARGET_IMAXBEL  0x00002000  /* ring bell on input queue full */
+
+/*
+ * Output flags - software output processing
+ */
+#define TARGET_OPOST    0x00000001  /* enable following output processing */
+#define TARGET_ONLCR    0x00000002  /* map NL to CR-NL (ala CRMOD) */
+#define TARGET_TABDLY   0x00000004  /* tab delay mask */
+#define TARGET_TAB0     0x00000000  /* no tab delay and expansion */
+#define TARGET_TAB3     0x00000004  /* expand tabs to spaces */
+#define TARGET_ONOEOT   0x00000008  /* discard EOT's (^D) on output) */
+#define TARGET_OCRNL    0x00000010  /* map CR to NL on output */
+#define TARGET_ONOCR    0x00000020  /* no CR output at column 0 */
+#define TARGET_ONLRET   0x00000040  /* NL performs CR function */
+
+/*
+ * Control flags - hardware control of terminal
+ */
+#define TARGET_CIGNORE      0x00000001  /* ignore control flags */
+#define TARGET_CSIZE        0x00000300  /* character size mask */
+#define     TARGET_CS5      0x00000000  /* 5 bits (pseudo) */
+#define     TARGET_CS6      0x00000100  /* 6 bits */
+#define     TARGET_CS7      0x00000200  /* 7 bits */
+#define     TARGET_CS8      0x00000300  /* 8 bits */
+#define TARGET_CSTOPB       0x00000400  /* send 2 stop bits */
+#define TARGET_CREAD        0x00000800  /* enable receiver */
+#define TARGET_PARENB       0x00001000  /* parity enable */
+#define TARGET_PARODD       0x00002000  /* odd parity, else even */
+#define TARGET_HUPCL        0x00004000  /* hang up on last close */
+#define TARGET_CLOCAL       0x00008000  /* ignore modem status lines */
+#define TARGET_CCTS_OFLOW   0x00010000  /* CTS flow control of output */
+#define TARGET_CRTSCTS      (TARGET_CCTS_OFLOW | TARGET_CRTS_IFLOW)
+#define TARGET_CRTS_IFLOW   0x00020000  /* RTS flow control of input */
+#define TARGET_CDTR_IFLOW   0x00040000  /* DTR flow control of input */
+#define TARGET_CDSR_OFLOW   0x00080000  /* DSR flow control of output */
+#define TARGET_CCAR_OFLOW   0x00100000  /* DCD flow control of output */
+
+/*
+ * "Local" flags - dumping ground for other state
+ */
+#define TARGET_ECHOKE   0x00000001  /* visual erase for line kill */
+#define TARGET_ECHOE    0x00000002  /* visually erase chars */
+#define TARGET_ECHOK    0x00000004  /* echo NL after line kill */
+#define TARGET_ECHO 0x00000008  /* enable echoing */
+#define TARGET_ECHONL   0x00000010  /* echo NL even if ECHO is off */
+#define TARGET_ECHOPRT  0x00000020  /* visual erase mode for hardcopy */
+#define TARGET_ECHOCTL  0x00000040  /* echo control chars as ^(Char) */
+#define TARGET_ISIG 0x00000080  /* enable signals INTR, QUIT, [D]SUSP */
+#define TARGET_ICANON   0x00000100  /* canonicalize input lines */
+#define TARGET_ALTWERASE 0x00000200 /* use alternate WERASE algorithm */
+#define TARGET_IEXTEN   0x00000400  /* enable DISCARD and LNEXT */
+#define TARGET_EXTPROC  0x00000800  /* external processing */
+#define TARGET_TOSTOP   0x00400000  /* stop background jobs from output */
+#define TARGET_FLUSHO   0x00800000  /* output being flushed (state) */
+#define TARGET_NOKERNINFO 0x02000000    /* no kernel output from VSTATUS */
+#define TARGET_PENDIN   0x20000000  /* XXX retype pending input (state) */
+#define TARGET_NOFLSH   0x80000000  /* don't flush after interrupt */
+
+struct target_termios {
+    uint32_t c_iflag;   /* input flags */
+    uint32_t c_oflag;   /* output flags */
+    uint32_t c_cflag;   /* control flags */
+    uint32_t c_lflag;   /* local flags */
+    uint8_t  c_cc[TARGET_NCCS]; /* control chars */
+    uint32_t c_ispeed;  /* input speed */
+    uint32_t c_ospeed;  /* output speed */
+};
+
+
+struct target_winsize {
+    uint16_t ws_row;    /* rows, in characters */
+    uint16_t ws_col;    /* columns, in characters */
+    uint16_t ws_xpixel; /* horizontal size, pixels */
+    uint16_t ws_ypixel; /* vertical size, pixels */
+};
+
+                        /* 0-2 compat */
+                        /* 3-7 unused */
+                        /* 8-10 compat */
+                        /* 11-12 unused */
+#define TARGET_TIOCEXCL  TARGET_IO('t', 13) /* set exclusive use of tty */
+#define TARGET_TIOCNXCL  TARGET_IO('t', 14) /* reset exclusive use of tty */
+#define TARGET_TIOCGPTN  TARGET_IOR('t', 15, int) /* Get pts number. */
+#define TARGET_TIOCFLUSH TARGET_IOW('t', 16, int) /* flush buffers */
+                    /* 17-18 compat */
+/* get termios struct */
+#define TARGET_TIOCGETA TARGET_IOR('t', 19, struct target_termios)
+/* set termios struct */
+#define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios)
+/* drain output, set */
+#define TARGET_TIOCSETAW    TARGET_IOW('t', 21, struct target_termios)
+/* drn out, fls in, set */
+#define TARGET_TIOCSETAF    TARGET_IOW('t', 22, struct target_termios)
+                        /* 23-25 unused */
+#define TARGET_TIOCGETD TARGET_IOR('t', 26, int) /* get line discipline */
+#define TARGET_TIOCSETD TARGET_IOW('t', 27, int) /* set line discipline */
+#define TARGET_TIOCPTMASTER  TARGET_IO('t', 28) /* pts master validation */
+                    /* 29-85 unused */
+/* get ttywait timeout */
+#define TARGET_TIOCGDRAINWAIT   TARGET_IOR('t', 86, int)
+/* set ttywait timeout */
+#define TARGET_TIOCSDRAINWAIT   TARGET_IOW('t', 87, int)
+                    /* 88 unused */
+                    /* 89-91 conflicts: tun and tap */
+/* enable/get timestamp of last input event */
+#define TARGET_TIOCTIMESTAMP    TARGET_IOR('t', 89, struct target_timeval)
+/* modem: get wait on close */
+#define TARGET_TIOCMGDTRWAIT    TARGET_IOR('t', 90, int)
+/* modem: set wait on close */
+#define TARGET_TIOCMSDTRWAIT    TARGET_IOW('t', 91, int)
+                    /* 92-93 tun and tap */
+                    /* 94-97 conflicts: tun and tap */
+/* wait till output drained */
+#define TARGET_TIOCDRAIN     TARGET_IO('t', 94)
+ /* pty: generate signal */
+#define TARGET_TIOCSIG      TARGET_IOWINT('t', 95)
+/* pty: external processing */
+#define TARGET_TIOCEXT      TARGET_IOW('t', 96, int)
+/* become controlling tty */
+#define TARGET_TIOCSCTTY     TARGET_IO('t', 97)
+/* become virtual console */
+#define TARGET_TIOCCONS TARGET_IOW('t', 98, int)
+/* get session id */
+#define TARGET_TIOCGSID TARGET_IOR('t', 99, int)
+                        /* 100 unused */
+/* simulate ^T status message */
+#define TARGET_TIOCSTAT  TARGET_IO('t', 101)
+ /* pty: set/clr usr cntl mode */
+#define TARGET_TIOCUCNTL    TARGET_IOW('t', 102, int)
+/* usr cntl op "n" */
+#define TARGET_TIOCCMD(n)   TARGET_IO('u', n)
+/* set window size */
+#define TARGET_TIOCSWINSZ   TARGET_IOW('t', 103, struct target_winsize)
+/* get window size */
+#define TARGET_TIOCGWINSZ   TARGET_IOR('t', 104, struct target_winsize)
+                        /* 105 unused */
+/* get all modem bits */
+#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
+#define     TARGET_TIOCM_LE 0001        /* line enable */
+#define     TARGET_TIOCM_DTR    0002    /* data terminal ready */
+#define     TARGET_TIOCM_RTS    0004    /* request to send */
+#define     TARGET_TIOCM_ST 0010        /* secondary transmit */
+#define     TARGET_TIOCM_SR 0020        /* secondary receive */
+#define     TARGET_TIOCM_CTS    0040    /* clear to send */
+#define     TARGET_TIOCM_DCD    0100    /* data carrier detect */
+#define     TARGET_TIOCM_RI     0200    /* ring indicate */
+#define     TARGET_TIOCM_DSR    0400    /* data set ready */
+#define     TARGET_TIOCM_CD TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_CAR    TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_RNG    TARGET_TIOCM_RI
+#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) /* bic modem bits */
+#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) /* bis modem bits */
+#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) /* set all modem bits */
+/* start output, like ^Q */
+#define TARGET_TIOCSTART     TARGET_IO('t', 110)
+/* stop output, like ^S */
+#define TARGET_TIOCSTOP  TARGET_IO('t', 111)
+/* pty: set/clear packet mode */
+#define TARGET_TIOCPKT      TARGET_IOW('t', 112, int)
+#define     TARGET_TIOCPKT_DATA     0x00    /* data packet */
+#define     TARGET_TIOCPKT_FLUSHREAD    0x01    /* flush packet */
+#define     TARGET_TIOCPKT_FLUSHWRITE   0x02    /* flush packet */
+#define     TARGET_TIOCPKT_STOP     0x04    /* stop output */
+#define     TARGET_TIOCPKT_START        0x08    /* start output */
+#define     TARGET_TIOCPKT_NOSTOP       0x10    /* no more ^S, ^Q */
+#define     TARGET_TIOCPKT_DOSTOP       0x20    /* now do ^S ^Q */
+#define     TARGET_TIOCPKT_IOCTL        0x40    /* state change of pty
+                               driver */
+#define TARGET_TIOCNOTTY     TARGET_IO('t', 113)    /* void tty
+                               association */
+#define TARGET_TIOCSTI      TARGET_IOW('t', 114, char)  /* simulate
+                            terminal input */
+#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)   /* output queue size */
+                        /* 116-117 compat */
+#define TARGET_TIOCSPGRP    TARGET_IOW('t', 118, int) /* set pgrp of tty */
+#define TARGET_TIOCGPGRP    TARGET_IOR('t', 119, int) /* get pgrp of tty */
+#define TARGET_TIOCCDTR  TARGET_IO('t', 120)        /* clear data terminal
+                               ready */
+#define TARGET_TIOCSDTR  TARGET_IO('t', 121)        /* set data terminal
+                               ready */
+#define TARGET_TIOCCBRK  TARGET_IO('t', 122)        /* clear break bit */
+#define TARGET_TIOCSBRK  TARGET_IO('t', 123)        /* set break bit */
+                        /* 124-127 compat */
+
+#define TARGET_TTYDISC      0       /* termios tty line
+                           discipline */
+#define TARGET_SLIPDISC     4       /* serial IP discipline */
+#define TARGET_PPPDISC      5       /* PPP discipline */
+#define TARGET_NETGRAPHDISC 6       /* Netgraph tty node
+                           discipline */
+#define TARGET_H4DISC       7       /* Netgraph Bluetooth H4
+                           discipline */
+
+#endif /*! _IOCTL_TTYCOM_H_ */
diff --git a/bsd-user/freebsd/os-ioctl-types.h b/bsd-user/freebsd/os-ioctl-types.h
new file mode 100644
index 0000000..60b9288
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-types.h
@@ -0,0 +1,7 @@
+
+STRUCT_SPECIAL(termios)
+
+STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
+
+STRUCT(fiodgname_arg, TYPE_INT, TYPE_PTRVOID)
+
diff --git a/bsd-user/netbsd/os-ioctl-cmds.h b/bsd-user/netbsd/os-ioctl-cmds.h
new file mode 100644
index 0000000..12af33c
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-cmds.h
@@ -0,0 +1,48 @@
+/* XXX should be fixed for NetBSD ioctl cmds */
+
+/* sys/ttycom.h tty(4) */
+IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCCBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCSDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCCDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR))
+IOCTL(TIOCNOTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCSTOP, IOC_, TYPE_NULL)
+IOCTL(TIOCSTART, IOC_, TYPE_NULL)
+IOCTL(TIOCSCTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCDRAIN, IOC_, TYPE_NULL)
+IOCTL(TIOCEXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCNXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
+
+/* sys/filio.h */
+IOCTL(FIOCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODTYPE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOGETLBA, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODGNAME, IOC_R, MK_PTR(STRUCT_fiodgname_arg))
+IOCTL(FIONWRITE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONSPACE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOSEEKDATA, IOC_RW, MK_PTR(TYPE_ULONG))
+IOCTL(FIOSEEKHOLE, IOC_RW, MK_PTR(TYPE_ULONG))
diff --git a/bsd-user/netbsd/os-ioctl-filio.h b/bsd-user/netbsd/os-ioctl-filio.h
new file mode 100644
index 0000000..24b63ae
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-filio.h
@@ -0,0 +1,29 @@
+#ifndef _IOCTL_FILIO_H_
+#define _IOCTL_FILIO_H_
+
+/* XXX needs to be fixed for NetBSD dependencies */
+
+/* see sys/filio.h */
+#define TARGET_FIOCLEX      TARGET_IO('f', 1)
+#define TARGET_FIONCLEX     TARGET_IO('f', 2)
+#define TARGET_FIONREAD     TARGET_IOR('f', 127, int)
+#define TARGET_FIONBIO      TARGET_IOW('f', 126, int)
+#define TARGET_FIOASYNC     TARGET_IOW('f', 125, int)
+#define TARGET_FIOSETOWN    TARGET_IOW('f', 124, int)
+#define TARGET_FIOGETOWN    TARGET_IOR('f', 123, int)
+#define TARGET_FIODTYPE     TARGET_IOR('f', 122, int)
+#define TARGET_FIOGETLBA    TARGET_IOR('f', 121, int)
+
+struct target_fiodgname_arg {
+    int32_t     len;
+    abi_ulong   buf;
+};
+
+#define TARGET_FIODGNAME    TARGET_IOW('f', 120,    \
+                struct target_fiodgname_arg)
+#define TARGET_FIONWRITE    TARGET_IOR('f', 119, int)
+#define TARGET_FIONSPACE    TARGET_IOR('f', 118, int)
+#define TARGET_FIOSEEKDATA  TARGET_IOWR('f', 97, off_t)
+#define TARGET_FIOSEEKHOLE  TARGET_IOWR('f', 98, off_t)
+
+#endif /* !_IOCTL_FILIO_H_ */
diff --git a/bsd-user/netbsd/os-ioctl-ioccom.h b/bsd-user/netbsd/os-ioctl-ioccom.h
new file mode 100644
index 0000000..e193a16
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-ioccom.h
@@ -0,0 +1,38 @@
+#ifndef _IOCTL_IOCCOM_H_
+#define _IOCTL_IOCCOM_H_
+
+/* XXX needs to be fixed for NetBSD dependencies */
+
+/*
+ * Ioctl's have the command encoded in the lower word, and the size of
+ * any in or out parameters in the upper word.  The high 3 bits of the
+ * upper word are used to encode the in/out status of the parameter.
+ */
+/* number of bits for ioctl size */
+#define TARGET_IOCPARM_SHIFT    13
+
+/* parameter length mask */
+#define TARGET_IOCPARM_MASK ((1 << TARGET_IOCPARM_SHIFT) - 1)
+
+#define TARGET_IOCPARM_LEN(x)   (((x) >> 16) & TARGET_IOCPARM_MASK)
+#define TARGET_IOCBASECMD(x)    ((x) & ~(TARGET_IOCPARM_MASK << 16))
+#define TARGET_IOCGROUP(x)  (((x) >> 8) & 0xff)
+
+#define TARGET_IOCPARM_MAX  (1 << TARGET_IOCPARM_SHIFT) /* max size of ioctl */
+#define TARGET_IOC_VOID     0x20000000  /* no parameters */
+#define TARGET_IOC_OUT      0x40000000  /* copy out parameters */
+#define TARGET_IOC_IN       0x80000000  /* copy in parameters */
+#define TARGET_IOC_INOUT    (TARGET_IOC_IN|TARGET_IOC_OUT)
+#define TARGET_IOC_DIRMASK  (TARGET_IOC_VOID|TARGET_IOC_OUT|TARGET_IOC_IN)
+
+#define TARGET_IOC(inout, group, num, len) ((abi_ulong) \
+    ((inout) | (((len) & TARGET_IOCPARM_MASK) << 16) | ((group) << 8) \
+     | (num)))
+#define TARGET_IO(g, n)      TARGET_IOC(IOC_VOID,    (g), (n), 0)
+#define TARGET_IOWINT(g, n)  TARGET_IOC(IOC_VOID,    (g), (n), sizeof(int))
+#define TARGET_IOR(g, n, t)   TARGET_IOC(IOC_OUT, (g), (n), sizeof(t))
+#define TARGET_IOW(g, n, t)   TARGET_IOC(IOC_IN,  (g), (n), sizeof(t))
+/* this should be _IORW, but stdio got there first */
+#define TARGET_IOWR(g, n, t)  TARGET_IOC(IOC_INOUT,   (g), (n), sizeof(t))
+
+#endif /* !_IOCTL_IOCCOM_H_ */
diff --git a/bsd-user/netbsd/os-ioctl-ttycom.h b/bsd-user/netbsd/os-ioctl-ttycom.h
new file mode 100644
index 0000000..9086635
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-ttycom.h
@@ -0,0 +1,240 @@
+#ifndef _IOCTL_TTYCOM_H_
+#define _IOCTL_TTYCOM_H_
+
+/* XXX Needs to be fixed for NetBSD dependencies */
+
+#include "os-ioctl-ioccom.h"
+
+/* From sys/ttycom.h and sys/_termios.h */
+
+#define TARGET_VEOF     0   /* ICANON */
+#define TARGET_VEOL     1   /* ICANON */
+#define TARGET_VEOL2    2   /* ICANON together with IEXTEN */
+#define TARGET_VERASE   3   /* ICANON */
+#define TARGET_VWERASE  4   /* ICANON together with IEXTEN */
+#define TARGET_VKILL    5   /* ICANON */
+#define TARGET_VREPRINT 6   /* ICANON together with IEXTEN */
+#define TARGET_VERASE2  7   /* ICANON */
+#define TARGET_VINTR    8   /* ISIG */
+#define TARGET_VQUIT    9   /* ISIG */
+#define TARGET_VSUSP    10  /* ISIG */
+#define TARGET_VDSUSP   11  /* ISIG together with IEXTEN */
+#define TARGET_VSTART   12  /* IXON, IXOFF */
+#define TARGET_VSTOP    13  /* IXON, IXOFF */
+#define TARGET_VLNEXT   14  /* IEXTEN */
+#define TARGET_VDISCARD 15  /* IEXTEN */
+#define TARGET_VMIN     16  /* !ICANON */
+#define TARGET_VTIME    17  /* !ICANON */
+#define TARGET_VSTATUS  18  /* ICANON together with IEXTEN */
+/*                      19         spare 2 */
+#define TARGET_NCCS     20
+
+/*
+ * Input flags - software input processing
+ */
+#define TARGET_IGNBRK   0x00000001  /* ignore BREAK condition */
+#define TARGET_BRKINT   0x00000002  /* map BREAK to SIGINTR */
+#define TARGET_IGNPAR   0x00000004  /* ignore (discard) parity errors */
+#define TARGET_PARMRK   0x00000008  /* mark parity and framing errors */
+#define TARGET_INPCK    0x00000010  /* enable checking of parity errors */
+#define TARGET_ISTRIP   0x00000020  /* strip 8th bit off chars */
+#define TARGET_INLCR    0x00000040  /* map NL into CR */
+#define TARGET_IGNCR    0x00000080  /* ignore CR */
+#define TARGET_ICRNL    0x00000100  /* map CR to NL (ala CRMOD) */
+#define TARGET_IXON     0x00000200  /* enable output flow control */
+#define TARGET_IXOFF    0x00000400  /* enable input flow control */
+#define TARGET_IXANY    0x00000800  /* any char will restart after stop */
+#define TARGET_IMAXBEL  0x00002000  /* ring bell on input queue full */
+
+/*
+ * Output flags - software output processing
+ */
+#define TARGET_OPOST    0x00000001  /* enable following output processing */
+#define TARGET_ONLCR    0x00000002  /* map NL to CR-NL (ala CRMOD) */
+#define TARGET_TABDLY   0x00000004  /* tab delay mask */
+#define TARGET_TAB0     0x00000000  /* no tab delay and expansion */
+#define TARGET_TAB3     0x00000004  /* expand tabs to spaces */
+#define TARGET_ONOEOT   0x00000008  /* discard EOT's (^D) on output) */
+#define TARGET_OCRNL    0x00000010  /* map CR to NL on output */
+#define TARGET_ONOCR    0x00000020  /* no CR output at column 0 */
+#define TARGET_ONLRET   0x00000040  /* NL performs CR function */
+
+/*
+ * Control flags - hardware control of terminal
+ */
+#define TARGET_CIGNORE      0x00000001  /* ignore control flags */
+#define TARGET_CSIZE        0x00000300  /* character size mask */
+#define     TARGET_CS5      0x00000000  /* 5 bits (pseudo) */
+#define     TARGET_CS6      0x00000100  /* 6 bits */
+#define     TARGET_CS7      0x00000200  /* 7 bits */
+#define     TARGET_CS8      0x00000300  /* 8 bits */
+#define TARGET_CSTOPB       0x00000400  /* send 2 stop bits */
+#define TARGET_CREAD        0x00000800  /* enable receiver */
+#define TARGET_PARENB       0x00001000  /* parity enable */
+#define TARGET_PARODD       0x00002000  /* odd parity, else even */
+#define TARGET_HUPCL        0x00004000  /* hang up on last close */
+#define TARGET_CLOCAL       0x00008000  /* ignore modem status lines */
+#define TARGET_CCTS_OFLOW   0x00010000  /* CTS flow control of output */
+#define TARGET_CRTSCTS      (TARGET_CCTS_OFLOW | TARGET_CRTS_IFLOW)
+#define TARGET_CRTS_IFLOW   0x00020000  /* RTS flow control of input */
+#define TARGET_CDTR_IFLOW   0x00040000  /* DTR flow control of input */
+#define TARGET_CDSR_OFLOW   0x00080000  /* DSR flow control of output */
+#define TARGET_CCAR_OFLOW   0x00100000  /* DCD flow control of output */
+
+/*
+ * "Local" flags - dumping ground for other state
+ */
+#define TARGET_ECHOKE   0x00000001  /* visual erase for line kill */
+#define TARGET_ECHOE    0x00000002  /* visually erase chars */
+#define TARGET_ECHOK    0x00000004  /* echo NL after line kill */
+#define TARGET_ECHO 0x00000008  /* enable echoing */
+#define TARGET_ECHONL   0x00000010  /* echo NL even if ECHO is off */
+#define TARGET_ECHOPRT  0x00000020  /* visual erase mode for hardcopy */
+#define TARGET_ECHOCTL  0x00000040  /* echo control chars as ^(Char) */
+#define TARGET_ISIG 0x00000080  /* enable signals INTR, QUIT, [D]SUSP */
+#define TARGET_ICANON   0x00000100  /* canonicalize input lines */
+#define TARGET_ALTWERASE 0x00000200 /* use alternate WERASE algorithm */
+#define TARGET_IEXTEN   0x00000400  /* enable DISCARD and LNEXT */
+#define TARGET_EXTPROC  0x00000800  /* external processing */
+#define TARGET_TOSTOP   0x00400000  /* stop background jobs from output */
+#define TARGET_FLUSHO   0x00800000  /* output being flushed (state) */
+#define TARGET_NOKERNINFO 0x02000000    /* no kernel output from VSTATUS */
+#define TARGET_PENDIN   0x20000000  /* XXX retype pending input (state) */
+#define TARGET_NOFLSH   0x80000000  /* don't flush after interrupt */
+
+struct target_termios {
+    uint32_t c_iflag;   /* input flags */
+    uint32_t c_oflag;   /* output flags */
+    uint32_t c_cflag;   /* control flags */
+    uint32_t c_lflag;   /* local flags */
+    uint8_t  c_cc[TARGET_NCCS]; /* control chars */
+    uint32_t c_ispeed;  /* input speed */
+    uint32_t c_ospeed;  /* output speed */
+};
+
+
+struct target_winsize {
+    uint16_t ws_row;    /* rows, in characters */
+    uint16_t ws_col;    /* columns, in characters */
+    uint16_t ws_xpixel; /* horizontal size, pixels */
+    uint16_t ws_ypixel; /* vertical size, pixels */
+};
+
+                        /* 0-2 compat */
+                        /* 3-7 unused */
+                        /* 8-10 compat */
+                        /* 11-12 unused */
+#define TARGET_TIOCEXCL  TARGET_IO('t', 13) /* set exclusive use of tty */
+#define TARGET_TIOCNXCL  TARGET_IO('t', 14) /* reset exclusive use of tty */
+#define TARGET_TIOCGPTN  TARGET_IOR('t', 15, int) /* Get pts number. */
+#define TARGET_TIOCFLUSH TARGET_IOW('t', 16, int) /* flush buffers */
+                    /* 17-18 compat */
+/* get termios struct */
+#define TARGET_TIOCGETA TARGET_IOR('t', 19, struct target_termios)
+/* set termios struct */
+#define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios)
+/* drain output, set */
+#define TARGET_TIOCSETAW    TARGET_IOW('t', 21, struct target_termios)
+/* drn out, fls in, set */
+#define TARGET_TIOCSETAF    TARGET_IOW('t', 22, struct target_termios)
+                        /* 23-25 unused */
+#define TARGET_TIOCGETD TARGET_IOR('t', 26, int) /* get line discipline */
+#define TARGET_TIOCSETD TARGET_IOW('t', 27, int) /* set line discipline */
+#define TARGET_TIOCPTMASTER  TARGET_IO('t', 28) /* pts master validation */
+                    /* 29-85 unused */
+/* get ttywait timeout */
+#define TARGET_TIOCGDRAINWAIT   TARGET_IOR('t', 86, int)
+/* set ttywait timeout */
+#define TARGET_TIOCSDRAINWAIT   TARGET_IOW('t', 87, int)
+                    /* 88 unused */
+                    /* 89-91 conflicts: tun and tap */
+/* enable/get timestamp of last input event */
+#define TARGET_TIOCTIMESTAMP    TARGET_IOR('t', 89, struct target_timeval)
+/* modem: get wait on close */
+#define TARGET_TIOCMGDTRWAIT    TARGET_IOR('t', 90, int)
+/* modem: set wait on close */
+#define TARGET_TIOCMSDTRWAIT    TARGET_IOW('t', 91, int)
+                    /* 92-93 tun and tap */
+                    /* 94-97 conflicts: tun and tap */
+/* wait till output drained */
+#define TARGET_TIOCDRAIN     TARGET_IO('t', 94)
+ /* pty: generate signal */
+#define TARGET_TIOCSIG      TARGET_IOWINT('t', 95)
+/* pty: external processing */
+#define TARGET_TIOCEXT      TARGET_IOW('t', 96, int)
+/* become controlling tty */
+#define TARGET_TIOCSCTTY     TARGET_IO('t', 97)
+/* become virtual console */
+#define TARGET_TIOCCONS TARGET_IOW('t', 98, int)
+/* get session id */
+#define TARGET_TIOCGSID TARGET_IOR('t', 99, int)
+                        /* 100 unused */
+/* simulate ^T status message */
+#define TARGET_TIOCSTAT  TARGET_IO('t', 101)
+ /* pty: set/clr usr cntl mode */
+#define TARGET_TIOCUCNTL    TARGET_IOW('t', 102, int)
+/* usr cntl op "n" */
+#define TARGET_TIOCCMD(n)   TARGET_IO('u', n)
+/* set window size */
+#define TARGET_TIOCSWINSZ   TARGET_IOW('t', 103, struct target_winsize)
+/* get window size */
+#define TARGET_TIOCGWINSZ   TARGET_IOR('t', 104, struct target_winsize)
+                        /* 105 unused */
+/* get all modem bits */
+#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
+#define     TARGET_TIOCM_LE 0001        /* line enable */
+#define     TARGET_TIOCM_DTR    0002    /* data terminal ready */
+#define     TARGET_TIOCM_RTS    0004    /* request to send */
+#define     TARGET_TIOCM_ST 0010        /* secondary transmit */
+#define     TARGET_TIOCM_SR 0020        /* secondary receive */
+#define     TARGET_TIOCM_CTS    0040    /* clear to send */
+#define     TARGET_TIOCM_DCD    0100    /* data carrier detect */
+#define     TARGET_TIOCM_RI     0200    /* ring indicate */
+#define     TARGET_TIOCM_DSR    0400    /* data set ready */
+#define     TARGET_TIOCM_CD TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_CAR    TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_RNG    TARGET_TIOCM_RI
+#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) /* bic modem bits */
+#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) /* bis modem bits */
+#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) /* set all modem bits */
+/* start output, like ^Q */
+#define TARGET_TIOCSTART     TARGET_IO('t', 110)
+/* stop output, like ^S */
+#define TARGET_TIOCSTOP  TARGET_IO('t', 111)
+/* pty: set/clear packet mode */
+#define TARGET_TIOCPKT      TARGET_IOW('t', 112, int)
+#define     TARGET_TIOCPKT_DATA     0x00    /* data packet */
+#define     TARGET_TIOCPKT_FLUSHREAD    0x01    /* flush packet */
+#define     TARGET_TIOCPKT_FLUSHWRITE   0x02    /* flush packet */
+#define     TARGET_TIOCPKT_STOP     0x04    /* stop output */
+#define     TARGET_TIOCPKT_START        0x08    /* start output */
+#define     TARGET_TIOCPKT_NOSTOP       0x10    /* no more ^S, ^Q */
+#define     TARGET_TIOCPKT_DOSTOP       0x20    /* now do ^S ^Q */
+#define     TARGET_TIOCPKT_IOCTL        0x40    /* state change of pty
+                               driver */
+#define TARGET_TIOCNOTTY     TARGET_IO('t', 113)    /* void tty
+                               association */
+#define TARGET_TIOCSTI      TARGET_IOW('t', 114, char)  /* simulate
+                            terminal input */
+#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)   /* output queue size */
+                        /* 116-117 compat */
+#define TARGET_TIOCSPGRP    TARGET_IOW('t', 118, int) /* set pgrp of tty */
+#define TARGET_TIOCGPGRP    TARGET_IOR('t', 119, int) /* get pgrp of tty */
+#define TARGET_TIOCCDTR  TARGET_IO('t', 120)        /* clear data terminal
+                               ready */
+#define TARGET_TIOCSDTR  TARGET_IO('t', 121)        /* set data terminal
+                               ready */
+#define TARGET_TIOCCBRK  TARGET_IO('t', 122)        /* clear break bit */
+#define TARGET_TIOCSBRK  TARGET_IO('t', 123)        /* set break bit */
+                        /* 124-127 compat */
+
+#define TARGET_TTYDISC      0       /* termios tty line
+                           discipline */
+#define TARGET_SLIPDISC     4       /* serial IP discipline */
+#define TARGET_PPPDISC      5       /* PPP discipline */
+#define TARGET_NETGRAPHDISC 6       /* Netgraph tty node
+                           discipline */
+#define TARGET_H4DISC       7       /* Netgraph Bluetooth H4
+                           discipline */
+
+#endif /*! _IOCTL_TTYCOM_H_ */
diff --git a/bsd-user/netbsd/os-ioctl-types.h b/bsd-user/netbsd/os-ioctl-types.h
new file mode 100644
index 0000000..e761c20
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-types.h
@@ -0,0 +1,7 @@
+/* XXX should be fixed for NetBSD types and structs */
+STRUCT_SPECIAL(termios)
+
+STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
+
+STRUCT(fiodgname_arg, TYPE_INT, TYPE_PTRVOID)
+
diff --git a/bsd-user/openbsd/os-ioctl-cmds.h b/bsd-user/openbsd/os-ioctl-cmds.h
new file mode 100644
index 0000000..a15f056
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-cmds.h
@@ -0,0 +1,48 @@
+/* XXX should be fixed for OpenBSD ioctl cmds */
+
+/* sys/ttycom.h tty(4) */
+IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCCBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCSDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCCDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR))
+IOCTL(TIOCNOTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCSTOP, IOC_, TYPE_NULL)
+IOCTL(TIOCSTART, IOC_, TYPE_NULL)
+IOCTL(TIOCSCTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCDRAIN, IOC_, TYPE_NULL)
+IOCTL(TIOCEXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCNXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
+
+/* sys/filio.h */
+IOCTL(FIOCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODTYPE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOGETLBA, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODGNAME, IOC_R, MK_PTR(STRUCT_fiodgname_arg))
+IOCTL(FIONWRITE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONSPACE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOSEEKDATA, IOC_RW, MK_PTR(TYPE_ULONG))
+IOCTL(FIOSEEKHOLE, IOC_RW, MK_PTR(TYPE_ULONG))
diff --git a/bsd-user/openbsd/os-ioctl-filio.h b/bsd-user/openbsd/os-ioctl-filio.h
new file mode 100644
index 0000000..e3f7474
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-filio.h
@@ -0,0 +1,29 @@
+#ifndef _IOCTL_FILIO_H_
+#define _IOCTL_FILIO_H_
+
+/* XXX needs to be fixed for OpenBSD dependencies */
+
+/* see sys/filio.h */
+#define TARGET_FIOCLEX      TARGET_IO('f', 1)
+#define TARGET_FIONCLEX     TARGET_IO('f', 2)
+#define TARGET_FIONREAD     TARGET_IOR('f', 127, int)
+#define TARGET_FIONBIO      TARGET_IOW('f', 126, int)
+#define TARGET_FIOASYNC     TARGET_IOW('f', 125, int)
+#define TARGET_FIOSETOWN    TARGET_IOW('f', 124, int)
+#define TARGET_FIOGETOWN    TARGET_IOR('f', 123, int)
+#define TARGET_FIODTYPE     TARGET_IOR('f', 122, int)
+#define TARGET_FIOGETLBA    TARGET_IOR('f', 121, int)
+
+struct target_fiodgname_arg {
+    int32_t     len;
+    abi_ulong   buf;
+};
+
+#define TARGET_FIODGNAME    TARGET_IOW('f', 120,    \
+                struct target_fiodgname_arg)
+#define TARGET_FIONWRITE    TARGET_IOR('f', 119, int)
+#define TARGET_FIONSPACE    TARGET_IOR('f', 118, int)
+#define TARGET_FIOSEEKDATA  TARGET_IOWR('f', 97, off_t)
+#define TARGET_FIOSEEKHOLE  TARGET_IOWR('f', 98, off_t)
+
+#endif /* !_IOCTL_FILIO_H_ */
diff --git a/bsd-user/openbsd/os-ioctl-ioccom.h b/bsd-user/openbsd/os-ioctl-ioccom.h
new file mode 100644
index 0000000..fa1c6b4
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-ioccom.h
@@ -0,0 +1,38 @@
+#ifndef _IOCTL_IOCCOM_H_
+#define _IOCTL_IOCCOM_H_
+
+/* XXX needs to be fixed for OpenBSD dependencies */
+
+/*
+ * Ioctl's have the command encoded in the lower word, and the size of
+ * any in or out parameters in the upper word.  The high 3 bits of the
+ * upper word are used to encode the in/out status of the parameter.
+ */
+/* number of bits for ioctl size */
+#define TARGET_IOCPARM_SHIFT    13
+
+/* parameter length mask */
+#define TARGET_IOCPARM_MASK ((1 << TARGET_IOCPARM_SHIFT) - 1)
+
+#define TARGET_IOCPARM_LEN(x)   (((x) >> 16) & TARGET_IOCPARM_MASK)
+#define TARGET_IOCBASECMD(x)    ((x) & ~(TARGET_IOCPARM_MASK << 16))
+#define TARGET_IOCGROUP(x)  (((x) >> 8) & 0xff)
+
+#define TARGET_IOCPARM_MAX  (1 << TARGET_IOCPARM_SHIFT) /* max size of ioctl */
+#define TARGET_IOC_VOID     0x20000000  /* no parameters */
+#define TARGET_IOC_OUT      0x40000000  /* copy out parameters */
+#define TARGET_IOC_IN       0x80000000  /* copy in parameters */
+#define TARGET_IOC_INOUT    (TARGET_IOC_IN|TARGET_IOC_OUT)
+#define TARGET_IOC_DIRMASK  (TARGET_IOC_VOID|TARGET_IOC_OUT|TARGET_IOC_IN)
+
+#define TARGET_IOC(inout, group, num, len) ((abi_ulong) \
+    ((inout) | (((len) & TARGET_IOCPARM_MASK) << 16) | ((group) << 8) \
+     | (num)))
+#define TARGET_IO(g, n)       TARGET_IOC(IOC_VOID,    (g), (n), 0)
+#define TARGET_IOWINT(g, n)   TARGET_IOC(IOC_VOID,    (g), (n), sizeof(int))
+#define TARGET_IOR(g, n, t)   TARGET_IOC(IOC_OUT, (g), (n), sizeof(t))
+#define TARGET_IOW(g, n, t)   TARGET_IOC(IOC_IN,  (g), (n), sizeof(t))
+/* this should be _IORW, but stdio got there first */
+#define TARGET_IOWR(g, n, t)  TARGET_IOC(IOC_INOUT,   (g), (n), sizeof(t))
+
+#endif /* !_IOCTL_IOCCOM_H_ */
diff --git a/bsd-user/openbsd/os-ioctl-ttycom.h b/bsd-user/openbsd/os-ioctl-ttycom.h
new file mode 100644
index 0000000..745d702
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-ttycom.h
@@ -0,0 +1,240 @@
+#ifndef _IOCTL_TTYCOM_H_
+#define _IOCTL_TTYCOM_H_
+
+/* XXX Needs to be fixed for OpenBSD dependencies */
+
+#include "os-ioctl-ioccom.h"
+
+/* From sys/ttycom.h and sys/_termios.h */
+
+#define TARGET_VEOF     0   /* ICANON */
+#define TARGET_VEOL     1   /* ICANON */
+#define TARGET_VEOL2    2   /* ICANON together with IEXTEN */
+#define TARGET_VERASE   3   /* ICANON */
+#define TARGET_VWERASE  4   /* ICANON together with IEXTEN */
+#define TARGET_VKILL    5   /* ICANON */
+#define TARGET_VREPRINT 6   /* ICANON together with IEXTEN */
+#define TARGET_VERASE2  7   /* ICANON */
+#define TARGET_VINTR    8   /* ISIG */
+#define TARGET_VQUIT    9   /* ISIG */
+#define TARGET_VSUSP    10  /* ISIG */
+#define TARGET_VDSUSP   11  /* ISIG together with IEXTEN */
+#define TARGET_VSTART   12  /* IXON, IXOFF */
+#define TARGET_VSTOP    13  /* IXON, IXOFF */
+#define TARGET_VLNEXT   14  /* IEXTEN */
+#define TARGET_VDISCARD 15  /* IEXTEN */
+#define TARGET_VMIN     16  /* !ICANON */
+#define TARGET_VTIME    17  /* !ICANON */
+#define TARGET_VSTATUS  18  /* ICANON together with IEXTEN */
+/*                      19         spare 2 */
+#define TARGET_NCCS     20
+
+/*
+ * Input flags - software input processing
+ */
+#define TARGET_IGNBRK   0x00000001  /* ignore BREAK condition */
+#define TARGET_BRKINT   0x00000002  /* map BREAK to SIGINTR */
+#define TARGET_IGNPAR   0x00000004  /* ignore (discard) parity errors */
+#define TARGET_PARMRK   0x00000008  /* mark parity and framing errors */
+#define TARGET_INPCK    0x00000010  /* enable checking of parity errors */
+#define TARGET_ISTRIP   0x00000020  /* strip 8th bit off chars */
+#define TARGET_INLCR    0x00000040  /* map NL into CR */
+#define TARGET_IGNCR    0x00000080  /* ignore CR */
+#define TARGET_ICRNL    0x00000100  /* map CR to NL (ala CRMOD) */
+#define TARGET_IXON     0x00000200  /* enable output flow control */
+#define TARGET_IXOFF    0x00000400  /* enable input flow control */
+#define TARGET_IXANY    0x00000800  /* any char will restart after stop */
+#define TARGET_IMAXBEL  0x00002000  /* ring bell on input queue full */
+
+/*
+ * Output flags - software output processing
+ */
+#define TARGET_OPOST    0x00000001  /* enable following output processing */
+#define TARGET_ONLCR    0x00000002  /* map NL to CR-NL (ala CRMOD) */
+#define TARGET_TABDLY   0x00000004  /* tab delay mask */
+#define TARGET_TAB0     0x00000000  /* no tab delay and expansion */
+#define TARGET_TAB3     0x00000004  /* expand tabs to spaces */
+#define TARGET_ONOEOT   0x00000008  /* discard EOT's (^D) on output) */
+#define TARGET_OCRNL    0x00000010  /* map CR to NL on output */
+#define TARGET_ONOCR    0x00000020  /* no CR output at column 0 */
+#define TARGET_ONLRET   0x00000040  /* NL performs CR function */
+
+/*
+ * Control flags - hardware control of terminal
+ */
+#define TARGET_CIGNORE      0x00000001  /* ignore control flags */
+#define TARGET_CSIZE        0x00000300  /* character size mask */
+#define     TARGET_CS5      0x00000000  /* 5 bits (pseudo) */
+#define     TARGET_CS6      0x00000100  /* 6 bits */
+#define     TARGET_CS7      0x00000200  /* 7 bits */
+#define     TARGET_CS8      0x00000300  /* 8 bits */
+#define TARGET_CSTOPB       0x00000400  /* send 2 stop bits */
+#define TARGET_CREAD        0x00000800  /* enable receiver */
+#define TARGET_PARENB       0x00001000  /* parity enable */
+#define TARGET_PARODD       0x00002000  /* odd parity, else even */
+#define TARGET_HUPCL        0x00004000  /* hang up on last close */
+#define TARGET_CLOCAL       0x00008000  /* ignore modem status lines */
+#define TARGET_CCTS_OFLOW   0x00010000  /* CTS flow control of output */
+#define TARGET_CRTSCTS      (TARGET_CCTS_OFLOW | TARGET_CRTS_IFLOW)
+#define TARGET_CRTS_IFLOW   0x00020000  /* RTS flow control of input */
+#define TARGET_CDTR_IFLOW   0x00040000  /* DTR flow control of input */
+#define TARGET_CDSR_OFLOW   0x00080000  /* DSR flow control of output */
+#define TARGET_CCAR_OFLOW   0x00100000  /* DCD flow control of output */
+
+/*
+ * "Local" flags - dumping ground for other state
+ */
+#define TARGET_ECHOKE   0x00000001  /* visual erase for line kill */
+#define TARGET_ECHOE    0x00000002  /* visually erase chars */
+#define TARGET_ECHOK    0x00000004  /* echo NL after line kill */
+#define TARGET_ECHO 0x00000008  /* enable echoing */
+#define TARGET_ECHONL   0x00000010  /* echo NL even if ECHO is off */
+#define TARGET_ECHOPRT  0x00000020  /* visual erase mode for hardcopy */
+#define TARGET_ECHOCTL  0x00000040  /* echo control chars as ^(Char) */
+#define TARGET_ISIG 0x00000080  /* enable signals INTR, QUIT, [D]SUSP */
+#define TARGET_ICANON   0x00000100  /* canonicalize input lines */
+#define TARGET_ALTWERASE 0x00000200 /* use alternate WERASE algorithm */
+#define TARGET_IEXTEN   0x00000400  /* enable DISCARD and LNEXT */
+#define TARGET_EXTPROC  0x00000800  /* external processing */
+#define TARGET_TOSTOP   0x00400000  /* stop background jobs from output */
+#define TARGET_FLUSHO   0x00800000  /* output being flushed (state) */
+#define TARGET_NOKERNINFO 0x02000000    /* no kernel output from VSTATUS */
+#define TARGET_PENDIN   0x20000000  /* XXX retype pending input (state) */
+#define TARGET_NOFLSH   0x80000000  /* don't flush after interrupt */
+
+struct target_termios {
+    uint32_t c_iflag;   /* input flags */
+    uint32_t c_oflag;   /* output flags */
+    uint32_t c_cflag;   /* control flags */
+    uint32_t c_lflag;   /* local flags */
+    uint8_t  c_cc[TARGET_NCCS]; /* control chars */
+    uint32_t c_ispeed;  /* input speed */
+    uint32_t c_ospeed;  /* output speed */
+};
+
+
+struct target_winsize {
+    uint16_t ws_row;    /* rows, in characters */
+    uint16_t ws_col;    /* columns, in characters */
+    uint16_t ws_xpixel; /* horizontal size, pixels */
+    uint16_t ws_ypixel; /* vertical size, pixels */
+};
+
+                        /* 0-2 compat */
+                        /* 3-7 unused */
+                        /* 8-10 compat */
+                        /* 11-12 unused */
+#define TARGET_TIOCEXCL  TARGET_IO('t', 13) /* set exclusive use of tty */
+#define TARGET_TIOCNXCL  TARGET_IO('t', 14) /* reset exclusive use of tty */
+#define TARGET_TIOCGPTN  TARGET_IOR('t', 15, int) /* Get pts number. */
+#define TARGET_TIOCFLUSH TARGET_IOW('t', 16, int) /* flush buffers */
+                    /* 17-18 compat */
+/* get termios struct */
+#define TARGET_TIOCGETA TARGET_IOR('t', 19, struct target_termios)
+/* set termios struct */
+#define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios)
+/* drain output, set */
+#define TARGET_TIOCSETAW    TARGET_IOW('t', 21, struct target_termios)
+/* drn out, fls in, set */
+#define TARGET_TIOCSETAF    TARGET_IOW('t', 22, struct target_termios)
+                        /* 23-25 unused */
+#define TARGET_TIOCGETD TARGET_IOR('t', 26, int) /* get line discipline */
+#define TARGET_TIOCSETD TARGET_IOW('t', 27, int) /* set line discipline */
+#define TARGET_TIOCPTMASTER  TARGET_IO('t', 28) /* pts master validation */
+                    /* 29-85 unused */
+/* get ttywait timeout */
+#define TARGET_TIOCGDRAINWAIT   TARGET_IOR('t', 86, int)
+/* set ttywait timeout */
+#define TARGET_TIOCSDRAINWAIT   TARGET_IOW('t', 87, int)
+                    /* 88 unused */
+                    /* 89-91 conflicts: tun and tap */
+/* enable/get timestamp of last input event */
+#define TARGET_TIOCTIMESTAMP    TARGET_IOR('t', 89, struct target_timeval)
+/* modem: get wait on close */
+#define TARGET_TIOCMGDTRWAIT    TARGET_IOR('t', 90, int)
+/* modem: set wait on close */
+#define TARGET_TIOCMSDTRWAIT    TARGET_IOW('t', 91, int)
+                    /* 92-93 tun and tap */
+                    /* 94-97 conflicts: tun and tap */
+/* wait till output drained */
+#define TARGET_TIOCDRAIN     TARGET_IO('t', 94)
+ /* pty: generate signal */
+#define TARGET_TIOCSIG      TARGET_IOWINT('t', 95)
+/* pty: external processing */
+#define TARGET_TIOCEXT      TARGET_IOW('t', 96, int)
+/* become controlling tty */
+#define TARGET_TIOCSCTTY     TARGET_IO('t', 97)
+/* become virtual console */
+#define TARGET_TIOCCONS TARGET_IOW('t', 98, int)
+/* get session id */
+#define TARGET_TIOCGSID TARGET_IOR('t', 99, int)
+                        /* 100 unused */
+/* simulate ^T status message */
+#define TARGET_TIOCSTAT  TARGET_IO('t', 101)
+ /* pty: set/clr usr cntl mode */
+#define TARGET_TIOCUCNTL    TARGET_IOW('t', 102, int)
+/* usr cntl op "n" */
+#define TARGET_TIOCCMD(n)   TARGET_IO('u', n)
+/* set window size */
+#define TARGET_TIOCSWINSZ   TARGET_IOW('t', 103, struct target_winsize)
+/* get window size */
+#define TARGET_TIOCGWINSZ   TARGET_IOR('t', 104, struct target_winsize)
+                        /* 105 unused */
+/* get all modem bits */
+#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
+#define     TARGET_TIOCM_LE 0001        /* line enable */
+#define     TARGET_TIOCM_DTR    0002    /* data terminal ready */
+#define     TARGET_TIOCM_RTS    0004    /* request to send */
+#define     TARGET_TIOCM_ST 0010        /* secondary transmit */
+#define     TARGET_TIOCM_SR 0020        /* secondary receive */
+#define     TARGET_TIOCM_CTS    0040    /* clear to send */
+#define     TARGET_TIOCM_DCD    0100    /* data carrier detect */
+#define     TARGET_TIOCM_RI     0200    /* ring indicate */
+#define     TARGET_TIOCM_DSR    0400    /* data set ready */
+#define     TARGET_TIOCM_CD TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_CAR    TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_RNG    TARGET_TIOCM_RI
+#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) /* bic modem bits */
+#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) /* bis modem bits */
+#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) /* set all modem bits */
+/* start output, like ^Q */
+#define TARGET_TIOCSTART     TARGET_IO('t', 110)
+/* stop output, like ^S */
+#define TARGET_TIOCSTOP  TARGET_IO('t', 111)
+/* pty: set/clear packet mode */
+#define TARGET_TIOCPKT      TARGET_IOW('t', 112, int)
+#define     TARGET_TIOCPKT_DATA     0x00    /* data packet */
+#define     TARGET_TIOCPKT_FLUSHREAD    0x01    /* flush packet */
+#define     TARGET_TIOCPKT_FLUSHWRITE   0x02    /* flush packet */
+#define     TARGET_TIOCPKT_STOP     0x04    /* stop output */
+#define     TARGET_TIOCPKT_START        0x08    /* start output */
+#define     TARGET_TIOCPKT_NOSTOP       0x10    /* no more ^S, ^Q */
+#define     TARGET_TIOCPKT_DOSTOP       0x20    /* now do ^S ^Q */
+#define     TARGET_TIOCPKT_IOCTL        0x40    /* state change of pty
+                               driver */
+#define TARGET_TIOCNOTTY     TARGET_IO('t', 113)    /* void tty
+                               association */
+#define TARGET_TIOCSTI      TARGET_IOW('t', 114, char)  /* simulate
+                            terminal input */
+#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)   /* output queue size */
+                        /* 116-117 compat */
+#define TARGET_TIOCSPGRP    TARGET_IOW('t', 118, int) /* set pgrp of tty */
+#define TARGET_TIOCGPGRP    TARGET_IOR('t', 119, int) /* get pgrp of tty */
+#define TARGET_TIOCCDTR  TARGET_IO('t', 120)        /* clear data terminal
+                               ready */
+#define TARGET_TIOCSDTR  TARGET_IO('t', 121)        /* set data terminal
+                               ready */
+#define TARGET_TIOCCBRK  TARGET_IO('t', 122)        /* clear break bit */
+#define TARGET_TIOCSBRK  TARGET_IO('t', 123)        /* set break bit */
+                        /* 124-127 compat */
+
+#define TARGET_TTYDISC      0       /* termios tty line
+                           discipline */
+#define TARGET_SLIPDISC     4       /* serial IP discipline */
+#define TARGET_PPPDISC      5       /* PPP discipline */
+#define TARGET_NETGRAPHDISC 6       /* Netgraph tty node
+                           discipline */
+#define TARGET_H4DISC       7       /* Netgraph Bluetooth H4
+                           discipline */
+
+#endif /*! _IOCTL_TTYCOM_H_ */
diff --git a/bsd-user/openbsd/os-ioctl-types.h b/bsd-user/openbsd/os-ioctl-types.h
new file mode 100644
index 0000000..6f8b97b
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-types.h
@@ -0,0 +1,7 @@
+/* XXX should be fixed for OpenBSD types and structs */
+STRUCT_SPECIAL(termios)
+
+STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
+
+STRUCT(fiodgname_arg, TYPE_INT, TYPE_PTRVOID)
+
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 4b2add2..10d0fc4 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -36,6 +36,7 @@ enum BSDType {
 };
 extern enum BSDType bsd_type;
 
+#include "exec/user/thunk.h"
 #include "syscall_defs.h"
 #include "syscall.h"
 #include "target_os_vmparam.h"
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 0a851fe..6cd7dbd 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -35,6 +35,7 @@
 
 /* BSD independent syscall shims */
 #include "bsd-file.h"
+#include "bsd-ioctl.h"
 #include "bsd-mem.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
@@ -81,16 +82,18 @@ int is_error(abi_long ret)
  * 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)
+        int count, int copy)
 {
     struct target_iovec *target_vec;
     abi_ulong base;
     int i;
 
-    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
-    if (!target_vec)
+    target_vec = lock_user(VERIFY_READ, target_addr,
+            count * sizeof(struct target_iovec), 1);
+    if (!target_vec) {
         return -TARGET_EFAULT;
-    for(i = 0;i < count; i++) {
+    }
+    for (i = 0; i < count; i++) {
         base = tswapl(target_vec[i].iov_base);
         vec[i].iov_len = tswapl(target_vec[i].iov_len);
         if (vec[i].iov_len != 0) {
@@ -107,16 +110,17 @@ static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
 }
 
 static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
-                             int count, int copy)
+        int count, int copy)
 {
     struct target_iovec *target_vec;
     abi_ulong base;
     int i;
 
-    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
+    target_vec = lock_user(VERIFY_READ, target_addr,
+            count * sizeof(struct target_iovec), 1);
     if (!target_vec)
         return -TARGET_EFAULT;
-    for(i = 0;i < count; i++) {
+    for (i = 0; i < count; i++) {
         if (target_vec[i].iov_base) {
             base = tswapl(target_vec[i].iov_base);
             unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
@@ -1177,6 +1181,13 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * ioctl(2)
+         */
+    case TARGET_FREEBSD_NR_ioctl: /* ioctl(2) */
+        ret = do_bsd_ioctl(arg1, arg2, arg3);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
@@ -1309,4 +1320,6 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
 
 void syscall_init(void)
 {
+
+    init_bsd_ioctl();
 }
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 16/19] bsd-user: add support for extended attribute and ACL related syscalls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (35 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 15/19] bsd-user: add support for the ioctl system call Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 17/19] bsd-user: add support for miscellaneous system calls Stacey Son
                   ` (2 subsequent siblings)
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change add support for extended attribute and Access Control List
(ACL) related system calls including extattrctl(), extattr_set_file(2),
extattr_delete_file(2), extattr_set_fd(2), extattr_get_fd(2),
extattr_delete_fd(2), extattr_get_link(2), extattr_set_link(2),
extattr_delete_link(2), extattr_list_fd(2), extattr_list_file(2),
extattr_list_link(2), __acl_aclcheck_fd(), __acl_aclcheck_file(),
__acl_aclcheck_link(), __acl_delete_fd(), __acl_delete_file(),
__acl_delete_link(), __acl_get_fd(), __acl_get_file(), __acl_get_link(),
__acl_get_fd(), __acl_set_file(), and __acl_set_link().

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs        |    2 +-
 bsd-user/freebsd/os-extattr.c |  119 ++++++++
 bsd-user/freebsd/os-extattr.h |  644 +++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h    |    6 +
 bsd-user/netbsd/os-extattr.h  |  247 ++++++++++++++++
 bsd-user/openbsd/os-extattr.h |  247 ++++++++++++++++
 bsd-user/syscall.c            |  104 +++++++
 7 files changed, 1368 insertions(+), 1 deletions(-)
 create mode 100644 bsd-user/freebsd/os-extattr.c
 create mode 100644 bsd-user/freebsd/os-extattr.h
 create mode 100644 bsd-user/netbsd/os-extattr.h
 create mode 100644 bsd-user/openbsd/os-extattr.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 242e6f4..b9eaf2d 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,6 +1,6 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
 	        uaccess.o bsd-ioctl.o bsd-mem.o bsd-proc.o bsd-socket.o \
-			$(HOST_ABI_DIR)/os-proc.o \
+			$(HOST_ABI_DIR)/os-extattr.o $(HOST_ABI_DIR)/os-proc.o \
 			$(HOST_ABI_DIR)/os-socket.o $(HOST_ABI_DIR)/os-stat.o \
 			$(HOST_ABI_DIR)/os-sys.o $(HOST_ABI_DIR)/os-thread.o \
 			$(HOST_ABI_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/freebsd/os-extattr.c b/bsd-user/freebsd/os-extattr.c
new file mode 100644
index 0000000..7a10047
--- /dev/null
+++ b/bsd-user/freebsd/os-extattr.c
@@ -0,0 +1,119 @@
+/*
+ *  FreeBSD extend attributes and ACL conversions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#ifndef _ACL_PRIVATE
+#define _ACL_PRIVATE
+#endif
+#include <sys/acl.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+/*
+ * FreeBSD ACL conversion.
+ */
+abi_long t2h_freebsd_acl(struct acl *host_acl, abi_ulong target_addr)
+{
+    uint32_t i;
+    struct target_freebsd_acl *target_acl;
+
+    if (!lock_user_struct(VERIFY_READ, target_acl, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt);
+    __get_user(host_acl->acl_cnt, &target_acl->acl_cnt);
+
+    for (i = 0; i < host_acl->acl_maxcnt; i++) {
+        __get_user(host_acl->acl_entry[i].ae_tag,
+            &target_acl->acl_entry[i].ae_tag);
+        __get_user(host_acl->acl_entry[i].ae_id,
+            &target_acl->acl_entry[i].ae_id);
+        __get_user(host_acl->acl_entry[i].ae_perm,
+            &target_acl->acl_entry[i].ae_perm);
+        __get_user(host_acl->acl_entry[i].ae_entry_type,
+            &target_acl->acl_entry[i].ae_entry_type);
+        __get_user(host_acl->acl_entry[i].ae_flags,
+            &target_acl->acl_entry[i].ae_flags);
+    }
+
+    unlock_user_struct(target_acl, target_addr, 0);
+    return 0;
+}
+
+abi_long h2t_freebsd_acl(abi_ulong target_addr, struct acl *host_acl)
+{
+    uint32_t i;
+    struct target_freebsd_acl *target_acl;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_acl, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    __put_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt);
+    __put_user(host_acl->acl_cnt, &target_acl->acl_cnt);
+
+    for (i = 0; i < host_acl->acl_maxcnt; i++) {
+        __put_user(host_acl->acl_entry[i].ae_tag,
+            &target_acl->acl_entry[i].ae_tag);
+        __put_user(host_acl->acl_entry[i].ae_id,
+            &target_acl->acl_entry[i].ae_id);
+        __put_user(host_acl->acl_entry[i].ae_perm,
+            &target_acl->acl_entry[i].ae_perm);
+        __get_user(host_acl->acl_entry[i].ae_entry_type,
+            &target_acl->acl_entry[i].ae_entry_type);
+        __get_user(host_acl->acl_entry[i].ae_flags,
+            &target_acl->acl_entry[i].ae_flags);
+    }
+
+    unlock_user_struct(target_acl, target_addr, 1);
+    return 0;
+}
+
+abi_long t2h_freebsd_acl_type(acl_type_t *host_type, abi_long target_type)
+{
+    acl_type_t type = tswap32(target_type);
+
+    switch (type) {
+    case TARGET_FREEBSD_ACL_TYPE_ACCESS_OLD:
+        *host_type = ACL_TYPE_ACCESS_OLD;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_DEFAULT_OLD:
+        *host_type = ACL_TYPE_DEFAULT_OLD;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_ACCESS:
+        *host_type = ACL_TYPE_ACCESS;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_DEFAULT:
+        *host_type = ACL_TYPE_ACCESS;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_NFS4:
+        *host_type = ACL_TYPE_NFS4;
+        break;
+
+    default:
+        return -TARGET_EINVAL;
+    }
+    return 0;
+}
+
diff --git a/bsd-user/freebsd/os-extattr.h b/bsd-user/freebsd/os-extattr.h
new file mode 100644
index 0000000..0cae8b0
--- /dev/null
+++ b/bsd-user/freebsd/os-extattr.h
@@ -0,0 +1,644 @@
+/*
+ *  FreeBSD extended attributes and ACL system call support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/extattr.h>
+#ifndef _ACL_PRIVATE
+#define _ACL_PRIVATE
+#endif
+#include <sys/acl.h>
+
+#include "qemu-os.h"
+
+/* extattrctl() */
+static inline abi_long do_freebsd_extattrctl(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *p, *a, *f;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    f = lock_user_string(arg3);
+    if (f == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg5);
+    if (a == NULL) {
+        unlock_user(f, arg3, 0);
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattrctl(path(p), arg2, f, arg4, a));
+    unlock_user(a, arg5, 0);
+    unlock_user(f, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_set_file(2) */
+static inline abi_long do_freebsd_extattr_set_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    d = lock_user(VERIFY_READ, arg4, arg5, 1);
+    if (d == NULL) {
+        unlock_user(a, arg3, 0);
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_set_file(path(p), arg2, a, d, arg5));
+    unlock_user(d, arg4, arg5);
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_get_file(2) */
+static inline abi_long do_freebsd_extattr_get_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    if (arg4 && arg5 > 0) {
+        d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
+        if (d == NULL) {
+            unlock_user(a, arg3, 0);
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_get_file(path(p), arg2, a, d, arg5));
+        unlock_user(d, arg4, arg5);
+    } else {
+        ret = get_errno(extattr_get_file(path(p), arg2, a, NULL, arg5));
+    }
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_delete_file(2) */
+static inline abi_long do_freebsd_extattr_delete_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *p, *a;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_delete_file(path(p), arg2, a));
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_set_fd(2) */
+static inline abi_long do_freebsd_extattr_set_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *a, *d;
+
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+    d = lock_user(VERIFY_READ, arg4, arg5, 1);
+    if (d == NULL) {
+        unlock_user(a, arg3, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_set_fd(arg1, arg2, a, d, arg5));
+    unlock_user(d, arg4, arg5);
+    unlock_user(a, arg3, 0);
+
+    return ret;
+}
+
+/* extattr_get_fd(2) */
+static inline abi_long do_freebsd_extattr_get_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *a, *d;
+
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+
+    if (arg4 && arg5 > 0) {
+        d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
+        if (d == NULL) {
+            unlock_user(a, arg3, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_get_fd(arg1, arg2, a, d, arg5));
+        unlock_user(d, arg4, arg5);
+    } else {
+        ret = get_errno(extattr_get_fd(arg1, arg2, a, NULL, arg5));
+    }
+    unlock_user(a, arg3, 0);
+
+    return ret;
+}
+
+/* extattr_delete_fd(2) */
+static inline abi_long do_freebsd_extattr_delete_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *a;
+
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_delete_fd(arg1, arg2, a));
+    unlock_user(a, arg3, 0);
+
+    return ret;
+}
+
+/* extattr_get_link(2) */
+static inline abi_long do_freebsd_extattr_get_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void  *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    if (arg4 && arg5 > 0) {
+        d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
+        if (d == NULL) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_get_link(path(p), arg2, a, d, arg5));
+        unlock_user(d, arg4, arg5);
+    } else {
+        ret = get_errno(extattr_get_link(path(p), arg2, a, NULL, arg5));
+    }
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_set_link(2) */
+static inline abi_long do_freebsd_extattr_set_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void  *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    d = lock_user(VERIFY_READ, arg4, arg5, 1);
+    if (d == NULL) {
+        unlock_user(a, arg3, 0);
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_set_link(path(p), arg2, a, d, arg5));
+    unlock_user(d, arg4, arg5);
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_delete_link(2) */
+static inline abi_long do_freebsd_extattr_delete_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *p, *a;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_delete_link(path(p), arg2, a));
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_list_fd(2) */
+static inline abi_long do_freebsd_extattr_list_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3, abi_ulong arg4)
+{
+    abi_long ret;
+    void *d;
+
+    if (arg3 && arg4 > 0) {
+        d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+        if (d == NULL) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_list_fd(arg1, arg2, d, arg4));
+        unlock_user(d, arg3, arg4);
+    } else {
+        ret = get_errno(extattr_list_fd(arg1, arg2, NULL, arg4));
+    }
+    return ret;
+}
+
+/* extattr_list_file(2) */
+static inline abi_long do_freebsd_extattr_list_file(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+    abi_long ret;
+    void *p, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (arg3 && arg4 > 0) {
+        d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+        if (d == NULL) {
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_list_file(path(p), arg2, d, arg4));
+        unlock_user(d, arg3, arg4);
+    } else {
+        ret = get_errno(extattr_list_file(path(p), arg2, NULL, arg4));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_list_link(2) */
+static inline abi_long do_freebsd_extattr_list_link(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+    abi_long ret;
+    void *p, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (arg3 && arg4 > 0) {
+        d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+        if (d == NULL) {
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_list_link(path(p), arg2, d, arg4));
+        unlock_user(d, arg3, arg4);
+    } else {
+        ret = get_errno(extattr_list_link(path(p), arg2, NULL, arg4));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/*
+ *  Access Control Lists
+ */
+
+/* __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_fd(abi_long arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    struct acl host_acl;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_aclcheck_fd(arg1, type, &host_acl));
+    }
+
+    return ret;
+}
+
+/* __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    struct acl host_acl;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_aclcheck_file(path(p) , arg2, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    struct acl host_acl;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_aclcheck_link(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_delete_fd(int filedes, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_fd(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    return get_errno(__acl_delete_fd(arg1, type));
+}
+
+/* int __acl_delete_file(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_file(abi_ulong arg1,
+        abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_delete_file(path(p), type));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_delete_link(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_link(abi_ulong arg1,
+        abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_delete_link(path(p), type));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = get_errno(__acl_get_fd(arg1, type, &host_acl));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_acl(arg3, &host_acl);
+    }
+    return ret;
+}
+
+/* __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_get_file(path(p), type, &host_acl));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_acl(arg3, &host_acl);
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_get_link(path(p), type, &host_acl));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_acl(arg3, &host_acl);
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_set_fd(arg1, type, &host_acl));
+    }
+
+    return ret;
+}
+
+/* int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_set_file(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_set_link(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index b5510dc..7d79e52 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -70,4 +70,10 @@ abi_long h2t_freebsd_rtprio(abi_ulong target_addr, struct rtprio *host_rtp);
 abi_long do_freebsd_thr_new(CPUArchState *env, abi_ulong target_param_addr,
         int32_t param_size);
 
+/* os-extattr.c */
+struct acl;
+abi_long t2h_freebsd_acl(struct acl *host_acl, abi_ulong target_addr);
+abi_long h2t_freebsd_acl(abi_ulong target_addr, struct acl *host_acl);
+abi_long t2h_freebsd_acl_type(acl_type_t *host_type, abi_long target_type);
+
 #endif /* !_QEMU_OS_H_ */
diff --git a/bsd-user/netbsd/os-extattr.h b/bsd-user/netbsd/os-extattr.h
new file mode 100644
index 0000000..c2f42ac
--- /dev/null
+++ b/bsd-user/netbsd/os-extattr.h
@@ -0,0 +1,247 @@
+/*
+ *  NetBSD extended attributes and ACL system call support
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* XXX To support FreeBSD targets the following will need to be added. */
+
+/* extattrctl() */
+static inline abi_long do_freebsd_extattrctl(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattrctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_file(2) */
+static inline abi_long do_freebsd_extattr_set_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_file(2) */
+static inline abi_long do_freebsd_extattr_get_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_file(2) */
+static inline abi_long do_freebsd_extattr_delete_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_fd(2) */
+static inline abi_long do_freebsd_extattr_set_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_fd(2) */
+static inline abi_long do_freebsd_extattr_get_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_fd(2) */
+static inline abi_long do_freebsd_extattr_delete_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_link(2) */
+static inline abi_long do_freebsd_extattr_get_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_link(2) */
+static inline abi_long do_freebsd_extattr_set_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_link(2) */
+static inline abi_long do_freebsd_extattr_delete_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_fd(2) */
+static inline abi_long do_freebsd_extattr_list_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall exattr_list_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_file(2) */
+static inline abi_long do_freebsd_extattr_list_file(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_list_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_link(2) */
+static inline abi_long do_freebsd_extattr_list_link(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_list_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ *  Access Control Lists
+ */
+
+/* __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_fd(abi_long arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_fd(int filedes, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_fd(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_file(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_file(abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_fil()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_link(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_link(abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall _acl_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
diff --git a/bsd-user/openbsd/os-extattr.h b/bsd-user/openbsd/os-extattr.h
new file mode 100644
index 0000000..5c23af3
--- /dev/null
+++ b/bsd-user/openbsd/os-extattr.h
@@ -0,0 +1,247 @@
+/*
+ *  OpenBSD extended attributes and ACL system call support
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* XXX To support FreeBSD targets the following will need to be added. */
+
+/* extattrctl() */
+static inline abi_long do_freebsd_extattrctl(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattrctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_file(2) */
+static inline abi_long do_freebsd_extattr_set_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_file(2) */
+static inline abi_long do_freebsd_extattr_get_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_file(2) */
+static inline abi_long do_freebsd_extattr_delete_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_fd(2) */
+static inline abi_long do_freebsd_extattr_set_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_fd(2) */
+static inline abi_long do_freebsd_extattr_get_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_fd(2) */
+static inline abi_long do_freebsd_extattr_delete_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_link(2) */
+static inline abi_long do_freebsd_extattr_get_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_link(2) */
+static inline abi_long do_freebsd_extattr_set_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_link(2) */
+static inline abi_long do_freebsd_extattr_delete_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_fd(2) */
+static inline abi_long do_freebsd_extattr_list_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall exattr_list_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_file(2) */
+static inline abi_long do_freebsd_extattr_list_file(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_list_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_link(2) */
+static inline abi_long do_freebsd_extattr_list_link(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_list_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ *  Access Control Lists
+ */
+
+/* __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_fd(abi_long arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_fd(int filedes, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_fd(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_file(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_file(abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_fil()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_link(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_link(abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall _acl_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 6cd7dbd..ab17f3f 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -42,6 +42,7 @@
 #include "bsd-socket.h"
 
 /* *BSD dependent syscall shims */
+#include "os-extattr.h"
 #include "os-time.h"
 #include "os-proc.h"
 #include "os-signal.h"
@@ -1204,6 +1205,109 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                 arg5, arg6, arg7, arg8, 0);
         break;
 
+        /*
+         * extended attributes system calls
+         */
+    case TARGET_FREEBSD_NR_extattrctl: /* extattrctl() */
+        ret = do_freebsd_extattrctl(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_set_file: /* extattr_set_file(2) */
+        ret = do_freebsd_extattr_set_file(arg1, arg2, arg3, arg4, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_get_file: /* extattr_get_file(2) */
+        ret = do_freebsd_extattr_get_file(arg1, arg2, arg3, arg4, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_delete_file: /* extattr_delete_file(2) */
+        ret = do_freebsd_extattr_delete_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_set_fd: /* extattr_set_fd(2) */
+        ret = do_freebsd_extattr_set_fd(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_get_fd: /* extattr_get_fd(2) */
+        ret = do_freebsd_extattr_get_fd(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_delete_fd: /* extattr_delete_fd(2) */
+        ret = do_freebsd_extattr_delete_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_get_link: /* extattr_get_link(2) */
+        ret = do_freebsd_extattr_get_link(arg1, arg2, arg3, arg4, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_set_link: /* extattr_set_link(2) */
+        ret = do_freebsd_extattr_set_link(arg1, arg2, arg3, arg4, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_delete_link: /* extattr_delete_link(2) */
+        ret = do_freebsd_extattr_delete_link(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_list_fd: /* extattr_list_fd(2) */
+        ret = do_freebsd_extattr_list_fd(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_list_file: /* extattr_list_file(2) */
+        ret = do_freebsd_extattr_list_file(arg1, arg2, arg3,  arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_list_link: /* extattr_list_link(2) */
+        ret = do_freebsd_extattr_list_link(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_aclcheck_fd: /* __acl_aclcheck_fd() */
+        ret = do_freebsd__acl_aclcheck_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_aclcheck_file: /* __acl_aclcheck_file() */
+        ret = do_freebsd__acl_aclcheck_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_aclcheck_link: /* __acl_aclcheck_link() */
+        ret = do_freebsd__acl_aclcheck_link(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_delete_fd: /* __acl_delete_fd() */
+        ret = do_freebsd__acl_delete_fd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_delete_file: /* __acl_delete_file() */
+        ret = do_freebsd__acl_delete_file(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_delete_link: /* __acl_delete_link() */
+        ret = do_freebsd__acl_delete_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_get_fd: /* __acl_get_fd() */
+        ret =  do_freebsd__acl_get_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_get_file: /* __acl_get_file() */
+        ret = do_freebsd__acl_get_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_get_link: /* __acl_get_link() */
+        ret = do_freebsd__acl_get_link(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_set_fd: /* __acl_get_fd() */
+        ret = do_freebsd__acl_set_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_set_file: /* __acl_set_file() */
+        ret = do_freebsd__acl_set_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_set_link: /* __acl_set_link() */
+        ret = do_freebsd__acl_set_link(arg1, arg2, arg3);
+        break;
+
     default:
         ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
                     arg8));
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 17/19] bsd-user: add support for miscellaneous system calls
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (36 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 16/19] bsd-user: add support for extended attribute and ACL related syscalls Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 18/19] bsd-user: add arm, mips and mips64 options to configure target-list Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto Stacey Son
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for miscellaneous system calls including
extattr*() (extended attributes), __acl*() (access control lists),
sem*() (system V semaphores), msg*() (system V messages), sched_*()
(scheduler control), cpuset*() (CPU affinity set management),
mod*() and kld*() (kernel module), rctl_*() (resource controls),
__mac_*() (Mandatory Access Control), posix_*() (additional posix support),
and other miscellaneous system calls.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs     |    2 +-
 bsd-user/bsd-misc.c        |  209 +++++++++++++++++++++
 bsd-user/bsd-misc.h        |  339 +++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-misc.h |  442 ++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/netbsd/os-misc.h  |  375 +++++++++++++++++++++++++++++++++++++
 bsd-user/openbsd/os-misc.h |  375 +++++++++++++++++++++++++++++++++++++
 bsd-user/qemu-bsd.h        |   18 ++
 bsd-user/syscall.c         |  229 +++++++++++++++++++++++
 8 files changed, 1988 insertions(+), 1 deletions(-)
 create mode 100644 bsd-user/bsd-misc.c
 create mode 100644 bsd-user/bsd-misc.h
 create mode 100644 bsd-user/freebsd/os-misc.h
 create mode 100644 bsd-user/netbsd/os-misc.h
 create mode 100644 bsd-user/openbsd/os-misc.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index b9eaf2d..e6078ab 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,5 +1,5 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-ioctl.o bsd-mem.o bsd-proc.o bsd-socket.o \
+	        uaccess.o bsd-ioctl.o bsd-mem.o bsd-misc.o bsd-proc.o bsd-socket.o \
 			$(HOST_ABI_DIR)/os-extattr.o $(HOST_ABI_DIR)/os-proc.o \
 			$(HOST_ABI_DIR)/os-socket.o $(HOST_ABI_DIR)/os-stat.o \
 			$(HOST_ABI_DIR)/os-sys.o $(HOST_ABI_DIR)/os-thread.o \
diff --git a/bsd-user/bsd-misc.c b/bsd-user/bsd-misc.c
new file mode 100644
index 0000000..bc85473
--- /dev/null
+++ b/bsd-user/bsd-misc.c
@@ -0,0 +1,209 @@
+/*
+ *  BSD misc system call conversions routines
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/uuid.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+/*
+ * BSD uuidgen(2) struct uuid conversion
+ */
+abi_long host_to_target_uuid(abi_ulong target_addr, struct uuid *host_uuid)
+{
+    struct target_uuid *target_uuid;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_uuid, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_uuid->time_low, &target_uuid->time_low);
+    __put_user(host_uuid->time_mid, &target_uuid->time_mid);
+    __put_user(host_uuid->time_hi_and_version,
+        &target_uuid->time_hi_and_version);
+    host_uuid->clock_seq_hi_and_reserved =
+        target_uuid->clock_seq_hi_and_reserved;
+    host_uuid->clock_seq_low = target_uuid->clock_seq_low;
+    memcpy(host_uuid->node, target_uuid->node, TARGET_UUID_NODE_LEN);
+    unlock_user_struct(target_uuid, target_addr, 1);
+    return 0;
+}
+
+abi_long target_to_host_semarray(int semid, unsigned short **host_array,
+        abi_ulong target_addr)
+{
+    abi_long ret;
+    int nsems, i;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+
+    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 = (unsigned short *)malloc(nsems * sizeof(unsigned short));
+    array = lock_user(VERIFY_READ, target_addr,
+        nsems*sizeof(unsigned short), 1);
+    if (array == NULL) {
+        free(*host_array);
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsems; i++) {
+        (*host_array)[i] = array[i];
+    }
+    unlock_user(array, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+        unsigned short **host_array)
+{
+    abi_long ret;
+    int nsems, i;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1) {
+        free(*host_array);
+        return get_errno(ret);
+    }
+
+    nsems = semid_ds.sem_nsems;
+    array = (unsigned short *)lock_user(VERIFY_WRITE, target_addr,
+        nsems*sizeof(unsigned short), 0);
+    if (array == NULL) {
+        free(*host_array);
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsems; i++) {
+        array[i] = (*host_array)[i];
+    }
+    free(*host_array);
+    unlock_user(array, target_addr, 1);
+    return 0;
+}
+
+abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
+        abi_ulong target_addr)
+{
+    struct target_semid_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->sem_perm), (target_addr +
+                    offsetof(struct target_semid_ds, sem_perm)))) {
+        return -TARGET_EFAULT;
+    }
+    /* sem_base is not used by kernel for IPC_STAT/IPC_SET */
+    /* host_sd->sem_base  = g2h(target_sd->sem_base); */
+    host_sd->sem_nsems = tswap16(target_sd->sem_nsems);
+    host_sd->sem_otime = tswapal(target_sd->sem_otime);
+    host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+abi_long host_to_target_semid_ds(abi_ulong target_addr,
+        struct semid_ds *host_sd)
+{
+    struct target_semid_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 +
+                    offsetof(struct target_semid_ds, sem_perm)),
+                &(host_sd->sem_perm))) {
+        return -TARGET_EFAULT;
+    }
+    /* sem_base is not used by kernel for IPC_STAT/IPC_SET */
+    /* target_sd->sem_base = h2g((void *)host_sd->sem_base); */
+    target_sd->sem_nsems = tswap16(host_sd->sem_nsems);
+    target_sd->sem_otime = tswapal(host_sd->sem_otime);
+    target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 1);
+
+    return 0;
+}
+
+abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
+        abi_ulong target_addr)
+{
+    struct target_msqid_ds *target_md;
+
+    if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    if (target_to_host_ipc_perm(&(host_md->msg_perm), target_addr)) {
+        return -TARGET_EFAULT;
+    }
+
+    /* msg_first and msg_last are not used by IPC_SET/IPC_STAT in kernel. */
+    host_md->msg_first = host_md->msg_last = NULL;
+    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);
+    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);
+    unlock_user_struct(target_md, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_msqid_ds(abi_ulong target_addr,
+        struct msqid_ds *host_md)
+{
+    struct target_msqid_ds *target_md;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    if (host_to_target_ipc_perm(target_addr, &(host_md->msg_perm))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* msg_first and msg_last are not used by IPC_SET/IPC_STAT in kernel. */
+    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);
+    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);
+    unlock_user_struct(target_md, target_addr, 1);
+
+    return 0;
+}
+
diff --git a/bsd-user/bsd-misc.h b/bsd-user/bsd-misc.h
new file mode 100644
index 0000000..0c34089
--- /dev/null
+++ b/bsd-user/bsd-misc.h
@@ -0,0 +1,339 @@
+/*
+ *  miscellaneous BSD system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_MISC_H_
+#define __BSD_MISC_H_
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/uuid.h>
+
+#include "qemu-bsd.h"
+
+/* quotactl(2) */
+static inline abi_long do_bsd_quotactl(abi_ulong path, abi_long cmd,
+        abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall quotactl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* reboot(2) */
+static inline abi_long do_bsd_reboot(abi_long how)
+{
+
+    qemu_log("qemu: Unsupported syscall reboot()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* uuidgen(2) */
+static inline abi_long do_bsd_uuidgen(abi_ulong target_addr, int count)
+{
+    int i;
+    abi_long ret;
+    struct uuid *host_uuid;
+
+    if (count < 1 || count > 2048) {
+        return -TARGET_EINVAL;
+    }
+
+    host_uuid = (struct uuid *)g_malloc(count * sizeof(struct uuid));
+
+    if (host_uuid == NULL) {
+        return -TARGET_ENOMEM;
+    }
+
+    ret = get_errno(uuidgen(host_uuid, count));
+    if (is_error(ret)) {
+        goto out;
+    }
+    for (i = 0; i < count; i++) {
+        ret = host_to_target_uuid(target_addr +
+            (abi_ulong)(sizeof(struct target_uuid) * i), &host_uuid[i]);
+        if (is_error(ret)) {
+            goto out;
+        }
+    }
+
+out:
+    g_free(host_uuid);
+    return ret;
+}
+
+
+/*
+ * System V Semaphores
+ */
+
+/* semget(2) */
+static inline abi_long do_bsd_semget(abi_long key, int nsems,
+        int target_flags)
+{
+
+    return get_errno(semget(key, nsems,
+                target_to_host_bitmask(target_flags, ipc_flags_tbl)));
+}
+
+/* semop(2) */
+static inline abi_long do_bsd_semop(int semid, abi_long ptr, unsigned nsops)
+{
+    struct sembuf sops[nsops];
+    struct target_sembuf *target_sembuf;
+    int i;
+
+    target_sembuf = lock_user(VERIFY_READ, ptr,
+            nsops * sizeof(struct target_sembuf), 1);
+    if (target_sembuf == NULL) {
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsops; i++) {
+        __get_user(sops[i].sem_num, &target_sembuf[i].sem_num);
+        __get_user(sops[i].sem_op, &target_sembuf[i].sem_op);
+        __get_user(sops[i].sem_flg, &target_sembuf[i].sem_flg);
+    }
+    unlock_user(target_sembuf, ptr, 0);
+
+    return semop(semid, sops, nsops);
+}
+
+/* __semctl(2) */
+static inline abi_long do_bsd___semctl(int semid, int semnum, int target_cmd,
+        union target_semun target_su)
+{
+    union semun arg;
+    struct semid_ds dsarg;
+    unsigned short *array = NULL;
+    int host_cmd;
+    abi_long ret = 0;
+    abi_long err;
+    abi_ulong target_addr;
+
+    switch (target_cmd) {
+    case TARGET_GETVAL:
+        host_cmd = GETVAL;
+        break;
+
+    case TARGET_SETVAL:
+        host_cmd = SETVAL;
+        break;
+
+    case TARGET_GETALL:
+        host_cmd = GETALL;
+        break;
+
+    case TARGET_SETALL:
+        host_cmd = SETALL;
+        break;
+
+    case TARGET_IPC_STAT:
+        host_cmd = IPC_STAT;
+        break;
+
+    case TARGET_IPC_SET:
+        host_cmd = IPC_SET;
+        break;
+
+    case TARGET_IPC_RMID:
+        host_cmd = IPC_RMID;
+        break;
+
+    case TARGET_GETPID:
+        host_cmd = GETPID;
+        break;
+
+    case TARGET_GETNCNT:
+        host_cmd = GETNCNT;
+        break;
+
+    case TARGET_GETZCNT:
+        host_cmd = GETZCNT;
+        break;
+
+    default:
+        return -TARGET_EINVAL;
+    }
+
+    switch (host_cmd) {
+    case GETVAL:
+    case SETVAL:
+        arg.val = tswap32(target_su.val);
+        ret = get_errno(semctl(semid, semnum, host_cmd, arg));
+        target_su.val = tswap32(arg.val);
+        break;
+
+    case GETALL:
+    case SETALL:
+        if (get_user_ual(target_addr, (abi_ulong)target_su.array)) {
+            return -TARGET_EFAULT;
+        }
+        err = target_to_host_semarray(semid, &array, target_addr);
+        if (is_error(err)) {
+            return err;
+        }
+        arg.array = array;
+        ret = get_errno(semctl(semid, semnum, host_cmd, arg));
+        err = host_to_target_semarray(semid, target_addr, &array);
+        if (is_error(err)) {
+            return err;
+        }
+        break;
+
+    case IPC_STAT:
+    case IPC_SET:
+        if (get_user_ual(target_addr, (abi_ulong)target_su.buf)) {
+            return -TARGET_EFAULT;
+        }
+        err = target_to_host_semid_ds(&dsarg, target_addr);
+        if (is_error(err)) {
+            return err;
+        }
+        arg.buf = &dsarg;
+        ret = get_errno(semctl(semid, semnum, host_cmd, arg));
+        err = host_to_target_semid_ds(target_addr, &dsarg);
+        if (is_error(err)) {
+            return err;
+        }
+        break;
+
+    case IPC_RMID:
+    case GETPID:
+    case GETNCNT:
+    case GETZCNT:
+        ret = get_errno(semctl(semid, semnum, host_cmd, NULL));
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+/* msgctl(2) */
+static inline abi_long do_bsd_msgctl(int msgid, int target_cmd, abi_long ptr)
+{
+    struct msqid_ds dsarg;
+    abi_long ret = -TARGET_EINVAL;
+    int host_cmd;
+
+    switch (target_cmd) {
+    case TARGET_IPC_STAT:
+        host_cmd = IPC_STAT;
+        break;
+
+    case TARGET_IPC_SET:
+        host_cmd = IPC_SET;
+        break;
+
+    case TARGET_IPC_RMID:
+        host_cmd = IPC_RMID;
+        break;
+
+    default:
+        return -TARGET_EINVAL;
+    }
+
+    switch (host_cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+        if (target_to_host_msqid_ds(&dsarg, ptr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(msgctl(msgid, host_cmd, &dsarg));
+        if (host_to_target_msqid_ds(ptr, &dsarg)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    case IPC_RMID:
+        ret = get_errno(msgctl(msgid, host_cmd, NULL));
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+/* msgsnd(2) */
+static inline abi_long do_bsd_msgsnd(int msqid, abi_long msgp,
+        unsigned int msgsz, int msgflg)
+{
+    struct target_msgbuf *target_mb;
+    struct mymsg *host_mb;
+    abi_long ret;
+
+    if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) {
+        return -TARGET_EFAULT;
+    }
+    host_mb = g_malloc(msgsz+sizeof(long));
+    host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
+    memcpy(host_mb->mtext, target_mb->mtext, msgsz);
+    ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
+    g_free(host_mb);
+    unlock_user_struct(target_mb, msgp, 0);
+
+    return ret;
+}
+
+/* msgrcv(2) */
+static inline abi_long do_bsd_msgrcv(int msqid, abi_long msgp,
+        unsigned int msgsz, abi_long msgtyp, int msgflg)
+{
+    struct target_msgbuf *target_mb = NULL;
+    char *target_mtext;
+    struct mymsg *host_mb;
+    abi_long ret = 0;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) {
+        return -TARGET_EFAULT;
+    }
+    host_mb = g_malloc(msgsz+sizeof(long));
+    ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
+    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 == NULL) {
+            ret = -TARGET_EFAULT;
+            goto end;
+        }
+        memcpy(target_mb->mtext, host_mb->mtext, ret);
+        unlock_user(target_mtext, target_mtext_addr, ret);
+    }
+    target_mb->mtype = tswapal(host_mb->mtype);
+end:
+    if (target_mb != NULL) {
+        unlock_user_struct(target_mb, msgp, 1);
+    }
+    g_free(host_mb);
+    return ret;
+}
+
+/* getdtablesize(2) */
+static inline abi_long do_bsd_getdtablesize(void)
+{
+
+    return get_errno(getdtablesize());
+}
+
+#endif /* ! __BSD_MISC_H_ */
diff --git a/bsd-user/freebsd/os-misc.h b/bsd-user/freebsd/os-misc.h
new file mode 100644
index 0000000..07e60fe
--- /dev/null
+++ b/bsd-user/freebsd/os-misc.h
@@ -0,0 +1,442 @@
+/*
+ *  miscellaneous FreeBSD system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __OS_MISC_H_
+#define __OS_MISC_H_
+
+#include <sys/cpuset.h>
+#include <sched.h>
+
+/* sched_setparam(2) */
+static inline abi_long do_freebsd_sched_setparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+    abi_long ret;
+    struct sched_param host_sp;
+
+    ret = get_user_s32(host_sp.sched_priority, target_sp_addr);
+    if (!is_error(ret)) {
+        ret = get_errno(sched_setparam(pid, &host_sp));
+    }
+    return ret;
+}
+
+/* sched_get_param(2) */
+static inline abi_long do_freebsd_sched_getparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+    abi_long ret;
+    struct sched_param host_sp;
+
+    ret = get_errno(sched_getparam(pid, &host_sp));
+    if (!is_error(ret)) {
+        ret = put_user_s32(host_sp.sched_priority, target_sp_addr);
+    }
+    return ret;
+}
+
+/* sched_setscheduler(2) */
+static inline abi_long do_freebsd_sched_setscheduler(pid_t pid, int policy,
+        abi_ulong target_sp_addr)
+{
+    abi_long ret;
+    struct sched_param host_sp;
+
+    ret = get_user_s32(host_sp.sched_priority, target_sp_addr);
+    if (!is_error(ret)) {
+        ret = get_errno(sched_setscheduler(pid, policy, &host_sp));
+    }
+    return ret;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_getscheduler(pid_t pid)
+{
+
+    return get_errno(sched_getscheduler(pid));
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_rr_get_interval(pid_t pid,
+        abi_ulong target_ts_addr)
+{
+    abi_long ret;
+    struct timespec host_ts;
+
+    ret = get_errno(sched_rr_get_interval(pid, &host_ts));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_timespec(target_ts_addr, &host_ts);
+    }
+    return ret;
+}
+
+/* cpuset(2) */
+static inline abi_long do_freebsd_cpuset(abi_ulong target_cpuid)
+{
+    abi_long ret;
+    cpusetid_t setid;
+
+    ret = get_errno(cpuset(&setid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return put_user_s32(setid, target_cpuid);
+}
+
+#define target_to_host_cpuset_which(hp, t) { \
+    (*hp) = t;                               \
+} while (0)
+
+#define target_to_host_cpuset_level(hp, t) { \
+    (*hp) = t;                               \
+} while (0)
+
+/* cpuset_setid(2) */
+static inline abi_long do_freebsd_cpuset_setid(void *cpu_env, abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    id_t id;    /* 64-bit value */
+    cpusetid_t setid;
+    cpuwhich_t which;
+
+    target_to_host_cpuset_which(&which, arg1);
+#if TARGET_ABI_BITS == 32
+    /* See if we need to align the register pairs */
+    if (regpairs_aligned(cpu_env)) {
+        id = target_offset64(arg3, arg4);
+        setid = arg5;
+    } else {
+        id = target_offset64(arg2, arg3);
+        setid = arg4;
+    }
+#else
+    id = arg2;
+    setid = arg3;
+#endif
+    return get_errno(cpuset_setid(which, id, setid));
+}
+
+/* cpuset_getid(2) */
+static inline abi_long do_freebsd_cpuset_getid(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    id_t id;    /* 64-bit value */
+    cpusetid_t setid;
+    cpuwhich_t which;
+    cpulevel_t level;
+    abi_ulong target_setid;
+
+    target_to_host_cpuset_which(&which, arg1);
+    target_to_host_cpuset_level(&level, arg2);
+#if TARGET_ABI_BITS == 32
+    id = target_offset64(arg3, arg4);
+    target_setid = arg5;
+#else
+    id = arg3;
+    target_setid = arg4;
+#endif
+    ret = get_errno(cpuset_getid(level, which, id, &setid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return put_user_s32(setid, target_setid);
+}
+
+/* cpuset_getaffinity(2) */
+static inline abi_long do_freebsd_cpuset_getaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setaffinity(2) */
+static inline abi_long do_freebsd_cpuset_setaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* modfnext(2) */
+static inline abi_long do_freebsd_modfnext(abi_long modid)
+{
+
+    qemu_log("qemu: Unsupported syscall modfnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* modfind(2) */
+static inline abi_long do_freebsd_modfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall modfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldload(2) */
+static inline abi_long do_freebsd_kldload(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunload(2) */
+static inline abi_long do_freebsd_kldunload(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunloadf(2) */
+static inline abi_long do_freebsd_kldunloadf(abi_long fileid, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunloadf()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfind(2) */
+static inline abi_long do_freebsd_kldfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldnext(2) */
+static inline abi_long do_freebsd_kldnext(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* kldstat(2) */
+static inline abi_long do_freebsd_kldstat(abi_long fileid,
+        abi_ulong target_stat)
+{
+
+    qemu_log("qemu: Unsupported syscall kldstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfirstmod(2) */
+static inline abi_long do_freebsd_kldfirstmod(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfirstmod()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldsym(2) */
+static inline abi_long do_freebsd_kldsym(abi_long fileid, abi_long cmd,
+        abi_ulong target_data)
+{
+
+    qemu_log("qemu: Unsupported syscall kldsym()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Resource limits (undocumented except for rctl(8) and rctl.conf(5) )
+ */
+/* rctl_get_racct() */
+static inline abi_long do_freebsd_rctl_get_racct(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_racct()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_rules() */
+static inline abi_long do_freebsd_rctl_get_rules(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_rules()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_add_rule() */
+static inline abi_long do_freebsd_rctl_add_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_add_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_remove_rule() */
+static inline abi_long do_freebsd_rctl_remove_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_remove_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_limits() */
+static inline abi_long do_freebsd_rctl_get_limits(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_limits()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Kernel environment
+ */
+
+/* kenv(2) */
+static inline abi_long do_freebsd_kenv(abi_long what, abi_ulong target_name,
+        abi_ulong target_value, abi_long len)
+{
+
+    qemu_log("qemu: Unsupported syscall kenv()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ *  Mandatory Access Control
+ */
+
+/* __mac_get_proc */
+static inline abi_long do_freebsd___mac_get_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_proc */
+static inline abi_long do_freebsd___mac_set_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* __mac_get_fd */
+static inline abi_long do_freebsd___mac_get_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_fd */
+static inline abi_long do_freebsd___mac_set_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_file */
+static inline abi_long do_freebsd___mac_get_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_file */
+static inline abi_long do_freebsd___mac_set_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_link */
+static inline abi_long do_freebsd___mac_get_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_link */
+static inline abi_long do_freebsd___mac_set_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* mac_syscall */
+static inline abi_long do_freebsd_mac_syscall(abi_ulong target_policy,
+        abi_long call, abi_ulong target_arg)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_syscall()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ * New posix calls
+ */
+/* posix_fallocate(2) */
+static inline abi_long do_freebsd_posix_fallocate(abi_long fd, abi_ulong offset,
+        abi_ulong len)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fallocate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_openpt(2) */
+static inline abi_long do_freebsd_posix_openpt(abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_openpt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_fadvise(2) */
+static inline abi_long do_freebsd_posix_fadvise(abi_long fd, abi_ulong offset,
+        abi_ulong len, abi_long advise)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fadvise()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+#endif /* ! __OS_MISC_H_ */
diff --git a/bsd-user/netbsd/os-misc.h b/bsd-user/netbsd/os-misc.h
new file mode 100644
index 0000000..8be3662
--- /dev/null
+++ b/bsd-user/netbsd/os-misc.h
@@ -0,0 +1,375 @@
+/*
+ *  miscellaneous NetBSD system call shims
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __OS_MISC_H_
+#define __OS_MISC_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* sched_setparam(2) */
+static inline abi_long do_freebsd_sched_setparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_setparam()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_get_param(2) */
+static inline abi_long do_freebsd_sched_getparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_getparam()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_setscheduler(2) */
+static inline abi_long do_freebsd_sched_setscheduler(pid_t pid, int policy,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_setscheduler()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_getscheduler(pid_t pid)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_getscheduler()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_rr_get_interval(pid_t pid,
+        abi_ulong target_ts_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_rr_get_interval()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset(2) */
+static inline abi_long do_freebsd_cpuset(abi_ulong target_cpuid)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setid(2) */
+static inline abi_long do_freebsd_cpuset_setid(void *cpu_env, abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_getid(2) */
+static inline abi_long do_freebsd_cpuset_getid(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_getaffinity(2) */
+static inline abi_long do_freebsd_cpuset_getaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setaffinity(2) */
+static inline abi_long do_freebsd_cpuset_setaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* modfnext(2) */
+static inline abi_long do_freebsd_modfnext(abi_long modid)
+{
+
+    qemu_log("qemu: Unsupported syscall modfnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* modfind(2) */
+static inline abi_long do_freebsd_modfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall modfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldload(2) */
+static inline abi_long do_freebsd_kldload(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunload(2) */
+static inline abi_long do_freebsd_kldunload(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunloadf(2) */
+static inline abi_long do_freebsd_kldunloadf(abi_long fileid, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunloadf()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfind(2) */
+static inline abi_long do_freebsd_kldfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldnext(2) */
+static inline abi_long do_freebsd_kldnext(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* kldstat(2) */
+static inline abi_long do_freebsd_kldstat(abi_long fileid,
+        abi_ulong target_stat)
+{
+
+    qemu_log("qemu: Unsupported syscall kldstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfirstmod(2) */
+static inline abi_long do_freebsd_kldfirstmod(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfirstmod()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldsym(2) */
+static inline abi_long do_freebsd_kldsym(abi_long fileid, abi_long cmd,
+        abi_ulong target_data)
+{
+
+    qemu_log("qemu: Unsupported syscall kldsym()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Resource limits (undocumented except for rctl(8) and rctl.conf(5) )
+ */
+/* rctl_get_racct() */
+static inline abi_long do_freebsd_rctl_get_racct(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_racct()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_rules() */
+static inline abi_long do_freebsd_rctl_get_rules(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_rules()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_add_rule() */
+static inline abi_long do_freebsd_rctl_add_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_add_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_remove_rule() */
+static inline abi_long do_freebsd_rctl_remove_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_remove_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_limits() */
+static inline abi_long do_freebsd_rctl_get_limits(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_limits()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Kernel environment
+ */
+
+/* kenv(2) */
+static inline abi_long do_freebsd_kenv(abi_long what, abi_ulong target_name,
+        abi_ulong target_value, abi_long len)
+{
+
+    qemu_log("qemu: Unsupported syscall kenv()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ *  Mandatory Access Control
+ */
+
+/* __mac_get_proc */
+static inline abi_long do_freebsd___mac_get_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_proc */
+static inline abi_long do_freebsd___mac_set_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* __mac_get_fd */
+static inline abi_long do_freebsd___mac_get_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_fd */
+static inline abi_long do_freebsd___mac_set_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_file */
+static inline abi_long do_freebsd___mac_get_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_file */
+static inline abi_long do_freebsd___mac_set_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_link */
+static inline abi_long do_freebsd___mac_get_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_link */
+static inline abi_long do_freebsd___mac_set_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* mac_syscall */
+static inline abi_long do_freebsd_mac_syscall(abi_ulong target_policy,
+        abi_long call, abi_ulong target_arg)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_syscall()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ * New posix calls
+ */
+/* posix_fallocate(2) */
+static inline abi_long do_freebsd_posix_fallocate(abi_long fd, abi_ulong offset,
+        abi_ulong len)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fallocate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_openpt(2) */
+static inline abi_long do_freebsd_posix_openpt(abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_openpt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_fadvise(2) */
+static inline abi_long do_freebsd_posix_fadvise(abi_long fd, abi_ulong offset,
+        abi_ulong len, abi_long advise)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fadvise()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OS_MISC_H_ */
diff --git a/bsd-user/openbsd/os-misc.h b/bsd-user/openbsd/os-misc.h
new file mode 100644
index 0000000..5a17ac9
--- /dev/null
+++ b/bsd-user/openbsd/os-misc.h
@@ -0,0 +1,375 @@
+/*
+ *  miscellaneous OpenBSD system call shims
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __OS_MISC_H_
+#define __OS_MISC_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* sched_setparam(2) */
+static inline abi_long do_freebsd_sched_setparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_setparam()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_get_param(2) */
+static inline abi_long do_freebsd_sched_getparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_getparam()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_setscheduler(2) */
+static inline abi_long do_freebsd_sched_setscheduler(pid_t pid, int policy,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_setscheduler()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_getscheduler(pid_t pid)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_getscheduler()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_rr_get_interval(pid_t pid,
+        abi_ulong target_ts_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_rr_get_interval()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset(2) */
+static inline abi_long do_freebsd_cpuset(abi_ulong target_cpuid)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setid(2) */
+static inline abi_long do_freebsd_cpuset_setid(void *cpu_env, abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_getid(2) */
+static inline abi_long do_freebsd_cpuset_getid(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_getaffinity(2) */
+static inline abi_long do_freebsd_cpuset_getaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setaffinity(2) */
+static inline abi_long do_freebsd_cpuset_setaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* modfnext(2) */
+static inline abi_long do_freebsd_modfnext(abi_long modid)
+{
+
+    qemu_log("qemu: Unsupported syscall modfnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* modfind(2) */
+static inline abi_long do_freebsd_modfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall modfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldload(2) */
+static inline abi_long do_freebsd_kldload(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunload(2) */
+static inline abi_long do_freebsd_kldunload(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunloadf(2) */
+static inline abi_long do_freebsd_kldunloadf(abi_long fileid, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunloadf()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfind(2) */
+static inline abi_long do_freebsd_kldfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldnext(2) */
+static inline abi_long do_freebsd_kldnext(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* kldstat(2) */
+static inline abi_long do_freebsd_kldstat(abi_long fileid,
+        abi_ulong target_stat)
+{
+
+    qemu_log("qemu: Unsupported syscall kldstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfirstmod(2) */
+static inline abi_long do_freebsd_kldfirstmod(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfirstmod()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldsym(2) */
+static inline abi_long do_freebsd_kldsym(abi_long fileid, abi_long cmd,
+        abi_ulong target_data)
+{
+
+    qemu_log("qemu: Unsupported syscall kldsym()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Resource limits (undocumented except for rctl(8) and rctl.conf(5) )
+ */
+/* rctl_get_racct() */
+static inline abi_long do_freebsd_rctl_get_racct(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_racct()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_rules() */
+static inline abi_long do_freebsd_rctl_get_rules(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_rules()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_add_rule() */
+static inline abi_long do_freebsd_rctl_add_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_add_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_remove_rule() */
+static inline abi_long do_freebsd_rctl_remove_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_remove_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_limits() */
+static inline abi_long do_freebsd_rctl_get_limits(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_limits()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Kernel environment
+ */
+
+/* kenv(2) */
+static inline abi_long do_freebsd_kenv(abi_long what, abi_ulong target_name,
+        abi_ulong target_value, abi_long len)
+{
+
+    qemu_log("qemu: Unsupported syscall kenv()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ *  Mandatory Access Control
+ */
+
+/* __mac_get_proc */
+static inline abi_long do_freebsd___mac_get_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_proc */
+static inline abi_long do_freebsd___mac_set_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* __mac_get_fd */
+static inline abi_long do_freebsd___mac_get_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_fd */
+static inline abi_long do_freebsd___mac_set_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_file */
+static inline abi_long do_freebsd___mac_get_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_file */
+static inline abi_long do_freebsd___mac_set_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_link */
+static inline abi_long do_freebsd___mac_get_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_link */
+static inline abi_long do_freebsd___mac_set_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* mac_syscall */
+static inline abi_long do_freebsd_mac_syscall(abi_ulong target_policy,
+        abi_long call, abi_ulong target_arg)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_syscall()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ * New posix calls
+ */
+/* posix_fallocate(2) */
+static inline abi_long do_freebsd_posix_fallocate(abi_long fd, abi_ulong offset,
+        abi_ulong len)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fallocate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_openpt(2) */
+static inline abi_long do_freebsd_posix_openpt(abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_openpt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_fadvise(2) */
+static inline abi_long do_freebsd_posix_fadvise(abi_long fd, abi_ulong offset,
+        abi_ulong len, abi_long advise)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fadvise()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OS_MISC_H_ */
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
index 09b99ef..771245d 100644
--- a/bsd-user/qemu-bsd.h
+++ b/bsd-user/qemu-bsd.h
@@ -58,4 +58,22 @@ abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
 abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr,
         socklen_t len);
 
+/* bsd-misc.c */
+abi_long host_to_target_uuid(abi_ulong target_addr, struct uuid *host_uuid);
+
+abi_long target_to_host_semarray(int semid, unsigned short **host_array,
+        abi_ulong target_addr);
+abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+        unsigned short **host_array);
+
+abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
+        abi_ulong target_addr);
+abi_long host_to_target_semid_ds(abi_ulong target_addr,
+        struct semid_ds *host_sd);
+
+abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
+        abi_ulong target_addr);
+abi_long host_to_target_msqid_ds(abi_ulong target_addr,
+        struct msqid_ds *host_md);
+
 #endif /* !_QEMU_BSD_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index ab17f3f..35bf394 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -37,6 +37,7 @@
 #include "bsd-file.h"
 #include "bsd-ioctl.h"
 #include "bsd-mem.h"
+#include "bsd-misc.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
 #include "bsd-socket.h"
@@ -44,6 +45,7 @@
 /* *BSD dependent syscall shims */
 #include "os-extattr.h"
 #include "os-time.h"
+#include "os-misc.h"
 #include "os-proc.h"
 #include "os-signal.h"
 #include "os-socket.h"
@@ -1308,6 +1310,233 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = do_freebsd__acl_set_link(arg1, arg2, arg3);
         break;
 
+        /*
+         * SysV Semaphores
+         */
+    case TARGET_FREEBSD_NR_semget: /* semget(2) */
+        ret = do_bsd_semget(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_semop: /* semop(2) */
+        ret = do_bsd_semop(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___semctl: /* __semctl() undocumented */
+        ret = do_bsd___semctl(arg1, arg2, arg3,
+                (union target_semun)(abi_ulong)arg4);
+        break;
+
+        /*
+         * SysV Messages
+         */
+    case TARGET_FREEBSD_NR_msgctl: /* msgctl(2) */
+        ret = do_bsd_msgctl(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_msgsnd: /* msgsnd(2) */
+        ret = do_bsd_msgsnd(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_msgrcv: /* msgrcv(2) */
+        ret = do_bsd_msgrcv(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+        /*
+         * FreeBSD scheduler control
+         */
+    case TARGET_FREEBSD_NR_sched_setparam: /* sched_setparam(2) */
+        ret = do_freebsd_sched_setparam(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_getparam: /* sched_getparam(2) */
+        ret = do_freebsd_sched_getparam(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_setscheduler: /* sched_setscheduler(2) */
+        ret = do_freebsd_sched_setscheduler(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_getscheduler: /* sched_getscheduler(2) */
+        ret = do_freebsd_sched_getscheduler(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_rr_get_interval: /* sched_rr_get_interval(2) */
+        ret = do_freebsd_sched_rr_get_interval(arg1, arg2);
+        break;
+
+        /*
+         * FreeBSD CPU affinity sets management
+         */
+    case TARGET_FREEBSD_NR_cpuset: /* cpuset(2) */
+        ret = do_freebsd_cpuset(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_setid: /* cpuset_setid(2) */
+        ret = do_freebsd_cpuset_setid(cpu_env, arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_getid: /* cpuset_getid(2) */
+        ret = do_freebsd_cpuset_getid(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_getaffinity: /* cpuset_getaffinity(2) */
+        ret = do_freebsd_cpuset_getaffinity(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_setaffinity: /* cpuset_setaffinity(2) */
+        ret = do_freebsd_cpuset_setaffinity(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+
+        /*
+         * FreeBSD kernel module
+         */
+    case TARGET_FREEBSD_NR_modfnext: /* modfnext(2) */
+        ret = do_freebsd_modfnext(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_modfind: /* modfind(2) */
+        ret = do_freebsd_modfind(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldload: /* kldload(2) */
+        ret = do_freebsd_kldload(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldunload: /* kldunload(2) */
+        ret = do_freebsd_kldunload(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldunloadf: /* kldunloadf(2) */
+        ret = do_freebsd_kldunloadf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kldfind: /* kldfind(2) */
+        ret = do_freebsd_kldfind(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldnext: /* kldnext(2) */
+        ret = do_freebsd_kldnext(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldstat: /* kldstat(2) */
+        ret = do_freebsd_kldstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kldfirstmod: /* kldfirstmod(2) */
+        ret = do_freebsd_kldfirstmod(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldsym: /* kldsym(2) */
+        ret = do_freebsd_kldsym(arg1, arg2, arg3);
+        break;
+
+        /*
+         * FreeBSD resource controls (undocumented except for rctl(8)
+         * and rctl.conf(5) )
+         */
+    case TARGET_FREEBSD_NR_rctl_get_racct: /* rctl_get_racct() */
+        ret = do_freebsd_rctl_get_racct(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_rctl_get_rules: /* rctl_get_rules() */
+        ret = do_freebsd_rctl_get_rules(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_rctl_add_rule: /* rctl_add_rule() */
+        ret = do_freebsd_rctl_add_rule(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_rctl_remove_rule: /* rctl_remove_rule() */
+        ret = do_freebsd_rctl_remove_rule(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_rctl_get_limits: /* rctl_get_limits() */
+        ret = do_freebsd_rctl_get_limits(arg1, arg2, arg3, arg4);
+        break;
+
+        /*
+         * FreeBSD Mandatory Access Control
+         */
+    case TARGET_FREEBSD_NR___mac_get_proc: /* __mac_get_proc() */
+        ret = do_freebsd___mac_get_proc(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_set_proc: /* __mac_set_proc() */
+        ret = do_freebsd___mac_set_proc(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_get_fd: /* __mac_get_fd() */
+        ret = do_freebsd___mac_get_fd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_set_fd: /* __mac_set_fd() */
+        ret = do_freebsd___mac_set_fd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_get_file: /* __mac_get_file() */
+        ret = do_freebsd___mac_get_proc(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_set_file: /* __mac_set_file() */
+        ret = do_freebsd___mac_set_file(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_get_link: /* __mac_get_link() */
+        ret = do_freebsd___mac_get_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_set_link: /* __mac_set_link() */
+        ret = do_freebsd___mac_set_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mac_syscall: /* mac_syscall() */
+        ret = do_freebsd_mac_syscall(arg1, arg2, arg3);
+        break;
+
+        /*
+         * FreeBSD additional posix support
+         */
+    case TARGET_FREEBSD_NR_posix_fallocate: /* posix_fallocate(2) */
+        ret = do_freebsd_posix_fallocate(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_posix_openpt: /* posix_fallocate(2) */
+        ret = do_freebsd_posix_openpt(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_posix_fadvise: /* posix_fadvise(2) */
+        ret = do_freebsd_posix_fadvise(arg1, arg2, arg3, arg4);
+        break;
+
+        /*
+         * Misc
+         */
+    case TARGET_FREEBSD_NR_quotactl: /* quotactl(2) */
+        ret = do_bsd_quotactl(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_reboot: /* reboot(2) */
+        ret = do_bsd_reboot(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_uuidgen: /* uuidgen(2) */
+        ret = do_bsd_uuidgen(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getdtablesize: /* getdtablesize(2) */
+        ret = do_bsd_getdtablesize();
+        break;
+
+    case TARGET_FREEBSD_NR_kenv: /* kenv(2) */
+        ret = do_freebsd_kenv(arg1, arg2, arg2, arg4);
+        break;
+
+
+    case TARGET_FREEBSD_NR_break:
+        ret = do_obreak(arg1);
+        break;
+
     default:
         ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
                     arg8));
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 18/19] bsd-user: add arm, mips and mips64 options to configure target-list
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (37 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 17/19] bsd-user: add support for miscellaneous system calls Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto Stacey Son
  39 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds arm-bsd-user, mips-bsd-user, mips64-bsd-user,
mips64el-bsd-user, and mipsel-bsd-user as --target-list options to configure.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 default-configs/arm-bsd-user.mak      |    3 +++
 default-configs/mips-bsd-user.mak     |    1 +
 default-configs/mips64-bsd-user.mak   |    1 +
 default-configs/mips64el-bsd-user.mak |    1 +
 default-configs/mipsel-bsd-user.mak   |    1 +
 5 files changed, 7 insertions(+), 0 deletions(-)
 create mode 100644 default-configs/arm-bsd-user.mak
 create mode 100644 default-configs/mips-bsd-user.mak
 create mode 100644 default-configs/mips64-bsd-user.mak
 create mode 100644 default-configs/mips64el-bsd-user.mak
 create mode 100644 default-configs/mipsel-bsd-user.mak

diff --git a/default-configs/arm-bsd-user.mak b/default-configs/arm-bsd-user.mak
new file mode 100644
index 0000000..869e6fb
--- /dev/null
+++ b/default-configs/arm-bsd-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for arm-bsd-user
+
+CONFIG_GDBSTUB_XML=y
diff --git a/default-configs/mips-bsd-user.mak b/default-configs/mips-bsd-user.mak
new file mode 100644
index 0000000..3fb129a
--- /dev/null
+++ b/default-configs/mips-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips-bsd-user
diff --git a/default-configs/mips64-bsd-user.mak b/default-configs/mips64-bsd-user.mak
new file mode 100644
index 0000000..d4e72a6
--- /dev/null
+++ b/default-configs/mips64-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips64-bsd-user
diff --git a/default-configs/mips64el-bsd-user.mak b/default-configs/mips64el-bsd-user.mak
new file mode 100644
index 0000000..b879228
--- /dev/null
+++ b/default-configs/mips64el-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips64el-bsd-user
diff --git a/default-configs/mipsel-bsd-user.mak b/default-configs/mipsel-bsd-user.mak
new file mode 100644
index 0000000..312b9d5
--- /dev/null
+++ b/default-configs/mipsel-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for mipsel-bsd-user
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v2 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto
  2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
                   ` (38 preceding siblings ...)
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 18/19] bsd-user: add arm, mips and mips64 options to configure target-list Stacey Son
@ 2013-11-08 16:33 ` Stacey Son
  2013-11-27 11:23   ` Paolo Bonzini
  39 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-11-08 16:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

FreeBSD has it's own AES_set_decrypt_key, etc. in libcrypto.  This
change fixes these conflicts and allows statically linking BSD
user mode qemu.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 include/qemu/aes.h |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/include/qemu/aes.h b/include/qemu/aes.h
index e79c707..6d253a3 100644
--- a/include/qemu/aes.h
+++ b/include/qemu/aes.h
@@ -10,6 +10,15 @@ struct aes_key_st {
 };
 typedef struct aes_key_st AES_KEY;
 
+/* FreeBSD has it's own AES_set_decrypt_key in -lcrypto, avoid conflicts. */
+#ifdef __FreeBSD__
+#define AES_set_encrypt_key QEMU_AES_set_encrypt_key
+#define AES_set_decrypt_key QEMU_AES_set_decrypt_key
+#define AES_encrypt QEMU_AES_encrypt
+#define AES_decrypt QEMU_AES_decrypt
+#define AES_cbc_encrypt QEMU_AES_cbc_encrypt
+#endif
+
 int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
 	AES_KEY *key);
 int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v2 00/19] bsd-user: Add system call and mips/arm support.
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
@ 2013-11-26 21:01   ` Ed Maste
  2013-11-27 11:29     ` Paolo Bonzini
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 " Stacey Son
                     ` (19 subsequent siblings)
  20 siblings, 1 reply; 95+ messages in thread
From: Ed Maste @ 2013-11-26 21:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, Stacey Son

On 8 November 2013 11:33, Stacey Son <sson@freebsd.org> wrote:
> [v2]
>
> - Rebases to 1.7.0-rc0. (Requires, however, Andreas Tobler's patch to
>   build: see
>   http://lists.nongnu.org/archive/html/qemu-devel/2013-11/msg00000.html)
> - Fixes deadlock in the _umtx_op() system call handler.
> - Fixes race condition in mmap() system call handler.
> - Makes qemu-mips (o32) usable.
> - A small code clean up to the ARM cpu_loop().
> - Fixes comment in arm-bsd-user.mak to match filename.
> - Fixes symbol conflicts with FreeBSD's libcrypto for static link.

Ping.

This is a large change in an area that hasn't had a lot of activity of
late; what are the next steps here?

-Ed

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v2 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto Stacey Son
@ 2013-11-27 11:23   ` Paolo Bonzini
  0 siblings, 0 replies; 95+ messages in thread
From: Paolo Bonzini @ 2013-11-27 11:23 UTC (permalink / raw)
  To: Stacey Son; +Cc: qemu-devel

Il 08/11/2013 17:33, Stacey Son ha scritto:
> FreeBSD has it's own AES_set_decrypt_key, etc. in libcrypto.  This
> change fixes these conflicts and allows statically linking BSD
> user mode qemu.
> 
> Signed-off-by: Stacey Son <sson@FreeBSD.org>
> ---
>  include/qemu/aes.h |    9 +++++++++
>  1 files changed, 9 insertions(+), 0 deletions(-)
> 
> diff --git a/include/qemu/aes.h b/include/qemu/aes.h
> index e79c707..6d253a3 100644
> --- a/include/qemu/aes.h
> +++ b/include/qemu/aes.h
> @@ -10,6 +10,15 @@ struct aes_key_st {
>  };
>  typedef struct aes_key_st AES_KEY;
>  
> +/* FreeBSD has it's own AES_set_decrypt_key in -lcrypto, avoid conflicts. */
> +#ifdef __FreeBSD__
> +#define AES_set_encrypt_key QEMU_AES_set_encrypt_key
> +#define AES_set_decrypt_key QEMU_AES_set_decrypt_key
> +#define AES_encrypt QEMU_AES_encrypt
> +#define AES_decrypt QEMU_AES_decrypt
> +#define AES_cbc_encrypt QEMU_AES_cbc_encrypt
> +#endif
> +
>  int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
>  	AES_KEY *key);
>  int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
> 

What is the error?  Do the functions have different signatures or
semantics between QEMU and FreeBSD?

Paolo

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v2 02/19] bsd-user: add HOST_ABI_DIR for the various *BSD dependent code.
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 02/19] bsd-user: add HOST_ABI_DIR for the various *BSD dependent code Stacey Son
@ 2013-11-27 11:27   ` Paolo Bonzini
  0 siblings, 0 replies; 95+ messages in thread
From: Paolo Bonzini @ 2013-11-27 11:27 UTC (permalink / raw)
  To: Stacey Son; +Cc: qemu-devel

Il 08/11/2013 17:33, Stacey Son ha scritto:
> This change adds HOST_ABI_DIR (similar to TARGET_ABI_DIR) so the various
> BSD OS dependent code can be seperated into its own directories rather
> than using #ifdef's.

I would say this is not exactly an ABI, so it would be better to call it
HOST_VARIANT_DIR.

Also, is it really host-dependent?  If you had hypothetically a qemu
that ran OpenBSD targets on FreeBSD, would it use bsd-user/freebsd or
bsd-user/openbsd?

So, this should be either HOST_VARIANT_DIR or TARGET_VARIANT_DIR,
depending on the answer to the above question.

Apart from this, the patch looks good.

Paolo

> Signed-off-by: Stacey Son <sson@FreeBSD.org>
> ---
>  Makefile.target |    3 ++-
>  configure       |   11 +++++++++++
>  2 files changed, 13 insertions(+), 1 deletions(-)
> 
> diff --git a/Makefile.target b/Makefile.target
> index af6ac7e..82ae8cb 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -99,7 +99,8 @@ endif #CONFIG_LINUX_USER
>  
>  ifdef CONFIG_BSD_USER
>  
> -QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR)
> +QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR) \
> +			 -I$(SRC_PATH)/bsd-user/$(HOST_ABI_DIR)
>  
>  obj-y += bsd-user/
>  obj-y += gdbstub.o user-exec.o
> diff --git a/configure b/configure
> index 91372f9..14571c6 100755
> --- a/configure
> +++ b/configure
> @@ -449,6 +449,9 @@ fi
>  
>  # OS specific
>  
> +# host *BSD for user mode
> +HOST_ABI_DIR=""
> +
>  case $targetos in
>  CYGWIN*)
>    mingw32="yes"
> @@ -473,12 +476,14 @@ FreeBSD)
>    audio_possible_drivers="oss sdl esd pa"
>    # needed for kinfo_getvmmap(3) in libutil.h
>    LIBS="-lutil $LIBS"
> +  HOST_ABI_DIR="freebsd"
>  ;;
>  DragonFly)
>    bsd="yes"
>    make="${MAKE-gmake}"
>    audio_drv_list="oss"
>    audio_possible_drivers="oss sdl esd pa"
> +  HOST_ABI_DIR="dragonfly"
>  ;;
>  NetBSD)
>    bsd="yes"
> @@ -486,12 +491,14 @@ NetBSD)
>    audio_drv_list="oss"
>    audio_possible_drivers="oss sdl esd"
>    oss_lib="-lossaudio"
> +  HOST_ABI_DIR="netbsd"
>  ;;
>  OpenBSD)
>    bsd="yes"
>    make="${MAKE-gmake}"
>    audio_drv_list="sdl"
>    audio_possible_drivers="sdl esd"
> +  HOST_ABI_DIR="openbsd"
>  ;;
>  Darwin)
>    bsd="yes"
> @@ -510,6 +517,7 @@ Darwin)
>    # Disable attempts to use ObjectiveC features in os/object.h since they
>    # won't work when we're compiling with gcc as a C compiler.
>    QEMU_CFLAGS="-DOS_OBJECT_USE_OBJC=0 $QEMU_CFLAGS"
> +  HOST_ABI_DIR="darwin"
>  ;;
>  SunOS)
>    solaris="yes"
> @@ -4471,6 +4479,9 @@ if [ "$TARGET_ABI_DIR" = "" ]; then
>    TARGET_ABI_DIR=$TARGET_ARCH
>  fi
>  echo "TARGET_ABI_DIR=$TARGET_ABI_DIR" >> $config_target_mak
> +if [ "$HOST_ABI_DIR" != "" ]; then
> +    echo "HOST_ABI_DIR=$HOST_ABI_DIR" >> $config_target_mak
> +fi
>  case "$target_name" in
>    i386|x86_64)
>      if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
> 

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v2 14/19] bsd-user: add support for thread related system calls
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 14/19] bsd-user: add support for thread " Stacey Son
@ 2013-11-27 11:28   ` Paolo Bonzini
  0 siblings, 0 replies; 95+ messages in thread
From: Paolo Bonzini @ 2013-11-27 11:28 UTC (permalink / raw)
  To: Stacey Son; +Cc: qemu-devel

Il 08/11/2013 17:33, Stacey Son ha scritto:
> diff --git a/include/qemu/tls.h b/include/qemu/tls.h
> index b92ea9d..ae7d79d 100644
> --- a/include/qemu/tls.h
> +++ b/include/qemu/tls.h
> @@ -38,7 +38,7 @@
>   * TODO: proper implementations via Win32 .tls sections and
>   * POSIX pthread_getspecific.
>   */
> -#ifdef __linux__
> +#if defined(__linux__) || defined(__FreeBSD__)
>  #define DECLARE_TLS(type, x) extern DEFINE_TLS(type, x)
>  #define DEFINE_TLS(type, x)  __thread __typeof__(type) tls__##x
>  #define tls_var(x)           tls__##x

Acked-by: Paolo Bonzini <pbonzini@redhat.com>

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v2 00/19] bsd-user: Add system call and mips/arm support.
  2013-11-26 21:01   ` Ed Maste
@ 2013-11-27 11:29     ` Paolo Bonzini
  2013-12-12 19:57       ` Ed Maste
  0 siblings, 1 reply; 95+ messages in thread
From: Paolo Bonzini @ 2013-11-27 11:29 UTC (permalink / raw)
  To: Ed Maste; +Cc: blauwirbel, Stacey Son, qemu-devel

Il 26/11/2013 22:01, Ed Maste ha scritto:
> On 8 November 2013 11:33, Stacey Son <sson@freebsd.org> wrote:
>> [v2]
>>
>> - Rebases to 1.7.0-rc0. (Requires, however, Andreas Tobler's patch to
>>   build: see
>>   http://lists.nongnu.org/archive/html/qemu-devel/2013-11/msg00000.html)
>> - Fixes deadlock in the _umtx_op() system call handler.
>> - Fixes race condition in mmap() system call handler.
>> - Makes qemu-mips (o32) usable.
>> - A small code clean up to the ARM cpu_loop().
>> - Fixes comment in arm-bsd-user.mak to match filename.
>> - Fixes symbol conflicts with FreeBSD's libcrypto for static link.
> 
> Ping.
> 
> This is a large change in an area that hasn't had a lot of activity of
> late; what are the next steps here?

We're now in hard freeze, so the next step is to wait for 1.8 to be
released.

I reviewed the parts out of bsd-user, and had only one question.

Paolo

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v2 00/19] bsd-user: Add system call and mips/arm support.
  2013-11-27 11:29     ` Paolo Bonzini
@ 2013-12-12 19:57       ` Ed Maste
  2013-12-12 20:15         ` Stacey Son
  2013-12-13 12:44         ` Paolo Bonzini
  0 siblings, 2 replies; 95+ messages in thread
From: Ed Maste @ 2013-12-12 19:57 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Blue Swirl, Stacey Son, qemu-devel

On 27 November 2013 06:29, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 26/11/2013 22:01, Ed Maste ha scritto:
>> On 8 November 2013 11:33, Stacey Son <sson@freebsd.org> wrote:
>>> [v2]
>>>
>>> - Rebases to 1.7.0-rc0. (Requires, however, Andreas Tobler's patch to
>>>   build: see
>>>   http://lists.nongnu.org/archive/html/qemu-devel/2013-11/msg00000.html)
>>> - Fixes deadlock in the _umtx_op() system call handler.
>>> - Fixes race condition in mmap() system call handler.
>>> - Makes qemu-mips (o32) usable.
>>> - A small code clean up to the ARM cpu_loop().
>>> - Fixes comment in arm-bsd-user.mak to match filename.
>>> - Fixes symbol conflicts with FreeBSD's libcrypto for static link.
>>
>> Ping.
>>
>> This is a large change in an area that hasn't had a lot of activity of
>> late; what are the next steps here?
>
> We're now in hard freeze, so the next step is to wait for 1.8 to be
> released.
>
> I reviewed the parts out of bsd-user, and had only one question.

Ok, 1.7's now out, and we'll sort out the HOST_ABI vs. HOST_VARIANT
question.  What's our next step after that?

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v2 00/19] bsd-user: Add system call and mips/arm support.
  2013-12-12 19:57       ` Ed Maste
@ 2013-12-12 20:15         ` Stacey Son
  2013-12-13 12:44         ` Paolo Bonzini
  1 sibling, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-12-12 20:15 UTC (permalink / raw)
  To: Ed Maste; +Cc: Blue Swirl, Paolo Bonzini, qemu-devel


On Dec 12, 2013, at 1:57 PM, Ed Maste <emaste@freebsd.org> wrote:

> On 27 November 2013 06:29, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> Il 26/11/2013 22:01, Ed Maste ha scritto:
>>> 
>>> Ping.
>>> 
>>> This is a large change in an area that hasn't had a lot of activity of
>>> late; what are the next steps here?
>> 
>> We're now in hard freeze, so the next step is to wait for 1.8 to be
>> released.
>> 
>> I reviewed the parts out of bsd-user, and had only one question.
> 
> Ok, 1.7's now out, and we'll sort out the HOST_ABI vs. HOST_VARIANT
> question.  What's our next step after that?

FYI, I have some addition bug fixes that I will be adding in a new patch set (v3) and will be rebasing to HEAD.

Also, I'll make the change from HOST_ABI_DIR to HOST_VARIANT_DIR.  The idea is if someone wanted to run, say, OpenBSD targets on a FreeBSD host it would use the code in the bsd-user/freebsd directory to do that.   The code would need to support emulation for OpenBSD system calls that are not already natively supported by FreeBSD. 

Best Regards,

-stacey.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v2 00/19] bsd-user: Add system call and mips/arm support.
  2013-12-12 19:57       ` Ed Maste
  2013-12-12 20:15         ` Stacey Son
@ 2013-12-13 12:44         ` Paolo Bonzini
  1 sibling, 0 replies; 95+ messages in thread
From: Paolo Bonzini @ 2013-12-13 12:44 UTC (permalink / raw)
  To: Ed Maste; +Cc: Blue Swirl, Stacey Son, qemu-devel

Il 12/12/2013 20:57, Ed Maste ha scritto:
>>> >> This is a large change in an area that hasn't had a lot of activity of
>>> >> late; what are the next steps here?
>> >
>> > We're now in hard freeze, so the next step is to wait for 1.8 to be
>> > released.
>> >
>> > I reviewed the parts out of bsd-user, and had only one question.
> Ok, 1.7's now out, and we'll sort out the HOST_ABI vs. HOST_VARIANT
> question.  What's our next step after that?

Post the patches.  I'll review the non-bsd-user parts again.  And then
the next step is to find someone who commits them...  shouldn't be hard
since you probably know much more about this code than anyone else.

Paolo

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 00/19] bsd-user: Add system call and mips/arm support.
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
  2013-11-26 21:01   ` Ed Maste
@ 2013-12-17 11:52   ` Stacey Son
  2014-01-27 19:15     ` Peter Maydell
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 01/19] bsd-user: refresh freebsd system call numbers Stacey Son
                     ` (18 subsequent siblings)
  20 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

[v3]

- Rebases to commit f46e720a82ccdf1a521cf459448f3f96ed895d43 (HEAD).
- Changes 'HOST_API_DIR' to 'HOST_VARIANT_DIR' for the BSD variant.
- Fixes boundry condition bug in mmap() system call handler.
- Fixes floating point support for MIPS64.
- Fixes execve() syscall handler so shell scripts are properly exec'ed.
- Fixes uninitialized data bug for extended attribute syscall handlers.
- Fixes minor typos in ACL syscall structures.

[v2]

- Rebases to 1.7.0-rc0. (Requires, however, Andreas Tobler's patch to
  build: see
  http://lists.nongnu.org/archive/html/qemu-devel/2013-11/msg00000.html)
- Fixes deadlock in the _umtx_op() system call handler.
- Fixes race condition in mmap() system call handler.
- Makes qemu-mips (o32) usable.
- A small code clean up to the ARM cpu_loop().
- Fixes comment in arm-bsd-user.mak to match filename.
- Fixes symbol conflicts with FreeBSD's libcrypto for static link.

[v1]

This patch series adds a significant number of system calls and mips/arm
support for bsd-user.  In its current state it can emulate most
FreeBSD mips/mips64 and arm target binaries on a x86 host in a simple
chroot environment. (see https://wiki.freebsd.org/QemuUserModeHowTo for
the details.)

Besides adding a lot of shims and other support code this change
restructures the code significantly to reduce the amount of C
preprocessor conditionals for the various target and host arch/OS's.
In general, the target cpu depedent code has been moved into into
the various arch directories and the host OS dependent code (ie.
FreeBSD, NetBSD, OpenBSD) has been moved into the OS directories as
much as possible.

I would like to recognize Olivier Houchard for a lot of the arm
dependent code and Juergen Lock, the maintainer of the FreeBSD
Qemu port, for their contributions.

Note that these patches are also available at:

    http://people.freebsd.org/~sson/qemu/qemu-bsd-user/

and on github in the 'bsd-user' branch of the following repository:

    https://github.com/staceyson/qemu-bsd-user

Best Regards,

Stacey D. Son
---

Stacey Son (19):
  bsd-user: refresh freebsd system call numbers
  bsd-user: add HOST_VARIANT_DIR for various *BSD dependent code
  bsd-user: move strace OS/arch dependent code to host/arch dirs
  bsd-user: move arch/OS dependent code out of main.c
  bsd-user: move arch/OS dependent code out of syscall.c
  bsd-user: add support for freebsd time related system calls
  bsd-user: add support for freebsd signal related system calls
  bsd-user: move arch/OS dependent code out of elfload.c
  bsd-user: add support for freebsd process related system calls
  bsd-user: add support for file system related system calls
  bsd-user: add support for stat, dir, and fcntl related syscalls
  bsd-user: add support for memory management related syscalls
  bsd-user: add support for socket related system calls
  bsd-user: add support for thread related system calls
  bsd-user: add support for the ioctl system call
  bsd-user: add support for extattr and ACL related syscalls
  bsd-user: add support for miscellaneous system calls
  bsd-user: add arm, mips and mips64 options to configure target-list
  bsd-user: fix linking conflicts with FreeBSD libcrypto

 Makefile.target                         |    5 +-
 bsd-user/Makefile.objs                  |    6 +-
 bsd-user/arm/syscall.h                  |   36 +
 bsd-user/arm/target_arch.h              |   10 +
 bsd-user/arm/target_arch_cpu.c          |   27 +
 bsd-user/arm/target_arch_cpu.h          |  375 ++++++
 bsd-user/arm/target_arch_elf.h          |   54 +
 bsd-user/arm/target_arch_signal.h       |  257 +++++
 bsd-user/arm/target_arch_sigtramp.h     |   33 +
 bsd-user/arm/target_arch_sysarch.h      |   78 ++
 bsd-user/arm/target_arch_thread.h       |   67 ++
 bsd-user/arm/target_arch_vmparam.h      |   48 +
 bsd-user/bsd-file.h                     | 1111 ++++++++++++++++++
 bsd-user/bsd-ioctl.c                    |  448 ++++++++
 bsd-user/bsd-ioctl.h                    |   27 +
 bsd-user/bsd-mem.c                      |  122 ++
 bsd-user/bsd-mem.h                      |  393 +++++++
 bsd-user/bsd-misc.c                     |  209 ++++
 bsd-user/bsd-misc.h                     |  339 ++++++
 bsd-user/bsd-proc.c                     |  160 +++
 bsd-user/bsd-proc.h                     |  434 +++++++
 bsd-user/bsd-signal.h                   |  232 ++++
 bsd-user/bsd-socket.c                   |  108 ++
 bsd-user/bsd-socket.h                   |  266 +++++
 bsd-user/bsdload.c                      |  170 ++-
 bsd-user/elfload.c                      |  956 ++++-------------
 bsd-user/errno_defs.h                   |   13 +-
 bsd-user/freebsd/host_os.h              |   46 +
 bsd-user/freebsd/os-extattr.c           |  118 ++
 bsd-user/freebsd/os-extattr.h           |  654 +++++++++++
 bsd-user/freebsd/os-ioctl-cmds.h        |   47 +
 bsd-user/freebsd/os-ioctl-filio.h       |   45 +
 bsd-user/freebsd/os-ioctl-ioccom.h      |   54 +
 bsd-user/freebsd/os-ioctl-ttycom.h      |  257 +++++
 bsd-user/freebsd/os-ioctl-types.h       |    7 +
 bsd-user/freebsd/os-misc.h              |  442 ++++++++
 bsd-user/freebsd/os-proc.c              |  309 +++++
 bsd-user/freebsd/os-proc.h              |  428 +++++++
 bsd-user/freebsd/os-signal.h            |   43 +
 bsd-user/freebsd/os-socket.c            |  149 +++
 bsd-user/freebsd/os-socket.h            |  548 +++++++++
 bsd-user/freebsd/os-stat.c              |  234 ++++
 bsd-user/freebsd/os-stat.h              |  437 +++++++
 bsd-user/freebsd/os-strace.h            |   29 +
 bsd-user/freebsd/os-sys.c               |  284 +++++
 bsd-user/freebsd/os-thread.c            | 1001 ++++++++++++++++
 bsd-user/freebsd/os-thread.h            |  511 +++++++++
 bsd-user/freebsd/os-time.c              |  205 ++++
 bsd-user/freebsd/os-time.h              |  643 +++++++++++
 bsd-user/freebsd/qemu-os.h              |   79 ++
 bsd-user/freebsd/strace.list            |   76 ++-
 bsd-user/freebsd/syscall_nr.h           |  813 ++++++++------
 bsd-user/freebsd/target_os_elf.h        |  145 +++
 bsd-user/freebsd/target_os_siginfo.h    |  110 ++
 bsd-user/freebsd/target_os_signal.h     |   79 ++
 bsd-user/freebsd/target_os_stack.h      |  157 +++
 bsd-user/freebsd/target_os_thread.h     |    6 +
 bsd-user/freebsd/target_os_vmparam.h    |   23 +
 bsd-user/i386/syscall.h                 |   23 +
 bsd-user/i386/target_arch.h             |   13 +
 bsd-user/i386/target_arch_cpu.c         |   79 ++
 bsd-user/i386/target_arch_cpu.h         |  302 +++++
 bsd-user/i386/target_arch_elf.h         |   62 +
 bsd-user/i386/target_arch_signal.h      |   94 ++
 bsd-user/i386/target_arch_sigtramp.h    |   11 +
 bsd-user/i386/target_arch_sysarch.h     |   78 ++
 bsd-user/i386/target_arch_thread.h      |   45 +
 bsd-user/i386/target_arch_vmparam.h     |   28 +
 bsd-user/i386/target_signal.h           |    6 -
 bsd-user/main.c                         |  927 +++------------
 bsd-user/mips/syscall.h                 |   52 +
 bsd-user/mips/target_arch.h             |   10 +
 bsd-user/mips/target_arch_cpu.c         |   27 +
 bsd-user/mips/target_arch_cpu.h         |  257 +++++
 bsd-user/mips/target_arch_elf.h         |   36 +
 bsd-user/mips/target_arch_signal.h      |  237 ++++
 bsd-user/mips/target_arch_sigtramp.h    |   23 +
 bsd-user/mips/target_arch_sysarch.h     |   69 ++
 bsd-user/mips/target_arch_thread.h      |   54 +
 bsd-user/mips/target_arch_vmparam.h     |   50 +
 bsd-user/mips64/syscall.h               |   53 +
 bsd-user/mips64/target_arch.h           |   10 +
 bsd-user/mips64/target_arch_cpu.c       |   27 +
 bsd-user/mips64/target_arch_cpu.h       |  243 ++++
 bsd-user/mips64/target_arch_elf.h       |   36 +
 bsd-user/mips64/target_arch_signal.h    |  214 ++++
 bsd-user/mips64/target_arch_sigtramp.h  |   23 +
 bsd-user/mips64/target_arch_sysarch.h   |   69 ++
 bsd-user/mips64/target_arch_thread.h    |   54 +
 bsd-user/mips64/target_arch_vmparam.h   |   47 +
 bsd-user/mmap.c                         |  178 ++--
 bsd-user/netbsd/host_os.h               |   31 +
 bsd-user/netbsd/os-extattr.h            |  247 ++++
 bsd-user/netbsd/os-ioctl-cmds.h         |   48 +
 bsd-user/netbsd/os-ioctl-filio.h        |   29 +
 bsd-user/netbsd/os-ioctl-ioccom.h       |   38 +
 bsd-user/netbsd/os-ioctl-ttycom.h       |  240 ++++
 bsd-user/netbsd/os-ioctl-types.h        |    7 +
 bsd-user/netbsd/os-misc.h               |  375 ++++++
 bsd-user/netbsd/os-proc.c               |   11 +
 bsd-user/netbsd/os-proc.h               |  243 ++++
 bsd-user/netbsd/os-socket.c             |    1 +
 bsd-user/netbsd/os-socket.h             |   98 ++
 bsd-user/netbsd/os-stat.c               |    1 +
 bsd-user/netbsd/os-stat.h               |    1 +
 bsd-user/netbsd/os-strace.h             |    1 +
 bsd-user/netbsd/os-sys.c                |   46 +
 bsd-user/netbsd/os-thread.c             |    1 +
 bsd-user/netbsd/os-thread.h             |  133 +++
 bsd-user/netbsd/os-time.c               |    1 +
 bsd-user/netbsd/os-time.h               |  179 +++
 bsd-user/netbsd/qemu-os.h               |    1 +
 bsd-user/netbsd/target_os_elf.h         |  226 ++++
 bsd-user/netbsd/target_os_siginfo.h     |   82 ++
 bsd-user/netbsd/target_os_signal.h      |   70 ++
 bsd-user/netbsd/target_os_stack.h       |   33 +
 bsd-user/netbsd/target_os_thread.h      |    6 +
 bsd-user/openbsd/host_os.h              |   31 +
 bsd-user/openbsd/os-extattr.h           |  247 ++++
 bsd-user/openbsd/os-ioctl-cmds.h        |   48 +
 bsd-user/openbsd/os-ioctl-filio.h       |   29 +
 bsd-user/openbsd/os-ioctl-ioccom.h      |   38 +
 bsd-user/openbsd/os-ioctl-ttycom.h      |  240 ++++
 bsd-user/openbsd/os-ioctl-types.h       |    7 +
 bsd-user/openbsd/os-misc.h              |  375 ++++++
 bsd-user/openbsd/os-proc.c              |   11 +
 bsd-user/openbsd/os-proc.h              |  243 ++++
 bsd-user/openbsd/os-socket.c            |    1 +
 bsd-user/openbsd/os-socket.h            |   98 ++
 bsd-user/openbsd/os-stat.c              |    1 +
 bsd-user/openbsd/os-stat.h              |  176 +++
 bsd-user/openbsd/os-strace.h            |    1 +
 bsd-user/openbsd/os-sys.c               |   46 +
 bsd-user/openbsd/os-thread.c            |    1 +
 bsd-user/openbsd/os-thread.h            |  133 +++
 bsd-user/openbsd/os-time.c              |    1 +
 bsd-user/openbsd/os-time.h              |  179 +++
 bsd-user/openbsd/qemu-os.h              |    1 +
 bsd-user/openbsd/target_os_elf.h        |  226 ++++
 bsd-user/openbsd/target_os_siginfo.h    |   82 ++
 bsd-user/openbsd/target_os_signal.h     |   70 ++
 bsd-user/openbsd/target_os_stack.h      |   33 +
 bsd-user/openbsd/target_os_thread.h     |    6 +
 bsd-user/qemu-bsd.h                     |   79 ++
 bsd-user/qemu.h                         |  202 +++-
 bsd-user/signal.c                       |  907 +++++++++++++++-
 bsd-user/sparc/syscall.h                |   29 +-
 bsd-user/sparc/target_arch.h            |   11 +
 bsd-user/sparc/target_arch_cpu.c        |  113 ++
 bsd-user/sparc/target_arch_cpu.h        |  158 +++
 bsd-user/sparc/target_arch_elf.h        |   30 +
 bsd-user/sparc/target_arch_signal.h     |   77 ++
 bsd-user/sparc/target_arch_sigtramp.h   |   11 +
 bsd-user/sparc/target_arch_sysarch.h    |   52 +
 bsd-user/sparc/target_arch_thread.h     |   39 +
 bsd-user/sparc/target_arch_vmparam.h    |   37 +
 bsd-user/sparc/target_signal.h          |    5 -
 bsd-user/sparc64/syscall.h              |   28 +-
 bsd-user/sparc64/target_arch.h          |   11 +
 bsd-user/sparc64/target_arch_cpu.c      |  118 ++
 bsd-user/sparc64/target_arch_cpu.h      |  191 ++++
 bsd-user/sparc64/target_arch_elf.h      |   34 +
 bsd-user/sparc64/target_arch_signal.h   |   94 ++
 bsd-user/sparc64/target_arch_sigtramp.h |   11 +
 bsd-user/sparc64/target_arch_sysarch.h  |   52 +
 bsd-user/sparc64/target_arch_thread.h   |   55 +
 bsd-user/sparc64/target_arch_vmparam.h  |   37 +
 bsd-user/sparc64/target_signal.h        |    5 -
 bsd-user/strace.c                       |  175 ++-
 bsd-user/syscall.c                      | 1884 ++++++++++++++++++++++++-------
 bsd-user/syscall_defs.h                 |  860 +++++++++++++--
 bsd-user/x86_64/syscall.h               |   26 +-
 bsd-user/x86_64/target_arch.h           |   13 +
 bsd-user/x86_64/target_arch_cpu.c       |   79 ++
 bsd-user/x86_64/target_arch_cpu.h       |  324 ++++++
 bsd-user/x86_64/target_arch_elf.h       |   55 +
 bsd-user/x86_64/target_arch_signal.h    |   94 ++
 bsd-user/x86_64/target_arch_sigtramp.h  |   11 +
 bsd-user/x86_64/target_arch_sysarch.h   |   76 ++
 bsd-user/x86_64/target_arch_thread.h    |   40 +
 bsd-user/x86_64/target_arch_vmparam.h   |   28 +
 bsd-user/x86_64/target_signal.h         |    5 -
 configure                               |   11 +
 default-configs/arm-bsd-user.mak        |    3 +
 default-configs/mips-bsd-user.mak       |    1 +
 default-configs/mips64-bsd-user.mak     |    1 +
 default-configs/mips64el-bsd-user.mak   |    1 +
 default-configs/mipsel-bsd-user.mak     |    1 +
 include/qemu/aes.h                      |    9 +
 include/qemu/tls.h                      |    2 +-
 190 files changed, 25306 insertions(+), 2652 deletions(-)
 create mode 100644 bsd-user/arm/syscall.h
 create mode 100644 bsd-user/arm/target_arch.h
 create mode 100644 bsd-user/arm/target_arch_cpu.c
 create mode 100644 bsd-user/arm/target_arch_cpu.h
 create mode 100644 bsd-user/arm/target_arch_elf.h
 create mode 100644 bsd-user/arm/target_arch_signal.h
 create mode 100644 bsd-user/arm/target_arch_sigtramp.h
 create mode 100644 bsd-user/arm/target_arch_sysarch.h
 create mode 100644 bsd-user/arm/target_arch_thread.h
 create mode 100644 bsd-user/arm/target_arch_vmparam.h
 create mode 100644 bsd-user/bsd-file.h
 create mode 100644 bsd-user/bsd-ioctl.c
 create mode 100644 bsd-user/bsd-ioctl.h
 create mode 100644 bsd-user/bsd-mem.c
 create mode 100644 bsd-user/bsd-mem.h
 create mode 100644 bsd-user/bsd-misc.c
 create mode 100644 bsd-user/bsd-misc.h
 create mode 100644 bsd-user/bsd-proc.c
 create mode 100644 bsd-user/bsd-proc.h
 create mode 100644 bsd-user/bsd-signal.h
 create mode 100644 bsd-user/bsd-socket.c
 create mode 100644 bsd-user/bsd-socket.h
 create mode 100644 bsd-user/freebsd/host_os.h
 create mode 100644 bsd-user/freebsd/os-extattr.c
 create mode 100644 bsd-user/freebsd/os-extattr.h
 create mode 100644 bsd-user/freebsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/freebsd/os-ioctl-filio.h
 create mode 100644 bsd-user/freebsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/freebsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/freebsd/os-ioctl-types.h
 create mode 100644 bsd-user/freebsd/os-misc.h
 create mode 100644 bsd-user/freebsd/os-proc.c
 create mode 100644 bsd-user/freebsd/os-proc.h
 create mode 100644 bsd-user/freebsd/os-signal.h
 create mode 100644 bsd-user/freebsd/os-socket.c
 create mode 100644 bsd-user/freebsd/os-socket.h
 create mode 100644 bsd-user/freebsd/os-stat.c
 create mode 100644 bsd-user/freebsd/os-stat.h
 create mode 100644 bsd-user/freebsd/os-strace.h
 create mode 100644 bsd-user/freebsd/os-sys.c
 create mode 100644 bsd-user/freebsd/os-thread.c
 create mode 100644 bsd-user/freebsd/os-thread.h
 create mode 100644 bsd-user/freebsd/os-time.c
 create mode 100644 bsd-user/freebsd/os-time.h
 create mode 100644 bsd-user/freebsd/qemu-os.h
 create mode 100644 bsd-user/freebsd/target_os_elf.h
 create mode 100644 bsd-user/freebsd/target_os_siginfo.h
 create mode 100644 bsd-user/freebsd/target_os_signal.h
 create mode 100644 bsd-user/freebsd/target_os_stack.h
 create mode 100644 bsd-user/freebsd/target_os_thread.h
 create mode 100644 bsd-user/freebsd/target_os_vmparam.h
 create mode 100644 bsd-user/i386/target_arch.h
 create mode 100644 bsd-user/i386/target_arch_cpu.c
 create mode 100644 bsd-user/i386/target_arch_cpu.h
 create mode 100644 bsd-user/i386/target_arch_elf.h
 create mode 100644 bsd-user/i386/target_arch_signal.h
 create mode 100644 bsd-user/i386/target_arch_sigtramp.h
 create mode 100644 bsd-user/i386/target_arch_sysarch.h
 create mode 100644 bsd-user/i386/target_arch_thread.h
 create mode 100644 bsd-user/i386/target_arch_vmparam.h
 create mode 100644 bsd-user/mips/syscall.h
 create mode 100644 bsd-user/mips/target_arch.h
 create mode 100644 bsd-user/mips/target_arch_cpu.c
 create mode 100644 bsd-user/mips/target_arch_cpu.h
 create mode 100644 bsd-user/mips/target_arch_elf.h
 create mode 100644 bsd-user/mips/target_arch_signal.h
 create mode 100644 bsd-user/mips/target_arch_sigtramp.h
 create mode 100644 bsd-user/mips/target_arch_sysarch.h
 create mode 100644 bsd-user/mips/target_arch_thread.h
 create mode 100644 bsd-user/mips/target_arch_vmparam.h
 create mode 100644 bsd-user/mips64/syscall.h
 create mode 100644 bsd-user/mips64/target_arch.h
 create mode 100644 bsd-user/mips64/target_arch_cpu.c
 create mode 100644 bsd-user/mips64/target_arch_cpu.h
 create mode 100644 bsd-user/mips64/target_arch_elf.h
 create mode 100644 bsd-user/mips64/target_arch_signal.h
 create mode 100644 bsd-user/mips64/target_arch_sigtramp.h
 create mode 100644 bsd-user/mips64/target_arch_sysarch.h
 create mode 100644 bsd-user/mips64/target_arch_thread.h
 create mode 100644 bsd-user/mips64/target_arch_vmparam.h
 create mode 100644 bsd-user/netbsd/host_os.h
 create mode 100644 bsd-user/netbsd/os-extattr.h
 create mode 100644 bsd-user/netbsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/netbsd/os-ioctl-filio.h
 create mode 100644 bsd-user/netbsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/netbsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/netbsd/os-ioctl-types.h
 create mode 100644 bsd-user/netbsd/os-misc.h
 create mode 100644 bsd-user/netbsd/os-proc.c
 create mode 100644 bsd-user/netbsd/os-proc.h
 create mode 100644 bsd-user/netbsd/os-socket.c
 create mode 100644 bsd-user/netbsd/os-socket.h
 create mode 100644 bsd-user/netbsd/os-stat.c
 create mode 100644 bsd-user/netbsd/os-stat.h
 create mode 100644 bsd-user/netbsd/os-strace.h
 create mode 100644 bsd-user/netbsd/os-sys.c
 create mode 100644 bsd-user/netbsd/os-thread.c
 create mode 100644 bsd-user/netbsd/os-thread.h
 create mode 100644 bsd-user/netbsd/os-time.c
 create mode 100644 bsd-user/netbsd/os-time.h
 create mode 100644 bsd-user/netbsd/qemu-os.h
 create mode 100644 bsd-user/netbsd/target_os_elf.h
 create mode 100644 bsd-user/netbsd/target_os_siginfo.h
 create mode 100644 bsd-user/netbsd/target_os_signal.h
 create mode 100644 bsd-user/netbsd/target_os_stack.h
 create mode 100644 bsd-user/netbsd/target_os_thread.h
 create mode 100644 bsd-user/openbsd/host_os.h
 create mode 100644 bsd-user/openbsd/os-extattr.h
 create mode 100644 bsd-user/openbsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/openbsd/os-ioctl-filio.h
 create mode 100644 bsd-user/openbsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/openbsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/openbsd/os-ioctl-types.h
 create mode 100644 bsd-user/openbsd/os-misc.h
 create mode 100644 bsd-user/openbsd/os-proc.c
 create mode 100644 bsd-user/openbsd/os-proc.h
 create mode 100644 bsd-user/openbsd/os-socket.c
 create mode 100644 bsd-user/openbsd/os-socket.h
 create mode 100644 bsd-user/openbsd/os-stat.c
 create mode 100644 bsd-user/openbsd/os-stat.h
 create mode 100644 bsd-user/openbsd/os-strace.h
 create mode 100644 bsd-user/openbsd/os-sys.c
 create mode 100644 bsd-user/openbsd/os-thread.c
 create mode 100644 bsd-user/openbsd/os-thread.h
 create mode 100644 bsd-user/openbsd/os-time.c
 create mode 100644 bsd-user/openbsd/os-time.h
 create mode 100644 bsd-user/openbsd/qemu-os.h
 create mode 100644 bsd-user/openbsd/target_os_elf.h
 create mode 100644 bsd-user/openbsd/target_os_siginfo.h
 create mode 100644 bsd-user/openbsd/target_os_signal.h
 create mode 100644 bsd-user/openbsd/target_os_stack.h
 create mode 100644 bsd-user/openbsd/target_os_thread.h
 create mode 100644 bsd-user/qemu-bsd.h
 create mode 100644 bsd-user/sparc/target_arch.h
 create mode 100644 bsd-user/sparc/target_arch_cpu.c
 create mode 100644 bsd-user/sparc/target_arch_cpu.h
 create mode 100644 bsd-user/sparc/target_arch_elf.h
 create mode 100644 bsd-user/sparc/target_arch_signal.h
 create mode 100644 bsd-user/sparc/target_arch_sigtramp.h
 create mode 100644 bsd-user/sparc/target_arch_sysarch.h
 create mode 100644 bsd-user/sparc/target_arch_thread.h
 create mode 100644 bsd-user/sparc/target_arch_vmparam.h
 create mode 100644 bsd-user/sparc64/target_arch.h
 create mode 100644 bsd-user/sparc64/target_arch_cpu.c
 create mode 100644 bsd-user/sparc64/target_arch_cpu.h
 create mode 100644 bsd-user/sparc64/target_arch_elf.h
 create mode 100644 bsd-user/sparc64/target_arch_signal.h
 create mode 100644 bsd-user/sparc64/target_arch_sigtramp.h
 create mode 100644 bsd-user/sparc64/target_arch_sysarch.h
 create mode 100644 bsd-user/sparc64/target_arch_thread.h
 create mode 100644 bsd-user/sparc64/target_arch_vmparam.h
 create mode 100644 bsd-user/x86_64/target_arch.h
 create mode 100644 bsd-user/x86_64/target_arch_cpu.c
 create mode 100644 bsd-user/x86_64/target_arch_cpu.h
 create mode 100644 bsd-user/x86_64/target_arch_elf.h
 create mode 100644 bsd-user/x86_64/target_arch_signal.h
 create mode 100644 bsd-user/x86_64/target_arch_sigtramp.h
 create mode 100644 bsd-user/x86_64/target_arch_sysarch.h
 create mode 100644 bsd-user/x86_64/target_arch_thread.h
 create mode 100644 bsd-user/x86_64/target_arch_vmparam.h
 create mode 100644 default-configs/arm-bsd-user.mak
 create mode 100644 default-configs/mips-bsd-user.mak
 create mode 100644 default-configs/mips64-bsd-user.mak
 create mode 100644 default-configs/mips64el-bsd-user.mak
 create mode 100644 default-configs/mipsel-bsd-user.mak

-- 
1.7.8

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 01/19] bsd-user: refresh freebsd system call numbers
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
  2013-11-26 21:01   ` Ed Maste
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 " Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2014-01-27 19:30     ` Peter Maydell
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 02/19] bsd-user: add HOST_VARIANT_DIR for various *BSD dependent code Stacey Son
                     ` (17 subsequent siblings)
  20 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

Update FreeBSD system call numbers in freebsd/syscall_nr.h.

Reviewed-by: Ed Maste <emaste@freebsd.org>
---
 bsd-user/freebsd/syscall_nr.h |  813 ++++++++++++++++++++++-------------------
 1 files changed, 445 insertions(+), 368 deletions(-)

diff --git a/bsd-user/freebsd/syscall_nr.h b/bsd-user/freebsd/syscall_nr.h
index 36336ab..d849024 100644
--- a/bsd-user/freebsd/syscall_nr.h
+++ b/bsd-user/freebsd/syscall_nr.h
@@ -1,373 +1,450 @@
 /*
  * System call numbers.
  *
- * $FreeBSD: src/sys/sys/syscall.h,v 1.224 2008/08/24 21:23:08 rwatson Exp $
- * created from FreeBSD: head/sys/kern/syscalls.master 182123 2008-08-24 21:20:35Z rwatson
+ * created from FreeBSD: releng/9.1/sys/kern/syscalls.master 229723
+ * 2012-01-06 19:29:16Z jhb
  */
 
-#define TARGET_FREEBSD_NR_syscall     0
-#define TARGET_FREEBSD_NR_exit        1
-#define TARGET_FREEBSD_NR_fork        2
-#define TARGET_FREEBSD_NR_read        3
-#define TARGET_FREEBSD_NR_write       4
-#define TARGET_FREEBSD_NR_open        5
-#define TARGET_FREEBSD_NR_close       6
-#define TARGET_FREEBSD_NR_wait4       7
-#define TARGET_FREEBSD_NR_link        9
-#define TARGET_FREEBSD_NR_unlink      10
-#define TARGET_FREEBSD_NR_chdir       12
-#define TARGET_FREEBSD_NR_fchdir      13
-#define TARGET_FREEBSD_NR_mknod       14
-#define TARGET_FREEBSD_NR_chmod       15
-#define TARGET_FREEBSD_NR_chown       16
-#define TARGET_FREEBSD_NR_break       17
-#define TARGET_FREEBSD_NR_freebsd4_getfsstat  18
-#define TARGET_FREEBSD_NR_getpid      20
-#define TARGET_FREEBSD_NR_mount       21
-#define TARGET_FREEBSD_NR_unmount     22
-#define TARGET_FREEBSD_NR_setuid      23
-#define TARGET_FREEBSD_NR_getuid      24
-#define TARGET_FREEBSD_NR_geteuid     25
-#define TARGET_FREEBSD_NR_ptrace      26
-#define TARGET_FREEBSD_NR_recvmsg     27
-#define TARGET_FREEBSD_NR_sendmsg     28
-#define TARGET_FREEBSD_NR_recvfrom    29
-#define TARGET_FREEBSD_NR_accept      30
-#define TARGET_FREEBSD_NR_getpeername 31
-#define TARGET_FREEBSD_NR_getsockname 32
-#define TARGET_FREEBSD_NR_access      33
-#define TARGET_FREEBSD_NR_chflags     34
-#define TARGET_FREEBSD_NR_fchflags    35
-#define TARGET_FREEBSD_NR_sync        36
-#define TARGET_FREEBSD_NR_kill        37
-#define TARGET_FREEBSD_NR_getppid     39
-#define TARGET_FREEBSD_NR_dup 41
-#define TARGET_FREEBSD_NR_pipe        42
-#define TARGET_FREEBSD_NR_getegid     43
-#define TARGET_FREEBSD_NR_profil      44
-#define TARGET_FREEBSD_NR_ktrace      45
-#define TARGET_FREEBSD_NR_getgid      47
-#define TARGET_FREEBSD_NR_getlogin    49
-#define TARGET_FREEBSD_NR_setlogin    50
-#define TARGET_FREEBSD_NR_acct        51
-#define TARGET_FREEBSD_NR_sigaltstack 53
-#define TARGET_FREEBSD_NR_ioctl       54
-#define TARGET_FREEBSD_NR_reboot      55
-#define TARGET_FREEBSD_NR_revoke      56
-#define TARGET_FREEBSD_NR_symlink     57
-#define TARGET_FREEBSD_NR_readlink    58
-#define TARGET_FREEBSD_NR_execve      59
-#define TARGET_FREEBSD_NR_umask       60
-#define TARGET_FREEBSD_NR_chroot      61
-#define TARGET_FREEBSD_NR_msync       65
-#define TARGET_FREEBSD_NR_vfork       66
-#define TARGET_FREEBSD_NR_sbrk        69
-#define TARGET_FREEBSD_NR_sstk        70
-#define TARGET_FREEBSD_NR_vadvise     72
-#define TARGET_FREEBSD_NR_munmap      73
-#define TARGET_FREEBSD_NR_mprotect    74
-#define TARGET_FREEBSD_NR_madvise     75
-#define TARGET_FREEBSD_NR_mincore     78
-#define TARGET_FREEBSD_NR_getgroups   79
-#define TARGET_FREEBSD_NR_setgroups   80
-#define TARGET_FREEBSD_NR_getpgrp     81
-#define TARGET_FREEBSD_NR_setpgid     82
-#define TARGET_FREEBSD_NR_setitimer   83
-#define TARGET_FREEBSD_NR_swapon      85
-#define TARGET_FREEBSD_NR_getitimer   86
-#define TARGET_FREEBSD_NR_getdtablesize       89
-#define TARGET_FREEBSD_NR_dup2        90
-#define TARGET_FREEBSD_NR_fcntl       92
-#define TARGET_FREEBSD_NR_select      93
-#define TARGET_FREEBSD_NR_fsync       95
-#define TARGET_FREEBSD_NR_setpriority 96
-#define TARGET_FREEBSD_NR_socket      97
-#define TARGET_FREEBSD_NR_connect     98
-#define TARGET_FREEBSD_NR_getpriority 100
-#define TARGET_FREEBSD_NR_bind        104
-#define TARGET_FREEBSD_NR_setsockopt  105
-#define TARGET_FREEBSD_NR_listen      106
-#define TARGET_FREEBSD_NR_gettimeofday        116
-#define TARGET_FREEBSD_NR_getrusage   117
-#define TARGET_FREEBSD_NR_getsockopt  118
-#define TARGET_FREEBSD_NR_readv       120
-#define TARGET_FREEBSD_NR_writev      121
-#define TARGET_FREEBSD_NR_settimeofday        122
-#define TARGET_FREEBSD_NR_fchown      123
-#define TARGET_FREEBSD_NR_fchmod      124
-#define TARGET_FREEBSD_NR_setreuid    126
-#define TARGET_FREEBSD_NR_setregid    127
-#define TARGET_FREEBSD_NR_rename      128
-#define TARGET_FREEBSD_NR_flock       131
-#define TARGET_FREEBSD_NR_mkfifo      132
-#define TARGET_FREEBSD_NR_sendto      133
-#define TARGET_FREEBSD_NR_shutdown    134
-#define TARGET_FREEBSD_NR_socketpair  135
-#define TARGET_FREEBSD_NR_mkdir       136
-#define TARGET_FREEBSD_NR_rmdir       137
-#define TARGET_FREEBSD_NR_utimes      138
-#define TARGET_FREEBSD_NR_adjtime     140
-#define TARGET_FREEBSD_NR_setsid      147
-#define TARGET_FREEBSD_NR_quotactl    148
-#define TARGET_FREEBSD_NR_nlm_syscall 154
-#define TARGET_FREEBSD_NR_nfssvc      155
-#define TARGET_FREEBSD_NR_freebsd4_statfs     157
-#define TARGET_FREEBSD_NR_freebsd4_fstatfs    158
-#define TARGET_FREEBSD_NR_lgetfh      160
-#define TARGET_FREEBSD_NR_getfh       161
-#define TARGET_FREEBSD_NR_getdomainname       162
-#define TARGET_FREEBSD_NR_setdomainname       163
-#define TARGET_FREEBSD_NR_uname       164
-#define TARGET_FREEBSD_NR_sysarch     165
-#define TARGET_FREEBSD_NR_rtprio      166
-#define TARGET_FREEBSD_NR_semsys      169
-#define TARGET_FREEBSD_NR_msgsys      170
-#define TARGET_FREEBSD_NR_shmsys      171
-#define TARGET_FREEBSD_NR_freebsd6_pread      173
-#define TARGET_FREEBSD_NR_freebsd6_pwrite     174
-#define TARGET_FREEBSD_NR_setfib      175
-#define TARGET_FREEBSD_NR_ntp_adjtime 176
-#define TARGET_FREEBSD_NR_setgid      181
-#define TARGET_FREEBSD_NR_setegid     182
-#define TARGET_FREEBSD_NR_seteuid     183
-#define TARGET_FREEBSD_NR_stat        188
-#define TARGET_FREEBSD_NR_fstat       189
-#define TARGET_FREEBSD_NR_lstat       190
-#define TARGET_FREEBSD_NR_pathconf    191
-#define TARGET_FREEBSD_NR_fpathconf   192
-#define TARGET_FREEBSD_NR_getrlimit   194
-#define TARGET_FREEBSD_NR_setrlimit   195
-#define TARGET_FREEBSD_NR_getdirentries       196
-#define TARGET_FREEBSD_NR_freebsd6_mmap       197
-#define TARGET_FREEBSD_NR___syscall   198
-#define TARGET_FREEBSD_NR_freebsd6_lseek      199
-#define TARGET_FREEBSD_NR_freebsd6_truncate   200
-#define TARGET_FREEBSD_NR_freebsd6_ftruncate  201
-#define TARGET_FREEBSD_NR___sysctl    202
-#define TARGET_FREEBSD_NR_mlock       203
-#define TARGET_FREEBSD_NR_munlock     204
-#define TARGET_FREEBSD_NR_undelete    205
-#define TARGET_FREEBSD_NR_futimes     206
-#define TARGET_FREEBSD_NR_getpgid     207
-#define TARGET_FREEBSD_NR_poll        209
-#define TARGET_FREEBSD_NR___semctl    220
-#define TARGET_FREEBSD_NR_semget      221
-#define TARGET_FREEBSD_NR_semop       222
-#define TARGET_FREEBSD_NR_msgctl      224
-#define TARGET_FREEBSD_NR_msgget      225
-#define TARGET_FREEBSD_NR_msgsnd      226
-#define TARGET_FREEBSD_NR_msgrcv      227
-#define TARGET_FREEBSD_NR_shmat       228
-#define TARGET_FREEBSD_NR_shmctl      229
-#define TARGET_FREEBSD_NR_shmdt       230
-#define TARGET_FREEBSD_NR_shmget      231
-#define TARGET_FREEBSD_NR_clock_gettime       232
-#define TARGET_FREEBSD_NR_clock_settime       233
-#define TARGET_FREEBSD_NR_clock_getres        234
-#define TARGET_FREEBSD_NR_ktimer_create       235
-#define TARGET_FREEBSD_NR_ktimer_delete       236
-#define TARGET_FREEBSD_NR_ktimer_settime      237
-#define TARGET_FREEBSD_NR_ktimer_gettime      238
-#define TARGET_FREEBSD_NR_ktimer_getoverrun   239
-#define TARGET_FREEBSD_NR_nanosleep   240
-#define TARGET_FREEBSD_NR_ntp_gettime 248
-#define TARGET_FREEBSD_NR_minherit    250
-#define TARGET_FREEBSD_NR_rfork       251
-#define TARGET_FREEBSD_NR_openbsd_poll        252
-#define TARGET_FREEBSD_NR_issetugid   253
-#define TARGET_FREEBSD_NR_lchown      254
-#define TARGET_FREEBSD_NR_aio_read    255
-#define TARGET_FREEBSD_NR_aio_write   256
-#define TARGET_FREEBSD_NR_lio_listio  257
-#define TARGET_FREEBSD_NR_getdents    272
-#define TARGET_FREEBSD_NR_lchmod      274
-#define TARGET_FREEBSD_NR_netbsd_lchown       275
-#define TARGET_FREEBSD_NR_lutimes     276
-#define TARGET_FREEBSD_NR_netbsd_msync        277
-#define TARGET_FREEBSD_NR_nstat       278
-#define TARGET_FREEBSD_NR_nfstat      279
-#define TARGET_FREEBSD_NR_nlstat      280
-#define TARGET_FREEBSD_NR_preadv      289
-#define TARGET_FREEBSD_NR_pwritev     290
-#define TARGET_FREEBSD_NR_freebsd4_fhstatfs   297
-#define TARGET_FREEBSD_NR_fhopen      298
-#define TARGET_FREEBSD_NR_fhstat      299
-#define TARGET_FREEBSD_NR_modnext     300
-#define TARGET_FREEBSD_NR_modstat     301
-#define TARGET_FREEBSD_NR_modfnext    302
-#define TARGET_FREEBSD_NR_modfind     303
-#define TARGET_FREEBSD_NR_kldload     304
-#define TARGET_FREEBSD_NR_kldunload   305
-#define TARGET_FREEBSD_NR_kldfind     306
-#define TARGET_FREEBSD_NR_kldnext     307
-#define TARGET_FREEBSD_NR_kldstat     308
-#define TARGET_FREEBSD_NR_kldfirstmod 309
-#define TARGET_FREEBSD_NR_getsid      310
-#define TARGET_FREEBSD_NR_setresuid   311
-#define TARGET_FREEBSD_NR_setresgid   312
-#define TARGET_FREEBSD_NR_aio_return  314
-#define TARGET_FREEBSD_NR_aio_suspend 315
-#define TARGET_FREEBSD_NR_aio_cancel  316
-#define TARGET_FREEBSD_NR_aio_error   317
-#define TARGET_FREEBSD_NR_oaio_read   318
-#define TARGET_FREEBSD_NR_oaio_write  319
-#define TARGET_FREEBSD_NR_olio_listio 320
-#define TARGET_FREEBSD_NR_yield       321
-#define TARGET_FREEBSD_NR_mlockall    324
-#define TARGET_FREEBSD_NR_munlockall  325
-#define TARGET_FREEBSD_NR___getcwd    326
-#define TARGET_FREEBSD_NR_sched_setparam      327
-#define TARGET_FREEBSD_NR_sched_getparam      328
-#define TARGET_FREEBSD_NR_sched_setscheduler  329
-#define TARGET_FREEBSD_NR_sched_getscheduler  330
-#define TARGET_FREEBSD_NR_sched_yield 331
-#define TARGET_FREEBSD_NR_sched_get_priority_max      332
-#define TARGET_FREEBSD_NR_sched_get_priority_min      333
-#define TARGET_FREEBSD_NR_sched_rr_get_interval       334
-#define TARGET_FREEBSD_NR_utrace      335
-#define TARGET_FREEBSD_NR_freebsd4_sendfile   336
-#define TARGET_FREEBSD_NR_kldsym      337
-#define TARGET_FREEBSD_NR_jail        338
-#define TARGET_FREEBSD_NR_sigprocmask 340
-#define TARGET_FREEBSD_NR_sigsuspend  341
-#define TARGET_FREEBSD_NR_freebsd4_sigaction  342
-#define TARGET_FREEBSD_NR_sigpending  343
-#define TARGET_FREEBSD_NR_freebsd4_sigreturn  344
-#define TARGET_FREEBSD_NR_sigtimedwait        345
-#define TARGET_FREEBSD_NR_sigwaitinfo 346
-#define TARGET_FREEBSD_NR___acl_get_file      347
-#define TARGET_FREEBSD_NR___acl_set_file      348
-#define TARGET_FREEBSD_NR___acl_get_fd        349
-#define TARGET_FREEBSD_NR___acl_set_fd        350
-#define TARGET_FREEBSD_NR___acl_delete_file   351
-#define TARGET_FREEBSD_NR___acl_delete_fd     352
-#define TARGET_FREEBSD_NR___acl_aclcheck_file 353
-#define TARGET_FREEBSD_NR___acl_aclcheck_fd   354
-#define TARGET_FREEBSD_NR_extattrctl  355
-#define TARGET_FREEBSD_NR_extattr_set_file    356
-#define TARGET_FREEBSD_NR_extattr_get_file    357
-#define TARGET_FREEBSD_NR_extattr_delete_file 358
-#define TARGET_FREEBSD_NR_aio_waitcomplete    359
-#define TARGET_FREEBSD_NR_getresuid   360
-#define TARGET_FREEBSD_NR_getresgid   361
-#define TARGET_FREEBSD_NR_kqueue      362
-#define TARGET_FREEBSD_NR_kevent      363
-#define TARGET_FREEBSD_NR_extattr_set_fd      371
-#define TARGET_FREEBSD_NR_extattr_get_fd      372
-#define TARGET_FREEBSD_NR_extattr_delete_fd   373
-#define TARGET_FREEBSD_NR___setugid   374
-#define TARGET_FREEBSD_NR_nfsclnt     375
-#define TARGET_FREEBSD_NR_eaccess     376
-#define TARGET_FREEBSD_NR_nmount      378
-#define TARGET_FREEBSD_NR___mac_get_proc      384
-#define TARGET_FREEBSD_NR___mac_set_proc      385
-#define TARGET_FREEBSD_NR___mac_get_fd        386
-#define TARGET_FREEBSD_NR___mac_get_file      387
-#define TARGET_FREEBSD_NR___mac_set_fd        388
-#define TARGET_FREEBSD_NR___mac_set_file      389
-#define TARGET_FREEBSD_NR_kenv        390
-#define TARGET_FREEBSD_NR_lchflags    391
-#define TARGET_FREEBSD_NR_uuidgen     392
-#define TARGET_FREEBSD_NR_sendfile    393
-#define TARGET_FREEBSD_NR_mac_syscall 394
-#define TARGET_FREEBSD_NR_getfsstat   395
-#define TARGET_FREEBSD_NR_statfs      396
-#define TARGET_FREEBSD_NR_fstatfs     397
-#define TARGET_FREEBSD_NR_fhstatfs    398
-#define TARGET_FREEBSD_NR_ksem_close  400
-#define TARGET_FREEBSD_NR_ksem_post   401
-#define TARGET_FREEBSD_NR_ksem_wait   402
-#define TARGET_FREEBSD_NR_ksem_trywait        403
-#define TARGET_FREEBSD_NR_ksem_init   404
-#define TARGET_FREEBSD_NR_ksem_open   405
-#define TARGET_FREEBSD_NR_ksem_unlink 406
-#define TARGET_FREEBSD_NR_ksem_getvalue       407
-#define TARGET_FREEBSD_NR_ksem_destroy        408
-#define TARGET_FREEBSD_NR___mac_get_pid       409
-#define TARGET_FREEBSD_NR___mac_get_link      410
-#define TARGET_FREEBSD_NR___mac_set_link      411
-#define TARGET_FREEBSD_NR_extattr_set_link    412
-#define TARGET_FREEBSD_NR_extattr_get_link    413
-#define TARGET_FREEBSD_NR_extattr_delete_link 414
-#define TARGET_FREEBSD_NR___mac_execve        415
-#define TARGET_FREEBSD_NR_sigaction   416
-#define TARGET_FREEBSD_NR_sigreturn   417
-#define TARGET_FREEBSD_NR_getcontext  421
-#define TARGET_FREEBSD_NR_setcontext  422
-#define TARGET_FREEBSD_NR_swapcontext 423
-#define TARGET_FREEBSD_NR_swapoff     424
-#define TARGET_FREEBSD_NR___acl_get_link      425
-#define TARGET_FREEBSD_NR___acl_set_link      426
-#define TARGET_FREEBSD_NR___acl_delete_link   427
-#define TARGET_FREEBSD_NR___acl_aclcheck_link 428
-#define TARGET_FREEBSD_NR_sigwait     429
-#define TARGET_FREEBSD_NR_thr_create  430
-#define TARGET_FREEBSD_NR_thr_exit    431
-#define TARGET_FREEBSD_NR_thr_self    432
-#define TARGET_FREEBSD_NR_thr_kill    433
-#define TARGET_FREEBSD_NR__umtx_lock  434
-#define TARGET_FREEBSD_NR__umtx_unlock        435
-#define TARGET_FREEBSD_NR_jail_attach 436
-#define TARGET_FREEBSD_NR_extattr_list_fd     437
-#define TARGET_FREEBSD_NR_extattr_list_file   438
-#define TARGET_FREEBSD_NR_extattr_list_link   439
-#define TARGET_FREEBSD_NR_ksem_timedwait      441
-#define TARGET_FREEBSD_NR_thr_suspend 442
-#define TARGET_FREEBSD_NR_thr_wake    443
-#define TARGET_FREEBSD_NR_kldunloadf  444
-#define TARGET_FREEBSD_NR_audit       445
-#define TARGET_FREEBSD_NR_auditon     446
-#define TARGET_FREEBSD_NR_getauid     447
-#define TARGET_FREEBSD_NR_setauid     448
-#define TARGET_FREEBSD_NR_getaudit    449
-#define TARGET_FREEBSD_NR_setaudit    450
-#define TARGET_FREEBSD_NR_getaudit_addr       451
-#define TARGET_FREEBSD_NR_setaudit_addr       452
-#define TARGET_FREEBSD_NR_auditctl    453
-#define TARGET_FREEBSD_NR__umtx_op    454
-#define TARGET_FREEBSD_NR_thr_new     455
-#define TARGET_FREEBSD_NR_sigqueue    456
-#define TARGET_FREEBSD_NR_kmq_open    457
-#define TARGET_FREEBSD_NR_kmq_setattr 458
-#define TARGET_FREEBSD_NR_kmq_timedreceive    459
-#define TARGET_FREEBSD_NR_kmq_timedsend       460
-#define TARGET_FREEBSD_NR_kmq_notify  461
-#define TARGET_FREEBSD_NR_kmq_unlink  462
-#define TARGET_FREEBSD_NR_abort2      463
-#define TARGET_FREEBSD_NR_thr_set_name        464
-#define TARGET_FREEBSD_NR_aio_fsync   465
-#define TARGET_FREEBSD_NR_rtprio_thread       466
-#define TARGET_FREEBSD_NR_sctp_peeloff        471
-#define TARGET_FREEBSD_NR_sctp_generic_sendmsg        472
-#define TARGET_FREEBSD_NR_sctp_generic_sendmsg_iov    473
-#define TARGET_FREEBSD_NR_sctp_generic_recvmsg        474
-#define TARGET_FREEBSD_NR_pread       475
-#define TARGET_FREEBSD_NR_pwrite      476
-#define TARGET_FREEBSD_NR_mmap        477
-#define TARGET_FREEBSD_NR_lseek       478
-#define TARGET_FREEBSD_NR_truncate    479
-#define TARGET_FREEBSD_NR_ftruncate   480
-#define TARGET_FREEBSD_NR_thr_kill2   481
-#define TARGET_FREEBSD_NR_shm_open    482
-#define TARGET_FREEBSD_NR_shm_unlink  483
-#define TARGET_FREEBSD_NR_cpuset      484
-#define TARGET_FREEBSD_NR_cpuset_setid        485
-#define TARGET_FREEBSD_NR_cpuset_getid        486
-#define TARGET_FREEBSD_NR_cpuset_getaffinity  487
-#define TARGET_FREEBSD_NR_cpuset_setaffinity  488
-#define TARGET_FREEBSD_NR_faccessat   489
-#define TARGET_FREEBSD_NR_fchmodat    490
-#define TARGET_FREEBSD_NR_fchownat    491
-#define TARGET_FREEBSD_NR_fexecve     492
-#define TARGET_FREEBSD_NR_fstatat     493
-#define TARGET_FREEBSD_NR_futimesat   494
-#define TARGET_FREEBSD_NR_linkat      495
-#define TARGET_FREEBSD_NR_mkdirat     496
-#define TARGET_FREEBSD_NR_mkfifoat    497
-#define TARGET_FREEBSD_NR_mknodat     498
-#define TARGET_FREEBSD_NR_openat      499
-#define TARGET_FREEBSD_NR_readlinkat  500
-#define TARGET_FREEBSD_NR_renameat    501
-#define TARGET_FREEBSD_NR_symlinkat   502
-#define TARGET_FREEBSD_NR_unlinkat    503
-#define TARGET_FREEBSD_NR_posix_openpt        504
+#define TARGET_FREEBSD_NR_syscall   0
+#define TARGET_FREEBSD_NR_exit  1
+#define TARGET_FREEBSD_NR_fork  2
+#define TARGET_FREEBSD_NR_read  3
+#define TARGET_FREEBSD_NR_write 4
+#define TARGET_FREEBSD_NR_open  5
+#define TARGET_FREEBSD_NR_close 6
+#define TARGET_FREEBSD_NR_wait4 7
+                /* 8 is old creat */
+#define TARGET_FREEBSD_NR_link  9
+#define TARGET_FREEBSD_NR_unlink    10
+                /* 11 is obsolete execv */
+#define TARGET_FREEBSD_NR_chdir 12
+#define TARGET_FREEBSD_NR_fchdir    13
+#define TARGET_FREEBSD_NR_mknod 14
+#define TARGET_FREEBSD_NR_chmod 15
+#define TARGET_FREEBSD_NR_chown 16
+#define TARGET_FREEBSD_NR_break 17
+#define TARGET_FREEBSD_NR_freebsd4_getfsstat    18
+                /* 19 is old lseek */
+#define TARGET_FREEBSD_NR_getpid    20
+#define TARGET_FREEBSD_NR_mount 21
+#define TARGET_FREEBSD_NR_unmount   22
+#define TARGET_FREEBSD_NR_setuid    23
+#define TARGET_FREEBSD_NR_getuid    24
+#define TARGET_FREEBSD_NR_geteuid   25
+#define TARGET_FREEBSD_NR_ptrace    26
+#define TARGET_FREEBSD_NR_recvmsg   27
+#define TARGET_FREEBSD_NR_sendmsg   28
+#define TARGET_FREEBSD_NR_recvfrom  29
+#define TARGET_FREEBSD_NR_accept    30
+#define TARGET_FREEBSD_NR_getpeername   31
+#define TARGET_FREEBSD_NR_getsockname   32
+#define TARGET_FREEBSD_NR_access    33
+#define TARGET_FREEBSD_NR_chflags   34
+#define TARGET_FREEBSD_NR_fchflags  35
+#define TARGET_FREEBSD_NR_sync  36
+#define TARGET_FREEBSD_NR_kill  37
+                /* 38 is old stat */
+#define TARGET_FREEBSD_NR_getppid   39
+                /* 40 is old lstat */
+#define TARGET_FREEBSD_NR_dup   41
+#define TARGET_FREEBSD_NR_pipe  42
+#define TARGET_FREEBSD_NR_getegid   43
+#define TARGET_FREEBSD_NR_profil    44
+#define TARGET_FREEBSD_NR_ktrace    45
+                /* 46 is old sigaction */
+#define TARGET_FREEBSD_NR_getgid    47
+                /* 48 is old sigprocmask */
+#define TARGET_FREEBSD_NR_getlogin  49
+#define TARGET_FREEBSD_NR_setlogin  50
+#define TARGET_FREEBSD_NR_acct  51
+                /* 52 is old sigpending */
+#define TARGET_FREEBSD_NR_sigaltstack   53
+#define TARGET_FREEBSD_NR_ioctl 54
+#define TARGET_FREEBSD_NR_reboot    55
+#define TARGET_FREEBSD_NR_revoke    56
+#define TARGET_FREEBSD_NR_symlink   57
+#define TARGET_FREEBSD_NR_readlink  58
+#define TARGET_FREEBSD_NR_execve    59
+#define TARGET_FREEBSD_NR_umask 60
+#define TARGET_FREEBSD_NR_chroot    61
+                /* 62 is old fstat */
+                /* 63 is old getkerninfo */
+                /* 64 is old getpagesize */
+#define TARGET_FREEBSD_NR_msync 65
+#define TARGET_FREEBSD_NR_vfork 66
+                /* 67 is obsolete vread */
+                /* 68 is obsolete vwrite */
+#define TARGET_FREEBSD_NR_sbrk  69
+#define TARGET_FREEBSD_NR_sstk  70
+                /* 71 is old mmap */
+#define TARGET_FREEBSD_NR_vadvise   72
+#define TARGET_FREEBSD_NR_munmap    73
+#define TARGET_FREEBSD_NR_mprotect  74
+#define TARGET_FREEBSD_NR_madvise   75
+                /* 76 is obsolete vhangup */
+                /* 77 is obsolete vlimit */
+#define TARGET_FREEBSD_NR_mincore   78
+#define TARGET_FREEBSD_NR_getgroups 79
+#define TARGET_FREEBSD_NR_setgroups 80
+#define TARGET_FREEBSD_NR_getpgrp   81
+#define TARGET_FREEBSD_NR_setpgid   82
+#define TARGET_FREEBSD_NR_setitimer 83
+                /* 84 is old wait */
+#define TARGET_FREEBSD_NR_swapon    85
+#define TARGET_FREEBSD_NR_getitimer 86
+                /* 87 is old gethostname */
+                /* 88 is old sethostname */
+#define TARGET_FREEBSD_NR_getdtablesize 89
+#define TARGET_FREEBSD_NR_dup2  90
+#define TARGET_FREEBSD_NR_fcntl 92
+#define TARGET_FREEBSD_NR_select    93
+#define TARGET_FREEBSD_NR_fsync 95
+#define TARGET_FREEBSD_NR_setpriority   96
+#define TARGET_FREEBSD_NR_socket    97
+#define TARGET_FREEBSD_NR_connect   98
+                /* 99 is old accept */
+#define TARGET_FREEBSD_NR_getpriority   100
+                /* 101 is old send */
+                /* 102 is old recv */
+                /* 103 is old sigreturn */
+#define TARGET_FREEBSD_NR_bind  104
+#define TARGET_FREEBSD_NR_setsockopt    105
+#define TARGET_FREEBSD_NR_listen    106
+                /* 107 is obsolete vtimes */
+                /* 108 is old sigvec */
+                /* 109 is old sigblock */
+                /* 110 is old sigsetmask */
+                /* 111 is old sigsuspend */
+                /* 112 is old sigstack */
+                /* 113 is old recvmsg */
+                /* 114 is old sendmsg */
+                /* 115 is obsolete vtrace */
+#define TARGET_FREEBSD_NR_gettimeofday  116
+#define TARGET_FREEBSD_NR_getrusage 117
+#define TARGET_FREEBSD_NR_getsockopt    118
+#define TARGET_FREEBSD_NR_readv 120
+#define TARGET_FREEBSD_NR_writev    121
+#define TARGET_FREEBSD_NR_settimeofday  122
+#define TARGET_FREEBSD_NR_fchown    123
+#define TARGET_FREEBSD_NR_fchmod    124
+                /* 125 is old recvfrom */
+#define TARGET_FREEBSD_NR_setreuid  126
+#define TARGET_FREEBSD_NR_setregid  127
+#define TARGET_FREEBSD_NR_rename    128
+                /* 129 is old truncate */
+                /* 130 is old ftruncate */
+#define TARGET_FREEBSD_NR_flock 131
+#define TARGET_FREEBSD_NR_mkfifo    132
+#define TARGET_FREEBSD_NR_sendto    133
+#define TARGET_FREEBSD_NR_shutdown  134
+#define TARGET_FREEBSD_NR_socketpair    135
+#define TARGET_FREEBSD_NR_mkdir 136
+#define TARGET_FREEBSD_NR_rmdir 137
+#define TARGET_FREEBSD_NR_utimes    138
+                /* 139 is obsolete 4.2 sigreturn */
+#define TARGET_FREEBSD_NR_adjtime   140
+                /* 141 is old getpeername */
+                /* 142 is old gethostid */
+                /* 143 is old sethostid */
+                /* 144 is old getrlimit */
+                /* 145 is old setrlimit */
+                /* 146 is old killpg */
+#define TARGET_FREEBSD_NR_killpg    146 /* COMPAT */
+#define TARGET_FREEBSD_NR_setsid    147
+#define TARGET_FREEBSD_NR_quotactl  148
+                /* 149 is old quota */
+                /* 150 is old getsockname */
+#define TARGET_FREEBSD_NR_nlm_syscall   154
+#define TARGET_FREEBSD_NR_nfssvc    155
+                /* 156 is old getdirentries */
+#define TARGET_FREEBSD_NR_freebsd4_statfs   157
+#define TARGET_FREEBSD_NR_freebsd4_fstatfs  158
+#define TARGET_FREEBSD_NR_lgetfh    160
+#define TARGET_FREEBSD_NR_getfh 161
+#define TARGET_FREEBSD_NR_freebsd4_getdomainname    162
+#define TARGET_FREEBSD_NR_freebsd4_setdomainname    163
+#define TARGET_FREEBSD_NR_freebsd4_uname    164
+#define TARGET_FREEBSD_NR_sysarch   165
+#define TARGET_FREEBSD_NR_rtprio    166
+#define TARGET_FREEBSD_NR_semsys    169
+#define TARGET_FREEBSD_NR_msgsys    170
+#define TARGET_FREEBSD_NR_shmsys    171
+#define TARGET_FREEBSD_NR_freebsd6_pread    173
+#define TARGET_FREEBSD_NR_freebsd6_pwrite   174
+#define TARGET_FREEBSD_NR_setfib    175
+#define TARGET_FREEBSD_NR_ntp_adjtime   176
+#define TARGET_FREEBSD_NR_setgid    181
+#define TARGET_FREEBSD_NR_setegid   182
+#define TARGET_FREEBSD_NR_seteuid   183
+#define TARGET_FREEBSD_NR_stat  188
+#define TARGET_FREEBSD_NR_fstat 189
+#define TARGET_FREEBSD_NR_lstat 190
+#define TARGET_FREEBSD_NR_pathconf  191
+#define TARGET_FREEBSD_NR_fpathconf 192
+#define TARGET_FREEBSD_NR_getrlimit 194
+#define TARGET_FREEBSD_NR_setrlimit 195
+#define TARGET_FREEBSD_NR_getdirentries 196
+#define TARGET_FREEBSD_NR_freebsd6_mmap 197
+#define TARGET_FREEBSD_NR___syscall 198
+#define TARGET_FREEBSD_NR_freebsd6_lseek    199
+#define TARGET_FREEBSD_NR_freebsd6_truncate 200
+#define TARGET_FREEBSD_NR_freebsd6_ftruncate    201
+#define TARGET_FREEBSD_NR___sysctl  202
+#define TARGET_FREEBSD_NR_mlock 203
+#define TARGET_FREEBSD_NR_munlock   204
+#define TARGET_FREEBSD_NR_undelete  205
+#define TARGET_FREEBSD_NR_futimes   206
+#define TARGET_FREEBSD_NR_getpgid   207
+#define TARGET_FREEBSD_NR_poll  209
+#define TARGET_FREEBSD_NR_freebsd7___semctl 220
+#define TARGET_FREEBSD_NR_semget    221
+#define TARGET_FREEBSD_NR_semop 222
+#define TARGET_FREEBSD_NR_freebsd7_msgctl   224
+#define TARGET_FREEBSD_NR_msgget    225
+#define TARGET_FREEBSD_NR_msgsnd    226
+#define TARGET_FREEBSD_NR_msgrcv    227
+#define TARGET_FREEBSD_NR_shmat 228
+#define TARGET_FREEBSD_NR_freebsd7_shmctl   229
+#define TARGET_FREEBSD_NR_shmdt 230
+#define TARGET_FREEBSD_NR_shmget    231
+#define TARGET_FREEBSD_NR_clock_gettime 232
+#define TARGET_FREEBSD_NR_clock_settime 233
+#define TARGET_FREEBSD_NR_clock_getres  234
+#define TARGET_FREEBSD_NR_ktimer_create 235
+#define TARGET_FREEBSD_NR_ktimer_delete 236
+#define TARGET_FREEBSD_NR_ktimer_settime    237
+#define TARGET_FREEBSD_NR_ktimer_gettime    238
+#define TARGET_FREEBSD_NR_ktimer_getoverrun 239
+#define TARGET_FREEBSD_NR_nanosleep 240
+#define TARGET_FREEBSD_NR_ntp_gettime   248
+#define TARGET_FREEBSD_NR_minherit  250
+#define TARGET_FREEBSD_NR_rfork 251
+#define TARGET_FREEBSD_NR_openbsd_poll  252
+#define TARGET_FREEBSD_NR_issetugid 253
+#define TARGET_FREEBSD_NR_lchown    254
+#define TARGET_FREEBSD_NR_aio_read  255
+#define TARGET_FREEBSD_NR_aio_write 256
+#define TARGET_FREEBSD_NR_lio_listio    257
+#define TARGET_FREEBSD_NR_getdents  272
+#define TARGET_FREEBSD_NR_lchmod    274
+#define TARGET_FREEBSD_NR_netbsd_lchown 275
+#define TARGET_FREEBSD_NR_lutimes   276
+#define TARGET_FREEBSD_NR_netbsd_msync  277
+#define TARGET_FREEBSD_NR_nstat 278
+#define TARGET_FREEBSD_NR_nfstat    279
+#define TARGET_FREEBSD_NR_nlstat    280
+#define TARGET_FREEBSD_NR_preadv    289
+#define TARGET_FREEBSD_NR_pwritev   290
+#define TARGET_FREEBSD_NR_freebsd4_fhstatfs 297
+#define TARGET_FREEBSD_NR_fhopen    298
+#define TARGET_FREEBSD_NR_fhstat    299
+#define TARGET_FREEBSD_NR_modnext   300
+#define TARGET_FREEBSD_NR_modstat   301
+#define TARGET_FREEBSD_NR_modfnext  302
+#define TARGET_FREEBSD_NR_modfind   303
+#define TARGET_FREEBSD_NR_kldload   304
+#define TARGET_FREEBSD_NR_kldunload 305
+#define TARGET_FREEBSD_NR_kldfind   306
+#define TARGET_FREEBSD_NR_kldnext   307
+#define TARGET_FREEBSD_NR_kldstat   308
+#define TARGET_FREEBSD_NR_kldfirstmod   309
+#define TARGET_FREEBSD_NR_getsid    310
+#define TARGET_FREEBSD_NR_setresuid 311
+#define TARGET_FREEBSD_NR_setresgid 312
+                /* 313 is obsolete signanosleep */
+#define TARGET_FREEBSD_NR_aio_return    314
+#define TARGET_FREEBSD_NR_aio_suspend   315
+#define TARGET_FREEBSD_NR_aio_cancel    316
+#define TARGET_FREEBSD_NR_aio_error 317
+#define TARGET_FREEBSD_NR_oaio_read 318
+#define TARGET_FREEBSD_NR_oaio_write    319
+#define TARGET_FREEBSD_NR_olio_listio   320
+#define TARGET_FREEBSD_NR_yield 321
+                /* 322 is obsolete thr_sleep */
+                /* 323 is obsolete thr_wakeup */
+#define TARGET_FREEBSD_NR_mlockall  324
+#define TARGET_FREEBSD_NR_munlockall    325
+#define TARGET_FREEBSD_NR___getcwd  326
+#define TARGET_FREEBSD_NR_sched_setparam    327
+#define TARGET_FREEBSD_NR_sched_getparam    328
+#define TARGET_FREEBSD_NR_sched_setscheduler    329
+#define TARGET_FREEBSD_NR_sched_getscheduler    330
+#define TARGET_FREEBSD_NR_sched_yield   331
+#define TARGET_FREEBSD_NR_sched_get_priority_max    332
+#define TARGET_FREEBSD_NR_sched_get_priority_min    333
+#define TARGET_FREEBSD_NR_sched_rr_get_interval 334
+#define TARGET_FREEBSD_NR_utrace    335
+#define TARGET_FREEBSD_NR_freebsd4_sendfile 336
+#define TARGET_FREEBSD_NR_kldsym    337
+#define TARGET_FREEBSD_NR_jail  338
+#define TARGET_FREEBSD_NR_nnpfs_syscall 339
+#define TARGET_FREEBSD_NR_sigprocmask   340
+#define TARGET_FREEBSD_NR_sigsuspend    341
+#define TARGET_FREEBSD_NR_freebsd4_sigaction    342
+#define TARGET_FREEBSD_NR_sigpending    343
+#define TARGET_FREEBSD_NR_freebsd4_sigreturn    344
+#define TARGET_FREEBSD_NR_sigtimedwait  345
+#define TARGET_FREEBSD_NR_sigwaitinfo   346
+#define TARGET_FREEBSD_NR___acl_get_file    347
+#define TARGET_FREEBSD_NR___acl_set_file    348
+#define TARGET_FREEBSD_NR___acl_get_fd  349
+#define TARGET_FREEBSD_NR___acl_set_fd  350
+#define TARGET_FREEBSD_NR___acl_delete_file 351
+#define TARGET_FREEBSD_NR___acl_delete_fd   352
+#define TARGET_FREEBSD_NR___acl_aclcheck_file   353
+#define TARGET_FREEBSD_NR___acl_aclcheck_fd 354
+#define TARGET_FREEBSD_NR_extattrctl    355
+#define TARGET_FREEBSD_NR_extattr_set_file  356
+#define TARGET_FREEBSD_NR_extattr_get_file  357
+#define TARGET_FREEBSD_NR_extattr_delete_file   358
+#define TARGET_FREEBSD_NR_aio_waitcomplete  359
+#define TARGET_FREEBSD_NR_getresuid 360
+#define TARGET_FREEBSD_NR_getresgid 361
+#define TARGET_FREEBSD_NR_kqueue    362
+#define TARGET_FREEBSD_NR_kevent    363
+#define TARGET_FREEBSD_NR_extattr_set_fd    371
+#define TARGET_FREEBSD_NR_extattr_get_fd    372
+#define TARGET_FREEBSD_NR_extattr_delete_fd 373
+#define TARGET_FREEBSD_NR___setugid 374
+#define TARGET_FREEBSD_NR_eaccess   376
+#define TARGET_FREEBSD_NR_afs3_syscall  377
+#define TARGET_FREEBSD_NR_nmount    378
+#define TARGET_FREEBSD_NR___mac_get_proc    384
+#define TARGET_FREEBSD_NR___mac_set_proc    385
+#define TARGET_FREEBSD_NR___mac_get_fd  386
+#define TARGET_FREEBSD_NR___mac_get_file    387
+#define TARGET_FREEBSD_NR___mac_set_fd  388
+#define TARGET_FREEBSD_NR___mac_set_file    389
+#define TARGET_FREEBSD_NR_kenv  390
+#define TARGET_FREEBSD_NR_lchflags  391
+#define TARGET_FREEBSD_NR_uuidgen   392
+#define TARGET_FREEBSD_NR_sendfile  393
+#define TARGET_FREEBSD_NR_mac_syscall   394
+#define TARGET_FREEBSD_NR_getfsstat 395
+#define TARGET_FREEBSD_NR_statfs    396
+#define TARGET_FREEBSD_NR_fstatfs   397
+#define TARGET_FREEBSD_NR_fhstatfs  398
+#define TARGET_FREEBSD_NR_ksem_close    400
+#define TARGET_FREEBSD_NR_ksem_post 401
+#define TARGET_FREEBSD_NR_ksem_wait 402
+#define TARGET_FREEBSD_NR_ksem_trywait  403
+#define TARGET_FREEBSD_NR_ksem_init 404
+#define TARGET_FREEBSD_NR_ksem_open 405
+#define TARGET_FREEBSD_NR_ksem_unlink   406
+#define TARGET_FREEBSD_NR_ksem_getvalue 407
+#define TARGET_FREEBSD_NR_ksem_destroy  408
+#define TARGET_FREEBSD_NR___mac_get_pid 409
+#define TARGET_FREEBSD_NR___mac_get_link    410
+#define TARGET_FREEBSD_NR___mac_set_link    411
+#define TARGET_FREEBSD_NR_extattr_set_link  412
+#define TARGET_FREEBSD_NR_extattr_get_link  413
+#define TARGET_FREEBSD_NR_extattr_delete_link   414
+#define TARGET_FREEBSD_NR___mac_execve  415
+#define TARGET_FREEBSD_NR_sigaction 416
+#define TARGET_FREEBSD_NR_sigreturn 417
+#define TARGET_FREEBSD_NR_getcontext    421
+#define TARGET_FREEBSD_NR_setcontext    422
+#define TARGET_FREEBSD_NR_swapcontext   423
+#define TARGET_FREEBSD_NR_swapoff   424
+#define TARGET_FREEBSD_NR___acl_get_link    425
+#define TARGET_FREEBSD_NR___acl_set_link    426
+#define TARGET_FREEBSD_NR___acl_delete_link 427
+#define TARGET_FREEBSD_NR___acl_aclcheck_link   428
+#define TARGET_FREEBSD_NR_sigwait   429
+#define TARGET_FREEBSD_NR_thr_create    430
+#define TARGET_FREEBSD_NR_thr_exit  431
+#define TARGET_FREEBSD_NR_thr_self  432
+#define TARGET_FREEBSD_NR_thr_kill  433
+#define TARGET_FREEBSD_NR__umtx_lock    434
+#define TARGET_FREEBSD_NR__umtx_unlock  435
+#define TARGET_FREEBSD_NR_jail_attach   436
+#define TARGET_FREEBSD_NR_extattr_list_fd   437
+#define TARGET_FREEBSD_NR_extattr_list_file 438
+#define TARGET_FREEBSD_NR_extattr_list_link 439
+#define TARGET_FREEBSD_NR_ksem_timedwait    441
+#define TARGET_FREEBSD_NR_thr_suspend   442
+#define TARGET_FREEBSD_NR_thr_wake  443
+#define TARGET_FREEBSD_NR_kldunloadf    444
+#define TARGET_FREEBSD_NR_audit 445
+#define TARGET_FREEBSD_NR_auditon   446
+#define TARGET_FREEBSD_NR_getauid   447
+#define TARGET_FREEBSD_NR_setauid   448
+#define TARGET_FREEBSD_NR_getaudit  449
+#define TARGET_FREEBSD_NR_setaudit  450
+#define TARGET_FREEBSD_NR_getaudit_addr 451
+#define TARGET_FREEBSD_NR_setaudit_addr 452
+#define TARGET_FREEBSD_NR_auditctl  453
+#define TARGET_FREEBSD_NR__umtx_op  454
+#define TARGET_FREEBSD_NR_thr_new   455
+#define TARGET_FREEBSD_NR_sigqueue  456
+#define TARGET_FREEBSD_NR_kmq_open  457
+#define TARGET_FREEBSD_NR_kmq_setattr   458
+#define TARGET_FREEBSD_NR_kmq_timedreceive  459
+#define TARGET_FREEBSD_NR_kmq_timedsend 460
+#define TARGET_FREEBSD_NR_kmq_notify    461
+#define TARGET_FREEBSD_NR_kmq_unlink    462
+#define TARGET_FREEBSD_NR_abort2    463
+#define TARGET_FREEBSD_NR_thr_set_name  464
+#define TARGET_FREEBSD_NR_aio_fsync 465
+#define TARGET_FREEBSD_NR_rtprio_thread 466
+#define TARGET_FREEBSD_NR_sctp_peeloff  471
+#define TARGET_FREEBSD_NR_sctp_generic_sendmsg  472
+#define TARGET_FREEBSD_NR_sctp_generic_sendmsg_iov  473
+#define TARGET_FREEBSD_NR_sctp_generic_recvmsg  474
+#define TARGET_FREEBSD_NR_pread 475
+#define TARGET_FREEBSD_NR_pwrite    476
+#define TARGET_FREEBSD_NR_mmap  477
+#define TARGET_FREEBSD_NR_lseek 478
+#define TARGET_FREEBSD_NR_truncate  479
+#define TARGET_FREEBSD_NR_ftruncate 480
+#define TARGET_FREEBSD_NR_thr_kill2 481
+#define TARGET_FREEBSD_NR_shm_open  482
+#define TARGET_FREEBSD_NR_shm_unlink    483
+#define TARGET_FREEBSD_NR_cpuset    484
+#define TARGET_FREEBSD_NR_cpuset_setid  485
+#define TARGET_FREEBSD_NR_cpuset_getid  486
+#define TARGET_FREEBSD_NR_cpuset_getaffinity    487
+#define TARGET_FREEBSD_NR_cpuset_setaffinity    488
+#define TARGET_FREEBSD_NR_faccessat 489
+#define TARGET_FREEBSD_NR_fchmodat  490
+#define TARGET_FREEBSD_NR_fchownat  491
+#define TARGET_FREEBSD_NR_fexecve   492
+#define TARGET_FREEBSD_NR_fstatat   493
+#define TARGET_FREEBSD_NR_futimesat 494
+#define TARGET_FREEBSD_NR_linkat    495
+#define TARGET_FREEBSD_NR_mkdirat   496
+#define TARGET_FREEBSD_NR_mkfifoat  497
+#define TARGET_FREEBSD_NR_mknodat   498
+#define TARGET_FREEBSD_NR_openat    499
+#define TARGET_FREEBSD_NR_readlinkat    500
+#define TARGET_FREEBSD_NR_renameat  501
+#define TARGET_FREEBSD_NR_symlinkat 502
+#define TARGET_FREEBSD_NR_unlinkat  503
+#define TARGET_FREEBSD_NR_posix_openpt  504
+#define TARGET_FREEBSD_NR_gssd_syscall  505
+#define TARGET_FREEBSD_NR_jail_get  506
+#define TARGET_FREEBSD_NR_jail_set  507
+#define TARGET_FREEBSD_NR_jail_remove   508
+#define TARGET_FREEBSD_NR_closefrom 509
+#define TARGET_FREEBSD_NR___semctl  510
+#define TARGET_FREEBSD_NR_msgctl    511
+#define TARGET_FREEBSD_NR_shmctl    512
+#define TARGET_FREEBSD_NR_lpathconf 513
+#define TARGET_FREEBSD_NR_cap_new   514
+#define TARGET_FREEBSD_NR_cap_getrights 515
+#define TARGET_FREEBSD_NR_cap_enter 516
+#define TARGET_FREEBSD_NR_cap_getmode   517
+#define TARGET_FREEBSD_NR_pdfork    518
+#define TARGET_FREEBSD_NR_pdkill    519
+#define TARGET_FREEBSD_NR_pdgetpid  520
+#define TARGET_FREEBSD_NR_pselect   522
+#define TARGET_FREEBSD_NR_getloginclass 523
+#define TARGET_FREEBSD_NR_setloginclass 524
+#define TARGET_FREEBSD_NR_rctl_get_racct    525
+#define TARGET_FREEBSD_NR_rctl_get_rules    526
+#define TARGET_FREEBSD_NR_rctl_get_limits   527
+#define TARGET_FREEBSD_NR_rctl_add_rule 528
+#define TARGET_FREEBSD_NR_rctl_remove_rule  529
+#define TARGET_FREEBSD_NR_posix_fallocate   530
+#define TARGET_FREEBSD_NR_posix_fadvise 531
+#define TARGET_FREEBSD_NR_MAXSYSCALL    532
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 02/19] bsd-user: add HOST_VARIANT_DIR for various *BSD dependent code
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (2 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 01/19] bsd-user: refresh freebsd system call numbers Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2014-01-27 19:31     ` Peter Maydell
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 03/19] bsd-user: move strace OS/arch dependent code to host/arch dirs Stacey Son
                     ` (16 subsequent siblings)
  20 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds HOST_VARIANT_DIR so the various BSD OS dependent
code can be seperated into its own directories rather than
using #ifdef's.   This may also allow an BSD variant OS to host
another BSD variant's executible as a target.
---
 Makefile.target |    3 ++-
 configure       |   11 +++++++++++
 2 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/Makefile.target b/Makefile.target
index af6ac7e..1306b24 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -99,7 +99,8 @@ endif #CONFIG_LINUX_USER
 
 ifdef CONFIG_BSD_USER
 
-QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR)
+QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR) \
+			 -I$(SRC_PATH)/bsd-user/$(HOST_VARIANT_DIR)
 
 obj-y += bsd-user/
 obj-y += gdbstub.o user-exec.o
diff --git a/configure b/configure
index edfea95..4e834cf 100755
--- a/configure
+++ b/configure
@@ -465,6 +465,9 @@ fi
 
 # OS specific
 
+# host *BSD for user mode
+HOST_VARIANT_DIR=""
+
 case $targetos in
 CYGWIN*)
   mingw32="yes"
@@ -490,12 +493,14 @@ FreeBSD)
   # needed for kinfo_getvmmap(3) in libutil.h
   LIBS="-lutil $LIBS"
   netmap=""  # enable netmap autodetect
+  HOST_VARIANT_DIR="freebsd"
 ;;
 DragonFly)
   bsd="yes"
   make="${MAKE-gmake}"
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd pa"
+  HOST_VARIANT_DIR="dragonfly"
 ;;
 NetBSD)
   bsd="yes"
@@ -503,12 +508,14 @@ NetBSD)
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd"
   oss_lib="-lossaudio"
+  HOST_VARIANT_DIR="netbsd"
 ;;
 OpenBSD)
   bsd="yes"
   make="${MAKE-gmake}"
   audio_drv_list="sdl"
   audio_possible_drivers="sdl esd"
+  HOST_VARIANT_DIR="openbsd"
 ;;
 Darwin)
   bsd="yes"
@@ -527,6 +534,7 @@ Darwin)
   # Disable attempts to use ObjectiveC features in os/object.h since they
   # won't work when we're compiling with gcc as a C compiler.
   QEMU_CFLAGS="-DOS_OBJECT_USE_OBJC=0 $QEMU_CFLAGS"
+  HOST_VARIANT_DIR="darwin"
 ;;
 SunOS)
   solaris="yes"
@@ -4538,6 +4546,9 @@ if [ "$TARGET_ABI_DIR" = "" ]; then
   TARGET_ABI_DIR=$TARGET_ARCH
 fi
 echo "TARGET_ABI_DIR=$TARGET_ABI_DIR" >> $config_target_mak
+if [ "$HOST_VARIANT_DIR" != "" ]; then
+    echo "HOST_VARIANT_DIR=$HOST_VARIANT_DIR" >> $config_target_mak
+fi
 case "$target_name" in
   i386|x86_64)
     if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 03/19] bsd-user: move strace OS/arch dependent code to host/arch dirs
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (3 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 02/19] bsd-user: add HOST_VARIANT_DIR for various *BSD dependent code Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2014-01-27 19:46     ` Peter Maydell
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 04/19] bsd-user: move arch/OS dependent code out of main.c Stacey Son
                     ` (15 subsequent siblings)
  20 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change moves host OS and arch dependent code for the sysarch
system call related to the -strace functionality into the
appropriate host OS and target arch directories.
---
 bsd-user/arm/syscall.h                 |   36 +++++++
 bsd-user/arm/target_arch_sysarch.h     |   78 ++++++++++++++
 bsd-user/freebsd/os-strace.h           |   29 +++++
 bsd-user/freebsd/strace.list           |   76 +++++++++++++--
 bsd-user/i386/syscall.h                |   23 ++++
 bsd-user/i386/target_arch_sysarch.h    |   78 ++++++++++++++
 bsd-user/mips/syscall.h                |   52 ++++++++++
 bsd-user/mips/target_arch_sysarch.h    |   69 +++++++++++++
 bsd-user/mips64/syscall.h              |   53 ++++++++++
 bsd-user/mips64/target_arch_sysarch.h  |   69 +++++++++++++
 bsd-user/netbsd/os-strace.h            |    1 +
 bsd-user/openbsd/os-strace.h           |    1 +
 bsd-user/qemu.h                        |   26 +++++
 bsd-user/sparc/syscall.h               |   29 +++++-
 bsd-user/sparc/target_arch_sysarch.h   |   52 ++++++++++
 bsd-user/sparc64/syscall.h             |   28 +++++-
 bsd-user/sparc64/target_arch_sysarch.h |   52 ++++++++++
 bsd-user/strace.c                      |  175 +++++++++++++++++++++----------
 bsd-user/x86_64/syscall.h              |   26 +++++-
 bsd-user/x86_64/target_arch_sysarch.h  |   76 ++++++++++++++
 20 files changed, 962 insertions(+), 67 deletions(-)
 create mode 100644 bsd-user/arm/syscall.h
 create mode 100644 bsd-user/arm/target_arch_sysarch.h
 create mode 100644 bsd-user/freebsd/os-strace.h
 create mode 100644 bsd-user/i386/target_arch_sysarch.h
 create mode 100644 bsd-user/mips/syscall.h
 create mode 100644 bsd-user/mips/target_arch_sysarch.h
 create mode 100644 bsd-user/mips64/syscall.h
 create mode 100644 bsd-user/mips64/target_arch_sysarch.h
 create mode 100644 bsd-user/netbsd/os-strace.h
 create mode 100644 bsd-user/openbsd/os-strace.h
 create mode 100644 bsd-user/sparc/target_arch_sysarch.h
 create mode 100644 bsd-user/sparc64/target_arch_sysarch.h
 create mode 100644 bsd-user/x86_64/target_arch_sysarch.h

diff --git a/bsd-user/arm/syscall.h b/bsd-user/arm/syscall.h
new file mode 100644
index 0000000..bc3d6e6
--- /dev/null
+++ b/bsd-user/arm/syscall.h
@@ -0,0 +1,36 @@
+#ifndef __ARCH_SYSCALL_H_
+#define __ARCH_SYSCALL_H_
+
+struct target_pt_regs {
+    abi_long uregs[17];
+};
+
+#define ARM_cpsr    uregs[16]
+#define ARM_pc      uregs[15]
+#define ARM_lr      uregs[14]
+#define ARM_sp      uregs[13]
+#define ARM_ip      uregs[12]
+#define ARM_fp      uregs[11]
+#define ARM_r10     uregs[10]
+#define ARM_r9      uregs[9]
+#define ARM_r8      uregs[8]
+#define ARM_r7      uregs[7]
+#define ARM_r6      uregs[6]
+#define ARM_r5      uregs[5]
+#define ARM_r4      uregs[4]
+#define ARM_r3      uregs[3]
+#define ARM_r2      uregs[2]
+#define ARM_r1      uregs[1]
+#define ARM_r0      uregs[0]
+
+#define ARM_SYSCALL_BASE    0 /* XXX: FreeBSD only */
+
+#define TARGET_FREEBSD_ARM_SYNC_ICACHE      0
+#define TARGET_FREEBSD_ARM_DRAIN_WRITEBUF   1
+#define TARGET_FREEBSD_ARM_SET_TP       2
+#define TARGET_FREEBSD_ARM_GET_TP       3
+
+#define TARGET_HW_MACHINE       "arm"
+#define TARGET_HW_MACHINE_ARCH  "armv6"
+
+#endif /* !__ARCH_SYSCALL_H_ */
diff --git a/bsd-user/arm/target_arch_sysarch.h b/bsd-user/arm/target_arch_sysarch.h
new file mode 100644
index 0000000..96d617a
--- /dev/null
+++ b/bsd-user/arm/target_arch_sysarch.h
@@ -0,0 +1,78 @@
+/*
+ *  arm sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+#include "target_arch.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUARMState *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_FREEBSD_ARM_SYNC_ICACHE:
+    case TARGET_FREEBSD_ARM_DRAIN_WRITEBUF:
+        break;
+
+    case TARGET_FREEBSD_ARM_SET_TP:
+        target_cpu_set_tls(env, parms);
+        break;
+
+    case TARGET_FREEBSD_ARM_GET_TP:
+        ret = target_cpu_get_tls(env);
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    switch (arg1) {
+    case TARGET_FREEBSD_ARM_SYNC_ICACHE:
+        gemu_log("%s(ARM_SYNC_ICACHE, ...)", name->name);
+        break;
+
+    case TARGET_FREEBSD_ARM_DRAIN_WRITEBUF:
+        gemu_log("%s(ARM_DRAIN_WRITEBUF, ...)", name->name);
+        break;
+
+    case TARGET_FREEBSD_ARM_SET_TP:
+        gemu_log("%s(ARM_SET_TP, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    case TARGET_FREEBSD_ARM_GET_TP:
+        gemu_log("%s(ARM_GET_TP, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    default:
+        gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
+    }
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/freebsd/os-strace.h b/bsd-user/freebsd/os-strace.h
new file mode 100644
index 0000000..a222f09
--- /dev/null
+++ b/bsd-user/freebsd/os-strace.h
@@ -0,0 +1,29 @@
+/*
+ *  FreeBSD dependent strace print functions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "target_arch_sysarch.h"    /* architecture dependent functions */
+
+
+static inline void do_os_print_sysarch(const struct syscallname *name,
+        abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4,
+        abi_long arg5, abi_long arg6)
+{
+    /* This is arch dependent */
+    do_freebsd_arch_print_sysarch(name, arg1, arg2, arg3, arg4, arg5, arg6);
+}
diff --git a/bsd-user/freebsd/strace.list b/bsd-user/freebsd/strace.list
index 1edf412..ae2a4a3 100644
--- a/bsd-user/freebsd/strace.list
+++ b/bsd-user/freebsd/strace.list
@@ -1,7 +1,38 @@
+/*
+ *  FreeBSD strace list
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+{ TARGET_FREEBSD_NR___acl_aclcheck_fd, "__acl_get_fd", "%s(%d, %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_aclcheck_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_aclcheck_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_delete_fd, "__acl_delete_fd", "%s(%d, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_delete_file, "__acl_delete_file", "%s(\"%s\", %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_delete_link, "__acl_delete_link", "%s(\"%s\", %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_get_fd, "__acl_get_fd", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_get_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_get_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_set_fd, "__acl_get_fd", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_set_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR___acl_set_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL },
 { TARGET_FREEBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR___semctl, "__semctl", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR___syscall, "__syscall", NULL, NULL, NULL },
-{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, print_sysctl, NULL },
+{ TARGET_FREEBSD_NR__umtx_op, "_umtx_op", "%s(%#x, %d, %d, %#x, %#x)", NULL, NULL },
 { TARGET_FREEBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL },
 { TARGET_FREEBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL },
 { TARGET_FREEBSD_NR_acct, "acct", NULL, NULL, NULL },
@@ -20,24 +51,41 @@
 { TARGET_FREEBSD_NR_connect, "connect", "%s(%d,%#x,%d)", NULL, NULL },
 { TARGET_FREEBSD_NR_dup, "dup", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_dup2, "dup2", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_eaccess, "eaccess", "%s(%s,%#x)", NULL, NULL },
 { TARGET_FREEBSD_NR_execve, "execve", NULL, print_execve, NULL },
 { TARGET_FREEBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattrctl, "extattrctl", "%s(\"%s\", %d, \"%s\", %d, \"%s\"", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_delete_fd, "extattr_delete_fd", "%s(%d, %d, \"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_delete_file, "extattr_delete_file", "%s(\"%s\", %d, \"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_delete_link, "extattr_delete_link", "%s(\"%s\", %d, \"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_get_fd, "extattr_get_fd", "%s(%d, %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_get_file, "extattr_get_file", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_get_file, "extattr_get_link", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_list_fd, "extattr_list_fd", "%s(%d, %d, %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_list_file, "extattr_list_file", "%s(\"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_list_link, "extattr_list_link", "%s(\"%s\", %d, %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_set_fd, "extattr_set_fd", "%s(%d, %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_set_file, "extattr_set_file", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_extattr_set_link, "extattr_set_link", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL },
 { TARGET_FREEBSD_NR_fchdir, "fchdir", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fchflags, "fchflags", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL },
-{ TARGET_FREEBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fchown, "fchown", "%s(%d,%d,%d)", NULL, NULL },
 { TARGET_FREEBSD_NR_fcntl, "fcntl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_fexecve, "fexecve", NULL, print_execve, NULL },
 { TARGET_FREEBSD_NR_fhopen, "fhopen", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fhstat, "fhstat", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fhstatfs, "fhstatfs", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_flock, "flock", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_fork, "fork", "%s()", NULL, NULL },
 { TARGET_FREEBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL },
-{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%p)", NULL, NULL },
-{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%p)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fstatat, "fstatat", "%s(%d,\"%s\", %#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%#x)", NULL, NULL },
 { TARGET_FREEBSD_NR_fsync, "fsync", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getcontext, "getcontext", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_freebsd6_mmap, "freebsd6_mmap", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getegid, "getegid", "%s()", NULL, NULL },
@@ -63,7 +111,7 @@
 { TARGET_FREEBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getuid, "getuid", "%s()", NULL, NULL },
-{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, print_ioctl, NULL },
 { TARGET_FREEBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL },
 { TARGET_FREEBSD_NR_kevent, "kevent", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_kill, "kill", NULL, NULL, NULL },
@@ -72,6 +120,7 @@
 { TARGET_FREEBSD_NR_lchown, "lchown", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL },
 { TARGET_FREEBSD_NR_listen, "listen", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_lpathconf, "lpathconf", "%s(\"%s\", %d)", NULL, NULL },
 { TARGET_FREEBSD_NR_lseek, "lseek", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_lstat, "lstat", "%s(\"%s\",%p)", NULL, NULL },
 { TARGET_FREEBSD_NR_madvise, "madvise", NULL, NULL, NULL },
@@ -96,7 +145,9 @@
 { TARGET_FREEBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL },
+{ TARGET_FREEBSD_NR_openat, "openat", "%s(%d, \"%s\",%#x,%#o)", NULL, NULL },
 { TARGET_FREEBSD_NR_pathconf, "pathconf", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_pathconf, "pathconf", "%s(\"%s\", %d)", NULL, NULL },
 { TARGET_FREEBSD_NR_pipe, "pipe", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_poll, "poll", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_pread, "pread", NULL, NULL, NULL },
@@ -116,6 +167,7 @@
 { TARGET_FREEBSD_NR_revoke, "revoke", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_rfork, "rfork", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_rmdir, "rmdir", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_rtprio_thread, "rtprio_thread", "%s(%d, %d, %p)", NULL, NULL },
 { TARGET_FREEBSD_NR_sbrk, "sbrk", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_select, "select", NULL, NULL, NULL },
@@ -123,6 +175,7 @@
 { TARGET_FREEBSD_NR_semop, "semop", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sendto, "sendto", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setcontext, "setcontext", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_setegid, "setegid", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_seteuid, "seteuid", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_setgid, "setgid", NULL, NULL, NULL },
@@ -151,15 +204,24 @@
 { TARGET_FREEBSD_NR_sigprocmask, "sigprocmask", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sigreturn, "sigreturn", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sigsuspend, "sigsuspend", NULL, NULL, NULL },
-{ TARGET_FREEBSD_NR_socket, "socket", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_socket, "socket", "%s(%d,%d,%d)", NULL, NULL },
 { TARGET_FREEBSD_NR_socketpair, "socketpair", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_sstk, "sstk", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_stat, "stat", "%s(\"%s\",%p)", NULL, NULL },
 { TARGET_FREEBSD_NR_statfs, "statfs", "%s(\"%s\",%p)", NULL, NULL },
 { TARGET_FREEBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL },
 { TARGET_FREEBSD_NR_sync, "sync", NULL, NULL, NULL },
-{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, print_sysarch, NULL },
 { TARGET_FREEBSD_NR_syscall, "syscall", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_create, "thr_create", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_exit, "thr_exit", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_kill, "thr_kill", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_kill2, "thr_kill2", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_new, "thr_new", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_self, "thr_self", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_set_name, "thr_set_name", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_suspend, "thr_suspend", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_thr_wake, "thr_wake", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_truncate, "truncate", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL },
 { TARGET_FREEBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL },
diff --git a/bsd-user/i386/syscall.h b/bsd-user/i386/syscall.h
index 9b34c61..52de302 100644
--- a/bsd-user/i386/syscall.h
+++ b/bsd-user/i386/syscall.h
@@ -1,3 +1,23 @@
+/*
+ *  i386 system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _I386_SYSCALL_H_
+#define _I386_SYSCALL_H_
+
 /* default linux values for the selectors */
 #define __USER_CS	(0x23)
 #define __USER_DS	(0x2B)
@@ -158,4 +178,7 @@ struct target_vm86plus_struct {
 
 
 #define UNAME_MACHINE "i386"
+#define TARGET_HW_MACHINE UNAME_MACHINE
+#define TARGET_HW_MACHINE_ARCH UNAME_MACHINE
 
+#endif /* ! _I386_SYSCALL_H_ */
diff --git a/bsd-user/i386/target_arch_sysarch.h b/bsd-user/i386/target_arch_sysarch.h
new file mode 100644
index 0000000..4fa6698
--- /dev/null
+++ b/bsd-user/i386/target_arch_sysarch.h
@@ -0,0 +1,78 @@
+/*
+ *  i386 sysarch system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUX86State *env, int op,
+        abi_ulong parms)
+{
+    abi_long ret = 0;
+    abi_ulong val;
+    int idx;
+
+    switch (op) {
+    case TARGET_FREEBSD_I386_SET_GSBASE:
+    case TARGET_FREEBSD_I386_SET_FSBASE:
+        if (op == TARGET_FREEBSD_I386_SET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        if (get_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        cpu_x86_load_seg(env, idx, 0);
+        env->segs[idx].base = val;
+        break;
+
+    case TARGET_FREEBSD_I386_GET_GSBASE:
+    case TARGET_FREEBSD_I386_GET_FSBASE:
+        if (op == TARGET_FREEBSD_I386_GET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        val = env->segs[idx].base;
+        if (put_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    /* XXX handle the others... */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", "
+        TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4);
+}
+
+#endif /* !__ARCH_SYSARCH_H_ */
+
diff --git a/bsd-user/mips/syscall.h b/bsd-user/mips/syscall.h
new file mode 100644
index 0000000..aacc6dd
--- /dev/null
+++ b/bsd-user/mips/syscall.h
@@ -0,0 +1,52 @@
+/*
+ *  mips system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _MIPS_SYSCALL_H_
+#define _MIPS_SYSCALL_H_
+
+/*
+ * struct target_pt_regs defines the way the registers are stored on the stack
+ * during a system call.
+ */
+
+struct target_pt_regs {
+    /* Saved main processor registers. */
+    abi_ulong regs[32];
+
+    /* Saved special registers. */
+    abi_ulong cp0_status;
+    abi_ulong lo;
+    abi_ulong hi;
+    abi_ulong cp0_badvaddr;
+    abi_ulong cp0_cause;
+    abi_ulong cp0_epc;
+};
+
+#if defined(TARGET_WORDS_BIGENDIAN)
+#define UNAME_MACHINE "mips"
+#else
+#define UNAME_MACHINE "mipsel"
+#endif
+
+#define TARGET_HW_MACHINE       "mips"
+#define TARGET_HW_MACHINE_ARCH   UNAME_MACHINE
+
+/* sysarch() commands */
+#define TARGET_MIPS_SET_TLS     1
+#define TARGET_MIPS_GET_TLS     2
+
+#endif /* !_MIPS_SYSCALL_H_ */
diff --git a/bsd-user/mips/target_arch_sysarch.h b/bsd-user/mips/target_arch_sysarch.h
new file mode 100644
index 0000000..d333740
--- /dev/null
+++ b/bsd-user/mips/target_arch_sysarch.h
@@ -0,0 +1,69 @@
+/*
+ *  mips sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+#include "target_arch.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUMIPSState *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_MIPS_SET_TLS:
+        target_cpu_set_tls(env, parms);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        if (put_user(target_cpu_get_tls(env), parms, abi_ulong)) {
+            ret = -TARGET_EFAULT;
+        }
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    switch (arg1) {
+    case TARGET_MIPS_SET_TLS:
+        gemu_log("%s(SET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        gemu_log("%s(GET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    default:
+        gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
+    }
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/mips64/syscall.h b/bsd-user/mips64/syscall.h
new file mode 100644
index 0000000..bf4c598
--- /dev/null
+++ b/bsd-user/mips64/syscall.h
@@ -0,0 +1,53 @@
+/*
+ *  mips64 system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _MIPS64_SYSCALL_H_
+#define _MIPS64_SYSCALL_H_
+
+/*
+ * struct target_pt_regs defines the way the registers are stored on the stack
+ * during a system call.
+ */
+
+struct target_pt_regs {
+    /* Saved main processor registers. */
+    abi_ulong regs[32];
+
+    /* Saved special registers. */
+    abi_ulong cp0_status;
+    abi_ulong lo;
+    abi_ulong hi;
+    abi_ulong cp0_badvaddr;
+    abi_ulong cp0_cause;
+    abi_ulong cp0_epc;
+};
+
+
+#if defined(TARGET_WORDS_BIGENDIAN)
+#define UNAME_MACHINE "mips64"
+#else
+#define UNAME_MACHINE "mips64el"
+#endif
+
+#define TARGET_HW_MACHINE       "mips"
+#define TARGET_HW_MACHINE_ARCH  UNAME_MACHINE
+
+/* sysarch() commands */
+#define TARGET_MIPS_SET_TLS     1
+#define TARGET_MIPS_GET_TLS     2
+
+#endif /* !_MIPS64_SYSCALL_H_ */
diff --git a/bsd-user/mips64/target_arch_sysarch.h b/bsd-user/mips64/target_arch_sysarch.h
new file mode 100644
index 0000000..95b4e78
--- /dev/null
+++ b/bsd-user/mips64/target_arch_sysarch.h
@@ -0,0 +1,69 @@
+/*
+ *  mips64 sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+#include "target_arch.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUMIPSState *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_MIPS_SET_TLS:
+        target_cpu_set_tls(env, parms);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        if (put_user(target_cpu_get_tls(env), parms, abi_ulong)) {
+            ret = -TARGET_EFAULT;
+        }
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    switch (arg1) {
+    case TARGET_MIPS_SET_TLS:
+        gemu_log("%s(SET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        gemu_log("%s(GET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
+        break;
+
+    default:
+        gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
+    }
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/netbsd/os-strace.h b/bsd-user/netbsd/os-strace.h
new file mode 100644
index 0000000..70cf51d
--- /dev/null
+++ b/bsd-user/netbsd/os-strace.h
@@ -0,0 +1 @@
+/* XXX NetBSD dependent strace print functions */
diff --git a/bsd-user/openbsd/os-strace.h b/bsd-user/openbsd/os-strace.h
new file mode 100644
index 0000000..9161390
--- /dev/null
+++ b/bsd-user/openbsd/os-strace.h
@@ -0,0 +1 @@
+/* XXX OpenBSD dependent strace print functions */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index ddc74ed..b8a34c7 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -1,3 +1,19 @@
+/*
+ *  qemu bsd user mode definition
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
 #ifndef QEMU_H
 #define QEMU_H
 
@@ -149,6 +165,16 @@ void fork_end(int child);
 #include "qemu/log.h"
 
 /* strace.c */
+struct syscallname {
+    int nr;
+    const char *name;
+    const char *format;
+    void (*call)(const struct syscallname *,
+                 abi_long, abi_long, abi_long,
+                 abi_long, abi_long, abi_long);
+    void (*result)(const struct syscallname *, abi_long);
+};
+
 void
 print_freebsd_syscall(int num,
                       abi_long arg1, abi_long arg2, abi_long arg3,
diff --git a/bsd-user/sparc/syscall.h b/bsd-user/sparc/syscall.h
index 5a9bb7e..3a5b1e2 100644
--- a/bsd-user/sparc/syscall.h
+++ b/bsd-user/sparc/syscall.h
@@ -1,3 +1,23 @@
+/*
+ *  sparc dependent system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _SPARC_SYSCALL_H_
+#define _SPARC_SYSCALL_H_
+
 struct target_pt_regs {
 	abi_ulong psr;
 	abi_ulong pc;
@@ -6,4 +26,11 @@ struct target_pt_regs {
 	abi_ulong u_regs[16];
 };
 
-#define UNAME_MACHINE "sun4"
+#define UNAME_MACHINE           "sun4"
+#define TARGET_HW_MACHINE       "sparc"
+#define TARGET_HW_MACHINE_ARCH  "sparc"
+
+#define TARGET_SPARC_UTRAP_INSTALL      1
+#define TARGET_SPARC_SIGTRAMP_INSTALL   2
+
+#endif /* ! _SPARC_SYSCALL_H_ */
diff --git a/bsd-user/sparc/target_arch_sysarch.h b/bsd-user/sparc/target_arch_sysarch.h
new file mode 100644
index 0000000..454c084
--- /dev/null
+++ b/bsd-user/sparc/target_arch_sysarch.h
@@ -0,0 +1,52 @@
+/*
+ *  SPARC sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(void *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_SPARC_SIGTRAMP_INSTALL:
+        /* XXX not currently handled */
+    case TARGET_SPARC_UTRAP_INSTALL:
+        /* XXX not currently handled */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", "
+        TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4);
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/sparc64/syscall.h b/bsd-user/sparc64/syscall.h
index 81a816d..58cc38d 100644
--- a/bsd-user/sparc64/syscall.h
+++ b/bsd-user/sparc64/syscall.h
@@ -1,3 +1,22 @@
+/*
+ *  sparc64 dependent system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _SPARC64_SYSCALL_H_
+#define _SPARC64_SYSCALL_H_
 struct target_pt_regs {
 	abi_ulong u_regs[16];
 	abi_ulong tstate;
@@ -7,4 +26,11 @@ struct target_pt_regs {
 	abi_ulong fprs;
 };
 
-#define UNAME_MACHINE "sun4u"
+#define UNAME_MACHINE           "sun4u"
+#define TARGET_HW_MACHINE       "sparc"
+#define TARGET_HW_MACHINE_ARCH  "sparc64"
+
+#define TARGET_SPARC_UTRAP_INSTALL      1
+#define TARGET_SPARC_SIGTRAMP_INSTALL   2
+
+#endif /* !_SPARC64_SYSCALL_H_ */
diff --git a/bsd-user/sparc64/target_arch_sysarch.h b/bsd-user/sparc64/target_arch_sysarch.h
new file mode 100644
index 0000000..84e1339
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_sysarch.h
@@ -0,0 +1,52 @@
+/*
+ *  SPARC64 sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(void *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_SPARC_SIGTRAMP_INSTALL:
+        /* XXX not currently handled */
+    case TARGET_SPARC_UTRAP_INSTALL:
+        /* XXX not currently handled */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", "
+        TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4);
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/strace.c b/bsd-user/strace.c
index d73bbca..60aabc3 100644
--- a/bsd-user/strace.c
+++ b/bsd-user/strace.c
@@ -1,37 +1,73 @@
+/*
+ *  System call tracing and debugging
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
 #include <stdio.h>
 #include <errno.h>
 #include <sys/select.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <sys/syscall.h>
+#include <sys/ioccom.h>
+#include <ctype.h>
+
 #include "qemu.h"
 
-int do_strace=0;
+#include "os-strace.h"  /* OS dependent strace print functions */
 
-struct syscallname {
-    int nr;
-    const char *name;
-    const char *format;
-    void (*call)(const struct syscallname *,
-                 abi_long, abi_long, abi_long,
-                 abi_long, abi_long, abi_long);
-    void (*result)(const struct syscallname *, abi_long);
-};
+int do_strace;
 
 /*
  * Utility functions
  */
 
-static void
-print_execve(const struct syscallname *name,
-             abi_long arg1, abi_long arg2, abi_long arg3,
-             abi_long arg4, abi_long arg5, abi_long arg6)
+static void print_sysctl(const struct syscallname *name, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
+        abi_long arg6)
+{
+    uint32_t i;
+    int32_t *namep;
+
+    gemu_log("%s({ ", name->name);
+    namep = lock_user(VERIFY_READ, arg1, sizeof(int32_t) * arg2, 1);
+    if (namep) {
+        int32_t *p = namep;
+
+        for (i = 0; i < (uint32_t)arg2; i++) {
+            gemu_log("%d ", tswap32(*p++));
+        }
+        unlock_user(namep, arg1, 0);
+    }
+    gemu_log("}, %u, 0x" TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ", 0x"
+        TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ")",
+        (uint32_t)arg2, arg3, arg4, arg5, arg6);
+}
+
+static void print_execve(const struct syscallname *name, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
+        abi_long arg6)
 {
     abi_ulong arg_ptr_addr;
     char *s;
 
-    if (!(s = lock_user_string(arg1)))
+    s = lock_user_string(arg1);
+    if (s == NULL) {
         return;
+    }
     gemu_log("%s(\"%s\",{", name->name, s);
     unlock_user(s, arg1, 0);
 
@@ -39,29 +75,56 @@ print_execve(const struct syscallname *name,
         abi_ulong *arg_ptr, arg_addr;
 
         arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
-        if (!arg_ptr)
+        if (!arg_ptr) {
             return;
+        }
         arg_addr = tswapl(*arg_ptr);
         unlock_user(arg_ptr, arg_ptr_addr, 0);
-        if (!arg_addr)
+        if (!arg_addr) {
             break;
+        }
         if ((s = lock_user_string(arg_addr))) {
             gemu_log("\"%s\",", s);
             unlock_user(s, arg_addr, 0);
         }
     }
-
     gemu_log("NULL})");
 }
 
+static void print_ioctl(const struct syscallname *name,
+        abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4,
+        abi_long arg5, abi_long arg6)
+{
+    /* Decode the ioctl request */
+    gemu_log("%s(%d, 0x%0lx { IO%s%s GRP:0x%x('%c') CMD:%d LEN:%d }, 0x"
+            TARGET_ABI_FMT_lx ", ...)",
+            name->name,
+            (int)arg1,
+            (unsigned long)arg2,
+            arg2 & IOC_OUT ? "R" : "",
+            arg2 & IOC_IN ? "W" : "",
+            (unsigned)IOCGROUP(arg2),
+            isprint(IOCGROUP(arg2)) ? (char)IOCGROUP(arg2) : '?',
+            (int)arg2 & 0xFF,
+            (int)IOCPARM_LEN(arg2),
+            arg3);
+}
+
+static void print_sysarch(const struct syscallname *name, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
+        abi_long arg6)
+{
+    /* This is os dependent. */
+    do_os_print_sysarch(name, arg1, arg2, arg3, arg4, arg5, arg6);
+}
+
 /*
  * Variants for the return value output function
  */
 
-static void
-print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
+static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
 {
-if( ret == -1 ) {
+    if (ret == -1) {
         gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno));
     } else {
         gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
@@ -90,10 +153,9 @@ static const struct syscallname openbsd_scnames[] = {
 #include "openbsd/strace.list"
 };
 
-static void
-print_syscall(int num, const struct syscallname *scnames, unsigned int nscnames,
-              abi_long arg1, abi_long arg2, abi_long arg3,
-              abi_long arg4, abi_long arg5, abi_long arg6)
+static void print_syscall(int num, const struct syscallname *scnames,
+        unsigned int nscnames, abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5, abi_long arg6)
 {
     unsigned int i;
     const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
@@ -102,36 +164,37 @@ print_syscall(int num, const struct syscallname *scnames, unsigned int nscnames,
 
     gemu_log("%d ", getpid() );
 
-    for (i = 0; i < nscnames; i++)
+    for (i = 0; i < nscnames; i++) {
         if (scnames[i].nr == num) {
             if (scnames[i].call != NULL) {
                 scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5,
-                                arg6);
+                        arg6);
             } else {
                 /* XXX: this format system is broken because it uses
                    host types and host pointers for strings */
-                if (scnames[i].format != NULL)
+                if (scnames[i].format != NULL) {
                     format = scnames[i].format;
-                gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4,
-                         arg5, arg6);
+                }
+                gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4, arg5,
+                        arg6);
             }
             return;
         }
+    }
     gemu_log("Unknown syscall %d\n", num);
 }
 
-static void
-print_syscall_ret(int num, abi_long ret, const struct syscallname *scnames,
-                  unsigned int nscnames)
+static void print_syscall_ret(int num, abi_long ret,
+        const struct syscallname *scnames, unsigned int nscnames)
 {
     unsigned int i;
 
-    for (i = 0; i < nscnames; i++)
+    for (i = 0; i < nscnames; i++) {
         if (scnames[i].nr == num) {
             if (scnames[i].result != NULL) {
                 scnames[i].result(&scnames[i], ret);
             } else {
-                if( ret < 0 ) {
+                if (ret < 0) {
                     gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret,
                              strerror(-ret));
                 } else {
@@ -140,52 +203,50 @@ print_syscall_ret(int num, abi_long ret, const struct syscallname *scnames,
             }
             break;
         }
+    }
 }
 
 /*
  * The public interface to this module.
  */
-void
-print_freebsd_syscall(int num,
-                      abi_long arg1, abi_long arg2, abi_long arg3,
-                      abi_long arg4, abi_long arg5, abi_long arg6)
+void print_freebsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5, abi_long arg6)
 {
-    print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames),
-                  arg1, arg2, arg3, arg4, arg5, arg6);
+
+    print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames), arg1, arg2,
+            arg3, arg4, arg5, arg6);
 }
 
-void
-print_freebsd_syscall_ret(int num, abi_long ret)
+void print_freebsd_syscall_ret(int num, abi_long ret)
 {
+
     print_syscall_ret(num, ret, freebsd_scnames, ARRAY_SIZE(freebsd_scnames));
 }
 
-void
-print_netbsd_syscall(int num,
-                      abi_long arg1, abi_long arg2, abi_long arg3,
-                      abi_long arg4, abi_long arg5, abi_long arg6)
+void print_netbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5, abi_long arg6)
 {
+
     print_syscall(num, netbsd_scnames, ARRAY_SIZE(netbsd_scnames),
                   arg1, arg2, arg3, arg4, arg5, arg6);
 }
 
-void
-print_netbsd_syscall_ret(int num, abi_long ret)
+void print_netbsd_syscall_ret(int num, abi_long ret)
 {
+
     print_syscall_ret(num, ret, netbsd_scnames, ARRAY_SIZE(netbsd_scnames));
 }
 
-void
-print_openbsd_syscall(int num,
-                      abi_long arg1, abi_long arg2, abi_long arg3,
-                      abi_long arg4, abi_long arg5, abi_long arg6)
+void print_openbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5, abi_long arg6)
 {
-    print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames),
-                  arg1, arg2, arg3, arg4, arg5, arg6);
+
+    print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames), arg1, arg2,
+            arg3, arg4, arg5, arg6);
 }
 
-void
-print_openbsd_syscall_ret(int num, abi_long ret)
+void print_openbsd_syscall_ret(int num, abi_long ret)
 {
+
     print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
 }
diff --git a/bsd-user/x86_64/syscall.h b/bsd-user/x86_64/syscall.h
index 630514a..4fff6a5 100644
--- a/bsd-user/x86_64/syscall.h
+++ b/bsd-user/x86_64/syscall.h
@@ -1,3 +1,23 @@
+/*
+ *  x86_64 system call definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _X86_64_SYSCALL_H_
+#define _X86_64_SYSCALL_H_
+
 #define __USER_CS	(0x33)
 #define __USER_DS	(0x2B)
 
@@ -108,9 +128,13 @@ struct target_msqid64_ds {
 #define TARGET_FREEBSD_AMD64_SET_GSBASE	131
 
 
-#define UNAME_MACHINE "x86_64"
+#define UNAME_MACHINE           "x86_64"
+#define TARGET_HW_MACHINE       "amd64"
+#define TARGET_HW_MACHINE_ARCH  "amd64"
 
 #define TARGET_ARCH_SET_GS 0x1001
 #define TARGET_ARCH_SET_FS 0x1002
 #define TARGET_ARCH_GET_FS 0x1003
 #define TARGET_ARCH_GET_GS 0x1004
+
+#endif /* ! _X86_64_SYSCALL_H_ */
diff --git a/bsd-user/x86_64/target_arch_sysarch.h b/bsd-user/x86_64/target_arch_sysarch.h
new file mode 100644
index 0000000..6d09d50
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_sysarch.h
@@ -0,0 +1,76 @@
+/*
+ *  x86_64 sysarch() syscall emulation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUX86State *env, int op,
+        abi_ulong parms)
+{
+    abi_long ret = 0;
+    abi_ulong val;
+    int idx;
+
+    switch (op) {
+    case TARGET_FREEBSD_AMD64_SET_GSBASE:
+    case TARGET_FREEBSD_AMD64_SET_FSBASE:
+        if (op == TARGET_FREEBSD_AMD64_SET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        if (get_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        cpu_x86_load_seg(env, idx, 0);
+        env->segs[idx].base = val;
+        break;
+
+    case TARGET_FREEBSD_AMD64_GET_GSBASE:
+    case TARGET_FREEBSD_AMD64_GET_FSBASE:
+        if (op == TARGET_FREEBSD_AMD64_GET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        val = env->segs[idx].base;
+        if (put_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    /* XXX handle the others... */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+        const struct syscallname *name, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+    gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", "
+        TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4);
+}
+
+#endif /*! __ARCH_SYSARCH_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 04/19] bsd-user: move arch/OS dependent code out of main.c
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (4 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 03/19] bsd-user: move strace OS/arch dependent code to host/arch dirs Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2014-01-27 19:50     ` Peter Maydell
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 05/19] bsd-user: move arch/OS dependent code out of syscall.c Stacey Son
                     ` (14 subsequent siblings)
  20 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change moves the cpu initialization and main loop code from
main.c to the OS and arch dependent directories. This eliminates
many of the #ifdef's in main.c. The cpu initialization and loop
code is now located in the arch directory along with target arch
support code.
---
 bsd-user/Makefile.objs                 |    2 +-
 bsd-user/arm/target_arch.h             |   10 +
 bsd-user/arm/target_arch_cpu.c         |   27 +
 bsd-user/arm/target_arch_cpu.h         |  375 +++++++++++++
 bsd-user/arm/target_arch_vmparam.h     |   48 ++
 bsd-user/elfload.c                     |    2 +-
 bsd-user/freebsd/host_os.h             |   46 ++
 bsd-user/freebsd/target_os_vmparam.h   |   23 +
 bsd-user/i386/target_arch.h            |   13 +
 bsd-user/i386/target_arch_cpu.c        |   79 +++
 bsd-user/i386/target_arch_cpu.h        |  302 +++++++++++
 bsd-user/i386/target_arch_vmparam.h    |   28 +
 bsd-user/i386/target_signal.h          |    6 -
 bsd-user/main.c                        |  927 +++++++-------------------------
 bsd-user/mips/target_arch.h            |   10 +
 bsd-user/mips/target_arch_cpu.c        |   27 +
 bsd-user/mips/target_arch_cpu.h        |  257 +++++++++
 bsd-user/mips/target_arch_vmparam.h    |   50 ++
 bsd-user/mips64/target_arch.h          |   10 +
 bsd-user/mips64/target_arch_cpu.c      |   27 +
 bsd-user/mips64/target_arch_cpu.h      |  243 +++++++++
 bsd-user/mips64/target_arch_vmparam.h  |   47 ++
 bsd-user/netbsd/host_os.h              |   31 ++
 bsd-user/openbsd/host_os.h             |   31 ++
 bsd-user/qemu.h                        |   10 +-
 bsd-user/sparc/target_arch.h           |   11 +
 bsd-user/sparc/target_arch_cpu.c       |  113 ++++
 bsd-user/sparc/target_arch_cpu.h       |  158 ++++++
 bsd-user/sparc/target_arch_vmparam.h   |   37 ++
 bsd-user/sparc/target_signal.h         |    5 -
 bsd-user/sparc64/target_arch.h         |   11 +
 bsd-user/sparc64/target_arch_cpu.c     |  118 ++++
 bsd-user/sparc64/target_arch_cpu.h     |  191 +++++++
 bsd-user/sparc64/target_arch_vmparam.h |   37 ++
 bsd-user/sparc64/target_signal.h       |    5 -
 bsd-user/x86_64/target_arch.h          |   13 +
 bsd-user/x86_64/target_arch_cpu.c      |   79 +++
 bsd-user/x86_64/target_arch_cpu.h      |  324 +++++++++++
 bsd-user/x86_64/target_arch_vmparam.h  |   28 +
 bsd-user/x86_64/target_signal.h        |    5 -
 40 files changed, 3001 insertions(+), 765 deletions(-)
 create mode 100644 bsd-user/arm/target_arch.h
 create mode 100644 bsd-user/arm/target_arch_cpu.c
 create mode 100644 bsd-user/arm/target_arch_cpu.h
 create mode 100644 bsd-user/arm/target_arch_vmparam.h
 create mode 100644 bsd-user/freebsd/host_os.h
 create mode 100644 bsd-user/freebsd/target_os_vmparam.h
 create mode 100644 bsd-user/i386/target_arch.h
 create mode 100644 bsd-user/i386/target_arch_cpu.c
 create mode 100644 bsd-user/i386/target_arch_cpu.h
 create mode 100644 bsd-user/i386/target_arch_vmparam.h
 create mode 100644 bsd-user/mips/target_arch.h
 create mode 100644 bsd-user/mips/target_arch_cpu.c
 create mode 100644 bsd-user/mips/target_arch_cpu.h
 create mode 100644 bsd-user/mips/target_arch_vmparam.h
 create mode 100644 bsd-user/mips64/target_arch.h
 create mode 100644 bsd-user/mips64/target_arch_cpu.c
 create mode 100644 bsd-user/mips64/target_arch_cpu.h
 create mode 100644 bsd-user/mips64/target_arch_vmparam.h
 create mode 100644 bsd-user/netbsd/host_os.h
 create mode 100644 bsd-user/openbsd/host_os.h
 create mode 100644 bsd-user/sparc/target_arch.h
 create mode 100644 bsd-user/sparc/target_arch_cpu.c
 create mode 100644 bsd-user/sparc/target_arch_cpu.h
 create mode 100644 bsd-user/sparc/target_arch_vmparam.h
 create mode 100644 bsd-user/sparc64/target_arch.h
 create mode 100644 bsd-user/sparc64/target_arch_cpu.c
 create mode 100644 bsd-user/sparc64/target_arch_cpu.h
 create mode 100644 bsd-user/sparc64/target_arch_vmparam.h
 create mode 100644 bsd-user/x86_64/target_arch.h
 create mode 100644 bsd-user/x86_64/target_arch_cpu.c
 create mode 100644 bsd-user/x86_64/target_arch_cpu.h
 create mode 100644 bsd-user/x86_64/target_arch_vmparam.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 5e77f57..41e8dce 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,2 +1,2 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o
+	        uaccess.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/arm/target_arch.h b/bsd-user/arm/target_arch.h
new file mode 100644
index 0000000..b5c5ddb
--- /dev/null
+++ b/bsd-user/arm/target_arch.h
@@ -0,0 +1,10 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+#include "qemu.h"
+
+void target_cpu_set_tls(CPUARMState *env, target_ulong newtls);
+target_ulong target_cpu_get_tls(CPUARMState *env);
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/arm/target_arch_cpu.c b/bsd-user/arm/target_arch_cpu.c
new file mode 100644
index 0000000..d94a32a
--- /dev/null
+++ b/bsd-user/arm/target_arch_cpu.c
@@ -0,0 +1,27 @@
+/*
+ *  arm cpu related code
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "target_arch.h"
+
+void target_cpu_set_tls(CPUARMState *env, target_ulong newtls)
+{
+    env->cp15.c13_tls2 = newtls;
+}
+
+target_ulong target_cpu_get_tls(CPUARMState *env)
+{
+    return (env->cp15.c13_tls2);
+}
diff --git a/bsd-user/arm/target_arch_cpu.h b/bsd-user/arm/target_arch_cpu.h
new file mode 100644
index 0000000..3eeb34a
--- /dev/null
+++ b/bsd-user/arm/target_arch_cpu.h
@@ -0,0 +1,375 @@
+/*
+ *  arm cpu init and loop
+ *
+ *  Olivier Houchard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+// #define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__)
+#define DEBUG_PRINTF(...)
+
+#define TARGET_DEFAULT_CPU_MODEL "any"
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUARMState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    cpsr_write(env, regs->uregs[16], 0xffffffff);
+    for (i = 0; i < 16; i++) {
+        env->regs[i] = regs->uregs[i];
+    }
+}
+
+static inline int do_strex(CPUARMState *env)
+{
+    uint32_t val;
+    int size;
+    int rc = 1;
+    int segv = 0;
+    uint32_t addr;
+    start_exclusive();
+    addr = env->exclusive_addr;
+    if (addr != env->exclusive_test) {
+        goto fail;
+    }
+    size = env->exclusive_info & 0xf;
+    switch (size) {
+    case 0:
+        segv = get_user_u8(val, addr);
+        break;
+    case 1:
+        segv = get_user_u16(val, addr);
+        break;
+    case 2:
+    case 3:
+        segv = get_user_u32(val, addr);
+        break;
+    default:
+        abort();
+    }
+    if (segv) {
+        env->cp15.c6_data = addr;
+        goto done;
+    }
+    if (val != env->exclusive_val) {
+        goto fail;
+    }
+    if (size == 3) {
+        segv = get_user_u32(val, addr + 4);
+        if (segv) {
+            env->cp15.c6_data = addr + 4;
+            goto done;
+        }
+        if (val != env->exclusive_high) {
+            goto fail;
+        }
+    }
+    val = env->regs[(env->exclusive_info >> 8) & 0xf];
+    switch (size) {
+    case 0:
+        segv = put_user_u8(val, addr);
+        break;
+    case 1:
+        segv = put_user_u16(val, addr);
+        break;
+    case 2:
+    case 3:
+        segv = put_user_u32(val, addr);
+        break;
+    }
+    if (segv) {
+        env->cp15.c6_data = addr;
+        goto done;
+    }
+    if (size == 3) {
+        val = env->regs[(env->exclusive_info >> 12) & 0xf];
+        segv = put_user_u32(val, addr + 4);
+        if (segv) {
+            env->cp15.c6_data = addr + 4;
+            goto done;
+        }
+    }
+    rc = 0;
+fail:
+    env->regs[15] += 4;
+    env->regs[(env->exclusive_info >> 4) & 0xf] = rc;
+done:
+    end_exclusive();
+    return segv;
+}
+
+static inline void target_cpu_loop(CPUARMState *env)
+{
+    int trapnr;
+    target_siginfo_t info;
+    unsigned int n;
+    uint32_t addr;
+    CPUState *cs = CPU(arm_env_get_cpu(env));
+
+    for (;;) {
+        DEBUG_PRINTF("CPU_LOOPING\n");
+        cpu_exec_start(cs);
+        DEBUG_PRINTF("EXECUTING...\n");
+        trapnr = cpu_arm_exec(env);
+        DEBUG_PRINTF("trapnr %d\n", trapnr);
+        cpu_exec_end(cs);
+        switch (trapnr) {
+        case EXCP_UDEF:
+            {
+                /* See arm/arm/undefined.c undefinedinstruction(); */
+                info.si_addr = env->regs[15];
+
+                /*
+                 * Make sure the PC is correctly aligned. (It should
+                 * be.)
+                 */
+                if ((info.si_addr & 3) != 0) {
+                    info.si_signo = SIGILL;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_ILL_ILLADR;
+                    queue_signal(env, info.si_signo, &info);
+                } else {
+                    int rc = 0;
+#ifdef NOT_YET
+                    uint32_t opcode;
+
+                    /*
+                     * Get the opcode.
+                     *
+                     * FIXME - what to do if get_user() fails?
+                     */
+                    get_user_u32(opcode, env->regs[15]);
+
+                    /* Check the opcode with CP handlers we may have. */
+                    rc = EmulateAll(opcode, &ts-fpa, env);
+#endif /* NOT_YET */
+                    if (rc == 0) {
+                        /* illegal instruction */
+                        info.si_signo = SIGILL;
+                        info.si_errno = 0;
+                        info.si_code = TARGET_ILL_ILLOPC;
+                        queue_signal(env, info.si_signo, &info);
+                    }
+                }
+            }
+            break;
+        case EXCP_SWI:
+        case EXCP_BKPT:
+            {
+                unsigned int insn;
+#ifdef FREEBSD_ARM_OABI
+                env->eabi = 0;
+#else
+                env->eabi = 1;
+#endif
+                /*
+                 * system call
+                 * See arm/arm/trap.c cpu_fetch_syscall_args()
+                 */
+                if (trapnr == EXCP_BKPT) {
+                    if (env->thumb) {
+                        if (env->eabi) {
+                            n = env->regs[7];
+                        } else {
+                            /* FIXME - what to do if get_user() fails? */
+                            get_user_u16(insn, env->regs[15]);
+                            n = insn & 0xff;
+                        }
+                        env->regs[15] += 2;
+                    } else {
+                        if (env->eabi) {
+                            n = env->regs[7];
+                        } else {
+                            /* FIXME - what to do if get_user() fails? */
+                            get_user_u32(insn, env->regs[15]);
+                            n = (insn & 0xf) | ((insn >> 4) & 0xff0);
+                        }
+                        env->regs[15] += 4;
+                    }
+                } else { /* trapnr != EXCP_BKPT */
+                    if (env->thumb) {
+                        if (env->eabi) {
+                            n = env->regs[7];
+                        } else {
+                            /* FIXME - what to do if get_user() fails? */
+                            get_user_u16(insn, env->regs[15] - 2);
+                            n = insn & 0xff;
+                        }
+                    } else {
+                        if (env->eabi) {
+                            n = env->regs[7];
+                        } else {
+                            /* FIXME - what to do if get_user() fails? */
+                            get_user_u32(insn, env->regs[15] - 4);
+                            n = insn & 0xffffff;
+                        }
+                    }
+                }
+                DEBUG_PRINTF("AVANT CALL %d\n", n);
+                if (bsd_type == target_freebsd) {
+                    int ret;
+                    abi_ulong params = get_sp_from_cpustate(env);
+                    int32_t syscall_nr = n;
+                    int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+                    /* See arm/arm/trap.c cpu_fetch_syscall_args() */
+                    if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                        syscall_nr = env->regs[0];
+                        arg1 = env->regs[1];
+                        arg2 = env->regs[2];
+                        arg3 = env->regs[3];
+                        get_user_s32(arg4, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg5, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg6, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg7, params);
+                        arg8 = 0;
+                    } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+#ifdef TARGET_WORDS_BIGENDIAN
+                        syscall_nr = env->regs[1];
+#else
+                        syscall_nr = env->regs[0];
+#endif
+                        arg1 = env->regs[2];
+                        arg2 = env->regs[3];
+                        get_user_s32(arg3, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg4, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg5, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg6, params);
+                        arg7 = 0;
+                        arg8 = 0;
+                    } else {
+                        arg1 = env->regs[0];
+                        arg2 = env->regs[1];
+                        arg3 = env->regs[2];
+                        arg4 = env->regs[3];
+                        get_user_s32(arg5, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg6, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg7, params);
+                        params += sizeof(int32_t);
+                        get_user_s32(arg8, params);
+                    }
+                    ret = do_freebsd_syscall(env, syscall_nr, arg1, arg2, arg3,
+                            arg4, arg5, arg6, arg7, arg8);
+                    /*
+                     * Compare to arm/arm/vm_machdep.c
+                     * cpu_set_syscall_retval()
+                     */
+                    /* XXX armeb may need some extra magic here */
+                    if (-TARGET_EJUSTRETURN == ret) {
+                        /*
+                         * Returning from a successful sigreturn syscall.
+                         * Avoid clobbering register state.
+                         */
+                        break;
+                    }
+                    /*
+                     * XXX Need to handle ERESTART. Backup the PC by
+                     * 1 instruction.
+                     */
+                    if ((unsigned int)ret >= (unsigned int)(-515)) {
+                        ret = -ret;
+                        cpsr_write(env, CPSR_C, CPSR_C);
+                        env->regs[0] = ret;
+                    } else {
+                        cpsr_write(env, 0, CPSR_C);
+                        env->regs[0] = ret; /* XXX need to handle lseek()? */
+                        /* env->regs[1] = 0; */
+                    }
+                } /* else if (bsd_type == target_openbsd)... */
+                else {
+                    fprintf(stderr, "qemu: bsd_type (= %d) syscall "
+                            "not supported\n", bsd_type);
+                }
+                DEBUG_PRINTF("APRES CALL\n");
+            }
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_PREFETCH_ABORT:
+            /* See arm/arm/trap.c prefetch_abort_handler() */
+            addr = env->cp15.c6_insn;
+            goto do_segv;
+        case EXCP_DATA_ABORT:
+            /* See arm/arm/trap.c data_abort_handler() */
+            addr = env->cp15.c6_data;
+        do_segv:
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = 0;
+                info.si_addr = addr;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                }
+            }
+            break;
+        /* XXX case EXCP_KERNEL_TRAP: */
+        case EXCP_STREX:
+            if (do_strex(env)) {
+                addr = env->cp15.c6_data;
+                goto do_segv;
+            }
+            break;
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+                    trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            abort();
+        } /* switch() */
+        process_pending_signals(env);
+    } /* for (;;) */
+}
+
+static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[13] = newsp;
+    env->regs[0] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+}
+
+#endif /* !_TARGET_ARCH_CPU_H */
diff --git a/bsd-user/arm/target_arch_vmparam.h b/bsd-user/arm/target_arch_vmparam.h
new file mode 100644
index 0000000..014fc66
--- /dev/null
+++ b/bsd-user/arm/target_arch_vmparam.h
@@ -0,0 +1,48 @@
+/*
+ *  arm VM parameters definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to sys/arm/include/vmparam.h */
+#define TARGET_MAXTSIZ      (64UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ      (128UL*1024*1024)   /* initial data size limit */
+#define TARGET_MAXDSIZ      (512UL*1024*1024)    /* max data size */
+#define TARGET_DFLSSIZ      (2UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ      (8UL*1024*1024)    /* max stack size */
+#define TARGET_SGROWSIZ     (128UL*1024)        /* amount to grow stack */
+
+#define TARGET_RESERVED_VA  0xf7000000
+
+                /* KERNBASE - 512 MB */
+#define TARGET_VM_MAXUSER_ADDRESS   (0xc0000000 - (512 * 1024 * 1024))
+#define TARGET_USRSTACK             TARGET_VM_MAXUSER_ADDRESS
+
+static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
+{
+    return state->regs[13]; /* sp */
+}
+
+static inline void set_second_rval(CPUARMState *state, abi_ulong retval2)
+{
+    state->regs[1] = retval2;
+}
+
+#endif  /* ! _TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 93fd9e4..ccf72d1 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -674,7 +674,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
     /* Create enough stack to hold everything.  If we don't use
      * it for args, we'll use it for something else...
      */
-    size = x86_stack_size;
+    size = target_dflssiz;
     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
     error = target_mmap(0,
diff --git a/bsd-user/freebsd/host_os.h b/bsd-user/freebsd/host_os.h
new file mode 100644
index 0000000..efe2351
--- /dev/null
+++ b/bsd-user/freebsd/host_os.h
@@ -0,0 +1,46 @@
+/*
+ *  FreeBSD host dependent code and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST_OS_H_
+#define __HOST_OS_H_
+
+#include <stdio.h>
+#include <sys/sysctl.h>
+
+#include "qemu.h"
+
+#define HOST_DEFAULT_BSD_TYPE target_freebsd
+
+static inline void save_proc_pathname(char *argv0)
+{
+    int mib[4];
+    size_t len;
+
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_PATHNAME;
+    mib[3] = -1;
+
+    len = PATH_MAX;
+    if (sysctl(mib, 4, qemu_proc_pathname, &len, NULL, 0)) {
+        perror("sysctl");
+    }
+}
+
+#endif /*!__HOST_OS_H_ */
diff --git a/bsd-user/freebsd/target_os_vmparam.h b/bsd-user/freebsd/target_os_vmparam.h
new file mode 100644
index 0000000..80ac6c8
--- /dev/null
+++ b/bsd-user/freebsd/target_os_vmparam.h
@@ -0,0 +1,23 @@
+#ifndef _TARGET_OS_VMPARAM_H_
+#define _TARGET_OS_VMPARAM_H_
+
+#include "target_arch_vmparam.h"
+
+#define TARGET_SPACE_USRSPACE   4096
+#define TARGET_ARG_MAX          262144
+
+/* Compare to sys/exec.h */
+struct target_ps_strings {
+    abi_ulong ps_argvstr;
+    uint32_t ps_nargvstr;
+    abi_ulong ps_envstr;
+    uint32_t ps_nenvstr;
+};
+
+extern abi_ulong target_stkbas;
+extern abi_ulong target_stksiz;
+
+#define TARGET_PS_STRINGS  ((target_stkbas + target_stksiz) - \
+		sizeof(struct target_ps_strings))
+
+#endif /* !TARGET_OS_VMPARAM_H_ */
diff --git a/bsd-user/i386/target_arch.h b/bsd-user/i386/target_arch.h
new file mode 100644
index 0000000..4cb398c
--- /dev/null
+++ b/bsd-user/i386/target_arch.h
@@ -0,0 +1,13 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+/* target_arch_cpu.c */
+void bsd_i386_write_dt(void *ptr, unsigned long addr, unsigned long limit,
+                int flags);
+void bsd_i386_set_idt(int n, unsigned int dpl);
+void bsd_i386_set_idt_base(uint64_t base);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* ! _TARGET_ARCH_H_ */
diff --git a/bsd-user/i386/target_arch_cpu.c b/bsd-user/i386/target_arch_cpu.c
new file mode 100644
index 0000000..2e0eec0
--- /dev/null
+++ b/bsd-user/i386/target_arch_cpu.c
@@ -0,0 +1,79 @@
+/*
+ *  i386 cpu related code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+#include "qemu/timer.h"
+
+#include "target_arch.h"
+
+static uint64_t *idt_table;
+
+/* CPUX86 core interface */
+void cpu_smm_update(CPUX86State *env)
+{
+}
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+    return cpu_get_real_ticks();
+}
+
+int cpu_get_pic_interrupt(CPUX86State *env)
+{
+    return -1;
+}
+
+void bsd_i386_write_dt(void *ptr, unsigned long addr, unsigned long limit,
+                     int flags)
+{
+    unsigned int e1, e2;
+    uint32_t *p;
+    e1 = (addr << 16) | (limit & 0xffff);
+    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+    e2 |= flags;
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+                     uint32_t addr, unsigned int sel)
+{
+    uint32_t *p, e1, e2;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+/* only dpl matters as we do only user space emulation */
+void bsd_i386_set_idt(int n, unsigned int dpl)
+{
+    set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+
+void bsd_i386_set_idt_base(uint64_t base)
+{
+    idt_table = g2h(base);
+}
+
diff --git a/bsd-user/i386/target_arch_cpu.h b/bsd-user/i386/target_arch_cpu.h
new file mode 100644
index 0000000..c3df814
--- /dev/null
+++ b/bsd-user/i386/target_arch_cpu.h
@@ -0,0 +1,302 @@
+/*
+ *  i386 cpu init and loop
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "qemu32"
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUX86State *env,
+        struct target_pt_regs *regs)
+{
+    uint64_t *gdt_table;
+
+    cpu_x86_set_cpl(env, 3);
+
+    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+    env->hflags |= HF_PE_MASK;
+    if (env->features[FEAT_1_EDX] & CPUID_SSE) {
+        env->cr[4] |= CR4_OSFXSR_MASK;
+        env->hflags |= HF_OSFXSR_MASK;
+    }
+
+    /* flags setup : we activate the IRQs by default as in user mode */
+    env->eflags |= IF_MASK;
+
+    /* register setup */
+    env->regs[R_EAX] = regs->eax;
+    env->regs[R_EBX] = regs->ebx;
+    env->regs[R_ECX] = regs->ecx;
+    env->regs[R_EDX] = regs->edx;
+    env->regs[R_ESI] = regs->esi;
+    env->regs[R_EDI] = regs->edi;
+    env->regs[R_EBP] = regs->ebp;
+    env->regs[R_ESP] = regs->esp;
+    env->eip = regs->eip;
+
+    /* interrupt setup */
+    env->idt.limit = 255;
+
+    env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+        PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    bsd_i386_set_idt_base(env->idt.base);
+    bsd_i386_set_idt(0, 0);
+    bsd_i386_set_idt(1, 0);
+    bsd_i386_set_idt(2, 0);
+    bsd_i386_set_idt(3, 3);
+    bsd_i386_set_idt(4, 3);
+    bsd_i386_set_idt(5, 0);
+    bsd_i386_set_idt(6, 0);
+    bsd_i386_set_idt(7, 0);
+    bsd_i386_set_idt(8, 0);
+    bsd_i386_set_idt(9, 0);
+    bsd_i386_set_idt(10, 0);
+    bsd_i386_set_idt(11, 0);
+    bsd_i386_set_idt(12, 0);
+    bsd_i386_set_idt(13, 0);
+    bsd_i386_set_idt(14, 0);
+    bsd_i386_set_idt(15, 0);
+    bsd_i386_set_idt(16, 0);
+    bsd_i386_set_idt(17, 0);
+    bsd_i386_set_idt(18, 0);
+    bsd_i386_set_idt(19, 0);
+    bsd_i386_set_idt(0x80, 3);
+
+    /* segment setup */
+    env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+            PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+    gdt_table = g2h(env->gdt.base);
+
+    bsd_i386_write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+            (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+
+    bsd_i386_write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+            (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+
+    cpu_x86_load_seg(env, R_CS, __USER_CS);
+    cpu_x86_load_seg(env, R_SS, __USER_DS);
+    cpu_x86_load_seg(env, R_DS, __USER_DS);
+    cpu_x86_load_seg(env, R_ES, __USER_DS);
+    cpu_x86_load_seg(env, R_FS, __USER_DS);
+    cpu_x86_load_seg(env, R_GS, __USER_DS);
+    /* This hack makes Wine work... */
+    env->segs[R_FS].selector = 0;
+}
+
+static inline void target_cpu_loop(CPUX86State *env)
+{
+    int trapnr;
+    abi_ulong pc;
+    /* target_siginfo_t info; */
+
+    for (;;) {
+        trapnr = cpu_x86_exec(env);
+        switch (trapnr) {
+        case 0x80:
+            /* syscall from int $0x80 */
+            if (bsd_type == target_freebsd) {
+                abi_ulong params = (abi_ulong) env->regs[R_ESP] +
+                    sizeof(int32_t);
+                int32_t syscall_nr = env->regs[R_EAX];
+                int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+                if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int32_t);
+                } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int64_t);
+                }
+                get_user_s32(arg1, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg2, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg3, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg4, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg5, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg6, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg7, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg8, params);
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      syscall_nr,
+                                                      arg1,
+                                                      arg2,
+                                                      arg3,
+                                                      arg4,
+                                                      arg5,
+                                                      arg6,
+                                                      arg7,
+                                                      arg8);
+            } else { /* if (bsd_type == target_openbsd) */
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EBX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_EBP]);
+            }
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
+            break;
+
+#if 0
+        case EXCP0B_NOSEG:
+        case EXCP0C_STACK:
+            info.si_signo = SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP0D_GPF:
+            /* XXX: potential problem if ABI32 */
+            if (env->eflags & VM_MASK) {
+                handle_vm86_fault(env);
+            } else {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+
+        case EXCP0E_PAGE:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            if (!(env->error_code & 1)) {
+                info.si_code = TARGET_SEGV_MAPERR;
+            } else {
+                info.si_code = TARGET_SEGV_ACCERR;
+            }
+            info._sifields._sigfault._addr = env->cr[2];
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP00_DIVZ:
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else {
+                /* division by zero */
+                info.si_signo = SIGFPE;
+                info.si_errno = 0;
+                info.si_code = TARGET_FPE_INTDIV;
+                info._sifields._sigfault._addr = env->eip;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+
+        case EXCP01_DB:
+        case EXCP03_INT3:
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else {
+                info.si_signo = SIGTRAP;
+                info.si_errno = 0;
+                if (trapnr == EXCP01_DB) {
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    info._sifields._sigfault._addr = env->eip;
+                } else {
+                    info.si_code = TARGET_SI_KERNEL;
+                    info._sifields._sigfault._addr = 0;
+                }
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+
+        case EXCP04_INTO:
+        case EXCP05_BOUND:
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+
+        case EXCP06_ILLOP:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(env, info.si_signo, &info);
+            break;
+#endif
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+#if 0
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(env, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                }
+            }
+            break;
+#endif
+        default:
+            pc = env->segs[R_CS].base + env->eip;
+            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - "
+                    "aborting\n", (long)pc, trapnr);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[R_ESP] = newsp;
+    env->regs[R_EAX] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+    cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/i386/target_arch_vmparam.h b/bsd-user/i386/target_arch_vmparam.h
new file mode 100644
index 0000000..f15af91
--- /dev/null
+++ b/bsd-user/i386/target_arch_vmparam.h
@@ -0,0 +1,28 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to i386/include/vmparam.h */
+#define TARGET_MAXTSIZ  (128UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ  (128UL*1024*1024)   /* initial data size limit */
+#define TARGET_MAXDSIZ  (512UL*1024*1024)   /* max data size */
+#define TARGET_DFLSSIZ  (8UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ  (64UL*1024*1024)    /* max stack size */
+#define TARGET_SGROWSIZ (128UL*1024)        /* amount to grow stack */
+
+#define TARGET_RESERVED_VA 0xf7000000
+
+#define TARGET_USRSTACK (0xbfc00000)
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+    return state->regs[R_ESP];
+}
+
+static inline void set_second_rval(CPUX86State *state, abi_ulong retval2)
+{
+    state->regs[R_EDX] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/i386/target_signal.h b/bsd-user/i386/target_signal.h
index 2ef36d1..5491687 100644
--- a/bsd-user/i386/target_signal.h
+++ b/bsd-user/i386/target_signal.h
@@ -11,10 +11,4 @@ typedef struct target_sigaltstack {
 	abi_ulong ss_size;
 } target_stack_t;
 
-
-static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
-{
-    return state->regs[R_ESP];
-}
-
 #endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/main.c b/bsd-user/main.c
index f9246aa..44d8f98 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -1,7 +1,8 @@
 /*
- *  qemu user main
+ *  qemu bsd user main
  *
  *  Copyright (c) 2003-2008 Fabrice Bellard
+ *  Copyright (c) 2013 Stacey Son
  *
  *  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
@@ -23,652 +24,183 @@
 #include <errno.h>
 #include <unistd.h>
 #include <machine/trap.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
 #include <sys/mman.h>
 
 #include "qemu.h"
 #include "qemu-common.h"
-/* For tb_lock */
 #include "cpu.h"
 #include "tcg.h"
 #include "qemu/timer.h"
 #include "qemu/envlist.h"
 
+#include "host_os.h"
+#include "target_arch_cpu.h"
+
 int singlestep;
-#if defined(CONFIG_USE_GUEST_BASE)
+static const char *cpu_model;
 unsigned long mmap_min_addr;
+#if defined(CONFIG_USE_GUEST_BASE)
 unsigned long guest_base;
 int have_guest_base;
+#if (TARGET_LONG_BITS == 32) && (HOST_LONG_BITS == 64)
+/*
+ * When running 32-on-64 we should make sure we can fit all of the possible
+ * guest address space into a contiguous chunk of virtual host memory.
+ *
+ * This way we will never overlap with our own libraries or binaries or stack
+ * or anything else that QEMU maps.
+ */
+unsigned long reserved_va = TARGET_RESERVED_VA;
+#else
 unsigned long reserved_va;
 #endif
+#endif /* CONFIG_USE_GUEST_BASE */
 
 static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 extern char **environ;
 enum BSDType bsd_type;
 
-/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
-   we allocate a bigger stack. Need a better solution, for example
-   by remapping the process stack directly at the right place */
-unsigned long x86_stack_size = 512 * 1024;
-
-void gemu_log(const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-}
-
-#if defined(TARGET_I386)
-int cpu_get_pic_interrupt(CPUX86State *env)
-{
-    return -1;
-}
-#endif
-
-/* These are no-ops because we are not threadsafe.  */
-static inline void cpu_exec_start(CPUArchState *env)
-{
-}
+unsigned long target_maxtsiz = TARGET_MAXTSIZ;   /* max text size */
+unsigned long target_dfldsiz = TARGET_DFLDSIZ;   /* initial data size limit */
+unsigned long target_maxdsiz = TARGET_MAXDSIZ;   /* max data size */
+unsigned long target_dflssiz = TARGET_DFLSSIZ;   /* initial data size limit */
+unsigned long target_maxssiz = TARGET_MAXSSIZ;   /* max stack size */
+unsigned long target_sgrowsiz = TARGET_SGROWSIZ; /* amount to grow stack */
 
-static inline void cpu_exec_end(CPUArchState *env)
-{
-}
+char qemu_proc_pathname[PATH_MAX];  /* full path to exeutable */
 
-static inline void start_exclusive(void)
-{
-}
+/* Helper routines for implementing atomic operations. */
 
-static inline void end_exclusive(void)
-{
-}
+/*
+ * To implement exclusive operations we force all cpus to synchronize.
+ * We don't require a full sync, only that no cpus are executing guest code.
+ * The alternative is to map target atomic ops onto host eqivalents,
+ * which requires quite a lot of per host/target work.
+ */
+static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
+static int pending_cpus;
 
+/* Make sure everything is in a consistent state for calling fork(). */
 void fork_start(void)
 {
+    pthread_mutex_lock(&tcg_ctx.tb_ctx.tb_lock);
+    pthread_mutex_lock(&exclusive_lock);
+    mmap_fork_start();
 }
 
 void fork_end(int child)
 {
+    mmap_fork_end(child);
     if (child) {
+        CPUState *cpu, *next_cpu;
+        /*
+         * Child processes created by fork() only have a single thread.
+         * Discard information about the parent threads.
+         */
+        CPU_FOREACH_SAFE(cpu, next_cpu) {
+            if (cpu != thread_cpu) {
+                QTAILQ_REMOVE(&cpus, thread_cpu, node);
+            }
+        }
+        pending_cpus = 0;
+        pthread_mutex_init(&exclusive_lock, NULL);
+        pthread_mutex_init(&cpu_list_mutex, NULL);
+        pthread_cond_init(&exclusive_cond, NULL);
+        pthread_cond_init(&exclusive_resume, NULL);
+        pthread_mutex_init(&tcg_ctx.tb_ctx.tb_lock, NULL);
         gdbserver_fork((CPUArchState *)thread_cpu->env_ptr);
+    } else {
+        pthread_mutex_unlock(&exclusive_lock);
+        pthread_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
     }
 }
 
-void cpu_list_lock(void)
+/*
+ * Wait for pending exclusive operations to complete.  The exclusive lock
+ * must be held.
+ */
+static inline void exclusive_idle(void)
 {
+    while (pending_cpus) {
+        pthread_cond_wait(&exclusive_resume, &exclusive_lock);
+    }
 }
 
-void cpu_list_unlock(void)
+/* Start an exclusive operation.  Must only be called outside of cpu_exec. */
+void start_exclusive(void)
 {
-}
+    CPUState *other_cpu;
 
-#ifdef TARGET_I386
-/***********************************************************/
-/* CPUX86 core interface */
+    pthread_mutex_lock(&exclusive_lock);
+    exclusive_idle();
 
-void cpu_smm_update(CPUX86State *env)
-{
-}
-
-uint64_t cpu_get_tsc(CPUX86State *env)
-{
-    return cpu_get_real_ticks();
+    pending_cpus = 1;
+    /* Make all other cpus stop executing. */
+    CPU_FOREACH(other_cpu) {
+        if (other_cpu->running) {
+            pending_cpus++;
+            cpu_exit(other_cpu);
+        }
+    }
+    if (pending_cpus > 1) {
+        pthread_cond_wait(&exclusive_cond, &exclusive_lock);
+    }
 }
 
-static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
-                     int flags)
+/* Finish an exclusive operation. */
+void end_exclusive(void)
 {
-    unsigned int e1, e2;
-    uint32_t *p;
-    e1 = (addr << 16) | (limit & 0xffff);
-    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
-    e2 |= flags;
-    p = ptr;
-    p[0] = tswap32(e1);
-    p[1] = tswap32(e2);
+    pending_cpus = 0;
+    pthread_cond_broadcast(&exclusive_resume);
+    pthread_mutex_unlock(&exclusive_lock);
 }
 
-static uint64_t *idt_table;
-#ifdef TARGET_X86_64
-static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
-                       uint64_t addr, unsigned int sel)
-{
-    uint32_t *p, e1, e2;
-    e1 = (addr & 0xffff) | (sel << 16);
-    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
-    p = ptr;
-    p[0] = tswap32(e1);
-    p[1] = tswap32(e2);
-    p[2] = tswap32(addr >> 32);
-    p[3] = 0;
-}
-/* only dpl matters as we do only user space emulation */
-static void set_idt(int n, unsigned int dpl)
+/* Wait for exclusive ops to finish, and begin cpu execution. */
+void cpu_exec_start(CPUState *cpu)
 {
-    set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
-}
-#else
-static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
-                     uint32_t addr, unsigned int sel)
-{
-    uint32_t *p, e1, e2;
-    e1 = (addr & 0xffff) | (sel << 16);
-    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
-    p = ptr;
-    p[0] = tswap32(e1);
-    p[1] = tswap32(e2);
+    pthread_mutex_lock(&exclusive_lock);
+    exclusive_idle();
+    cpu->running = true;
+    pthread_mutex_unlock(&exclusive_lock);
 }
 
-/* only dpl matters as we do only user space emulation */
-static void set_idt(int n, unsigned int dpl)
+/* Mark cpu as not excuting, and release pending exclusive ops. */
+void cpu_exec_end(CPUState *cpu)
 {
-    set_gate(idt_table + n, 0, dpl, 0, 0);
-}
-#endif
-
-void cpu_loop(CPUX86State *env)
-{
-    int trapnr;
-    abi_ulong pc;
-    //target_siginfo_t info;
-
-    for(;;) {
-        trapnr = cpu_x86_exec(env);
-        switch(trapnr) {
-        case 0x80:
-            /* syscall from int $0x80 */
-            if (bsd_type == target_freebsd) {
-                abi_ulong params = (abi_ulong) env->regs[R_ESP] +
-                    sizeof(int32_t);
-                int32_t syscall_nr = env->regs[R_EAX];
-                int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
-
-                if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
-                    get_user_s32(syscall_nr, params);
-                    params += sizeof(int32_t);
-                } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
-                    get_user_s32(syscall_nr, params);
-                    params += sizeof(int64_t);
-                }
-                get_user_s32(arg1, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg2, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg3, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg4, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg5, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg6, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg7, params);
-                params += sizeof(int32_t);
-                get_user_s32(arg8, params);
-                env->regs[R_EAX] = do_freebsd_syscall(env,
-                                                      syscall_nr,
-                                                      arg1,
-                                                      arg2,
-                                                      arg3,
-                                                      arg4,
-                                                      arg5,
-                                                      arg6,
-                                                      arg7,
-                                                      arg8);
-            } else { //if (bsd_type == target_openbsd)
-                env->regs[R_EAX] = do_openbsd_syscall(env,
-                                                      env->regs[R_EAX],
-                                                      env->regs[R_EBX],
-                                                      env->regs[R_ECX],
-                                                      env->regs[R_EDX],
-                                                      env->regs[R_ESI],
-                                                      env->regs[R_EDI],
-                                                      env->regs[R_EBP]);
-            }
-            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
-                env->regs[R_EAX] = -env->regs[R_EAX];
-                env->eflags |= CC_C;
-            } else {
-                env->eflags &= ~CC_C;
-            }
-            break;
-#ifndef TARGET_ABI32
-        case EXCP_SYSCALL:
-            /* syscall from syscall instruction */
-            if (bsd_type == target_freebsd)
-                env->regs[R_EAX] = do_freebsd_syscall(env,
-                                                      env->regs[R_EAX],
-                                                      env->regs[R_EDI],
-                                                      env->regs[R_ESI],
-                                                      env->regs[R_EDX],
-                                                      env->regs[R_ECX],
-                                                      env->regs[8],
-                                                      env->regs[9], 0, 0);
-            else { //if (bsd_type == target_openbsd)
-                env->regs[R_EAX] = do_openbsd_syscall(env,
-                                                      env->regs[R_EAX],
-                                                      env->regs[R_EDI],
-                                                      env->regs[R_ESI],
-                                                      env->regs[R_EDX],
-                                                      env->regs[10],
-                                                      env->regs[8],
-                                                      env->regs[9]);
-            }
-            env->eip = env->exception_next_eip;
-            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
-                env->regs[R_EAX] = -env->regs[R_EAX];
-                env->eflags |= CC_C;
-            } else {
-                env->eflags &= ~CC_C;
-            }
-            break;
-#endif
-#if 0
-        case EXCP0B_NOSEG:
-        case EXCP0C_STACK:
-            info.si_signo = SIGBUS;
-            info.si_errno = 0;
-            info.si_code = TARGET_SI_KERNEL;
-            info._sifields._sigfault._addr = 0;
-            queue_signal(env, info.si_signo, &info);
-            break;
-        case EXCP0D_GPF:
-            /* XXX: potential problem if ABI32 */
-#ifndef TARGET_X86_64
-            if (env->eflags & VM_MASK) {
-                handle_vm86_fault(env);
-            } else
-#endif
-            {
-                info.si_signo = SIGSEGV;
-                info.si_errno = 0;
-                info.si_code = TARGET_SI_KERNEL;
-                info._sifields._sigfault._addr = 0;
-                queue_signal(env, info.si_signo, &info);
-            }
-            break;
-        case EXCP0E_PAGE:
-            info.si_signo = SIGSEGV;
-            info.si_errno = 0;
-            if (!(env->error_code & 1))
-                info.si_code = TARGET_SEGV_MAPERR;
-            else
-                info.si_code = TARGET_SEGV_ACCERR;
-            info._sifields._sigfault._addr = env->cr[2];
-            queue_signal(env, info.si_signo, &info);
-            break;
-        case EXCP00_DIVZ:
-#ifndef TARGET_X86_64
-            if (env->eflags & VM_MASK) {
-                handle_vm86_trap(env, trapnr);
-            } else
-#endif
-            {
-                /* division by zero */
-                info.si_signo = SIGFPE;
-                info.si_errno = 0;
-                info.si_code = TARGET_FPE_INTDIV;
-                info._sifields._sigfault._addr = env->eip;
-                queue_signal(env, info.si_signo, &info);
-            }
-            break;
-        case EXCP01_DB:
-        case EXCP03_INT3:
-#ifndef TARGET_X86_64
-            if (env->eflags & VM_MASK) {
-                handle_vm86_trap(env, trapnr);
-            } else
-#endif
-            {
-                info.si_signo = SIGTRAP;
-                info.si_errno = 0;
-                if (trapnr == EXCP01_DB) {
-                    info.si_code = TARGET_TRAP_BRKPT;
-                    info._sifields._sigfault._addr = env->eip;
-                } else {
-                    info.si_code = TARGET_SI_KERNEL;
-                    info._sifields._sigfault._addr = 0;
-                }
-                queue_signal(env, info.si_signo, &info);
-            }
-            break;
-        case EXCP04_INTO:
-        case EXCP05_BOUND:
-#ifndef TARGET_X86_64
-            if (env->eflags & VM_MASK) {
-                handle_vm86_trap(env, trapnr);
-            } else
-#endif
-            {
-                info.si_signo = SIGSEGV;
-                info.si_errno = 0;
-                info.si_code = TARGET_SI_KERNEL;
-                info._sifields._sigfault._addr = 0;
-                queue_signal(env, info.si_signo, &info);
-            }
-            break;
-        case EXCP06_ILLOP:
-            info.si_signo = SIGILL;
-            info.si_errno = 0;
-            info.si_code = TARGET_ILL_ILLOPN;
-            info._sifields._sigfault._addr = env->eip;
-            queue_signal(env, info.si_signo, &info);
-            break;
-#endif
-        case EXCP_INTERRUPT:
-            /* just indicate that signals should be handled asap */
-            break;
-#if 0
-        case EXCP_DEBUG:
-            {
-                int sig;
-
-                sig = gdb_handlesig (env, TARGET_SIGTRAP);
-                if (sig)
-                  {
-                    info.si_signo = sig;
-                    info.si_errno = 0;
-                    info.si_code = TARGET_TRAP_BRKPT;
-                    queue_signal(env, info.si_signo, &info);
-                  }
-            }
-            break;
-#endif
-        default:
-            pc = env->segs[R_CS].base + env->eip;
-            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
-                    (long)pc, trapnr);
-            abort();
+    pthread_mutex_lock(&exclusive_lock);
+    cpu->running = false;
+    if (pending_cpus > 1) {
+        pending_cpus--;
+        if (pending_cpus == 1) {
+            pthread_cond_signal(&exclusive_cond);
         }
-        process_pending_signals(env);
     }
+    exclusive_idle();
+    pthread_mutex_unlock(&exclusive_lock);
 }
-#endif
-
-#ifdef TARGET_SPARC
-#define SPARC64_STACK_BIAS 2047
-
-//#define DEBUG_WIN
-/* WARNING: dealing with register windows _is_ complicated. More info
-   can be found at http://www.sics.se/~psm/sparcstack.html */
-static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
-{
-    index = (index + cwp * 16) % (16 * env->nwindows);
-    /* wrap handling : if cwp is on the last window, then we use the
-       registers 'after' the end */
-    if (index < 8 && env->cwp == env->nwindows - 1)
-        index += 16 * env->nwindows;
-    return index;
-}
-
-/* save the register window 'cwp1' */
-static inline void save_window_offset(CPUSPARCState *env, int cwp1)
-{
-    unsigned int i;
-    abi_ulong sp_ptr;
 
-    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
-#ifdef TARGET_SPARC64
-    if (sp_ptr & 3)
-        sp_ptr += SPARC64_STACK_BIAS;
-#endif
-#if defined(DEBUG_WIN)
-    printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
-           sp_ptr, cwp1);
-#endif
-    for(i = 0; i < 16; i++) {
-        /* FIXME - what to do if put_user() fails? */
-        put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
-        sp_ptr += sizeof(abi_ulong);
-    }
-}
-
-static void save_window(CPUSPARCState *env)
+void cpu_list_lock(void)
 {
-#ifndef TARGET_SPARC64
-    unsigned int new_wim;
-    new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
-        ((1LL << env->nwindows) - 1);
-    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
-    env->wim = new_wim;
-#else
-    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
-    env->cansave++;
-    env->canrestore--;
-#endif
+    pthread_mutex_lock(&cpu_list_mutex);
 }
 
-static void restore_window(CPUSPARCState *env)
-{
-#ifndef TARGET_SPARC64
-    unsigned int new_wim;
-#endif
-    unsigned int i, cwp1;
-    abi_ulong sp_ptr;
-
-#ifndef TARGET_SPARC64
-    new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
-        ((1LL << env->nwindows) - 1);
-#endif
-
-    /* restore the invalid window */
-    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
-    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
-#ifdef TARGET_SPARC64
-    if (sp_ptr & 3)
-        sp_ptr += SPARC64_STACK_BIAS;
-#endif
-#if defined(DEBUG_WIN)
-    printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
-           sp_ptr, cwp1);
-#endif
-    for(i = 0; i < 16; i++) {
-        /* FIXME - what to do if get_user() fails? */
-        get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
-        sp_ptr += sizeof(abi_ulong);
-    }
-#ifdef TARGET_SPARC64
-    env->canrestore++;
-    if (env->cleanwin < env->nwindows - 1)
-        env->cleanwin++;
-    env->cansave--;
-#else
-    env->wim = new_wim;
-#endif
-}
-
-static void flush_windows(CPUSPARCState *env)
+void cpu_list_unlock(void)
 {
-    int offset, cwp1;
-
-    offset = 1;
-    for(;;) {
-        /* if restore would invoke restore_window(), then we can stop */
-        cwp1 = cpu_cwp_inc(env, env->cwp + offset);
-#ifndef TARGET_SPARC64
-        if (env->wim & (1 << cwp1))
-            break;
-#else
-        if (env->canrestore == 0)
-            break;
-        env->cansave++;
-        env->canrestore--;
-#endif
-        save_window_offset(env, cwp1);
-        offset++;
-    }
-    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
-#ifndef TARGET_SPARC64
-    /* set wim so that restore will reload the registers */
-    env->wim = 1 << cwp1;
-#endif
-#if defined(DEBUG_WIN)
-    printf("flush_windows: nb=%d\n", offset - 1);
-#endif
+    pthread_mutex_unlock(&cpu_list_mutex);
 }
 
-void cpu_loop(CPUSPARCState *env)
+void cpu_loop(CPUArchState *env)
 {
-    CPUState *cs = CPU(sparc_env_get_cpu(env));
-    int trapnr, ret, syscall_nr;
-    //target_siginfo_t info;
 
-    while (1) {
-        trapnr = cpu_sparc_exec (env);
-
-        switch (trapnr) {
-#ifndef TARGET_SPARC64
-        case 0x80:
-#else
-        /* FreeBSD uses 0x141 for syscalls too */
-        case 0x141:
-            if (bsd_type != target_freebsd)
-                goto badtrap;
-        case 0x100:
-#endif
-            syscall_nr = env->gregs[1];
-            if (bsd_type == target_freebsd)
-                ret = do_freebsd_syscall(env, syscall_nr,
-                                         env->regwptr[0], env->regwptr[1],
-                                         env->regwptr[2], env->regwptr[3],
-                                         env->regwptr[4], env->regwptr[5], 0, 0);
-            else if (bsd_type == target_netbsd)
-                ret = do_netbsd_syscall(env, syscall_nr,
-                                        env->regwptr[0], env->regwptr[1],
-                                        env->regwptr[2], env->regwptr[3],
-                                        env->regwptr[4], env->regwptr[5]);
-            else { //if (bsd_type == target_openbsd)
-#if defined(TARGET_SPARC64)
-                syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
-                                TARGET_OPENBSD_SYSCALL_G2RFLAG);
-#endif
-                ret = do_openbsd_syscall(env, syscall_nr,
-                                         env->regwptr[0], env->regwptr[1],
-                                         env->regwptr[2], env->regwptr[3],
-                                         env->regwptr[4], env->regwptr[5]);
-            }
-            if ((unsigned int)ret >= (unsigned int)(-515)) {
-                ret = -ret;
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
-                env->xcc |= PSR_CARRY;
-#else
-                env->psr |= PSR_CARRY;
-#endif
-            } else {
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
-                env->xcc &= ~PSR_CARRY;
-#else
-                env->psr &= ~PSR_CARRY;
-#endif
-            }
-            env->regwptr[0] = ret;
-            /* next instruction */
-#if defined(TARGET_SPARC64)
-            if (bsd_type == target_openbsd &&
-                env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
-                env->pc = env->gregs[2];
-                env->npc = env->pc + 4;
-            } else if (bsd_type == target_openbsd &&
-                       env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
-                env->pc = env->gregs[7];
-                env->npc = env->pc + 4;
-            } else {
-                env->pc = env->npc;
-                env->npc = env->npc + 4;
-            }
-#else
-            env->pc = env->npc;
-            env->npc = env->npc + 4;
-#endif
-            break;
-        case 0x83: /* flush windows */
-#ifdef TARGET_ABI32
-        case 0x103:
-#endif
-            flush_windows(env);
-            /* next instruction */
-            env->pc = env->npc;
-            env->npc = env->npc + 4;
-            break;
-#ifndef TARGET_SPARC64
-        case TT_WIN_OVF: /* window overflow */
-            save_window(env);
-            break;
-        case TT_WIN_UNF: /* window underflow */
-            restore_window(env);
-            break;
-        case TT_TFAULT:
-        case TT_DFAULT:
-#if 0
-            {
-                info.si_signo = SIGSEGV;
-                info.si_errno = 0;
-                /* XXX: check env->error_code */
-                info.si_code = TARGET_SEGV_MAPERR;
-                info._sifields._sigfault._addr = env->mmuregs[4];
-                queue_signal(env, info.si_signo, &info);
-            }
-#endif
-            break;
-#else
-        case TT_SPILL: /* window overflow */
-            save_window(env);
-            break;
-        case TT_FILL: /* window underflow */
-            restore_window(env);
-            break;
-        case TT_TFAULT:
-        case TT_DFAULT:
-#if 0
-            {
-                info.si_signo = SIGSEGV;
-                info.si_errno = 0;
-                /* XXX: check env->error_code */
-                info.si_code = TARGET_SEGV_MAPERR;
-                if (trapnr == TT_DFAULT)
-                    info._sifields._sigfault._addr = env->dmmuregs[4];
-                else
-                    info._sifields._sigfault._addr = env->tsptr->tpc;
-                //queue_signal(env, info.si_signo, &info);
-            }
-#endif
-            break;
-#endif
-        case EXCP_INTERRUPT:
-            /* just indicate that signals should be handled asap */
-            break;
-        case EXCP_DEBUG:
-            {
-                int sig;
-
-                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
-#if 0
-                if (sig)
-                  {
-                    info.si_signo = sig;
-                    info.si_errno = 0;
-                    info.si_code = TARGET_TRAP_BRKPT;
-                    //queue_signal(env, info.si_signo, &info);
-                  }
-#endif
-            }
-            break;
-        default:
-#ifdef TARGET_SPARC64
-        badtrap:
-#endif
-            printf ("Unhandled trap: 0x%x\n", trapnr);
-            cpu_dump_state(cs, stderr, fprintf, 0);
-            exit (1);
-        }
-        process_pending_signals (env);
-    }
+    target_cpu_loop(env);
 }
 
-#endif
-
 static void usage(void)
 {
     printf("qemu-" TARGET_NAME " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
@@ -709,12 +241,21 @@ static void usage(void)
            ,
            TARGET_NAME,
            interp_prefix,
-           x86_stack_size);
+           target_dflssiz);
     exit(1);
 }
 
 THREAD CPUState *thread_cpu;
 
+void stop_all_tasks(void)
+{
+    /*
+     * We trust when using NPTL (pthreads) start_exclusive() handles thread
+     * stopping correctly.
+     */
+    start_exclusive();
+}
+
 /* Assumes contents are already zeroed.  */
 void init_task_state(TaskState *ts)
 {
@@ -728,14 +269,54 @@ void init_task_state(TaskState *ts)
     ts->sigqueue_table[i].next = NULL;
 }
 
+CPUArchState *cpu_copy(CPUArchState *env)
+{
+    CPUArchState *new_env = cpu_init(cpu_model);
+#if defined(TARGET_HAS_ICE)
+    CPUBreakpoint *bp;
+    CPUWatchpoint *wp;
+#endif
+
+    /* Reset non arch specific state */
+    cpu_reset(ENV_GET_CPU(new_env));
+
+    memcpy(new_env, env, sizeof(CPUArchState));
+
+    /* Clone all break/watchpoints.
+       Note: Once we support ptrace with hw-debug register access, make sure
+       BP_CPU break/watchpoints are handled correctly on clone. */
+    QTAILQ_INIT(&env->breakpoints);
+    QTAILQ_INIT(&env->watchpoints);
+#if defined(TARGET_HAS_ICE)
+    QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
+    }
+    QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+        cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
+                              wp->flags, NULL);
+    }
+#endif
+
+    return new_env;
+}
+
+void gemu_log(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+}
+
 int main(int argc, char **argv)
 {
     const char *filename;
-    const char *cpu_model;
     const char *log_file = NULL;
     const char *log_mask = NULL;
     struct target_pt_regs regs1, *regs = &regs1;
     struct image_info info1, *info = &info1;
+    struct bsd_binprm bprm;
     TaskState ts1, *ts = &ts1;
     CPUArchState *env;
     CPUState *cpu;
@@ -744,11 +325,13 @@ int main(int argc, char **argv)
     int gdbstub_port = 0;
     char **target_environ, **wrk;
     envlist_t *envlist = NULL;
-    bsd_type = target_openbsd;
+    bsd_type = HOST_DEFAULT_BSD_TYPE;
 
     if (argc <= 1)
         usage();
 
+    save_proc_pathname(argv[0]);
+
     module_call_init(MODULE_INIT_QOM);
 
     if ((envlist = envlist_create()) == NULL) {
@@ -767,7 +350,7 @@ int main(int argc, char **argv)
 #endif
 
     optind = 1;
-    for(;;) {
+    for (;;) {
         if (optind >= argc)
             break;
         r = argv[optind];
@@ -803,13 +386,18 @@ int main(int argc, char **argv)
                 usage();
         } else if (!strcmp(r, "s")) {
             r = argv[optind++];
-            x86_stack_size = strtol(r, (char **)&r, 0);
-            if (x86_stack_size <= 0)
+            target_dflssiz = strtol(r, (char **)&r, 0);
+            if (target_dflssiz <= 0) {
+                usage();
+            }
+            if (*r == 'M') {
+                target_dflssiz *= 1024 * 1024;
+            } else if (*r == 'k' || *r == 'K') {
+                target_dflssiz *= 1024;
+            }
+            if (target_dflssiz > target_maxssiz) {
                 usage();
-            if (*r == 'M')
-                x86_stack_size *= 1024 * 1024;
-            else if (*r == 'k' || *r == 'K')
-                x86_stack_size *= 1024;
+            }
         } else if (!strcmp(r, "L")) {
             interp_prefix = argv[optind++];
         } else if (!strcmp(r, "p")) {
@@ -881,6 +469,8 @@ int main(int argc, char **argv)
     /* Zero out regs */
     memset(regs, 0, sizeof(struct target_pt_regs));
 
+    memset(&bprm, 0, sizeof(bprm));
+
     /* Zero out image_info */
     memset(info, 0, sizeof(struct image_info));
 
@@ -888,21 +478,7 @@ int main(int argc, char **argv)
     init_paths(interp_prefix);
 
     if (cpu_model == NULL) {
-#if defined(TARGET_I386)
-#ifdef TARGET_X86_64
-        cpu_model = "qemu64";
-#else
-        cpu_model = "qemu32";
-#endif
-#elif defined(TARGET_SPARC)
-#ifdef TARGET_SPARC64
-        cpu_model = "TI UltraSparc II";
-#else
-        cpu_model = "Fujitsu MB86904";
-#endif
-#else
-        cpu_model = "any";
-#endif
+        cpu_model = TARGET_DEFAULT_CPU_MODEL;
     }
     tcg_exec_init(0);
     cpu_exec_init_all();
@@ -914,9 +490,7 @@ int main(int argc, char **argv)
         exit(1);
     }
     cpu = ENV_GET_CPU(env);
-#if defined(TARGET_SPARC) || defined(TARGET_PPC)
-    cpu_reset(cpu);
-#endif
+    TARGET_CPU_RESET(env);
     thread_cpu = cpu;
 
     if (getenv("QEMU_STRACE")) {
@@ -955,7 +529,7 @@ int main(int argc, char **argv)
     }
 #endif /* CONFIG_USE_GUEST_BASE */
 
-    if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
+    if (loader_exec(filename, argv+optind, target_environ, regs, info, &bprm)) {
         printf("Error loading %s\n", filename);
         _exit(1);
     }
@@ -1000,139 +574,10 @@ int main(int argc, char **argv)
     memset(ts, 0, sizeof(TaskState));
     init_task_state(ts);
     ts->info = info;
+    ts->bprm = &bprm;
     env->opaque = ts;
 
-#if defined(TARGET_I386)
-    cpu_x86_set_cpl(env, 3);
-
-    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
-    env->hflags |= HF_PE_MASK;
-    if (env->features[FEAT_1_EDX] & CPUID_SSE) {
-        env->cr[4] |= CR4_OSFXSR_MASK;
-        env->hflags |= HF_OSFXSR_MASK;
-    }
-#ifndef TARGET_ABI32
-    /* enable 64 bit mode if possible */
-    if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
-        fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
-        exit(1);
-    }
-    env->cr[4] |= CR4_PAE_MASK;
-    env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
-    env->hflags |= HF_LMA_MASK;
-#endif
-
-    /* flags setup : we activate the IRQs by default as in user mode */
-    env->eflags |= IF_MASK;
-
-    /* linux register setup */
-#ifndef TARGET_ABI32
-    env->regs[R_EAX] = regs->rax;
-    env->regs[R_EBX] = regs->rbx;
-    env->regs[R_ECX] = regs->rcx;
-    env->regs[R_EDX] = regs->rdx;
-    env->regs[R_ESI] = regs->rsi;
-    env->regs[R_EDI] = regs->rdi;
-    env->regs[R_EBP] = regs->rbp;
-    env->regs[R_ESP] = regs->rsp;
-    env->eip = regs->rip;
-#else
-    env->regs[R_EAX] = regs->eax;
-    env->regs[R_EBX] = regs->ebx;
-    env->regs[R_ECX] = regs->ecx;
-    env->regs[R_EDX] = regs->edx;
-    env->regs[R_ESI] = regs->esi;
-    env->regs[R_EDI] = regs->edi;
-    env->regs[R_EBP] = regs->ebp;
-    env->regs[R_ESP] = regs->esp;
-    env->eip = regs->eip;
-#endif
-
-    /* linux interrupt setup */
-#ifndef TARGET_ABI32
-    env->idt.limit = 511;
-#else
-    env->idt.limit = 255;
-#endif
-    env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
-                                PROT_READ|PROT_WRITE,
-                                MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-    idt_table = g2h(env->idt.base);
-    set_idt(0, 0);
-    set_idt(1, 0);
-    set_idt(2, 0);
-    set_idt(3, 3);
-    set_idt(4, 3);
-    set_idt(5, 0);
-    set_idt(6, 0);
-    set_idt(7, 0);
-    set_idt(8, 0);
-    set_idt(9, 0);
-    set_idt(10, 0);
-    set_idt(11, 0);
-    set_idt(12, 0);
-    set_idt(13, 0);
-    set_idt(14, 0);
-    set_idt(15, 0);
-    set_idt(16, 0);
-    set_idt(17, 0);
-    set_idt(18, 0);
-    set_idt(19, 0);
-    set_idt(0x80, 3);
-
-    /* linux segment setup */
-    {
-        uint64_t *gdt_table;
-        env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
-                                    PROT_READ|PROT_WRITE,
-                                    MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-        env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
-        gdt_table = g2h(env->gdt.base);
-#ifdef TARGET_ABI32
-        write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
-                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
-                 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
-#else
-        /* 64 bit code segment */
-        write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
-                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
-                 DESC_L_MASK |
-                 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
-#endif
-        write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
-                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
-                 (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
-    }
-
-    cpu_x86_load_seg(env, R_CS, __USER_CS);
-    cpu_x86_load_seg(env, R_SS, __USER_DS);
-#ifdef TARGET_ABI32
-    cpu_x86_load_seg(env, R_DS, __USER_DS);
-    cpu_x86_load_seg(env, R_ES, __USER_DS);
-    cpu_x86_load_seg(env, R_FS, __USER_DS);
-    cpu_x86_load_seg(env, R_GS, __USER_DS);
-    /* This hack makes Wine work... */
-    env->segs[R_FS].selector = 0;
-#else
-    cpu_x86_load_seg(env, R_DS, 0);
-    cpu_x86_load_seg(env, R_ES, 0);
-    cpu_x86_load_seg(env, R_FS, 0);
-    cpu_x86_load_seg(env, R_GS, 0);
-#endif
-#elif defined(TARGET_SPARC)
-    {
-        int i;
-        env->pc = regs->pc;
-        env->npc = regs->npc;
-        env->y = regs->y;
-        for(i = 0; i < 8; i++)
-            env->gregs[i] = regs->u_regs[i];
-        for(i = 0; i < 8; i++)
-            env->regwptr[i] = regs->u_regs[i + 8];
-    }
-#else
-#error unsupported target CPU
-#endif
+    target_cpu_init(env, regs);
 
     if (gdbstub_port) {
         gdbserver_start (gdbstub_port);
diff --git a/bsd-user/mips/target_arch.h b/bsd-user/mips/target_arch.h
new file mode 100644
index 0000000..b3d32ba
--- /dev/null
+++ b/bsd-user/mips/target_arch.h
@@ -0,0 +1,10 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+#include "qemu.h"
+
+void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls);
+target_ulong target_cpu_get_tls(CPUMIPSState *env);
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/mips/target_arch_cpu.c b/bsd-user/mips/target_arch_cpu.c
new file mode 100644
index 0000000..dd59435
--- /dev/null
+++ b/bsd-user/mips/target_arch_cpu.c
@@ -0,0 +1,27 @@
+/*
+ *  mips cpu related code
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "target_arch.h"
+
+void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls)
+{
+    env->tls_value = newtls;
+}
+
+target_ulong target_cpu_get_tls(CPUMIPSState *env)
+{
+    return (env->tls_value);
+}
diff --git a/bsd-user/mips/target_arch_cpu.h b/bsd-user/mips/target_arch_cpu.h
new file mode 100644
index 0000000..5098b7d
--- /dev/null
+++ b/bsd-user/mips/target_arch_cpu.h
@@ -0,0 +1,257 @@
+/*
+ *  mips cpu init and loop
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#if defined(TARGET_ABI_MIPSN32)
+#  define TARGET_DEFAULT_CPU_MODEL "24Kc"
+#else
+#  define TARGET_DEFAULT_CPU_MODEL "24Kf"
+#endif
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUMIPSState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    for (i = 0; i < 32; i++) {
+        env->active_tc.gpr[i] = regs->regs[i];
+    }
+    env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
+    if (regs->cp0_epc & 1) {
+        env->hflags |= MIPS_HFLAG_M16;
+    }
+}
+
+static int do_store_exclusive(CPUMIPSState *env)
+{
+    target_ulong addr;
+    target_ulong page_addr;
+    target_ulong val;
+    int flags;
+    int segv = 0;
+    int reg;
+    int d;
+
+    addr = env->lladdr;
+    page_addr = addr & TARGET_PAGE_MASK;
+    start_exclusive();
+    mmap_lock();
+    flags = page_get_flags(page_addr);
+    if ((flags & PAGE_READ) == 0) {
+        segv = 1;
+    } else {
+        reg = env->llreg & 0x1f;
+        d = (env->llreg & 0x20) != 0;
+        if (d) {
+            segv = get_user_s64(val, addr);
+        } else {
+            segv = get_user_s32(val, addr);
+        }
+        if (!segv) {
+            if (val != env->llval) {
+                env->active_tc.gpr[reg] = 0;
+            } else {
+                if (d) {
+                    segv = put_user_u64(env->llnewval, addr);
+                } else {
+                    segv = put_user_u32(env->llnewval, addr);
+                }
+                if (!segv) {
+                    env->active_tc.gpr[reg] = 1;
+                }
+            }
+        }
+    }
+    env->lladdr = -1;
+    if (!segv) {
+        env->active_tc.PC += 4;
+    }
+    mmap_unlock();
+    end_exclusive();
+    return segv;
+}
+
+static inline void target_cpu_loop(CPUMIPSState *env)
+{
+    CPUState *cs = CPU(mips_env_get_cpu(env));
+    target_siginfo_t info;
+    int trapnr;
+    abi_long ret;
+    unsigned int syscall_num;
+
+    for (;;) {
+        cpu_exec_start(cs);
+        trapnr = cpu_mips_exec(env);
+        cpu_exec_end(cs);
+        switch (trapnr) {
+        case EXCP_SYSCALL: /* syscall exception */
+            if (bsd_type == target_freebsd) {
+                syscall_num = env->active_tc.gpr[2]; /* v0 */
+                env->active_tc.PC += TARGET_INSN_SIZE;
+                if (syscall_num >= TARGET_FREEBSD_NR_MAXSYSCALL) {
+                    ret = -TARGET_ENOSYS;
+                } else {
+		    abi_ulong arg4 = 0, arg5 = 0, arg6 = 0, arg7 =0;
+		    abi_ulong sp_reg = env->active_tc.gpr[29];
+
+# ifdef TARGET_ABI_MIPSO32
+		    get_user_ual(arg4, sp_reg + 16);
+		    get_user_ual(arg5, sp_reg + 20);
+		    get_user_ual(arg6, sp_reg + 24);
+		    get_user_ual(arg7, sp_reg + 28);
+#else
+		    arg4 = env->active_tc.gpr[12]; /* t4/arg4 */
+		    arg5 = env->active_tc.gpr[13]; /* t5/arg5 */
+		    arg6 = env->active_tc.gpr[14]; /* t6/arg6 */
+		    arg7 = env->active_tc.gpr[15]; /* t7/arg7 */
+#endif
+                    /* mips(32) uses regs 4-7,12-15 for args */
+                    if (TARGET_FREEBSD_NR___syscall == syscall_num ||
+                            TARGET_FREEBSD_NR_syscall == syscall_num) {
+                        /* indirect syscall */
+                        ret = do_freebsd_syscall(env,
+                                env->active_tc.gpr[4],/* syscall #*/
+                                env->active_tc.gpr[5], /* a1/arg0 */
+                                env->active_tc.gpr[6], /* a2/arg1 */
+                                env->active_tc.gpr[7], /* a3/arg2 */
+				arg4,
+				arg5,
+				arg6,
+				arg7,
+                                0  /* no arg7 */
+                                );
+                    } else {
+                        /* direct syscall */
+                        ret = do_freebsd_syscall(env,
+                                syscall_num,
+                                env->active_tc.gpr[4], /* a0/arg0 */
+                                env->active_tc.gpr[5], /* a1/arg1 */
+                                env->active_tc.gpr[6], /* a2/arg2 */
+                                env->active_tc.gpr[7], /* a3/arg3 */
+				arg4,
+				arg5,
+				arg6,
+				arg7
+                                );
+                    }
+                }
+                /* Compare to mips/mips/vm_machdep.c cpu_set_syscall_retval() */
+                if (-TARGET_EJUSTRETURN == ret) {
+                    /*
+                     * Returning from a successful sigreturn
+                     * syscall.  Avoid clobbering register state.
+                     */
+                    break;
+                }
+                if (-TARGET_ERESTART == ret) {
+                    /* Backup the pc to point at the swi. */
+                    env->active_tc.PC -= TARGET_INSN_SIZE;
+                    break;
+                }
+                if ((unsigned int)ret >= (unsigned int)(-1133)) {
+                    env->active_tc.gpr[7] = 1;
+                    ret = -ret;
+                } else {
+                    env->active_tc.gpr[7] = 0;
+                }
+                env->active_tc.gpr[2] = ret; /* v0 <- ret */
+            } /* else if (bsd_type == target_openbsd)... */
+            else {
+                fprintf(stderr, "qemu: bsd_type (= %d) syscall not supported\n",
+                        bsd_type);
+            }
+            break;
+
+        case EXCP_TLBL: /* TLB miss on load */
+        case EXCP_TLBS: /* TLB miss on store */
+        case EXCP_AdEL: /* bad address on load */
+        case EXCP_AdES: /* bad address on store */
+            info.target_si_signo = TARGET_SIGSEGV;
+            info.target_si_errno = 0;
+            /* XXX: check env->error_code */
+            info.target_si_code = TARGET_SEGV_MAPERR;
+            info.target_si_addr = env->CP0_BadVAddr;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP_CpU: /* coprocessor unusable */
+        case EXCP_RI:  /* reserved instruction */
+            info.target_si_signo = TARGET_SIGILL;
+            info.target_si_errno = 0;
+            info.target_si_code = 0;
+            queue_signal(env, info.target_si_signo, &info);
+            break;
+
+        case EXCP_INTERRUPT: /* async interrupt */
+            /* just indicate that signals should be handled asap */
+            break;
+
+        case EXCP_DEBUG: /* cpu stopped after a breakpoint */
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+                if (sig) {
+                    info.target_si_signo = sig;
+                    info.target_si_errno = 0;
+                    info.target_si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.target_si_signo, &info);
+                }
+            }
+            break;
+
+        case EXCP_SC:
+            if (do_store_exclusive(env)) {
+                info.target_si_signo = TARGET_SIGSEGV;
+                info.target_si_errno = 0;
+                info.target_si_code = TARGET_SEGV_MAPERR;
+                info.target_si_addr = env->active_tc.PC;
+                queue_signal(env, info.target_si_signo, &info);
+            }
+            break;
+
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception "
+                "0x%x - aborting\n", trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUMIPSState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->active_tc.gpr[29] = newsp;
+    env->active_tc.gpr[7] = 0;
+    env->active_tc.gpr[2] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/mips/target_arch_vmparam.h b/bsd-user/mips/target_arch_vmparam.h
new file mode 100644
index 0000000..695877a
--- /dev/null
+++ b/bsd-user/mips/target_arch_vmparam.h
@@ -0,0 +1,50 @@
+/*
+ *  mips VM parameters definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to sys/mips/include/vmparam.h */
+#define TARGET_MAXTSIZ      (128UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ      (128UL*1024*1024)   /* initial data size limit */
+#define TARGET_MAXDSIZ      (1*1024UL*1024*1024)    /* max data size */
+#define TARGET_DFLSSIZ      (8UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ      (64UL*1024*1024)    /* max stack size */
+#define TARGET_SGROWSIZ     (128UL*1024)        /* amount to grow stack */
+
+/* MIPS only supports 31 bits of virtual address space for user space */
+#define TARGET_RESERVED_VA  0x77000000
+
+#define TARGET_VM_MINUSER_ADDRESS   (0x00000000)
+#define TARGET_VM_MAXUSER_ADDRESS   (0x80000000)
+
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
+{
+    return state->active_tc.gpr[29];
+}
+
+static inline void set_second_rval(CPUMIPSState *state, abi_ulong retval2)
+{
+    state->active_tc.gpr[3] = retval2;
+}
+
+#endif  /* ! _TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/mips64/target_arch.h b/bsd-user/mips64/target_arch.h
new file mode 100644
index 0000000..b3d32ba
--- /dev/null
+++ b/bsd-user/mips64/target_arch.h
@@ -0,0 +1,10 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+#include "qemu.h"
+
+void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls);
+target_ulong target_cpu_get_tls(CPUMIPSState *env);
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/mips64/target_arch_cpu.c b/bsd-user/mips64/target_arch_cpu.c
new file mode 100644
index 0000000..9d016a3
--- /dev/null
+++ b/bsd-user/mips64/target_arch_cpu.c
@@ -0,0 +1,27 @@
+/*
+ *  mips64 cpu related code
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "target_arch.h"
+
+void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls)
+{
+    env->tls_value = newtls;
+}
+
+target_ulong target_cpu_get_tls(CPUMIPSState *env)
+{
+    return (env->tls_value);
+}
diff --git a/bsd-user/mips64/target_arch_cpu.h b/bsd-user/mips64/target_arch_cpu.h
new file mode 100644
index 0000000..f4e212f
--- /dev/null
+++ b/bsd-user/mips64/target_arch_cpu.h
@@ -0,0 +1,243 @@
+/*
+ *  mips64 cpu init and loop
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
+#  define TARGET_DEFAULT_CPU_MODEL "MIPS64R2-generic"
+#else
+#  define TARGET_DEFAULT_CPU_MODEL "24f"
+#endif
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUMIPSState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    for (i = 0; i < 32; i++) {
+        env->active_tc.gpr[i] = regs->regs[i];
+    }
+    env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
+    if (regs->cp0_epc & 1) {
+        env->hflags |= MIPS_HFLAG_M16;
+    }
+    env->hflags |= MIPS_HFLAG_UX | MIPS_HFLAG_64;
+}
+
+static int do_store_exclusive(CPUMIPSState *env)
+{
+    target_ulong addr;
+    target_ulong page_addr;
+    target_ulong val;
+    int flags;
+    int segv = 0;
+    int reg;
+    int d;
+
+    addr = env->lladdr;
+    page_addr = addr & TARGET_PAGE_MASK;
+    start_exclusive();
+    mmap_lock();
+    flags = page_get_flags(page_addr);
+    if ((flags & PAGE_READ) == 0) {
+        segv = 1;
+    } else {
+        reg = env->llreg & 0x1f;
+        d = (env->llreg & 0x20) != 0;
+        if (d) {
+            segv = get_user_s64(val, addr);
+        } else {
+            segv = get_user_s32(val, addr);
+        }
+        if (!segv) {
+            if (val != env->llval) {
+                env->active_tc.gpr[reg] = 0;
+            } else {
+                if (d) {
+                    segv = put_user_u64(env->llnewval, addr);
+                } else {
+                    segv = put_user_u32(env->llnewval, addr);
+                }
+                if (!segv) {
+                    env->active_tc.gpr[reg] = 1;
+                }
+            }
+        }
+    }
+    env->lladdr = -1;
+    if (!segv) {
+        env->active_tc.PC += 4;
+    }
+    mmap_unlock();
+    end_exclusive();
+    return segv;
+}
+
+static inline void target_cpu_loop(CPUMIPSState *env)
+{
+    CPUState *cs = CPU(mips_env_get_cpu(env));
+    target_siginfo_t info;
+    int trapnr;
+    abi_long ret;
+    unsigned int syscall_num;
+
+    for (;;) {
+        cpu_exec_start(cs);
+        trapnr = cpu_mips_exec(env);
+        cpu_exec_end(cs);
+        switch (trapnr) {
+        case EXCP_SYSCALL: /* syscall exception */
+            if (bsd_type == target_freebsd) {
+                syscall_num = env->active_tc.gpr[2]; /* v0 */
+                env->active_tc.PC += TARGET_INSN_SIZE;
+                if (syscall_num >= TARGET_FREEBSD_NR_MAXSYSCALL) {
+                    ret = -TARGET_ENOSYS;
+                } else {
+                    /* mips64 uses regs 4-11 for args */
+                    if (TARGET_FREEBSD_NR___syscall == syscall_num ||
+                            TARGET_FREEBSD_NR_syscall == syscall_num) {
+                        /* indirect syscall */
+                        ret = do_freebsd_syscall(env,
+                                env->active_tc.gpr[4],/* syscall #*/
+                                env->active_tc.gpr[5], /* arg0 */
+                                env->active_tc.gpr[6], /* arg1 */
+                                env->active_tc.gpr[7], /* arg2 */
+                                env->active_tc.gpr[8], /* arg3 */
+                                env->active_tc.gpr[9], /* arg4 */
+                                env->active_tc.gpr[10],/* arg5 */
+                                env->active_tc.gpr[11],/* arg6 */
+                                0 /* no arg 7 */);
+                    } else {
+                        /* direct syscall */
+                        ret = do_freebsd_syscall(env,
+                                syscall_num,
+                                env->active_tc.gpr[4],
+                                env->active_tc.gpr[5],
+                                env->active_tc.gpr[6],
+                                env->active_tc.gpr[7],
+                                env->active_tc.gpr[8],
+                                env->active_tc.gpr[9],
+                                env->active_tc.gpr[10],
+                                env->active_tc.gpr[11]
+                                );
+                    }
+                }
+                /* Compare to mips/mips/vm_machdep.c cpu_set_syscall_retval() */
+                if (-TARGET_EJUSTRETURN == ret) {
+                    /*
+                     * Returning from a successful sigreturn
+                     * syscall.  Avoid clobbering register state.
+                     */
+                    break;
+                }
+                if (-TARGET_ERESTART == ret) {
+                    /* Backup the pc to point at the swi. */
+                    env->active_tc.PC -= TARGET_INSN_SIZE;
+                    break;
+                }
+                if ((unsigned int)ret >= (unsigned int)(-1133)) {
+                    env->active_tc.gpr[7] = 1;
+                    ret = -ret;
+                } else {
+                    env->active_tc.gpr[7] = 0;
+                }
+                env->active_tc.gpr[2] = ret; /* v0 <- ret */
+            } /* else if (bsd_type == target_openbsd)... */
+            else {
+                fprintf(stderr, "qemu: bsd_type (= %d) syscall not supported\n",
+                        bsd_type);
+            }
+            break;
+
+        case EXCP_TLBL: /* TLB miss on load */
+        case EXCP_TLBS: /* TLB miss on store */
+        case EXCP_AdEL: /* bad address on load */
+        case EXCP_AdES: /* bad address on store */
+            info.target_si_signo = TARGET_SIGSEGV;
+            info.target_si_errno = 0;
+            /* XXX: check env->error_code */
+            info.target_si_code = TARGET_SEGV_MAPERR;
+            info.target_si_addr = env->CP0_BadVAddr;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP_CpU: /* coprocessor unusable */
+        case EXCP_RI:  /* reserved instruction */
+            info.target_si_signo = TARGET_SIGILL;
+            info.target_si_errno = 0;
+            info.target_si_code = 0;
+            queue_signal(env, info.target_si_signo, &info);
+            break;
+
+        case EXCP_INTERRUPT: /* async interrupt */
+            /* just indicate that signals should be handled asap */
+            break;
+
+        case EXCP_DEBUG: /* cpu stopped after a breakpoint */
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+                if (sig) {
+                    info.target_si_signo = sig;
+                    info.target_si_errno = 0;
+                    info.target_si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.target_si_signo, &info);
+                }
+            }
+            break;
+
+        case EXCP_SC:
+            if (do_store_exclusive(env)) {
+                info.target_si_signo = TARGET_SIGSEGV;
+                info.target_si_errno = 0;
+                info.target_si_code = TARGET_SEGV_MAPERR;
+                info.target_si_addr = env->active_tc.PC;
+                queue_signal(env, info.target_si_signo, &info);
+            }
+            break;
+
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception "
+                "0x%x - aborting\n", trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUMIPSState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->active_tc.gpr[29] = newsp;
+    env->active_tc.gpr[7] = 0;
+    env->active_tc.gpr[2] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/mips64/target_arch_vmparam.h b/bsd-user/mips64/target_arch_vmparam.h
new file mode 100644
index 0000000..1ba09e0
--- /dev/null
+++ b/bsd-user/mips64/target_arch_vmparam.h
@@ -0,0 +1,47 @@
+/*
+ *  mips64 VM parameters definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to sys/mips/include/vmparam.h */
+#define TARGET_MAXTSIZ      (128UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ      (128UL*1024*1024)   /* initial data size limit */
+#define TARGET_MAXDSIZ      (1*1024UL*1024*1024)    /* max data size */
+#define TARGET_DFLSSIZ      (8UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ      (64UL*1024*1024)    /* max stack size */
+#define TARGET_SGROWSIZ     (128UL*1024)        /* amount to grow stack */
+
+#define TARGET_VM_MINUSER_ADDRESS   (0x0000000000000000UL)
+#define TARGET_VM_MAXUSER_ADDRESS   (0x0000008000000000UL)
+
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
+{
+    return state->active_tc.gpr[29];
+}
+
+static inline void set_second_rval(CPUMIPSState *state, abi_ulong retval2)
+{
+    state->active_tc.gpr[3] = retval2;
+}
+
+#endif  /* ! _TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/netbsd/host_os.h b/bsd-user/netbsd/host_os.h
new file mode 100644
index 0000000..5c492e3
--- /dev/null
+++ b/bsd-user/netbsd/host_os.h
@@ -0,0 +1,31 @@
+/*
+ *  NetBSD host dependent code and definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST_OS_H_
+#define __HOST_OS_H_
+
+#include "qemu.h"
+
+#define HOST_DEFAULT_BSD_TYPE target_netbsd
+
+static inline void save_proc_pathname(char *argv0)
+{
+    /* XXX */
+}
+
+#endif /*!__HOST_OS_H_ */
diff --git a/bsd-user/openbsd/host_os.h b/bsd-user/openbsd/host_os.h
new file mode 100644
index 0000000..162ce58
--- /dev/null
+++ b/bsd-user/openbsd/host_os.h
@@ -0,0 +1,31 @@
+/*
+ *  OpenBSD host dependent code and definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST_OS_H_
+#define __HOST_OS_H_
+
+#include "qemu.h"
+
+#define HOST_DEFAULT_BSD_TYPE target_openbsd
+
+static inline void save_proc_pathname(char *argv0)
+{
+    /* XXX */
+}
+
+#endif /*!__HOST_OS_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index b8a34c7..cb77069 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -38,6 +38,7 @@ extern enum BSDType bsd_type;
 
 #include "syscall_defs.h"
 #include "syscall.h"
+#include "target_os_vmparam.h"
 #include "target_signal.h"
 #include "exec/gdbstub.h"
 
@@ -99,6 +100,7 @@ typedef struct TaskState {
 } __attribute__((aligned(16))) TaskState;
 
 void init_task_state(TaskState *ts);
+void stop_all_tasks(void);
 extern const char *qemu_uname_release;
 #if defined(CONFIG_USE_GUEST_BASE)
 extern unsigned long mmap_min_addr;
@@ -222,7 +224,13 @@ void mmap_fork_end(int child);
 #endif
 
 /* main.c */
-extern unsigned long x86_stack_size;
+extern unsigned long target_maxtsiz;
+extern unsigned long target_dfldsiz;
+extern unsigned long target_maxdsiz;
+extern unsigned long target_dflssiz;
+extern unsigned long target_maxssiz;
+extern unsigned long target_sgrowsiz;
+extern char qemu_proc_pathname[];
 
 /* user access */
 
diff --git a/bsd-user/sparc/target_arch.h b/bsd-user/sparc/target_arch.h
new file mode 100644
index 0000000..5ee479b
--- /dev/null
+++ b/bsd-user/sparc/target_arch.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+void bsd_sparc_save_window(CPUSPARCState *env);
+void bsd_sparc_restore_window(CPUSPARCState *env);
+void bsd_sparc_flush_windows(CPUSPARCState *env);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* ! _TARGET_ARCH_H_ */
diff --git a/bsd-user/sparc/target_arch_cpu.c b/bsd-user/sparc/target_arch_cpu.c
new file mode 100644
index 0000000..0af5c7e
--- /dev/null
+++ b/bsd-user/sparc/target_arch_cpu.c
@@ -0,0 +1,113 @@
+/*
+ *  sparc cpu related code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+
+#include "target_arch.h"
+
+/* #define DEBUG_WIN */
+/* WARNING: dealing with register windows _is_ complicated. More info
+   can be found at http://www.sics.se/~psm/sparcstack.html */
+static int get_reg_index(CPUSPARCState *env, int cwp, int index)
+{
+    index = (index + cwp * 16) % (16 * env->nwindows);
+    /* wrap handling : if cwp is on the last window, then we use the
+       registers 'after' the end */
+    if (index < 8 && env->cwp == env->nwindows - 1) {
+        index += 16 * env->nwindows;
+    }
+    return index;
+}
+
+/* save the register window 'cwp1' */
+static void save_window_offset(CPUSPARCState *env, int cwp1)
+{
+    unsigned int i;
+    abi_ulong sp_ptr;
+
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#if defined(DEBUG_WIN)
+    printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for (i = 0; i < 16; i++) {
+        /* FIXME - what to do if put_user() fails? */
+        put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+}
+
+void bsd_sparc_save_window(CPUSPARCState *env)
+{
+    unsigned int new_wim;
+
+    new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
+        ((1LL << env->nwindows) - 1);
+    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+    env->wim = new_wim;
+}
+
+void bsd_sparc_restore_window(CPUSPARCState *env)
+{
+    unsigned int new_wim;
+    unsigned int i, cwp1;
+    abi_ulong sp_ptr;
+
+    new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
+        ((1LL << env->nwindows) - 1);
+
+    /* restore the invalid window */
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#if defined(DEBUG_WIN)
+    printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for (i = 0; i < 16; i++) {
+        /* FIXME - what to do if get_user() fails? */
+        get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+    env->wim = new_wim;
+}
+
+void bsd_sparc_flush_windows(CPUSPARCState *env)
+{
+    int offset, cwp1;
+
+    offset = 1;
+    for (;;) {
+        /* if restore would invoke restore_window(), then we can stop */
+        cwp1 = cpu_cwp_inc(env, env->cwp + offset);
+        if (env->wim & (1 << cwp1)) {
+            break;
+        }
+        save_window_offset(env, cwp1);
+        offset++;
+    }
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+    /* set wim so that restore will reload the registers */
+    env->wim = 1 << cwp1;
+#if defined(DEBUG_WIN)
+    printf("bsd_sparc_flush_windows: nb=%d\n", offset - 1);
+#endif
+}
+
diff --git a/bsd-user/sparc/target_arch_cpu.h b/bsd-user/sparc/target_arch_cpu.h
new file mode 100644
index 0000000..f61884b
--- /dev/null
+++ b/bsd-user/sparc/target_arch_cpu.h
@@ -0,0 +1,158 @@
+/*
+ *  sparc cpu init and loop
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "Fujitsu MB86904"
+
+#define TARGET_CPU_RESET(env) cpu_reset(ENV_GET_CPU(env))
+
+static inline void target_cpu_init(CPUSPARCState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    env->pc = regs->pc;
+    env->npc = regs->npc;
+    env->y = regs->y;
+    for (i = 0; i < 8; i++) {
+        env->gregs[i] = regs->u_regs[i];
+    }
+    for (i = 0; i < 8; i++) {
+        env->regwptr[i] = regs->u_regs[i + 8];
+    }
+}
+
+static inline void target_cpu_loop(CPUSPARCState *env)
+{
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
+    int trapnr, ret, syscall_nr;
+    /* target_siginfo_t info; */
+
+    while (1) {
+        trapnr = cpu_sparc_exec(env);
+
+        switch (trapnr) {
+        case 0x80:
+            syscall_nr = env->gregs[1];
+            if (bsd_type == target_freebsd) {
+                ret = do_freebsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5], 0, 0);
+            } else if (bsd_type == target_netbsd) {
+                ret = do_netbsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5]);
+            } else { /* if (bsd_type == target_openbsd) */
+                ret = do_openbsd_syscall(env, syscall_nr,
+                                         env->regwptr[0], env->regwptr[1],
+                                         env->regwptr[2], env->regwptr[3],
+                                         env->regwptr[4], env->regwptr[5]);
+            }
+            if ((unsigned int)ret >= (unsigned int)(-515)) {
+                ret = -ret;
+                env->psr |= PSR_CARRY;
+            } else {
+                env->psr &= ~PSR_CARRY;
+            }
+            env->regwptr[0] = ret;
+            /* next instruction */
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+            break;
+        case 0x83: /* flush windows */
+#ifdef TARGET_ABI32
+        case 0x103:
+#endif
+            bsd_sparc_flush_windows(env);
+            /* next instruction */
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+            break;
+
+        case TT_WIN_OVF: /* window overflow */
+            bsd_sparc_save_window(env);
+            break;
+
+        case TT_WIN_UNF: /* window underflow */
+            bsd_sparc_restore_window(env);
+            break;
+
+        case TT_TFAULT:
+        case TT_DFAULT:
+#if 0
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = env->mmuregs[4];
+                queue_signal(env, info.si_signo, &info);
+            }
+#endif
+            break;
+
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+
+        case EXCP_DEBUG:
+#if 0
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    /* queue_signal(env, info.si_signo, &info); */
+                }
+            }
+#endif
+            break;
+        default:
+            printf("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            exit(1);
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUSPARCState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regwptr[22] = newsp;
+    env->regwptr[0] = 0;
+    /* FIXME: Do we also need to clear CF?  */
+    /* XXXXX */
+    printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+    cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/sparc/target_arch_vmparam.h b/bsd-user/sparc/target_arch_vmparam.h
new file mode 100644
index 0000000..5f28fcf
--- /dev/null
+++ b/bsd-user/sparc/target_arch_vmparam.h
@@ -0,0 +1,37 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+#define TARGET_MAXTSIZ  (1*1024*1024*1024)  /* max text size */
+#define TARGET_DFLDSIZ  (128*1024*1024)     /* initial data size limit */
+#define TARGET_MAXDSIZ  (1*1024*1024*1024)  /* max data size */
+#define TARGET_DFLSSIZ  (128*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ  (1*1024*1024*1024)  /* max stack size */
+#define TARGET_SGROWSIZ (128*1024)      /* amount to grow stack */
+
+#define TARGET_RESERVED_VA 0xf7000000
+
+/* XXX this may not be right */
+#define TARGET_VM_MAXUSER_ADDRESS   (0xc0000000 - (512 * 1024 * 1024))
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+#ifndef UREG_I6
+#define UREG_I6        6
+#endif
+#ifndef UREG_FP
+#define UREG_FP        UREG_I6
+#endif
+
+static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+    return state->regwptr[UREG_FP];
+}
+
+static inline void set_second_rval(CPUSPARCState *state, abi_ulong retval2)
+{
+    state->regwptr[1] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
+
diff --git a/bsd-user/sparc/target_signal.h b/bsd-user/sparc/target_signal.h
index 5b2abba..181867a 100644
--- a/bsd-user/sparc/target_signal.h
+++ b/bsd-user/sparc/target_signal.h
@@ -19,9 +19,4 @@ typedef struct target_sigaltstack {
 #define UREG_FP        UREG_I6
 #endif
 
-static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
-{
-    return state->regwptr[UREG_FP];
-}
-
 #endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/sparc64/target_arch.h b/bsd-user/sparc64/target_arch.h
new file mode 100644
index 0000000..46bbcf8
--- /dev/null
+++ b/bsd-user/sparc64/target_arch.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+void bsd_sparc64_save_window(CPUSPARCState *env);
+void bsd_sparc64_restore_window(CPUSPARCState *env);
+void bsd_sparc64_flush_windows(CPUSPARCState *env);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* ! _TARGET_ARCH_H_ */
diff --git a/bsd-user/sparc64/target_arch_cpu.c b/bsd-user/sparc64/target_arch_cpu.c
new file mode 100644
index 0000000..e7bede8
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_cpu.c
@@ -0,0 +1,118 @@
+/*
+ *  sparc64 cpu related code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+
+#include "target_arch.h"
+
+#define SPARC64_STACK_BIAS 2047
+
+/* #define DEBUG_WIN */
+/* WARNING: dealing with register windows _is_ complicated. More info
+   can be found at http://www.sics.se/~psm/sparcstack.html */
+static int get_reg_index(CPUSPARCState *env, int cwp, int index)
+{
+    index = (index + cwp * 16) % (16 * env->nwindows);
+    /* wrap handling : if cwp is on the last window, then we use the
+       registers 'after' the end */
+    if (index < 8 && env->cwp == env->nwindows - 1) {
+        index += 16 * env->nwindows;
+    }
+    return index;
+}
+
+/* save the register window 'cwp1' */
+static void save_window_offset(CPUSPARCState *env, int cwp1)
+{
+    unsigned int i;
+    abi_ulong sp_ptr;
+
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+    if (sp_ptr & 3) {
+        sp_ptr += SPARC64_STACK_BIAS;
+    }
+#if defined(DEBUG_WIN)
+    printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for (i = 0; i < 16; i++) {
+        /* FIXME - what to do if put_user() fails? */
+        put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+}
+
+void bsd_sparc64_save_window(CPUSPARCState *env)
+{
+    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+    env->cansave++;
+    env->canrestore--;
+}
+
+void bsd_sparc64_restore_window(CPUSPARCState *env)
+{
+    unsigned int i, cwp1;
+    abi_ulong sp_ptr;
+
+    /* restore the invalid window */
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+    if (sp_ptr & 3) {
+        sp_ptr += SPARC64_STACK_BIAS;
+    }
+#if defined(DEBUG_WIN)
+    printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for (i = 0; i < 16; i++) {
+        /* FIXME - what to do if get_user() fails? */
+        get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+    env->canrestore++;
+    if (env->cleanwin < env->nwindows - 1) {
+        env->cleanwin++;
+    }
+    env->cansave--;
+}
+
+void bsd_sparc64_flush_windows(CPUSPARCState *env)
+{
+    int offset, cwp1;
+
+    offset = 1;
+    for (;;) {
+        /* if restore would invoke restore_window(), then we can stop */
+        cwp1 = cpu_cwp_inc(env, env->cwp + offset);
+        if (env->canrestore == 0) {
+            break;
+        }
+        env->cansave++;
+        env->canrestore--;
+        save_window_offset(env, cwp1);
+        offset++;
+    }
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+#if defined(DEBUG_WIN)
+    printf("bsd_sparc64_flush_windows: nb=%d\n", offset - 1);
+#endif
+}
+
diff --git a/bsd-user/sparc64/target_arch_cpu.h b/bsd-user/sparc64/target_arch_cpu.h
new file mode 100644
index 0000000..e497711
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_cpu.h
@@ -0,0 +1,191 @@
+/*
+ *  sparc64 cpu init and loop
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "TI UltraSparc II"
+
+#define TARGET_CPU_RESET(env) cpu_reset(ENV_GET_CPU(env))
+
+static inline void target_cpu_init(CPUSPARCState *env,
+        struct target_pt_regs *regs)
+{
+    int i;
+
+    env->pc = regs->pc;
+    env->npc = regs->npc;
+    env->y = regs->y;
+    for (i = 0; i < 8; i++) {
+        env->gregs[i] = regs->u_regs[i];
+    }
+    for (i = 0; i < 8; i++) {
+        env->regwptr[i] = regs->u_regs[i + 8];
+    }
+}
+
+
+static inline void target_cpu_loop(CPUSPARCState *env)
+{
+    CPUState *cs = CPU(sparc_env_get_cpu(env));
+    int trapnr, ret, syscall_nr;
+    /* target_siginfo_t info; */
+
+    while (1) {
+        trapnr = cpu_sparc_exec(env);
+
+        switch (trapnr) {
+        /* FreeBSD uses 0x141 for syscalls too */
+        case 0x141:
+            if (bsd_type != target_freebsd) {
+                goto badtrap;
+            }
+        case 0x100:
+            syscall_nr = env->gregs[1];
+            if (bsd_type == target_freebsd) {
+                ret = do_freebsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5], 0, 0);
+            } else if (bsd_type == target_netbsd) {
+                ret = do_netbsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5]);
+            } else { /* if (bsd_type == target_openbsd) */
+                syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
+                                TARGET_OPENBSD_SYSCALL_G2RFLAG);
+                ret = do_openbsd_syscall(env, syscall_nr,
+                                         env->regwptr[0], env->regwptr[1],
+                                         env->regwptr[2], env->regwptr[3],
+                                         env->regwptr[4], env->regwptr[5]);
+            }
+            if ((unsigned int)ret >= (unsigned int)(-515)) {
+                ret = -ret;
+#if !defined(TARGET_ABI32)
+                env->xcc |= PSR_CARRY;
+#else
+                env->psr |= PSR_CARRY;
+#endif
+            } else {
+#if !defined(TARGET_ABI32)
+                env->xcc &= ~PSR_CARRY;
+#else
+                env->psr &= ~PSR_CARRY;
+#endif
+            }
+            env->regwptr[0] = ret;
+            /* next instruction */
+            if (bsd_type == target_openbsd &&
+                env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
+                env->pc = env->gregs[2];
+                env->npc = env->pc + 4;
+            } else if (bsd_type == target_openbsd &&
+                       env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
+                env->pc = env->gregs[7];
+                env->npc = env->pc + 4;
+            } else {
+                env->pc = env->npc;
+                env->npc = env->npc + 4;
+            }
+            break;
+
+        case 0x83: /* flush windows */
+#ifdef TARGET_ABI32
+        case 0x103:
+#endif
+            bsd_sparc64_flush_windows(env);
+            /* next instruction */
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+            break;
+
+        case TT_SPILL: /* window overflow */
+            bsd_sparc64_save_window(env);
+            break;
+
+        case TT_FILL: /* window underflow */
+            bsd_sparc64_restore_window(env);
+            break;
+
+        case TT_TFAULT:
+        case TT_DFAULT:
+#if 0
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                if (trapnr == TT_DFAULT) {
+                    info._sifields._sigfault._addr = env->dmmuregs[4];
+                } else {
+                    info._sifields._sigfault._addr = env->tsptr->tpc;
+                    /* queue_signal(env, info.si_signo, &info); */
+                }
+            }
+#endif
+            break;
+
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+#if 0
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    /* queue_signal(env, info.si_signo, &info); */
+                }
+#endif
+            }
+            break;
+
+        default:
+badtrap:
+            printf("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(cs, stderr, fprintf, 0);
+            exit(1);
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUSPARCState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regwptr[22] = newsp;
+    env->regwptr[0] = 0;
+    /* FIXME: Do we also need to clear CF?  */
+    /* XXXXX */
+    printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+    cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/sparc64/target_arch_vmparam.h b/bsd-user/sparc64/target_arch_vmparam.h
new file mode 100644
index 0000000..2c2323b
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_vmparam.h
@@ -0,0 +1,37 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to amd64/include/vmparam.h */
+#define TARGET_MAXTSIZ  (1*1024*1024*1024)  /* max text size */
+#define TARGET_DFLDSIZ  (128*1024*1024)     /* initial data size limit */
+#define TARGET_MAXDSIZ  (1*1024*1024*1024)  /* max data size */
+#define TARGET_DFLSSIZ  (128*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ  (1*1024*1024*1024)  /* max stack size */
+#define TARGET_SGROWSIZ (128*1024)      /* amount to grow stack */
+
+/* XXX */
+#define TARGET_VM_MINUSER_ADDRESS   (0x0000000000000000UL)
+#define TARGET_VM_MAXUSER_ADDRESS   (0x000007fe00000000UL)
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+#ifndef UREG_I6
+#define UREG_I6        6
+#endif
+#ifndef UREG_FP
+#define UREG_FP        UREG_I6
+#endif
+
+static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+    return state->regwptr[UREG_FP];
+}
+
+static inline void set_second_rval(CPUSPARCState *state, abi_ulong retval2)
+{
+    state->regwptr[1] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
+
diff --git a/bsd-user/sparc64/target_signal.h b/bsd-user/sparc64/target_signal.h
index 5b2abba..181867a 100644
--- a/bsd-user/sparc64/target_signal.h
+++ b/bsd-user/sparc64/target_signal.h
@@ -19,9 +19,4 @@ typedef struct target_sigaltstack {
 #define UREG_FP        UREG_I6
 #endif
 
-static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
-{
-    return state->regwptr[UREG_FP];
-}
-
 #endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/x86_64/target_arch.h b/bsd-user/x86_64/target_arch.h
new file mode 100644
index 0000000..7fe81dc
--- /dev/null
+++ b/bsd-user/x86_64/target_arch.h
@@ -0,0 +1,13 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+/* target_arch_cpu.c */
+void bsd_x86_64_write_dt(void *ptr, unsigned long addr, unsigned long limit,
+                int flags);
+void bsd_x86_64_set_idt(int n, unsigned int dpl);
+void bsd_x86_64_set_idt_base(uint64_t base);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/x86_64/target_arch_cpu.c b/bsd-user/x86_64/target_arch_cpu.c
new file mode 100644
index 0000000..5cfdfca
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_cpu.c
@@ -0,0 +1,79 @@
+/*
+ *  x86_64 cpu related code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+#include "qemu/timer.h"
+
+#include "target_arch.h"
+
+static uint64_t *idt_table;
+
+/* CPUX86 core interface */
+void cpu_smm_update(CPUX86State *env)
+{
+}
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+    return cpu_get_real_ticks();
+}
+
+int cpu_get_pic_interrupt(CPUX86State *env)
+{
+    return -1;
+}
+
+void bsd_x86_64_write_dt(void *ptr, unsigned long addr,
+        unsigned long limit, int flags)
+{
+    unsigned int e1, e2;
+    uint32_t *p;
+    e1 = (addr << 16) | (limit & 0xffff);
+    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+    e2 |= flags;
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
+        uint64_t addr, unsigned int sel)
+{
+    uint32_t *p, e1, e2;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+    p[2] = tswap32(addr >> 32);
+    p[3] = 0;
+}
+
+/* only dpl matters as we do only user space emulation */
+void bsd_x86_64_set_idt(int n, unsigned int dpl)
+{
+    set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
+}
+
+void bsd_x86_64_set_idt_base(uint64_t base)
+{
+    idt_table = g2h(base);
+}
diff --git a/bsd-user/x86_64/target_arch_cpu.h b/bsd-user/x86_64/target_arch_cpu.h
new file mode 100644
index 0000000..9a66b67
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_cpu.h
@@ -0,0 +1,324 @@
+/*
+ *  x86_64 cpu init and loop
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "qemu64"
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUX86State *env,
+        struct target_pt_regs *regs)
+{
+    uint64_t *gdt_table;
+
+    cpu_x86_set_cpl(env, 3);
+
+    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+    env->hflags |= HF_PE_MASK;
+    if (env->features[FEAT_1_EDX] & CPUID_SSE) {
+        env->cr[4] |= CR4_OSFXSR_MASK;
+        env->hflags |= HF_OSFXSR_MASK;
+    }
+
+    /* enable 64 bit mode if possible */
+    if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
+        fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
+        exit(1);
+    }
+    env->cr[4] |= CR4_PAE_MASK;
+    env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
+    env->hflags |= HF_LMA_MASK;
+
+    /* flags setup : we activate the IRQs by default as in user mode */
+    env->eflags |= IF_MASK;
+
+    /* register setup */
+    env->regs[R_EAX] = regs->rax;
+    env->regs[R_EBX] = regs->rbx;
+    env->regs[R_ECX] = regs->rcx;
+    env->regs[R_EDX] = regs->rdx;
+    env->regs[R_ESI] = regs->rsi;
+    env->regs[R_EDI] = regs->rdi;
+    env->regs[R_EBP] = regs->rbp;
+    env->regs[R_ESP] = regs->rsp;
+    env->eip = regs->rip;
+
+    /* interrupt setup */
+    env->idt.limit = 511;
+
+    env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+        PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    bsd_x86_64_set_idt_base(env->idt.base);
+    bsd_x86_64_set_idt(0, 0);
+    bsd_x86_64_set_idt(1, 0);
+    bsd_x86_64_set_idt(2, 0);
+    bsd_x86_64_set_idt(3, 3);
+    bsd_x86_64_set_idt(4, 3);
+    bsd_x86_64_set_idt(5, 0);
+    bsd_x86_64_set_idt(6, 0);
+    bsd_x86_64_set_idt(7, 0);
+    bsd_x86_64_set_idt(8, 0);
+    bsd_x86_64_set_idt(9, 0);
+    bsd_x86_64_set_idt(10, 0);
+    bsd_x86_64_set_idt(11, 0);
+    bsd_x86_64_set_idt(12, 0);
+    bsd_x86_64_set_idt(13, 0);
+    bsd_x86_64_set_idt(14, 0);
+    bsd_x86_64_set_idt(15, 0);
+    bsd_x86_64_set_idt(16, 0);
+    bsd_x86_64_set_idt(17, 0);
+    bsd_x86_64_set_idt(18, 0);
+    bsd_x86_64_set_idt(19, 0);
+    bsd_x86_64_set_idt(0x80, 3);
+
+    /* segment setup */
+    env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+            PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+    gdt_table = g2h(env->gdt.base);
+
+    /* 64 bit code segment */
+    bsd_x86_64_write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_L_MASK
+            | (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+
+    bsd_x86_64_write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+            (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+
+    cpu_x86_load_seg(env, R_CS, __USER_CS);
+    cpu_x86_load_seg(env, R_SS, __USER_DS);
+    cpu_x86_load_seg(env, R_DS, 0);
+    cpu_x86_load_seg(env, R_ES, 0);
+    cpu_x86_load_seg(env, R_FS, 0);
+    cpu_x86_load_seg(env, R_GS, 0);
+}
+
+static inline void target_cpu_loop(CPUX86State *env)
+{
+    int trapnr;
+    abi_ulong pc;
+    /* target_siginfo_t info; */
+
+    for (;;) {
+        trapnr = cpu_x86_exec(env);
+        switch (trapnr) {
+        case 0x80:
+            /* syscall from int $0x80 */
+            if (bsd_type == target_freebsd) {
+                abi_ulong params = (abi_ulong) env->regs[R_ESP] +
+                    sizeof(int32_t);
+                int32_t syscall_nr = env->regs[R_EAX];
+                int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+                if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int32_t);
+                } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int64_t);
+                }
+                get_user_s32(arg1, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg2, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg3, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg4, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg5, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg6, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg7, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg8, params);
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      syscall_nr,
+                                                      arg1,
+                                                      arg2,
+                                                      arg3,
+                                                      arg4,
+                                                      arg5,
+                                                      arg6,
+                                                      arg7,
+                                                      arg8);
+            } else { /* if (bsd_type == target_openbsd) */
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EBX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_EBP]);
+            }
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
+            break;
+
+        case EXCP_SYSCALL:
+            /* syscall from syscall instruction */
+            if (bsd_type == target_freebsd) {
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[8],
+                                                      env->regs[9], 0, 0);
+            } else { /* if (bsd_type == target_openbsd) */
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDX],
+                                                      env->regs[10],
+                                                      env->regs[8],
+                                                      env->regs[9]);
+            }
+            env->eip = env->exception_next_eip;
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
+            break;
+
+#if 0
+        case EXCP0B_NOSEG:
+        case EXCP0C_STACK:
+            info.si_signo = SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP0D_GPF:
+            /* XXX: potential problem if ABI32 */
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP0E_PAGE:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            if (!(env->error_code & 1)) {
+                info.si_code = TARGET_SEGV_MAPERR;
+            } else {
+                info.si_code = TARGET_SEGV_ACCERR;
+            }
+            info._sifields._sigfault._addr = env->cr[2];
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP00_DIVZ:
+            /* division by zero */
+            info.si_signo = SIGFPE;
+            info.si_errno = 0;
+            info.si_code = TARGET_FPE_INTDIV;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP01_DB:
+        case EXCP03_INT3:
+            info.si_signo = SIGTRAP;
+            info.si_errno = 0;
+            if (trapnr == EXCP01_DB) {
+                info.si_code = TARGET_TRAP_BRKPT;
+                info._sifields._sigfault._addr = env->eip;
+            } else {
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+            }
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP04_INTO:
+        case EXCP05_BOUND:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+
+        case EXCP06_ILLOP:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(env, info.si_signo, &info);
+            break;
+#endif
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+#if 0
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(env, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                }
+            }
+            break;
+#endif
+        default:
+            pc = env->segs[R_CS].base + env->eip;
+            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - "
+                    "aborting\n", (long)pc, trapnr);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[R_ESP] = newsp;
+    env->regs[R_EAX] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+    cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/x86_64/target_arch_vmparam.h b/bsd-user/x86_64/target_arch_vmparam.h
new file mode 100644
index 0000000..5e13076
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_vmparam.h
@@ -0,0 +1,28 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to amd64/include/vmparam.h */
+#define TARGET_MAXTSIZ  (128UL*1024*1024)   /* max text size */
+#define TARGET_DFLDSIZ  (32768UL*1024*1024) /* initial data size limit */
+#define TARGET_MAXDSIZ  (32768UL*1024*1024) /* max data size */
+#define TARGET_DFLSSIZ  (8UL*1024*1024)     /* initial stack size limit */
+#define TARGET_MAXSSIZ  (512UL*1024*1024)   /* max stack size */
+#define TARGET_SGROWSIZ (128UL*1024)        /* amount to grow stack */
+
+#define TARGET_VM_MAXUSER_ADDRESS   (0x0000800000000000UL)
+
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+    return state->regs[R_ESP];
+}
+
+static inline void set_second_rval(CPUX86State *state, abi_ulong retval2)
+{
+    state->regs[R_EDX] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/x86_64/target_signal.h b/bsd-user/x86_64/target_signal.h
index 659cd40..5491687 100644
--- a/bsd-user/x86_64/target_signal.h
+++ b/bsd-user/x86_64/target_signal.h
@@ -11,9 +11,4 @@ typedef struct target_sigaltstack {
 	abi_ulong ss_size;
 } target_stack_t;
 
-static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
-{
-    return state->regs[R_ESP];
-}
-
 #endif /* TARGET_SIGNAL_H */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 05/19] bsd-user: move arch/OS dependent code out of syscall.c
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (5 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 04/19] bsd-user: move arch/OS dependent code out of main.c Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2014-01-27 19:52     ` Peter Maydell
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 06/19] bsd-user: add support for freebsd time related system calls Stacey Son
                     ` (13 subsequent siblings)
  20 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change moves the system call handler for sysctl(2) and
sysarch(2) from syscall.c to the OS and arch dependent directories.
This eliminates many of the #ifdef's in syscall.c.  These system
call handlers are now located in the host os and target arch
directories.
---
 bsd-user/Makefile.objs                  |    2 +-
 bsd-user/arm/target_arch_sigtramp.h     |   33 ++++
 bsd-user/bsdload.c                      |  170 +++++++++++++-----
 bsd-user/elfload.c                      |    9 +-
 bsd-user/freebsd/os-sys.c               |  284 +++++++++++++++++++++++++++++++
 bsd-user/freebsd/target_os_stack.h      |  157 +++++++++++++++++
 bsd-user/i386/target_arch_sigtramp.h    |   11 ++
 bsd-user/mips/target_arch_sigtramp.h    |   23 +++
 bsd-user/mips64/target_arch_sigtramp.h  |   23 +++
 bsd-user/netbsd/os-sys.c                |   46 +++++
 bsd-user/netbsd/target_os_stack.h       |   33 ++++
 bsd-user/openbsd/os-sys.c               |   46 +++++
 bsd-user/openbsd/target_os_stack.h      |   33 ++++
 bsd-user/qemu.h                         |   30 +++-
 bsd-user/sparc/target_arch_sigtramp.h   |   11 ++
 bsd-user/sparc64/target_arch_sigtramp.h |   11 ++
 bsd-user/syscall.c                      |  210 +++--------------------
 bsd-user/x86_64/target_arch_sigtramp.h  |   11 ++
 18 files changed, 900 insertions(+), 243 deletions(-)
 create mode 100644 bsd-user/arm/target_arch_sigtramp.h
 create mode 100644 bsd-user/freebsd/os-sys.c
 create mode 100644 bsd-user/freebsd/target_os_stack.h
 create mode 100644 bsd-user/i386/target_arch_sigtramp.h
 create mode 100644 bsd-user/mips/target_arch_sigtramp.h
 create mode 100644 bsd-user/mips64/target_arch_sigtramp.h
 create mode 100644 bsd-user/netbsd/os-sys.c
 create mode 100644 bsd-user/netbsd/target_os_stack.h
 create mode 100644 bsd-user/openbsd/os-sys.c
 create mode 100644 bsd-user/openbsd/target_os_stack.h
 create mode 100644 bsd-user/sparc/target_arch_sigtramp.h
 create mode 100644 bsd-user/sparc64/target_arch_sigtramp.h
 create mode 100644 bsd-user/x86_64/target_arch_sigtramp.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 41e8dce..a4dca8e 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,2 +1,2 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o $(TARGET_ABI_DIR)/target_arch_cpu.o
+	        uaccess.o $(HOST_VARIANT_DIR)/os-sys.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/arm/target_arch_sigtramp.h b/bsd-user/arm/target_arch_sigtramp.h
new file mode 100644
index 0000000..98dc313
--- /dev/null
+++ b/bsd-user/arm/target_arch_sigtramp.h
@@ -0,0 +1,33 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+/* Compare to arm/arm/locore.S ENTRY_NP(sigcode) */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+    int i;
+    uint32_t sys_exit = TARGET_FREEBSD_NR_exit;
+    /*
+     * The code has to load r7 manually rather than using
+     * "ldr r7, =SYS_return to make sure the size of the
+     * code is correct.
+     */
+    uint32_t sigtramp_code[] = {
+    /* 1 */ 0xE1A0000D,         /* mov r0, sp */
+    /* 2 */ 0xE59F700C,         /* ldr r7, [pc, #12] */
+    /* 3 */ 0xEF000000 + sys_sigreturn, /* swi (SYS_sigreturn) */
+    /* 4 */ 0xE59F7008,         /* ldr r7, [pc, #8] */
+    /* 5 */ 0xEF000000 + sys_exit,      /* swi (SYS_exit)*/
+    /* 6 */ 0xEAFFFFFA,         /* b . -16 */
+    /* 7 */ sys_sigreturn,
+    /* 8 */ sys_exit
+    };
+
+    for (i = 0; i < 8; i++) {
+        tswap32s(&sigtramp_code[i]);
+    }
+
+    return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c
index 2abc713..45fdcf8 100644
--- a/bsd-user/bsdload.c
+++ b/bsd-user/bsdload.c
@@ -1,4 +1,19 @@
-/* Code for loading BSD executables.  Mostly linux kernel code.  */
+/*
+ *  Load BSD executables.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -26,38 +41,22 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src,
     return 0;
 }
 
-static int in_group_p(gid_t g)
-{
-    /* return TRUE if we're in the specified group, FALSE otherwise */
-    int         ngroup;
-    int         i;
-    gid_t       grouplist[TARGET_NGROUPS];
-
-    ngroup = getgroups(TARGET_NGROUPS, grouplist);
-    for(i = 0; i < ngroup; i++) {
-        if(grouplist[i] == g) {
-            return 1;
-        }
-    }
-    return 0;
-}
-
 static int count(char ** vec)
 {
     int         i;
 
-    for(i = 0; *vec; i++) {
+    for (i = 0; *vec; i++) {
         vec++;
     }
 
     return(i);
 }
 
-static int prepare_binprm(struct linux_binprm *bprm)
+static int prepare_binprm(struct bsd_binprm *bprm)
 {
     struct stat         st;
     int mode;
-    int retval, id_change;
+    int retval;
 
     if(fstat(bprm->fd, &st) < 0) {
         return(-errno);
@@ -73,14 +72,10 @@ static int prepare_binprm(struct linux_binprm *bprm)
 
     bprm->e_uid = geteuid();
     bprm->e_gid = getegid();
-    id_change = 0;
 
     /* Set-uid? */
     if(mode & S_ISUID) {
         bprm->e_uid = st.st_uid;
-        if(bprm->e_uid != geteuid()) {
-            id_change = 1;
-        }
     }
 
     /* Set-gid? */
@@ -91,9 +86,6 @@ static int prepare_binprm(struct linux_binprm *bprm)
      */
     if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
         bprm->e_gid = st.st_gid;
-        if (!in_group_p(bprm->e_gid)) {
-                id_change = 1;
-        }
     }
 
     memset(bprm->buf, 0, sizeof(bprm->buf));
@@ -154,34 +146,116 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
     return sp;
 }
 
+static int is_there(const char *candidate)
+{
+    struct stat fin;
+
+    /* XXX work around access(2) false positives for superuser */
+    if (access(candidate, X_OK) == 0 && stat(candidate, &fin) == 0 &&
+            S_ISREG(fin.st_mode) && (getuid() != 0 ||
+                (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static int find_in_path(char *path, const char *filename, char *retpath,
+        size_t rpsize)
+{
+    const char *d;
+    int found;
+
+    if (strchr(filename, '/') != NULL) {
+        if (is_there(filename)) {
+                if (!realpath(filename, retpath)) {
+                    return -1;
+                }
+                return 0;
+        } else {
+            return -1;
+        }
+    }
+
+    found = 0;
+    while ((d = strsep(&path, ":")) != NULL) {
+        if (*d == '\0') {
+            d = ".";
+        }
+        if (snprintf(retpath, rpsize, "%s/%s", d, filename) >= (int)rpsize) {
+            continue;
+        }
+        if (is_there((const char *)retpath)) {
+            found = 1;
+            break;
+        }
+    }
+    return found;
+}
+
 int loader_exec(const char * filename, char ** argv, char ** envp,
-             struct target_pt_regs * regs, struct image_info *infop)
+             struct target_pt_regs *regs, struct image_info *infop,
+             struct bsd_binprm *bprm)
 {
-    struct linux_binprm bprm;
-    int retval;
-    int i;
+    char *p, *path = NULL, fullpath[PATH_MAX];
+    const char *execname = NULL;
+    int retval, i, found;
 
-    bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
+    bprm->p = TARGET_PAGE_SIZE * MAX_ARG_PAGES; /* -sizeof(unsigned int); */
     for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
-            bprm.page[i] = NULL;
-    retval = open(filename, O_RDONLY);
-    if (retval < 0)
+            bprm->page[i] = NULL;
+
+    /* Find target executable in path, if not already an absolute path. */
+    p = getenv("PATH");
+    if (p != NULL) {
+        path = g_strdup(p);
+        if (path == NULL) {
+            fprintf(stderr, "Out of memory\n");
+            return -1;
+        }
+        execname = realpath(filename, NULL);
+        if (execname == NULL) {
+            execname = g_strdup(filename);
+        }
+        found = find_in_path(path, execname, fullpath, sizeof(fullpath));
+        /* Absolute path specified but not found? */
+        if (found == -1) {
+            return -1;
+        }
+        if (found) {
+            retval = open(fullpath, O_RDONLY);
+            bprm->fullpath = g_strdup(fullpath);
+        } else {
+            retval = open(execname, O_RDONLY);
+            bprm->fullpath = NULL;
+        }
+        if (execname) {
+            g_free((void *)execname);
+        }
+        g_free(path);
+    } else {
+        retval = open(filename, O_RDONLY);
+        bprm->fullpath = NULL;
+    }
+    if (retval < 0) {
         return retval;
-    bprm.fd = retval;
-    bprm.filename = (char *)filename;
-    bprm.argc = count(argv);
-    bprm.argv = argv;
-    bprm.envc = count(envp);
-    bprm.envp = envp;
+    }
+
+    bprm->fd = retval;
+    bprm->filename = (char *)filename;
+    bprm->argc = count(argv);
+    bprm->argv = argv;
+    bprm->envc = count(envp);
+    bprm->envp = envp;
 
-    retval = prepare_binprm(&bprm);
+    retval = prepare_binprm(bprm);
 
     if(retval>=0) {
-        if (bprm.buf[0] == 0x7f
-                && bprm.buf[1] == 'E'
-                && bprm.buf[2] == 'L'
-                && bprm.buf[3] == 'F') {
-            retval = load_elf_binary(&bprm,regs,infop);
+        if (bprm->buf[0] == 0x7f
+                && bprm->buf[1] == 'E'
+                && bprm->buf[2] == 'L'
+                && bprm->buf[3] == 'F') {
+            retval = load_elf_binary(bprm, regs, infop);
         } else {
             fprintf(stderr, "Unknown binary format\n");
             return -1;
@@ -196,7 +270,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
 
     /* Something went wrong, return the inode and free the argument pages*/
     for (i=0 ; i<MAX_ARG_PAGES ; i++) {
-        g_free(bprm.page[i]);
+        g_free(bprm->page[i]);
     }
     return(retval);
 }
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index ccf72d1..68d0209 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -91,6 +91,9 @@ enum {
 #define ELIBBAD 80
 #endif
 
+abi_ulong target_stksiz;
+abi_ulong target_stkbas;
+
 #ifdef TARGET_I386
 
 #define ELF_PLATFORM get_elf_platform()
@@ -665,7 +668,7 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
     return p;
 }
 
-static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
+static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm,
                                  struct image_info *info)
 {
     abi_ulong stack_base, size, error;
@@ -1147,8 +1150,8 @@ static void load_symbols(struct elfhdr *hdr, int fd)
     syminfos = s;
 }
 
-int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
-                    struct image_info * info)
+int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
+                    struct image_info *info)
 {
     struct elfhdr elf_ex;
     struct elfhdr interp_elf_ex;
diff --git a/bsd-user/freebsd/os-sys.c b/bsd-user/freebsd/os-sys.c
new file mode 100644
index 0000000..c8f999f
--- /dev/null
+++ b/bsd-user/freebsd/os-sys.c
@@ -0,0 +1,284 @@
+/*
+ *  FreeBSD sysctl() and sysarch() system call emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+#include "qemu.h"
+
+#include "target_arch_sysarch.h"
+#include "target_os_vmparam.h"
+
+/*
+ * XXX this uses the undocumented oidfmt interface to find the kind of
+ * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
+ * (compare to src/sbin/sysctl/sysctl.c)
+ */
+static int
+oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
+{
+    int qoid[CTL_MAXNAME+2];
+    uint8_t buf[BUFSIZ];
+    int i;
+    size_t j;
+
+    qoid[0] = 0;
+    qoid[1] = 4;
+    memcpy(qoid + 2, oid, len * sizeof(int));
+
+    j = sizeof(buf);
+    i = sysctl(qoid, len + 2, buf, &j, 0, 0);
+    if (i) {
+        return i;
+    }
+
+    if (kind) {
+        *kind = *(uint32_t *)buf;
+    }
+
+    if (fmt) {
+        strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
+    }
+    return 0;
+}
+
+/*
+ * try and convert sysctl return data for the target.
+ * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT.
+ */
+static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
+{
+    switch (kind & CTLTYPE) {
+    case CTLTYPE_INT:
+    case CTLTYPE_UINT:
+        *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp);
+        break;
+
+#ifdef TARGET_ABI32
+    case CTLTYPE_LONG:
+    case CTLTYPE_ULONG:
+        *(uint32_t *)holdp = tswap32(*(long *)holdp);
+        break;
+#else
+    case CTLTYPE_LONG:
+        *(uint64_t *)holdp = tswap64(*(long *)holdp);
+    case CTLTYPE_ULONG:
+        *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
+        break;
+#endif
+#if !defined(__FreeBSD_version) || __FreeBSD_version < 900031
+    case CTLTYPE_QUAD:
+#else
+    case CTLTYPE_U64:
+    case CTLTYPE_S64:
+#endif
+        *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
+        break;
+
+    case CTLTYPE_STRING:
+        break;
+
+    default:
+        /* XXX unhandled */
+        return -1;
+    }
+    return 0;
+}
+
+/*
+ * Convert the undocmented name2oid sysctl data for the target.
+ */
+static inline void sysctl_name2oid(uint32_t *holdp, size_t holdlen)
+{
+    size_t i;
+
+    for (i = 0; i < holdlen; i++) {
+        holdp[i] = tswap32(holdp[i]);
+    }
+}
+
+static inline void sysctl_oidfmt(uint32_t *holdp)
+{
+    /* byte swap the kind */
+    holdp[0] = tswap32(holdp[0]);
+}
+
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+    abi_long ret;
+    void *hnamep, *holdp = NULL, *hnewp = NULL;
+    size_t holdlen;
+    abi_ulong oldlen = 0;
+    int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
+    uint32_t kind = 0;
+    TaskState *ts = (TaskState *)env->opaque;
+
+    if (oldlenp) {
+        if (get_user_ual(oldlen, oldlenp)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    hnamep = lock_user(VERIFY_READ, namep, namelen, 1);
+    if (hnamep == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (newp) {
+        hnewp = lock_user(VERIFY_READ, newp, newlen, 1);
+        if (hnewp == NULL) {
+            return -TARGET_EFAULT;
+        }
+    }
+    if (oldp) {
+        holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0);
+        if (holdp == NULL) {
+            return -TARGET_EFAULT;
+        }
+    }
+    holdlen = oldlen;
+    for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++) {
+        *q++ = tswap32(*p);
+    }
+    oidfmt(snamep, namelen, NULL, &kind);
+
+    /* Handle some arch/emulator dependent sysctl()'s here. */
+    switch (snamep[0]) {
+    case CTL_KERN:
+        switch (snamep[1]) {
+        case KERN_USRSTACK:
+#if TARGET_USRSTACK != 0
+            (*(abi_ulong *)holdp) = tswapal(TARGET_USRSTACK);
+            holdlen = sizeof(abi_ulong);
+            ret = 0;
+#else
+            ret = -TARGET_ENOENT;
+#endif
+            goto out;
+
+        case KERN_PS_STRINGS:
+#if defined(TARGET_PS_STRINGS)
+            (*(abi_ulong *)holdp) = tswapal(TARGET_PS_STRINGS);
+            holdlen = sizeof(abi_ulong);
+            ret = 0;
+#else
+            ret = -TARGET_ENOENT;
+#endif
+            goto out;
+
+        case KERN_PROC:
+            switch (snamep[2]) {
+            case KERN_PROC_PATHNAME:
+                holdlen = strlen(ts->bprm->fullpath) + 1;
+                if (holdp) {
+                    if (oldlen < holdlen) {
+                        ret = -TARGET_EINVAL;
+                        goto out;
+                    }
+                    strlcpy(holdp, ts->bprm->fullpath, oldlen);
+                }
+                ret = 0;
+                goto out;
+
+            default:
+                break;
+            }
+            break;
+
+        default:
+            break;
+        }
+        break;
+
+    case CTL_HW:
+        switch (snamep[1]) {
+        case HW_MACHINE:
+            strlcpy(holdp, TARGET_HW_MACHINE, oldlen);
+            ret = 0;
+            goto out;
+
+        case HW_MACHINE_ARCH:
+            strlcpy(holdp, TARGET_HW_MACHINE_ARCH, oldlen);
+            ret = 0;
+            goto out;
+
+        case 851: /* hw.availpages */
+            {
+                long lvalue;
+                size_t len = sizeof(lvalue);
+
+                if (sysctlbyname("hw.availpages", &lvalue, &len, NULL, 0)
+                        == -1) {
+                    ret = -1;
+                } else {
+                    (*(abi_ulong *)holdp) = tswapal((abi_ulong)lvalue);
+                    holdlen = sizeof(abi_ulong);
+                    ret = 0;
+                }
+            }
+            goto out;
+
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
+    if (!ret && (holdp != 0 && holdlen != 0)) {
+        if (0 == snamep[0] && (3 == snamep[1] || 4 == snamep[1])) {
+            if (3 == snamep[1]) {
+                /* Handle the undocumented name2oid special case. */
+                sysctl_name2oid(holdp, holdlen);
+            } else {
+                /* Handle oidfmt */
+                sysctl_oidfmt(holdp);
+            }
+        } else {
+            sysctl_oldcvt(holdp, holdlen, kind);
+        }
+    }
+#ifdef DEBUG
+    else {
+        printf("sysctl(mib[0]=%d, mib[1]=%d, mib[3]=%d...) returned %d\n",
+        snamep[0], snamep[1], snamep[2], (int)ret);
+    }
+#endif
+
+out:
+    if (oldlenp) {
+        put_user_ual(holdlen, oldlenp);
+    }
+    unlock_user(hnamep, namep, 0);
+    unlock_user(holdp, oldp, holdlen);
+    if (hnewp) {
+        unlock_user(hnewp, newp, 0);
+    }
+    g_free(snamep);
+    return ret;
+}
+
+/* sysarch() is architecture dependent. */
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+{
+
+    return do_freebsd_arch_sysarch(cpu_env, arg1, arg2);
+}
diff --git a/bsd-user/freebsd/target_os_stack.h b/bsd-user/freebsd/target_os_stack.h
new file mode 100644
index 0000000..c84b69e
--- /dev/null
+++ b/bsd-user/freebsd/target_os_stack.h
@@ -0,0 +1,157 @@
+#ifndef _TARGET_OS_STACK_H_
+#define _TARGET_OS_STACK_H_
+
+#include <sys/param.h>
+#include "target_arch_sigtramp.h"
+
+/*
+ * The inital FreeBSD stack is as follows:
+ * (see kern/kern_exec.c exec_copyout_strings() )
+ *
+ *  Hi Address -> char **ps_argvstr  (struct ps_strings for ps, w, etc.)
+ *                unsigned ps_nargvstr
+ *                char **ps_envstr
+ *  PS_STRINGS -> unsigned ps_nenvstr
+ *
+ *                machine dependent sigcode (sv_sigcode of size
+ *                                           sv_szsigcode)
+ *
+ *                execpath          (absolute image path for rtld)
+ *
+ *                SSP Canary        (sizeof(long) * 8)
+ *
+ *                page sizes array  (usually sizeof(u_long) )
+ *
+ *  "destp" ->    argv, env strings (up to 262144 bytes)
+ */
+static inline int setup_initial_stack(struct bsd_binprm *bprm,
+        abi_ulong *ret_addr)
+{
+    int i;
+    abi_ulong stack_hi_addr;
+    size_t execpath_len, stringspace;
+    abi_ulong destp, argvp, envp, p;
+    struct target_ps_strings ps_strs;
+    char canary[sizeof(abi_long) * 8];
+
+    stack_hi_addr = p = target_stkbas + target_stksiz;
+
+    /* Save some space for ps_strings. */
+    p -= sizeof(struct target_ps_strings);
+
+#ifdef TARGET_SZSIGCODE
+    /* Add machine depedent sigcode. */
+    p -= TARGET_SZSIGCODE;
+    if (setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc),
+            TARGET_FREEBSD_NR_sigreturn)) {
+        errno = EFAULT;
+        return -1;
+    }
+#endif
+    if (bprm->fullpath) {
+        execpath_len = strlen(bprm->fullpath) + 1;
+        p -= roundup(execpath_len, sizeof(abi_ulong));
+        if (memcpy_to_target(p, bprm->fullpath, execpath_len)) {
+            errno = EFAULT;
+            return -1;
+        }
+    }
+    /* Add canary for SSP. */
+    arc4random_buf(canary, sizeof(canary));
+    p -= roundup(sizeof(canary), sizeof(abi_ulong));
+    if (memcpy_to_target(p, canary, sizeof(canary))) {
+        errno = EFAULT;
+        return -1;
+    }
+    /* Add page sizes array. */
+    /* p -= sizeof(int); */
+    p -= sizeof(abi_ulong);
+    /* if (put_user_u32(TARGET_PAGE_SIZE, p)) { */
+    if (put_user_ual(TARGET_PAGE_SIZE, p)) {
+        errno = EFAULT;
+        return -1;
+    }
+    /* Calculate the string space needed */
+    stringspace = 0;
+    for (i = 0; i < bprm->argc; ++i) {
+        stringspace += strlen(bprm->argv[i]) + 1;
+    }
+    for (i = 0; i < bprm->envc; ++i) {
+        stringspace += strlen(bprm->envp[i]) + 1;
+    }
+    if (stringspace > TARGET_ARG_MAX) {
+       errno = ENOMEM;
+       return -1;
+    }
+
+    /* Make room for the argv and envp strings */
+    /* p = destp = roundup(p - TARGET_SPACE_USRSPACE - (TARGET_ARG_MAX - stringspace), sizeof(abi_ulong)); */
+    argvp = p - TARGET_SPACE_USRSPACE;
+    p = destp = roundup(p - TARGET_SPACE_USRSPACE - TARGET_ARG_MAX, sizeof(abi_ulong));
+
+    /*
+     * Add argv strings.  Note that the argv[] vectors are added by
+     * loader_build_argptr()
+     */
+    /* XXX need to make room for auxargs */
+    /* argvp = destp - ((bprm->argc + bprm->envc + 2) * sizeof(abi_ulong)); */
+    /* envp = argvp + (bprm->argc + 2) * sizeof(abi_ulong); */
+    envp = argvp + (bprm->argc + 1) * sizeof(abi_ulong);
+    ps_strs.ps_argvstr = tswapl(argvp);
+    ps_strs.ps_nargvstr = tswap32(bprm->argc);
+    for (i = 0; i < bprm->argc; ++i) {
+        size_t len = strlen(bprm->argv[i]) + 1;
+
+        if (memcpy_to_target(destp, bprm->argv[i], len)) {
+            errno = EFAULT;
+            return -1;
+        }
+        if (put_user_ual(destp, argvp)) {
+            errno = EFAULT;
+            return -1;
+        }
+        argvp += sizeof(abi_ulong);
+        destp += len;
+    }
+    if (put_user_ual(0, argvp)) {
+        errno = EFAULT;
+        return -1;
+    }
+    /*
+     * Add env strings. Note that the envp[] vectors are added by
+     * loader_build_argptr().
+     */
+    ps_strs.ps_envstr = tswapl(envp);
+    ps_strs.ps_nenvstr = tswap32(bprm->envc);
+    for (i = 0; i < bprm->envc; ++i) {
+        size_t len = strlen(bprm->envp[i]) + 1;
+
+        if (memcpy_to_target(destp, bprm->envp[i], len)) {
+            errno = EFAULT;
+            return -1;
+        }
+        if (put_user_ual(destp, envp)) {
+            errno = EFAULT;
+            return -1;
+        }
+        envp += sizeof(abi_ulong);
+        destp += len;
+    }
+    if (put_user_ual(0, envp)) {
+        errno = EFAULT;
+        return -1;
+    }
+    if (memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs,
+                sizeof(ps_strs))) {
+        errno = EFAULT;
+        return -1;
+    }
+
+    if (ret_addr) {
+       *ret_addr = p;
+    }
+
+    return 0;
+ }
+
+#endif /* !_TARGET_OS_STACK_H_ */
diff --git a/bsd-user/i386/target_arch_sigtramp.h b/bsd-user/i386/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/i386/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/mips/target_arch_sigtramp.h b/bsd-user/mips/target_arch_sigtramp.h
new file mode 100644
index 0000000..5e3c69a
--- /dev/null
+++ b/bsd-user/mips/target_arch_sigtramp.h
@@ -0,0 +1,23 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+/* Compare to mips/mips/locore.S sigcode() */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+    int i;
+    uint32_t sigtramp_code[TARGET_SZSIGCODE/TARGET_INSN_SIZE] = {
+    /* 1 */ 0x67A40000 + sigf_uc,       /* daddu   $a0, $sp, (sigf_uc) */
+    /* 2 */ 0x24020000 + sys_sigreturn, /* li      $v0, (sys_sigreturn) */
+    /* 3 */ 0x0000000C,                 /* syscall */
+    /* 4 */ 0x0000000D                  /* break */
+    };
+
+    for (i = 0; i < 4; i++) {
+        tswap32s(&sigtramp_code[i]);
+    }
+
+    return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/mips64/target_arch_sigtramp.h b/bsd-user/mips64/target_arch_sigtramp.h
new file mode 100644
index 0000000..5e3c69a
--- /dev/null
+++ b/bsd-user/mips64/target_arch_sigtramp.h
@@ -0,0 +1,23 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+/* Compare to mips/mips/locore.S sigcode() */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+    int i;
+    uint32_t sigtramp_code[TARGET_SZSIGCODE/TARGET_INSN_SIZE] = {
+    /* 1 */ 0x67A40000 + sigf_uc,       /* daddu   $a0, $sp, (sigf_uc) */
+    /* 2 */ 0x24020000 + sys_sigreturn, /* li      $v0, (sys_sigreturn) */
+    /* 3 */ 0x0000000C,                 /* syscall */
+    /* 4 */ 0x0000000D                  /* break */
+    };
+
+    for (i = 0; i < 4; i++) {
+        tswap32s(&sigtramp_code[i]);
+    }
+
+    return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/netbsd/os-sys.c b/bsd-user/netbsd/os-sys.c
new file mode 100644
index 0000000..68ea0e1
--- /dev/null
+++ b/bsd-user/netbsd/os-sys.c
@@ -0,0 +1,46 @@
+/*
+ *  NetBSD sysctl() and sysarch() system call emulation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+#include "qemu.h"
+
+#include "target_arch_sysarch.h"
+#include "target_os_vmparam.h"
+
+
+/* This must be emulated to support FreeBSD target binaries on NetBSD host. */
+
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+
+    qemu_log("qemu: Unsupported syscall __sysctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sysarch() is architecture dependent. */
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall sysarch()\n");
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/netbsd/target_os_stack.h b/bsd-user/netbsd/target_os_stack.h
new file mode 100644
index 0000000..1a26c3f
--- /dev/null
+++ b/bsd-user/netbsd/target_os_stack.h
@@ -0,0 +1,33 @@
+#ifndef _TARGET_OS_STACK_H_
+#define _TARGET_OS_STACK_H_
+
+#include "target_arch_sigtramp.h"
+
+static inline int setup_initial_stack(struct bsd_binprm *bprm, abi_ulong *p)
+{
+    int i;
+    abi_ulong stack_base;
+
+    stack_base = (target_stkbas + target_stksiz) -
+                  MAX_ARG_PAGES * TARGET_PAGE_SIZE;
+    if (p) {
+        *p = stack_base;
+    }
+
+    for (i = 0; i < MAX_ARG_PAGES; i++) {
+        if (bprm->page[i]) {
+            info->rss++;
+            if (!memcpy_to_target(stack_base, bprm->page[i],
+                        TARGET_PAGE_SIZE)) {
+                errno = EFAULT;
+                return -1;
+            }
+            g_free(bprm->page[i]);
+        }
+        stack_base += TARGET_PAGE_SIZE;
+    }
+
+    return 0;
+}
+
+#endif /* !_TARGET_OS_STACK_H_ */
diff --git a/bsd-user/openbsd/os-sys.c b/bsd-user/openbsd/os-sys.c
new file mode 100644
index 0000000..30df472
--- /dev/null
+++ b/bsd-user/openbsd/os-sys.c
@@ -0,0 +1,46 @@
+/*
+ *  OpenBSD sysctl() and sysarch() system call emulation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+#include "qemu.h"
+
+#include "target_arch_sysarch.h"
+#include "target_os_vmparam.h"
+
+
+/* This must be emulated to support FreeBSD target binaries on NetBSD host. */
+
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+
+    qemu_log("qemu: Unsupported syscall __sysctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sysarch() is architecture dependent. */
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall sysarch()\n");
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/openbsd/target_os_stack.h b/bsd-user/openbsd/target_os_stack.h
new file mode 100644
index 0000000..1a26c3f
--- /dev/null
+++ b/bsd-user/openbsd/target_os_stack.h
@@ -0,0 +1,33 @@
+#ifndef _TARGET_OS_STACK_H_
+#define _TARGET_OS_STACK_H_
+
+#include "target_arch_sigtramp.h"
+
+static inline int setup_initial_stack(struct bsd_binprm *bprm, abi_ulong *p)
+{
+    int i;
+    abi_ulong stack_base;
+
+    stack_base = (target_stkbas + target_stksiz) -
+                  MAX_ARG_PAGES * TARGET_PAGE_SIZE;
+    if (p) {
+        *p = stack_base;
+    }
+
+    for (i = 0; i < MAX_ARG_PAGES; i++) {
+        if (bprm->page[i]) {
+            info->rss++;
+            if (!memcpy_to_target(stack_base, bprm->page[i],
+                        TARGET_PAGE_SIZE)) {
+                errno = EFAULT;
+                return -1;
+            }
+            g_free(bprm->page[i]);
+        }
+        stack_base += TARGET_PAGE_SIZE;
+    }
+
+    return 0;
+}
+
+#endif /* !_TARGET_OS_STACK_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index cb77069..594de5c 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -90,6 +90,7 @@ typedef struct TaskState {
     struct TaskState *next;
     int used; /* non zero if used */
     struct image_info *info;
+    struct bsd_binprm *bprm;
 
     struct emulated_sigtable sigtab[TARGET_NSIG];
     struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
@@ -118,7 +119,7 @@ extern unsigned long mmap_min_addr;
  * This structure is used to hold the arguments that are
  * used when loading binaries.
  */
-struct linux_binprm {
+struct bsd_binprm {
         char buf[128];
         void *page[MAX_ARG_PAGES];
         abi_ulong p;
@@ -127,19 +128,23 @@ struct linux_binprm {
         int argc, envc;
         char **argv;
         char **envp;
-        char * filename;        /* Name of binary */
+        char *filename;         /* (Given) Name of binary */
+        char *fullpath;         /* Full path of binary */
+        int (*core_dump)(int, const CPUArchState *);
 };
 
 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
                               abi_ulong stringp, int push_ptr);
-int loader_exec(const char * filename, char ** argv, char ** envp,
-             struct target_pt_regs * regs, struct image_info *infop);
+int loader_exec(const char *filename, char **argv, char **envp,
+             struct target_pt_regs *regs, struct image_info *infop,
+             struct bsd_binprm *bprm);
 
-int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
-                    struct image_info * info);
-int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
-                    struct image_info * info);
+int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
+                    struct image_info *info);
+int load_flt_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
+                    struct image_info *info);
+int is_target_elf_binary(int fd);
 
 abi_long memcpy_to_target(abi_ulong dest, const void *src,
                           unsigned long len);
@@ -232,6 +237,15 @@ extern unsigned long target_maxssiz;
 extern unsigned long target_sgrowsiz;
 extern char qemu_proc_pathname[];
 
+/* syscall.c */
+abi_long get_errno(abi_long ret);
+int is_error(abi_long ret);
+
+/* os-sys.c */
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen);
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2);
+
 /* user access */
 
 #define VERIFY_READ 0
diff --git a/bsd-user/sparc/target_arch_sigtramp.h b/bsd-user/sparc/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/sparc/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/sparc64/target_arch_sigtramp.h b/bsd-user/sparc64/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index a4d1583..dbc212d 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -2,6 +2,7 @@
  *  BSD syscalls
  *
  *  Copyright (c) 2003 - 2008 Fabrice Bellard
+ *  Copyright (c) 2013 Stacey D. Son
  *
  *  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
@@ -36,12 +37,17 @@
 #include "qemu.h"
 #include "qemu-common.h"
 
-//#define DEBUG
+#define target_to_host_bitmask(x, tbl) (x)
+
+/* #define DEBUG */
 
 static abi_ulong target_brk;
 static abi_ulong target_original_brk;
 
-static inline abi_long get_errno(abi_long ret)
+/*
+ * errno conversion.
+ */
+abi_long get_errno(abi_long ret)
 {
     if (ret == -1)
         /* XXX need to translate host -> target errnos here */
@@ -50,9 +56,7 @@ static inline abi_long get_errno(abi_long ret)
         return ret;
 }
 
-#define target_to_host_bitmask(x, tbl) (x)
-
-static inline int is_error(abi_long ret)
+int is_error(abi_long ret)
 {
     return (abi_ulong)ret >= (abi_ulong)(-4096);
 }
@@ -96,175 +100,6 @@ static abi_long do_obreak(abi_ulong new_brk)
     return 0;
 }
 
-#if defined(TARGET_I386)
-static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms)
-{
-    abi_long ret = 0;
-    abi_ulong val;
-    int idx;
-
-    switch(op) {
-#ifdef TARGET_ABI32
-    case TARGET_FREEBSD_I386_SET_GSBASE:
-    case TARGET_FREEBSD_I386_SET_FSBASE:
-        if (op == TARGET_FREEBSD_I386_SET_GSBASE)
-#else
-    case TARGET_FREEBSD_AMD64_SET_GSBASE:
-    case TARGET_FREEBSD_AMD64_SET_FSBASE:
-        if (op == TARGET_FREEBSD_AMD64_SET_GSBASE)
-#endif
-            idx = R_GS;
-        else
-            idx = R_FS;
-        if (get_user(val, parms, abi_ulong))
-            return -TARGET_EFAULT;
-        cpu_x86_load_seg(env, idx, 0);
-        env->segs[idx].base = val;
-        break;
-#ifdef TARGET_ABI32
-    case TARGET_FREEBSD_I386_GET_GSBASE:
-    case TARGET_FREEBSD_I386_GET_FSBASE:
-        if (op == TARGET_FREEBSD_I386_GET_GSBASE)
-#else
-    case TARGET_FREEBSD_AMD64_GET_GSBASE:
-    case TARGET_FREEBSD_AMD64_GET_FSBASE:
-        if (op == TARGET_FREEBSD_AMD64_GET_GSBASE)
-#endif
-            idx = R_GS;
-        else
-            idx = R_FS;
-        val = env->segs[idx].base;
-        if (put_user(val, parms, abi_ulong))
-            return -TARGET_EFAULT;
-        break;
-    /* XXX handle the others... */
-    default:
-        ret = -TARGET_EINVAL;
-        break;
-    }
-    return ret;
-}
-#endif
-
-#ifdef TARGET_SPARC
-static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms)
-{
-    /* XXX handle
-     * TARGET_FREEBSD_SPARC_UTRAP_INSTALL,
-     * TARGET_FREEBSD_SPARC_SIGTRAMP_INSTALL
-     */
-    return -TARGET_EINVAL;
-}
-#endif
-
-#ifdef __FreeBSD__
-/*
- * XXX this uses the undocumented oidfmt interface to find the kind of
- * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
- * (this is mostly copied from src/sbin/sysctl/sysctl.c)
- */
-static int
-oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
-{
-    int qoid[CTL_MAXNAME+2];
-    uint8_t buf[BUFSIZ];
-    int i;
-    size_t j;
-
-    qoid[0] = 0;
-    qoid[1] = 4;
-    memcpy(qoid + 2, oid, len * sizeof(int));
-
-    j = sizeof(buf);
-    i = sysctl(qoid, len + 2, buf, &j, 0, 0);
-    if (i)
-        return i;
-
-    if (kind)
-        *kind = *(uint32_t *)buf;
-
-    if (fmt)
-        strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
-    return (0);
-}
-
-/*
- * try and convert sysctl return data for the target.
- * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT.
- */
-static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
-{
-    switch (kind & CTLTYPE) {
-    case CTLTYPE_INT:
-    case CTLTYPE_UINT:
-        *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp);
-        break;
-#ifdef TARGET_ABI32
-    case CTLTYPE_LONG:
-    case CTLTYPE_ULONG:
-        *(uint32_t *)holdp = tswap32(*(long *)holdp);
-        break;
-#else
-    case CTLTYPE_LONG:
-        *(uint64_t *)holdp = tswap64(*(long *)holdp);
-    case CTLTYPE_ULONG:
-        *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
-        break;
-#endif
-#ifdef CTLTYPE_U64
-    case CTLTYPE_S64:
-    case CTLTYPE_U64:
-#else
-    case CTLTYPE_QUAD:
-#endif
-        *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
-        break;
-    case CTLTYPE_STRING:
-        break;
-    default:
-        /* XXX unhandled */
-        return -1;
-    }
-    return 0;
-}
-
-/* XXX this needs to be emulated on non-FreeBSD hosts... */
-static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp,
-                          abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
-{
-    abi_long ret;
-    void *hnamep, *holdp, *hnewp = NULL;
-    size_t holdlen;
-    abi_ulong oldlen = 0;
-    int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
-    uint32_t kind = 0;
-
-    if (oldlenp)
-        get_user_ual(oldlen, oldlenp);
-    if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1)))
-        return -TARGET_EFAULT;
-    if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1)))
-        return -TARGET_EFAULT;
-    if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0)))
-        return -TARGET_EFAULT;
-    holdlen = oldlen;
-    for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++)
-       *q++ = tswap32(*p);
-    oidfmt(snamep, namelen, NULL, &kind);
-    /* XXX swap hnewp */
-    ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
-    if (!ret)
-        sysctl_oldcvt(holdp, holdlen, kind);
-    put_user_ual(holdlen, oldlenp);
-    unlock_user(hnamep, namep, 0);
-    unlock_user(holdp, oldp, holdlen);
-    if (hnewp)
-        unlock_user(hnewp, newp, 0);
-    g_free(snamep);
-    return ret;
-}
-#endif
-
 /* 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.
@@ -387,20 +222,27 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_FREEBSD_NR_break:
         ret = do_obreak(arg1);
         break;
-#ifdef __FreeBSD__
-    case TARGET_FREEBSD_NR___sysctl:
-        ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6);
+
+        /*
+         * sys{ctl, arch, call}
+         */
+    case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
+        ret = do_freebsd_sysctl(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
-#endif
-    case TARGET_FREEBSD_NR_sysarch:
+
+    case TARGET_FREEBSD_NR_sysarch: /* sysarch(2) */
         ret = do_freebsd_sysarch(cpu_env, arg1, arg2);
         break;
-    case TARGET_FREEBSD_NR_syscall:
-    case TARGET_FREEBSD_NR___syscall:
-        ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0);
+
+    case TARGET_FREEBSD_NR_syscall: /* syscall(2) */
+    case TARGET_FREEBSD_NR___syscall: /* __syscall(2) */
+        ret = do_freebsd_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4,
+                arg5, arg6, arg7, arg8, 0);
         break;
+
     default:
-        ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
+        ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+                    arg8));
         break;
     }
  fail:
@@ -467,6 +309,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NETBSD_NR_mprotect:
         ret = get_errno(target_mprotect(arg1, arg2, arg3));
         break;
+
     case TARGET_NETBSD_NR_syscall:
     case TARGET_NETBSD_NR___syscall:
         ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
@@ -539,6 +382,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_OPENBSD_NR_mprotect:
         ret = get_errno(target_mprotect(arg1, arg2, arg3));
         break;
+
     case TARGET_OPENBSD_NR_syscall:
     case TARGET_OPENBSD_NR___syscall:
         ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
diff --git a/bsd-user/x86_64/target_arch_sigtramp.h b/bsd-user/x86_64/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 06/19] bsd-user: add support for freebsd time related system calls
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (6 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 05/19] bsd-user: move arch/OS dependent code out of syscall.c Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2014-01-27 19:58     ` Peter Maydell
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 07/19] bsd-user: add support for freebsd signal " Stacey Son
                     ` (12 subsequent siblings)
  20 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for time related system calls
including nanosleep(2), clock_gettime(2), clock_settime(2),
clock_getres(2), gettimeofday(2), settimeofday(2), adjtime(2),
ntp_adjtime(2), ntp_gettime(2), utimes(2), lutimes(2), futimes(2),
futimesat(2), select(2), pselect(2), kqueue(2), kevent(2),
setitimer(2), getitimer(2), and the undocumented ktimer_*() calls.
---
 bsd-user/Makefile.objs     |    3 +-
 bsd-user/freebsd/os-time.c |  205 ++++++++++++
 bsd-user/freebsd/os-time.h |  643 +++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h |   53 +++
 bsd-user/netbsd/os-time.c  |    1 +
 bsd-user/netbsd/os-time.h  |  179 ++++++++++
 bsd-user/netbsd/qemu-os.h  |    1 +
 bsd-user/openbsd/os-time.c |    1 +
 bsd-user/openbsd/os-time.h |  179 ++++++++++
 bsd-user/openbsd/qemu-os.h |    1 +
 bsd-user/syscall.c         |  102 ++++++
 bsd-user/syscall_defs.h    |  796 ++++++++++++++++++++++++++++++++++++++------
 12 files changed, 2061 insertions(+), 103 deletions(-)
 create mode 100644 bsd-user/freebsd/os-time.c
 create mode 100644 bsd-user/freebsd/os-time.h
 create mode 100644 bsd-user/freebsd/qemu-os.h
 create mode 100644 bsd-user/netbsd/os-time.c
 create mode 100644 bsd-user/netbsd/os-time.h
 create mode 100644 bsd-user/netbsd/qemu-os.h
 create mode 100644 bsd-user/openbsd/os-time.c
 create mode 100644 bsd-user/openbsd/os-time.h
 create mode 100644 bsd-user/openbsd/qemu-os.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index a4dca8e..ac69be7 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,2 +1,3 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o $(HOST_VARIANT_DIR)/os-sys.o $(TARGET_ABI_DIR)/target_arch_cpu.o
+	        uaccess.o $(HOST_VARIANT_DIR)/os-sys.o \
+			$(HOST_VARIANT_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/freebsd/os-time.c b/bsd-user/freebsd/os-time.c
new file mode 100644
index 0000000..7ac4397
--- /dev/null
+++ b/bsd-user/freebsd/os-time.c
@@ -0,0 +1,205 @@
+/*
+ *  FreeBSD time related system call helpers
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <time.h>
+#include <sys/timex.h>
+#include <sys/select.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+/*
+ * FreeBSD time conversion functions
+ */
+abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr)
+{
+    struct target_freebsd_timeval *target_tv;
+
+    if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __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, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr)
+{
+    struct target_freebsd_timeval *target_tv;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __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);
+
+    return 0;
+}
+
+abi_long t2h_freebsd_timespec(struct timespec *ts, abi_ulong target_ts_addr)
+{
+    struct target_freebsd_timespec *target_ts;
+
+    if (!lock_user_struct(VERIFY_READ, target_ts, target_ts_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(ts->tv_sec, &target_ts->tv_sec);
+    __get_user(ts->tv_nsec, &target_ts->tv_nsec);
+    unlock_user_struct(target_ts, target_ts_addr, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_timespec(abi_ulong target_ts_addr, struct timespec *ts)
+{
+    struct target_freebsd_timespec *target_ts;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ts, target_ts_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(ts->tv_sec, &target_ts->tv_sec);
+    __put_user(ts->tv_nsec, &target_ts->tv_nsec);
+    unlock_user_struct(target_ts, target_ts_addr, 1);
+
+    return 0;
+}
+
+abi_long t2h_freebsd_timex(struct timex *host_tx, abi_ulong target_tx_addr)
+{
+    struct target_freebsd_timex *target_tx;
+
+    if (!lock_user_struct(VERIFY_READ, target_tx, target_tx_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_tx->modes, &target_tx->modes);
+    __get_user(host_tx->offset, &target_tx->offset);
+    __get_user(host_tx->freq, &target_tx->freq);
+    __get_user(host_tx->maxerror, &target_tx->maxerror);
+    __get_user(host_tx->esterror, &target_tx->esterror);
+    __get_user(host_tx->status, &target_tx->status);
+    __get_user(host_tx->constant, &target_tx->constant);
+    __get_user(host_tx->precision, &target_tx->precision);
+    __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
+    __get_user(host_tx->jitter, &target_tx->jitter);
+    __get_user(host_tx->shift, &target_tx->shift);
+    __get_user(host_tx->stabil, &target_tx->stabil);
+    __get_user(host_tx->jitcnt, &target_tx->jitcnt);
+    __get_user(host_tx->calcnt, &target_tx->calcnt);
+    __get_user(host_tx->errcnt, &target_tx->errcnt);
+    __get_user(host_tx->stbcnt, &target_tx->stbcnt);
+    unlock_user_struct(target_tx, target_tx_addr, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_ntptimeval(abi_ulong target_ntv_addr,
+        struct ntptimeval *ntv)
+{
+    struct target_freebsd_ntptimeval *target_ntv;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ntv, target_ntv_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(ntv->time.tv_sec, &target_ntv->time.tv_sec);
+    __put_user(ntv->time.tv_nsec, &target_ntv->time.tv_nsec);
+    __put_user(ntv->maxerror, &target_ntv->maxerror);
+    __put_user(ntv->esterror, &target_ntv->esterror);
+    __put_user(ntv->tai, &target_ntv->tai);
+    __put_user(ntv->time_state, &target_ntv->time_state);
+
+    return 0;
+}
+
+/*
+ * select(2) fdset copy functions
+ */
+abi_ulong copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n)
+{
+    int i, nw, j, k;
+    abi_ulong b, *target_fds;
+
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    target_fds = lock_user(VERIFY_READ, target_fds_addr,
+            sizeof(abi_ulong) * nw, 1);
+    if (target_fds == NULL) {
+        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++;
+        }
+    }
+    unlock_user(target_fds, target_fds_addr, 0);
+
+    return 0;
+}
+
+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;
+}
+
+abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds, int n)
+{
+    int i, nw, j, k;
+    abi_long v;
+    abi_ulong *target_fds;
+
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    target_fds = lock_user(VERIFY_WRITE, target_fds_addr,
+            sizeof(abi_ulong) * nw, 0);
+    if (target_fds == NULL) {
+        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++;
+        }
+        __put_user(v, &target_fds[i]);
+    }
+    unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
+
+    return 0;
+}
+
diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h
new file mode 100644
index 0000000..c6b5b28
--- /dev/null
+++ b/bsd-user/freebsd/os-time.h
@@ -0,0 +1,643 @@
+/*
+ *  FreeBSD time related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_OS_TIME_H_
+#define __FREEBSD_OS_TIME_H_
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/select.h>
+#include <sys/timex.h>
+#include <signal.h>
+#include <time.h>
+
+#include "qemu-os.h"
+
+/* nanosleep(2) */
+static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct timespec req, rem;
+
+    ret = t2h_freebsd_timespec(&req, arg1);
+    if (!is_error(ret)) {
+        ret = get_errno(nanosleep(&req, &rem));
+        if (!is_error(ret) && arg2) {
+            h2t_freebsd_timespec(arg2, &rem);
+        }
+    }
+
+    return ret;
+}
+
+/* clock_gettime(2) */
+static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct timespec ts;
+
+    ret = get_errno(clock_gettime(arg1, &ts));
+    if (!is_error(ret)) {
+        if (h2t_freebsd_timespec(arg2, &ts)) {
+            return -TARGET_EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/* clock_settime(2) */
+static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2)
+{
+    struct timespec ts;
+
+    if (t2h_freebsd_timespec(&ts, arg2) != 0) {
+        return -TARGET_EFAULT;
+    }
+
+    return get_errno(clock_settime(arg1, &ts));
+}
+
+/* clock_getres(2) */
+static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct timespec ts;
+
+    ret = get_errno(clock_getres(arg1, &ts));
+    if (!is_error(ret)) {
+        if (h2t_freebsd_timespec(arg2, &ts)) {
+            return -TARGET_EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/* gettimeofday(2) */
+static inline abi_long do_freebsd_gettimeofday(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    struct timeval tv;
+    struct timezone tz, *target_tz; /* XXX */
+
+    if (arg2 != 0) {
+        if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
+        __get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
+        unlock_user_struct(target_tz, arg2, 1);
+    }
+    ret = get_errno(gettimeofday(&tv, arg2 != 0 ? &tz : NULL));
+    if (!is_error(ret)) {
+        if (h2t_freebsd_timeval(&tv, arg1)) {
+            return -TARGET_EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/* settimeofday(2) */
+static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2)
+{
+    struct timeval tv;
+    struct timezone tz, *target_tz; /* XXX */
+
+    if (arg2 != 0) {
+        if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
+        __get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
+        unlock_user_struct(target_tz, arg2, 1);
+    }
+    if (t2h_freebsd_timeval(&tv, arg1)) {
+        return -TARGET_EFAULT;
+    }
+
+    return get_errno(settimeofday(&tv, arg2 != 0 ? &tz : NULL));
+}
+
+/* adjtime(2) */
+static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr,
+        abi_ulong target_old_addr)
+{
+    abi_long ret;
+    struct timeval host_delta, host_old;
+
+    ret = t2h_freebsd_timeval(&host_delta, target_delta_addr);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    if (target_old_addr) {
+        ret = get_errno(adjtime(&host_delta, &host_old));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = h2t_freebsd_timeval(&host_old, target_old_addr);
+    } else {
+        ret = get_errno(adjtime(&host_delta, NULL));
+    }
+
+    return ret;
+}
+
+/* ntp_adjtime(2) */
+static abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr)
+{
+    abi_long ret;
+    struct timex host_tx;
+
+    ret = t2h_freebsd_timex(&host_tx, target_tx_addr);
+    if (ret == 0) {
+        ret = get_errno(ntp_adjtime(&host_tx));
+    }
+
+    return ret;
+}
+
+/* ntp_gettime(2) */
+static abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr)
+{
+    abi_long ret;
+    struct ntptimeval host_ntv;
+
+    ret = get_errno(ntp_gettime(&host_ntv));
+    if (ret == 0) {
+        ret = h2t_freebsd_ntptimeval(target_ntv_addr, &host_ntv);
+    }
+
+    return ret;
+}
+
+
+/* utimes(2) */
+static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct timeval *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg2) ||
+                t2h_freebsd_timeval(&tv[1], arg2 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(utimes(p, tvp));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* lutimes(2) */
+static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct timeval *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg2) ||
+                t2h_freebsd_timeval(&tv[1], arg2 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(lutimes(p, tvp));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* futimes(2) */
+static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2)
+{
+    struct timeval *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg2) ||
+                t2h_freebsd_timeval(&tv[1], arg2 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+
+    return get_errno(futimes(arg1, tvp));
+}
+
+/* futimesat(2) */
+static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    struct timeval *tvp, tv[2];
+
+    if (arg3 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg3) ||
+                t2h_freebsd_timeval(&tv[1], arg3 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+
+    p = lock_user_string(arg2);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(futimesat(arg1, p, tvp));
+    unlock_user(p, arg2, 0);
+
+    return ret;
+}
+
+/*
+ * undocumented ktimer_create(clockid_t clock_id,  struct sigevent *evp,
+ * int *timerid) syscall
+ */
+static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocumented ktimer_delete(int timerid) syscall */
+static inline abi_long do_freebsd_ktimer_delete(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_delete()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented ktimer_settime(int timerid, int flags,
+ * const struct itimerspec *value, struct itimerspec *ovalue) syscall
+ */
+static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_settime()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented ktimer_gettime(int timerid, struct itimerspec *value)
+ * syscall
+ */
+static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_gettime()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented ktimer_getoverrun(int timerid) syscall
+ */
+static inline abi_long do_freebsd_ktimer_getoverrun(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall ktimer_getoverrun()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* select(2) */
+static inline abi_long do_freebsd_select(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong target_tv_addr)
+{
+    fd_set rfds, wfds, efds;
+    fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+    struct timeval tv, *tv_ptr;
+    abi_long ret, error;
+
+    ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+    if (ret != 0) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+    if (ret != 0) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+    if (ret != 0) {
+        return ret;
+    }
+
+    if (target_tv_addr != 0) {
+        if (t2h_freebsd_timeval(&tv, target_tv_addr)) {
+            return -TARGET_EFAULT;
+        }
+        tv_ptr = &tv;
+    } else {
+        tv_ptr = NULL;
+    }
+
+    ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
+
+    if (!is_error(ret)) {
+        if (rfd_addr != 0) {
+            error = copy_to_user_fdset(rfd_addr, &rfds, n);
+            if (error != 0) {
+                return error;
+            }
+        }
+        if (wfd_addr != 0) {
+            error = copy_to_user_fdset(wfd_addr, &wfds, n);
+            if (error != 0) {
+                return error;
+            }
+        }
+        if (efd_addr != 0) {
+            error = copy_to_user_fdset(efd_addr, &efds, n);
+            if (error != 0) {
+                return error;
+            }
+        }
+        if (target_tv_addr != 0) {
+            error = h2t_freebsd_timeval(&tv, target_tv_addr);
+            if (is_error(error)) {
+                return error;
+            }
+        }
+    }
+    return ret;
+}
+
+/* pselect(2) */
+static inline abi_long do_freebsd_pselect(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong ts_addr,
+        abi_ulong set_addr)
+{
+    fd_set rfds, wfds, efds;
+    fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+    sigset_t set, *set_ptr;
+    struct timespec ts, *ts_ptr;
+    void *p;
+    abi_long ret;
+
+    ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    /* Unlike select(), pselect() uses struct timespec instead of timeval */
+    if (ts_addr) {
+        if (t2h_freebsd_timespec(&ts, ts_addr)) {
+            return -TARGET_EFAULT;
+        }
+        ts_ptr = &ts;
+    } else {
+        ts_ptr = NULL;
+    }
+
+    if (set_addr != 0) {
+        p = lock_user(VERIFY_READ, set_addr, sizeof(target_sigset_t), 1);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        target_to_host_sigset(&set, p);
+        unlock_user(p, set_addr, 0);
+        set_ptr = &set;
+    } else {
+        set_ptr = NULL;
+    }
+
+    ret = get_errno(pselect(n, rfds_ptr, wfds_ptr, efds_ptr, ts_ptr, set_ptr));
+
+    if (!is_error(ret)) {
+        if (rfd_addr != 0) {
+            ret = copy_to_user_fdset(rfd_addr, &rfds, n);
+            if (is_error(ret)) {
+                return ret;
+            }
+        }
+        if (wfd_addr != 0) {
+            ret = copy_to_user_fdset(wfd_addr, &wfds, n);
+            if (is_error(ret)) {
+                return ret;
+            }
+        }
+        if (efd_addr != 0) {
+            ret = copy_to_user_fdset(efd_addr, &efds, n);
+            if (is_error(ret)) {
+                return ret;
+            }
+        }
+        if (ts_addr != 0) {
+            ret = h2t_freebsd_timespec(ts_addr, &ts);
+            if (is_error(ret)) {
+                return ret;
+            }
+        }
+    }
+    return ret;
+}
+
+/* kqueue(2) */
+static inline abi_long do_freebsd_kqueue(void)
+{
+
+    return get_errno(kqueue());
+}
+
+/* kevent(2) */
+static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
+        abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    struct kevent *changelist = NULL, *eventlist = NULL;
+    struct target_freebsd_kevent *target_changelist, *target_eventlist;
+    struct timespec ts;
+    int i;
+
+    if (arg3 != 0) {
+        target_changelist = lock_user(VERIFY_READ, arg2,
+                sizeof(struct target_freebsd_kevent) * arg3, 1);
+        if (target_changelist == NULL) {
+            return -TARGET_EFAULT;
+        }
+
+        changelist = alloca(sizeof(struct kevent) * arg3);
+        for (i = 0; i < arg3; i++) {
+            __get_user(changelist[i].ident, &target_changelist[i].ident);
+            __get_user(changelist[i].filter, &target_changelist[i].filter);
+            __get_user(changelist[i].flags, &target_changelist[i].flags);
+            __get_user(changelist[i].fflags, &target_changelist[i].fflags);
+            __get_user(changelist[i].data, &target_changelist[i].data);
+            /* __get_user(changelist[i].udata, &target_changelist[i].udata); */
+#if TARGET_ABI_BITS == 32
+            changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata;
+            tswap32s((uint32_t *)&changelist[i].udata);
+#else
+            changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata;
+            tswap64s((uint64_t *)&changelist[i].udata);
+#endif
+        }
+        unlock_user(target_changelist, arg2, 0);
+    }
+
+    if (arg5 != 0) {
+        eventlist = alloca(sizeof(struct kevent) * arg5);
+    }
+    if (arg6 != 0) {
+        if (t2h_freebsd_timespec(&ts, arg6)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    ret = get_errno(kevent(arg1, changelist, arg3, eventlist, arg5,
+                arg6 != 0 ? &ts : NULL));
+    if (!is_error(ret)) {
+        target_eventlist = lock_user(VERIFY_WRITE, arg4,
+                sizeof(struct target_freebsd_kevent) * arg5, 0);
+        if (target_eventlist == NULL) {
+                return -TARGET_EFAULT;
+        }
+        for (i = 0; i < arg5; i++) {
+            __put_user(eventlist[i].ident, &target_eventlist[i].ident);
+            __put_user(eventlist[i].filter, &target_eventlist[i].filter);
+            __put_user(eventlist[i].flags, &target_eventlist[i].flags);
+            __put_user(eventlist[i].fflags, &target_eventlist[i].fflags);
+            __put_user(eventlist[i].data, &target_eventlist[i].data);
+            /* __put_user(eventlist[i].udata, &target_eventlist[i].udata);*/
+#if TARGET_ABI_BITS == 32
+            tswap32s((uint32_t *)&eventlist[i].data);
+            target_eventlist[i].data = (uintptr_t)eventlist[i].data;
+#else
+            tswap64s((uint64_t *)&eventlist[i].data);
+            target_eventlist[i].data = (uintptr_t)eventlist[i].data;
+#endif
+        }
+        unlock_user(target_eventlist, arg4,
+                sizeof(struct target_freebsd_kevent) * arg5);
+    }
+    return ret;
+}
+
+/* sigtimedwait(2) */
+static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    struct timespec uts, *puts;
+    siginfo_t uinfo;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    if (arg3) {
+        puts = &uts;
+        t2h_freebsd_timespec(puts, arg3);
+    } else {
+        puts = NULL;
+    }
+    ret = get_errno(sigtimedwait(&set, &uinfo, puts));
+    if (!is_error(ret) && arg2) {
+        p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_siginfo(p, &uinfo);
+        unlock_user(p, arg2, sizeof(target_siginfo_t));
+    }
+    return ret;
+}
+
+/* setitimer(2) */
+static inline abi_long do_freebsd_setitimer(int arg1, abi_ulong arg2, abi_ulong arg3)
+{
+   abi_long ret = 0;
+   struct itimerval value, ovalue, *pvalue;
+
+   if (arg2) {
+       pvalue = &value;
+       if (t2h_freebsd_timeval(&pvalue->it_interval, arg2) ||
+           t2h_freebsd_timeval(&pvalue->it_value, arg2 + sizeof(struct target_freebsd_timeval))) {
+             return -TARGET_EFAULT;
+       } 
+   } else {
+       pvalue = NULL;
+   }
+   ret = get_errno(setitimer(arg1, pvalue, &ovalue));
+   if (!is_error(ret) && arg3) {
+       if (h2t_freebsd_timeval(&ovalue.it_interval, arg3)
+          || h2t_freebsd_timeval(&ovalue.it_value, arg3 + sizeof(struct target_freebsd_timeval))) {
+             return -TARGET_EFAULT;
+       }
+   }
+   return ret;
+}
+
+/* getitimer(2) */
+static inline abi_long do_freebsd_getitimer(int arg1, abi_ulong arg2)
+{
+   abi_long ret = 0;
+   struct itimerval value;
+
+   ret = get_errno(getitimer(arg1, &value));
+   if (!is_error(ret) && arg2) {
+       if (h2t_freebsd_timeval(&value.it_interval, arg2) ||
+           h2t_freebsd_timeval(&value.it_value, arg2 + sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+       }
+   }
+   return ret;
+}
+
+#endif /* __FREEBSD_OS_TIME_H_ */
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
new file mode 100644
index 0000000..bde610e
--- /dev/null
+++ b/bsd-user/freebsd/qemu-os.h
@@ -0,0 +1,53 @@
+/*
+ *  FreeBSD conversion extern declarations
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _QEMU_OS_H_
+#define _QEMU_OS_H_
+
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/mount.h>
+#include <sys/timex.h>
+#include <sys/rtprio.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#include <time.h>
+
+/* os-time.c */
+abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr);
+abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr);
+
+abi_long t2h_freebsd_timespec(struct timespec *ts, abi_ulong target_ts_addr);
+abi_long h2t_freebsd_timespec(abi_ulong target_ts_addr, struct timespec *ts);
+
+abi_long t2h_freebsd_timex(struct timex *host_tx, abi_ulong target_tx_addr);
+
+abi_long h2t_freebsd_ntptimeval(abi_ulong target_ntv_addr,
+        struct ntptimeval *ntv);
+
+abi_ulong copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n);
+abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
+        abi_ulong target_fds_addr, int n);
+abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds,
+        int n);
+
+#endif /* !_QEMU_OS_H_ */
diff --git a/bsd-user/netbsd/os-time.c b/bsd-user/netbsd/os-time.c
new file mode 100644
index 0000000..ee2c7a0
--- /dev/null
+++ b/bsd-user/netbsd/os-time.c
@@ -0,0 +1 @@
+/* XXX NetBSD time related helpers */
diff --git a/bsd-user/netbsd/os-time.h b/bsd-user/netbsd/os-time.h
new file mode 100644
index 0000000..6d0f1de
--- /dev/null
+++ b/bsd-user/netbsd/os-time.h
@@ -0,0 +1,179 @@
+#ifndef __NETBSD_OS_TIME_H_
+#define __NETBSD_OS_TIME_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need to
+ * be emulated.
+ */
+static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_gettimeofday(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr,
+        abi_ulong target_old_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_delete(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_getoverrun(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_select(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong target_tv_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+
+static inline abi_long do_freebsd_pselect(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong ts_addr,
+        abi_ulong set_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_kqueue(void)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
+        abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __NETBSD_OS_TIME_H_ */
diff --git a/bsd-user/netbsd/qemu-os.h b/bsd-user/netbsd/qemu-os.h
new file mode 100644
index 0000000..016618b
--- /dev/null
+++ b/bsd-user/netbsd/qemu-os.h
@@ -0,0 +1 @@
+/* NetBSD conversion extern declarations */
diff --git a/bsd-user/openbsd/os-time.c b/bsd-user/openbsd/os-time.c
new file mode 100644
index 0000000..accd886
--- /dev/null
+++ b/bsd-user/openbsd/os-time.c
@@ -0,0 +1 @@
+/* XXX OpenBSD time related helpers */
diff --git a/bsd-user/openbsd/os-time.h b/bsd-user/openbsd/os-time.h
new file mode 100644
index 0000000..fc444bb
--- /dev/null
+++ b/bsd-user/openbsd/os-time.h
@@ -0,0 +1,179 @@
+#ifndef __OPENBSD_OS_TIME_H_
+#define __OPENBSD_OS_TIME_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need to
+ * be emulated.
+ */
+static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_gettimeofday(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr,
+        abi_ulong target_old_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_delete(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_ktimer_getoverrun(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_select(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong target_tv_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+
+static inline abi_long do_freebsd_pselect(int n, abi_ulong rfd_addr,
+        abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong ts_addr,
+        abi_ulong set_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_kqueue(void)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
+        abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_OS_TIME_H_ */
diff --git a/bsd-user/openbsd/qemu-os.h b/bsd-user/openbsd/qemu-os.h
new file mode 100644
index 0000000..f4ad3be
--- /dev/null
+++ b/bsd-user/openbsd/qemu-os.h
@@ -0,0 +1 @@
+/* OpenBSD conversion extern declarations */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index dbc212d..0996787 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -39,6 +39,9 @@
 
 #define target_to_host_bitmask(x, tbl) (x)
 
+/* *BSD dependent syscall shims */
+#include "os-time.h"
+
 /* #define DEBUG */
 
 static abi_ulong target_brk;
@@ -224,6 +227,105 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * time related system calls.
+         */
+    case TARGET_FREEBSD_NR_nanosleep: /* nanosleep(2) */
+        ret = do_freebsd_nanosleep(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_gettime: /* clock_gettime(2) */
+        ret = do_freebsd_clock_gettime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_settime: /* clock_settime(2) */
+        ret = do_freebsd_clock_settime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_getres: /* clock_getres(2) */
+        ret = do_freebsd_clock_getres(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_gettimeofday: /* gettimeofday(2) */
+        ret = do_freebsd_gettimeofday(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_settimeofday: /* settimeofday(2) */
+        ret = do_freebsd_settimeofday(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_adjtime: /* adjtime(2) */
+        ret = do_freebsd_adjtime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_ntp_adjtime: /* ntp_adjtime(2) */
+        ret = do_freebsd_ntp_adjtime(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_ntp_gettime: /* ntp_gettime(2) */
+        ret = do_freebsd_ntp_gettime(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_utimes: /* utimes(2) */
+        ret = do_freebsd_utimes(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lutimes: /* lutimes(2) */
+        ret = do_freebsd_lutimes(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_futimes: /* futimes(2) */
+        ret = do_freebsd_futimes(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_futimesat: /* futimesat(2) */
+        ret = do_freebsd_futimesat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_create: /* undocumented */
+        ret = do_freebsd_ktimer_create(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_delete: /* undocumented */
+        ret = do_freebsd_ktimer_delete(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_settime: /* undocumented */
+        ret = do_freebsd_ktimer_settime(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_gettime: /* undocumented */
+        ret = do_freebsd_ktimer_gettime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_getoverrun: /* undocumented */
+        ret = do_freebsd_ktimer_getoverrun(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_select: /* select(2) */
+        ret = do_freebsd_select(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_pselect: /* pselect(2) */
+        ret = do_freebsd_pselect(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_kqueue: /* kqueue(2) */
+        ret = do_freebsd_kqueue();
+        break;
+
+    case TARGET_FREEBSD_NR_kevent: /* kevent(2) */
+        ret = do_freebsd_kevent(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_setitimer: /* setitimer(2) */
+        ret = do_freebsd_setitimer(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getitimer: /* getitimer(2) */
+        ret = do_freebsd_getitimer(arg1, arg2);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 207ddee..ad84d33 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -1,105 +1,5 @@
-/*      $OpenBSD: signal.h,v 1.19 2006/01/08 14:20:16 millert Exp $     */
-/*      $NetBSD: signal.h,v 1.21 1996/02/09 18:25:32 christos Exp $     */
-
-/*
- * Copyright (c) 1982, 1986, 1989, 1991, 1993
- *      The Regents of the University of California.  All rights reserved.
- * (c) UNIX System Laboratories, Inc.
- * All or some portions of this file are derived from material licensed
- * to the University of California by American Telephone and Telegraph
- * Co. or Unix System Laboratories, Inc. and are reproduced herein with
- * the permission of UNIX System Laboratories, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *      @(#)signal.h    8.2 (Berkeley) 1/21/94
- */
-
-#define TARGET_NSIG     32              /* counting 0; could be 33 (mask is 1-32) */
-
-#define TARGET_SIGHUP  1       /* hangup */
-#define TARGET_SIGINT  2       /* interrupt */
-#define TARGET_SIGQUIT 3       /* quit */
-#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
-#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
-#define TARGET_SIGABRT 6       /* abort() */
-#define TARGET_SIGIOT  SIGABRT /* compatibility */
-#define TARGET_SIGEMT  7       /* EMT instruction */
-#define TARGET_SIGFPE  8       /* floating point exception */
-#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
-#define TARGET_SIGBUS  10      /* bus error */
-#define TARGET_SIGSEGV 11      /* segmentation violation */
-#define TARGET_SIGSYS  12      /* bad argument to system call */
-#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
-#define TARGET_SIGALRM 14      /* alarm clock */
-#define TARGET_SIGTERM 15      /* software termination signal from kill */
-#define TARGET_SIGURG  16      /* urgent condition on IO channel */
-#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
-#define TARGET_SIGTSTP 18      /* stop signal from tty */
-#define TARGET_SIGCONT 19      /* continue a stopped process */
-#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
-#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
-#define TARGET_SIGTTOU 22      /* like TTIN for output if (tp->t_local&LTOSTOP) */
-#define TARGET_SIGIO   23      /* input/output possible signal */
-#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
-#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
-#define TARGET_SIGVTALRM 26    /* virtual time alarm */
-#define TARGET_SIGPROF 27      /* profiling time alarm */
-#define TARGET_SIGWINCH 28      /* window size changes */
-#define TARGET_SIGINFO  29      /* information request */
-#define TARGET_SIGUSR1 30       /* user defined signal 1 */
-#define TARGET_SIGUSR2 31       /* user defined signal 2 */
-
-/*
- * Language spec says we must list exactly one parameter, even though we
- * actually supply three.  Ugh!
- */
-#define TARGET_SIG_DFL         (void (*)(int))0
-#define TARGET_SIG_IGN         (void (*)(int))1
-#define TARGET_SIG_ERR         (void (*)(int))-1
-
-#define TARGET_SA_ONSTACK       0x0001  /* take signal on signal stack */
-#define TARGET_SA_RESTART       0x0002  /* restart system on signal return */
-#define TARGET_SA_RESETHAND     0x0004  /* reset to SIG_DFL when taking signal */
-#define TARGET_SA_NODEFER       0x0010  /* don't mask the signal we're delivering */
-#define TARGET_SA_NOCLDWAIT     0x0020  /* don't create zombies (assign to pid 1) */
-#define TARGET_SA_USERTRAMP    0x0100  /* do not bounce off kernel's sigtramp */
-#define TARGET_SA_NOCLDSTOP     0x0008  /* do not generate SIGCHLD on child stop */
-#define TARGET_SA_SIGINFO       0x0040  /* generate siginfo_t */
-
-/*
- * Flags for sigprocmask:
- */
-#define TARGET_SIG_BLOCK       1       /* block specified signal set */
-#define TARGET_SIG_UNBLOCK     2       /* unblock specified signal set */
-#define TARGET_SIG_SETMASK     3       /* set specified signal set */
-
-#define TARGET_BADSIG          SIG_ERR
-
-#define TARGET_SS_ONSTACK       0x0001  /* take signals on alternate stack */
-#define TARGET_SS_DISABLE       0x0004  /* disable taking signals on alternate stack */
+#ifndef _SYSCALL_DEFS_H_
+#define _SYSCALL_DEFS_H_
 
 #include "errno_defs.h"
 
@@ -112,3 +12,695 @@ struct target_iovec {
     abi_long iov_len;   /* Number of bytes */
 };
 
+/*
+ * sys/ipc.h
+ */
+struct target_ipc_perm {
+    uint32_t    cuid;       /* creator user id */
+    uint32_t    cgid;       /* creator group id */
+    uint32_t    uid;        /* user id */
+    uint32_t    gid;        /* group id */
+    uint16_t    mode;       /* r/w permission */
+    uint16_t    seq;        /* sequence # */
+    abi_long    key;        /* user specified msg/sem/shm key */
+};
+
+#define TARGET_IPC_RMID 0   /* remove identifier */
+#define TARGET_IPC_SET  1   /* set options */
+#define TARGET_IPC_STAT 2   /* get options */
+
+/*
+ * sys/sem.h
+ */
+#define TARGET_GETNCNT  3   /* Return the value of semncnt {READ} */
+#define TARGET_GETPID   4   /* Return the value of sempid {READ} */
+#define TARGET_GETVAL   5   /* Return the value of semval {READ} */
+#define TARGET_GETALL   6   /* Return semvals into arg.array {READ} */
+#define TARGET_GETZCNT  7   /* Return the value of semzcnt {READ} */
+#define TARGET_SETVAL   8   /* Set the value of semval to arg.val {ALTER} */
+#define TARGET_SETALL   9   /* Set semvals from arg.array {ALTER} */
+#define TARGET_SEM_STAT 10 /* Like IPC_STAT but treats semid as sema-index */
+#define TARGET_SEM_INFO 11 /* Like IPC_INFO but treats semid as sema-index */
+
+struct target_sembuf {
+    unsigned short  sem_num;    /* semaphore # */
+    short       sem_op;         /* semaphore operation */
+    short       sem_flg;        /* operation flags */
+};
+
+union target_semun {
+    int     val;        /* value for SETVAL */
+    abi_ulong   buf;        /* buffer for IPC_STAT & IPC_SET */
+    abi_ulong   array;      /* array for GETALL & SETALL */
+};
+
+struct target_semid_ds {
+    struct target_ipc_perm sem_perm; /* operation permission struct */
+    abi_ulong   sem_base;   /* pointer to first semaphore in set */
+    uint16_t    sem_nsems;  /* number of sems in set */
+    abi_ulong   sem_otime;  /* last operation time */
+    abi_ulong   sem_ctime;  /* times measured in secs */
+};
+
+/*
+ * sys/shm.h
+ */
+struct target_shmid_ds {
+    struct  target_ipc_perm shm_perm; /* peration permission structure */
+    abi_ulong   shm_segsz;  /* size of segment in bytes */
+    int32_t     shm_lpid;   /* process ID of last shared memory op */
+    int32_t     shm_cpid;   /* process ID of creator */
+    int32_t     shm_nattch; /* number of current attaches */
+    abi_ulong   shm_atime;  /* time of last shmat() */
+    abi_ulong   shm_dtime;  /* time of last shmdt() */
+    abi_ulong   shm_ctime;  /* time of last change by shmctl() */
+};
+
+#define N_BSD_SHM_REGIONS   32
+struct bsd_shm_regions {
+    abi_long start;
+    abi_long size;
+};
+
+/*
+ * sys/msg.h
+ */
+struct target_msqid_ds {
+    struct  target_ipc_perm msg_perm; /* msg queue permission bits */
+    abi_ulong   msg_first;  /* first message in the queue */
+    abi_ulong   msg_last;   /* last message in the queue */
+    abi_ulong   msg_cbytes; /* # of bytes in use on the queue */
+    abi_ulong   msg_qnum;   /* number of msgs in the queue */
+    abi_ulong   msg_qbytes; /* max # of bytes on the queue */
+    int32_t     msg_lspid;  /* pid of last msgsnd() */
+    int32_t     msg_lrpid;  /* pid of last msgrcv() */
+    abi_ulong   msg_stime;  /* time of last msgsnd() */
+    abi_ulong   msg_rtime;  /* time of last msgrcv() */
+    abi_ulong   msg_ctime;  /* time of last msgctl() */
+};
+
+struct target_msgbuf {
+    abi_long    mtype;      /* message type */
+    char        mtext[1];   /* body of message */
+};
+
+/*
+ * sched.h
+ */
+struct target_sched_param {
+        int32_t sched_priority;
+};
+
+/*
+ *  sys/mman.h
+ */
+#define TARGET_FREEBSD_MAP_RESERVED0080 0x0080  /* previously misimplemented
+                                                   MAP_INHERIT */
+#define TARGET_FREEBSD_MAP_RESERVED0100 0x0100  /* previously unimplemented
+                                                   MAP_NOEXTEND */
+#define TARGET_FREEBSD_MAP_STACK        0x0400  /* region grows down, like a
+                                                   stack */
+#define TARGET_FREEBSD_MAP_NOSYNC       0x0800  /* page to but do not sync
+                                                   underlying file */
+
+#define TARGET_FREEBSD_MAP_FLAGMASK     0x1ff7
+
+#define TARGET_NETBSD_MAP_INHERIT       0x0080  /* region is retained after
+                                                   exec */
+#define TARGET_NETBSD_MAP_TRYFIXED      0x0400 /* attempt hint address, even
+                                                  within break */
+#define TARGET_NETBSD_MAP_WIRED         0x0800  /* mlock() mapping when it is
+                                                   established */
+
+#define TARGET_NETBSD_MAP_STACK         0x2000  /* allocated from memory, swap
+                                                   space (stack) */
+
+#define TARGET_NETBSD_MAP_FLAGMASK      0x3ff7
+
+#define TARGET_OPENBSD_MAP_INHERIT      0x0080  /* region is retained after
+                                                   exec */
+#define TARGET_OPENBSD_MAP_NOEXTEND     0x0100  /* for MAP_FILE, don't change
+                                                   file size */
+#define TARGET_OPENBSD_MAP_TRYFIXED     0x0400  /* attempt hint address,
+                                                   even within heap */
+
+#define TARGET_OPENBSD_MAP_FLAGMASK     0x17f7
+
+/* XXX */
+#define TARGET_BSD_MAP_FLAGMASK         0x3ff7
+
+/*
+ * sys/time.h
+ * sys/timex.h
+ */
+
+/*
+ * time_t seems to be very inconsistly defined for the different *BSD's...
+ *
+ * FreeBSD/{arm, mips} uses a 64bits time_t, even in 32bits mode,
+ * so we have to add a special case here.
+ *
+ * On NetBSD time_t is always defined as an int64_t.  On OpenBSD time_t
+ * is always defined as an int.
+ *
+ */
+#if (defined(TARGET_ARM) || defined(TARGET_MIPS))
+typedef int64_t target_freebsd_time_t;
+#else
+typedef abi_long target_freebsd_time_t;
+#endif
+
+typedef abi_long target_freebsd_suseconds_t;
+
+/* compare to sys/timespec.h */
+struct target_freebsd_timespec {
+    target_freebsd_time_t   tv_sec;     /* seconds */
+    abi_long                tv_nsec;    /* and nanoseconds */
+#if (defined(TARGET_ARM) || defined(TARGET_MIPS)) && TARGET_ABI_BITS == 32
+    abi_long _pad;
+#endif
+} __packed;
+
+struct target_freebsd_timeval {
+    target_freebsd_time_t       tv_sec; /* seconds */
+    target_freebsd_suseconds_t  tv_usec;/* and microseconds */
+#if (defined(TARGET_ARM) || defined(TARGET_MIPS)) && TARGET_ABI_BITS == 32
+    abi_long _pad;
+#endif
+} __packed;
+
+/* compare to sys/timex.h */
+struct target_freebsd_ntptimeval {
+    struct target_freebsd_timespec  time;
+    abi_long    maxerror;
+    abi_long    esterror;
+    abi_long    tai;
+    int32_t     time_state;
+};
+
+struct target_freebsd_timex {
+    uint32_t    modes;
+    abi_long    offset;
+    abi_long    freq;
+    abi_long    maxerror;
+    abi_long    esterror;
+    int32_t     status;
+    abi_long    constant;
+    abi_long    precision;
+    abi_long    tolerance;
+
+    abi_long    ppsfreq;
+    abi_long    jitter;
+    int32_t     shift;
+    abi_long    stabil;
+    abi_long    jitcnt;
+    abi_long    calcnt;
+    abi_long    errcnt;
+    abi_long    stbcnt;
+};
+
+/*
+ * sys/event.h
+ */
+struct target_freebsd_kevent {
+    abi_ulong  ident;
+    int16_t    filter;
+    uint16_t   flags;
+    uint32_t   fflags;
+    abi_long   data;
+    abi_ulong  udata;
+} __packed;
+
+/*
+ *  sys/resource.h
+ */
+#if defined(__FreeBSD__) && defined(TARGET_ALPHA)
+#define TARGET_RLIM_INFINITY    0x7fffffffffffffffull
+#elif defined(__FreeBSD__) && (defined(TARGET_MIPS) || \
+        (defined(TARGET_SPARC) && TARGET_ABI_BITS == 32))
+#define TARGET_RLIM_INFINITY    0x7fffffffUL
+#else
+#define TARGET_RLIM_INFINITY    ((abi_ulong)-1)
+#endif
+
+#define TARGET_RLIMIT_CPU       0
+#define TARGET_RLIMIT_FSIZE     1
+#define TARGET_RLIMIT_DATA      2
+#define TARGET_RLIMIT_STACK     3
+#define TARGET_RLIMIT_CORE      4
+#define TARGET_RLIMIT_RSS       5
+#define TARGET_RLIMIT_MEMLOCK   6
+#define TARGET_RLIMIT_NPROC     7
+#define TARGET_RLIMIT_NOFILE    8
+#define TARGET_RLIMIT_SBSIZE    9
+#define TARGET_RLIMIT_AS        10
+#define TARGET_RLIMIT_NPTS      11
+#define TARGET_RLIMIT_SWAP      12
+
+struct target_rlimit {
+    uint64_t rlim_cur;
+    uint64_t rlim_max;
+};
+
+struct target_freebsd_rusage {
+    struct target_freebsd_timeval ru_utime; /* user time used */
+    struct target_freebsd_timeval ru_stime; /* system time used */
+    abi_long    ru_maxrss;      /* maximum resident set size */
+    abi_long    ru_ixrss;       /* integral shared memory size */
+    abi_long    ru_idrss;       /* integral unshared data size */
+    abi_long    ru_isrss;       /* integral unshared stack size */
+    abi_long    ru_minflt;      /* page reclaims */
+    abi_long    ru_majflt;      /* page faults */
+    abi_long    ru_nswap;       /* swaps */
+    abi_long    ru_inblock;     /* block input operations */
+    abi_long    ru_oublock;     /* block output operations */
+    abi_long    ru_msgsnd;      /* messages sent */
+    abi_long    ru_msgrcv;      /* messages received */
+    abi_long    ru_nsignals;    /* signals received */
+    abi_long    ru_nvcsw;       /* voluntary context switches */
+    abi_long    ru_nivcsw;      /* involuntary context switches */
+};
+
+/*
+ * sys/socket.h
+ */
+
+/*
+ * Types
+ */
+#define TARGET_SOCK_STREAM      1   /* stream socket */
+#define TARGET_SOCK_DGRAM       2   /* datagram socket */
+#define TARGET_SOCK_RAW         3   /* raw-protocol interface */
+#define TARGET_SOCK_RDM         4   /* reliably-delivered message */
+#define TARGET_SOCK_SEQPACKET   5   /* sequenced packet stream */
+
+
+/*
+ * Option flags per-socket.
+ */
+
+#define TARGET_SO_DEBUG         0x0001  /* turn on debugging info recording */
+#define TARGET_SO_ACCEPTCONN    0x0002  /* socket has had listen() */
+#define TARGET_SO_REUSEADDR     0x0004  /* allow local address reuse */
+#define TARGET_SO_KEEPALIVE     0x0008  /* keep connections alive */
+#define TARGET_SO_DONTROUTE     0x0010  /* just use interface addresses */
+#define TARGET_SO_BROADCAST     0x0020  /* permit sending of broadcast msgs */
+#define TARGET_SO_USELOOPBACK   0x0040  /* bypass hardware when possible */
+#define TARGET_SO_LINGER        0x0080  /* linger on close if data present */
+#define TARGET_SO_OOBINLINE     0x0100  /* leave received OOB data in line */
+#define TARGET_SO_REUSEPORT     0x0200  /* allow local address & port reuse */
+#define TARGET_SO_TIMESTAMP     0x0400  /* timestamp received dgram traffic */
+#define TARGET_SO_NOSIGPIPE     0x0800  /* no SIGPIPE from EPIPE */
+#define TARGET_SO_ACCEPTFILTER  0x1000  /* there is an accept filter */
+#define TARGET_SO_BINTIME       0x2000  /* timestamp received dgram traffic */
+#define TARGET_SO_NO_OFFLOAD    0x4000  /* socket cannot be offloaded */
+#define TARGET_SO_NO_DDP        0x8000  /* disable direct data placement */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define TARGET_SO_SNDBUF        0x1001  /* send buffer size */
+#define TARGET_SO_RCVBUF        0x1002  /* receive buffer size */
+#define TARGET_SO_SNDLOWAT      0x1003  /* send low-water mark */
+#define TARGET_SO_RCVLOWAT      0x1004  /* receive low-water mark */
+#define TARGET_SO_SNDTIMEO      0x1005  /* send timeout */
+#define TARGET_SO_RCVTIMEO      0x1006  /* receive timeout */
+#define TARGET_SO_ERROR         0x1007  /* get error status and clear */
+#define TARGET_SO_TYPE          0x1008  /* get socket type */
+#define TARGET_SO_LABEL         0x1009  /* socket's MAC label */
+#define TARGET_SO_PEERLABEL     0x1010  /* socket's peer's MAC label */
+#define TARGET_SO_LISTENQLIMIT  0x1011  /* socket's backlog limit */
+#define TARGET_SO_LISTENQLEN    0x1012  /* socket's complete queue length */
+#define TARGET_SO_LISTENINCQLEN 0x1013  /* socket's incomplete queue length */
+#define TARGET_SO_SETFIB        0x1014  /* use this FIB to route */
+#define TARGET_SO_USER_COOKIE   0x1015  /* user cookie (dummynet etc.) */
+#define TARGET_SO_PROTOCOL      0x1016  /* get socket protocol (Linux name) */
+
+/* alias for SO_PROTOCOL (SunOS name) */
+#define TARGET_SO_PROTOTYPE     TARGET_SO_PROTOCOL
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define TARGET_SOL_SOCKET       0xffff  /* options for socket level */
+
+#ifndef CMSG_ALIGN
+#define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1))
+#endif
+
+struct target_msghdr {
+    abi_long    msg_name;       /* So cket name */
+    int32_t     msg_namelen;    /* Length of name */
+    abi_long    msg_iov;        /* Data blocks */
+    abi_long    msg_iovlen;     /* Number of blocks */
+    abi_long    msg_control;    /* Per protocol magic
+                                   (eg BSD file descriptor passing) */
+    abi_long    msg_controllen; /* Length of cmsg list */
+    int32_t     msg_flags;      /* flags on received message */
+};
+
+struct target_sockaddr {
+    uint8_t sa_len;
+    uint8_t sa_family;
+    uint8_t sa_data[14];
+} QEMU_PACKED;
+
+struct target_in_addr {
+    uint32_t s_addr; /* big endian */
+};
+
+struct target_cmsghdr {
+    abi_long    cmsg_len;
+    int32_t     cmsg_level;
+    int32_t     cmsg_type;
+};
+
+#define TARGET_CMSG_DATA(cmsg)  \
+    ((unsigned char *)((struct target_cmsghdr *) (cmsg) + 1))
+#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr(mhdr, cmsg)
+#define TARGET_CMSG_ALIGN(len) (((len) + sizeof(abi_long) - 1) \
+    & (size_t) ~(sizeof(abi_long) - 1))
+#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN(len) \
+    + TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr)))
+#define TARGET_CMSG_LEN(len)  \
+    (TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr)) + (len))
+
+static inline struct target_cmsghdr *__target_cmsg_nxthdr(
+        struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg)
+{
+    struct target_cmsghdr *__ptr;
+
+    __ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg +
+        TARGET_CMSG_ALIGN(tswapal(__cmsg->cmsg_len)));
+    if ((unsigned long)((char *)(__ptr+1) -
+        (char *)(size_t)tswapal(__mhdr->msg_control)) >
+        tswapal(__mhdr->msg_controllen)) {
+        /* No more entries.  */
+        return (struct target_cmsghdr *)0;
+    }
+    return __cmsg;
+}
+
+/*
+ * netinet/in.h
+ */
+struct target_ip_mreq {
+    struct target_in_addr   imr_multiaddr;
+    struct target_in_addr   imr_interface;
+};
+
+struct target_ip_mreqn {
+    struct target_in_addr   imr_multiaddr;
+    struct target_in_addr   imr_address;
+    int32_t                 imr_ifindex;
+};
+
+/*
+ * sys/stat.h
+ */
+#if defined(__FreeBSD_version) && __FreeBSD_version < 900000
+#define st_atim st_atimespec
+#define st_ctim st_ctimespec
+#define st_mtim st_mtimespec
+#define st_birthtim st_birthtimespec
+#endif
+
+struct target_freebsd_stat {
+    uint32_t  st_dev;       /* inode's device */
+    uint32_t  st_ino;       /* inode's number */
+    int16_t   st_mode;      /* inode protection mode */
+    int16_t   st_nlink;     /* number of hard links */
+    uint32_t  st_uid;       /* user ID of the file's owner */
+    uint32_t  st_gid;       /* group ID of the file's group */
+    uint32_t  st_rdev;      /* device type */
+    struct  target_freebsd_timespec st_atim; /* time last accessed */
+    struct  target_freebsd_timespec st_mtim; /* time last data modification */
+    struct  target_freebsd_timespec st_ctim; /* time last file status change */
+    int64_t    st_size;     /* file size, in bytes */
+    int64_t    st_blocks;   /* blocks allocated for file */
+    uint32_t   st_blksize;  /* optimal blocksize for I/O */
+    uint32_t   st_flags;    /* user defined flags for file */
+    __uint32_t st_gen;      /* file generation number */
+    __int32_t  st_lspare;
+    struct target_freebsd_timespec st_birthtim; /* time of file creation */
+    /*
+     * Explicitly pad st_birthtim to 16 bytes so that the size of
+     * struct stat is backwards compatible.  We use bitfields instead
+     * of an array of chars so that this doesn't require a C99 compiler
+     * to compile if the size of the padding is 0.  We use 2 bitfields
+     * to cover up to 64 bits on 32-bit machines.  We assume that
+     * CHAR_BIT is 8...
+     */
+    unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec));
+    unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec));
+} __packed;
+
+/* struct nstat is the same as stat above but without the st_lspare field */
+struct target_freebsd_nstat {
+    uint32_t  st_dev;       /* inode's device */
+    uint32_t  st_ino;       /* inode's number */
+    int16_t   st_mode;      /* inode protection mode */
+    int16_t   st_nlink;     /* number of hard links */
+    uint32_t  st_uid;       /* user ID of the file's owner */
+    uint32_t  st_gid;       /* group ID of the file's group */
+    uint32_t  st_rdev;      /* device type */
+    struct  target_freebsd_timespec st_atim; /* time last accessed */
+    struct  target_freebsd_timespec st_mtim; /* time last data modification */
+    struct  target_freebsd_timespec st_ctim; /* time last file status change */
+    int64_t    st_size;     /* file size, in bytes */
+    int64_t    st_blocks;   /* blocks allocated for file */
+    uint32_t   st_blksize;  /* optimal blocksize for I/O */
+    uint32_t   st_flags;    /* user defined flags for file */
+    __uint32_t st_gen;      /* file generation number */
+    /* __int32_t  st_lspare; */
+    struct target_freebsd_timespec st_birthtim; /* time of file creation */
+    /*
+     * Explicitly pad st_birthtim to 16 bytes so that the size of
+     * struct stat is backwards compatible.  We use bitfields instead
+     * of an array of chars so that this doesn't require a C99 compiler
+     * to compile if the size of the padding is 0.  We use 2 bitfields
+     * to cover up to 64 bits on 32-bit machines.  We assume that
+     * CHAR_BIT is 8...
+     */
+    unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec));
+    unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec));
+} __packed;
+
+/*
+ * sys/mount.h
+ */
+
+/* filesystem id type */
+typedef struct target_freebsd_fsid { int32_t val[2]; } target_freebsd_fsid_t;
+
+/* filesystem statistics */
+#define TARGET_MFSNAMELEN   16  /* length of type name include null */
+#define TARGET_MNAMELEN     88  /* size of on/from name bufs */
+#define TARGET_STATFS_VERSION   0x20030518  /* current version number */
+struct target_freebsd_statfs {
+    uint32_t f_version; /* structure version number */
+    uint32_t f_type;    /* type of filesystem */
+    uint64_t f_flags;   /* copy of mount exported flags */
+    uint64_t f_bsize;   /* filesystem fragment size */
+    uint64_t f_iosize;  /* optimal transfer block size */
+    uint64_t f_blocks;  /* total data blocks in filesystem */
+    uint64_t f_bfree;   /* free blocks in filesystem */
+    int64_t  f_bavail;  /* free blocks avail to non-superuser */
+    uint64_t f_files;   /* total file nodes in filesystem */
+    int64_t  f_ffree;   /* free nodes avail to non-superuser */
+    uint64_t f_syncwrites;  /* count of sync writes since mount */
+    uint64_t f_asyncwrites; /* count of async writes since mount */
+    uint64_t f_syncreads;   /* count of sync reads since mount */
+    uint64_t f_asyncreads;  /* count of async reads since mount */
+    uint64_t f_spare[10];   /* unused spare */
+    uint32_t f_namemax; /* maximum filename length */
+    uint32_t f_owner;   /* user that mounted the filesystem */
+    target_freebsd_fsid_t   f_fsid; /* filesystem id */
+    char     f_charspare[80];           /* spare string space */
+    char     f_fstypename[TARGET_MFSNAMELEN];   /* filesys type name */
+    char     f_mntfromname[TARGET_MNAMELEN];    /* mount filesystem */
+    char     f_mntonname[TARGET_MNAMELEN];      /* dir on which mounted*/
+};
+
+/* File identifier. These are unique per filesystem on a single machine. */
+#define TARGET_MAXFIDSZ     16
+
+struct target_freebsd_fid {
+    u_short     fid_len;            /* len of data in bytes */
+    u_short     fid_data0;          /* force longword align */
+    char        fid_data[TARGET_MAXFIDSZ];  /* data (variable len) */
+};
+
+/* Generic file handle */
+struct target_freebsd_fhandle {
+    target_freebsd_fsid_t   fh_fsid;    /* Filesystem id of mount point */
+    struct target_freebsd_fid fh_fid;   /* Filesys specific id */
+};
+typedef struct target_freebsd_fhandle target_freebsd_fhandle_t;
+
+/*
+ * sys/fcntl.h
+ */
+#define TARGET_F_DUPFD              0
+#define TARGET_F_GETFD              1
+#define TARGET_F_SETFD              2
+#define TARGET_F_GETFL              3
+#define TARGET_F_SETFL              4
+#define TARGET_F_GETOWN             5
+#define TARGET_F_SETOWN             6
+#define TARGET_F_OGETLK             7
+#define TARGET_F_OSETLK             8
+#define TARGET_F_OSETLKW            9
+#define TARGET_F_DUP2FD             10
+#define TARGET_F_GETLK              11
+#define TARGET_F_SETLK              12
+#define TARGET_F_SETLKW             13
+#define TARGET_F_SETLK_REMOTE       14
+#define TARGET_F_READAHEAD          15
+#define TARGET_F_RDAHEAD            16
+#define TARGET_F_DUPFD_CLOEXEC     17
+#define TARGET_F_DUP2FD_CLOEXEC    18
+
+struct target_freebsd_flock {
+    int64_t l_start;
+    int64_t l_len;
+    int32_t l_pid;
+    int16_t l_type;
+    int16_t l_whence;
+    int32_t l_sysid;
+} QEMU_PACKED;
+
+/*
+ * FreeBSD thread and user mutex support.
+ */
+
+/* sys/thr.h */
+#define TARGET_THR_SUSPENDED    0x0001
+#define TARGET_THR_SYSTEM_SCOPE 0x0002
+
+struct target_freebsd_thr_param {
+    abi_ulong   start_func; /* thread entry function. */
+    abi_ulong   arg;        /* argument for entry function. */
+    abi_ulong   stack_base; /* stack base address. */
+    abi_ulong   stack_size; /* stack size. */
+    abi_ulong   tls_base;   /* tls base address. */
+    abi_ulong   tls_size;   /* tls size. */
+    abi_ulong   child_tid;  /* address to store new TID. */
+    abi_ulong   parent_tid; /* parent access the new TID here. */
+    int32_t     flags;      /* thread flags. */
+    abi_ulong   rtp;        /* Real-time scheduling priority. */
+    abi_ulong   spare[3];   /* spares. */
+};
+
+/* sys/rtprio.h */
+struct target_freebsd_rtprio {
+    uint16_t    type;
+    uint16_t    prio;
+};
+
+typedef struct {
+    CPUArchState *env;
+    long parent_tid;
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    pthread_t thread;
+    sigset_t sigmask;
+    struct target_freebsd_thr_param param;
+} new_freebsd_thread_info_t;
+
+/* sys/utmx.h */
+/* op code for _umtx_op */
+#define TARGET_UMTX_OP_LOCK                 0
+#define TARGET_UMTX_OP_UNLOCK               1
+#define TARGET_UMTX_OP_WAIT                 2
+#define TARGET_UMTX_OP_WAKE                 3
+#define TARGET_UMTX_OP_MUTEX_TRYLOCK        4
+#define TARGET_UMTX_OP_MUTEX_LOCK           5
+#define TARGET_UMTX_OP_MUTEX_UNLOCK         6
+#define TARGET_UMTX_OP_SET_CEILING          7
+#define TARGET_UMTX_OP_CV_WAIT              8
+#define TARGET_UMTX_OP_CV_SIGNAL            9
+#define TARGET_UMTX_OP_CV_BROADCAST         10
+#define TARGET_UMTX_OP_WAIT_UINT            11
+#define TARGET_UMTX_OP_RW_RDLOCK            12
+#define TARGET_UMTX_OP_RW_WRLOCK            13
+#define TARGET_UMTX_OP_RW_UNLOCK            14
+#define TARGET_UMTX_OP_WAIT_UINT_PRIVATE    15
+#define TARGET_UMTX_OP_WAKE_PRIVATE         16
+#define TARGET_UMTX_OP_MUTEX_WAIT           17
+#define TARGET_UMTX_OP_MUTEX_WAKE           18
+#define TARGET_UMTX_OP_SEM_WAIT             19
+#define TARGET_UMTX_OP_SEM_WAKE             20
+#define TARGET_UMTX_OP_NWAKE_PRIVATE        21
+#define TARGET_UMTX_OP_MUTEX_WAKE2          22
+#define TARGET_UMTX_OP_MAX                  23
+
+/* flags for UMTX_OP_CV_WAIT */
+#define TARGET_CVWAIT_CHECK_UNPARKING       0x01
+#define TARGET_CVWAIT_ABSTIME               0x02
+#define TARGET_CVWAIT_CLOCKID               0x04
+
+#define TARGET_UMTX_UNOWNED                 0x0
+#define TARGET_UMUTEX_UNOWNED               0x0
+#define TARGET_UMTX_CONTESTED               (abi_ulong)(-1)
+#define TARGET_UMUTEX_CONTESTED             0x80000000U
+
+/* flags for umutex */
+#define TARGET_UMUTEX_ERROR_CHECK   0x0002  /* Error-checking mutex */
+#define TARGET_UMUTEX_PRIO_INHERIT  0x0004  /* Priority inherited mutex */
+#define TARGET_UMUTEX_PRIO_PROTECT  0x0008  /* Priority protect mutex */
+
+#define TARGET_UMUTEX_TRY           1
+#define TARGET_UMUTEX_WAIT          2
+
+/* urwlock flags */
+#define TARGET_URWLOCK_PREFER_READER    0x0002
+#define TARGET_URWLOCK_WRITE_OWNER      0x80000000U
+#define TARGET_URWLOCK_WRITE_WAITERS    0x40000000U
+#define TARGET_URWLOCK_READ_WAITERS     0x20000000U
+#define TARGET_URWLOCK_MAX_READERS      0x1fffffffU
+#define TARGET_URWLOCK_READER_COUNT(c)  ((c) & TARGET_URWLOCK_MAX_READERS)
+
+/*
+ * sys/acl.h
+ */
+#define TARGET_FREEBSD_ACL_MAX_ENTRIES          254
+
+/* vaild acl_type_t arguments */
+#define TARGET_FREEBSD_ACL_TYPE_ACCESS_OLD      0x00000000
+#define TARGET_FREEBSD_ACL_TYPE_DEFAULT_OLD     0x00000001
+#define TARGET_FREEBSD_ACL_TYPE_ACCESS          0x00000002
+#define TARGET_FREEBSD_ACL_TYPE_DEFAULT         0x00000003
+#define TARGET_FREEBSD_ACL_TYPE_NFS4            0x00000004
+
+struct target_freebsd_acl_entry {
+    uint32_t    ae_tag;
+    uint32_t    ae_id;
+    uint32_t    ae_perm;
+    uint16_t    ae_entry_type;
+    uint16_t    ae_flags;
+};
+
+struct target_freebsd_acl {
+    uint32_t            acl_maxcnt;
+    uint32_t            acl_cnt;
+    int32_t             acl_spare[4];
+    struct target_freebsd_acl_entry  acl_entry[TARGET_FREEBSD_ACL_MAX_ENTRIES];
+};
+
+/*
+ *  sys/uuid.h
+ */
+
+#define TARGET_UUID_NODE_LEN    6
+
+struct target_uuid {
+    uint32_t    time_low;
+    uint16_t    time_mid;
+    uint16_t    time_hi_and_version;
+    uint8_t     clock_seq_hi_and_reserved;
+    uint8_t     clock_seq_low;
+    uint8_t     node[TARGET_UUID_NODE_LEN];
+};
+
+#endif /* ! _SYSCALL_DEFS_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 07/19] bsd-user: add support for freebsd signal related system calls
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (7 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 06/19] bsd-user: add support for freebsd time related system calls Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 08/19] bsd-user: move arch/OS dependent code out of elfload.c Stacey Son
                     ` (11 subsequent siblings)
  20 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for signal related system calls
including sigtimedwait(2), sigaction(2), sigprocmask(2), sigpending(2),
sigsuspend(2), sigreturn(2), sigwait(2), sigwaitinfo(2), sigqueue(2),
sigaltstack(2), kill(2), killpg(2), and pdkill(2).
---
 bsd-user/arm/target_arch_signal.h     |  257 ++++++++++
 bsd-user/bsd-signal.h                 |  232 +++++++++
 bsd-user/errno_defs.h                 |   13 +-
 bsd-user/freebsd/os-signal.h          |   43 ++
 bsd-user/freebsd/target_os_siginfo.h  |  110 ++++
 bsd-user/freebsd/target_os_signal.h   |   79 +++
 bsd-user/i386/target_arch_signal.h    |   94 ++++
 bsd-user/mips/target_arch_signal.h    |  237 +++++++++
 bsd-user/mips64/target_arch_signal.h  |  214 ++++++++
 bsd-user/netbsd/target_os_siginfo.h   |   82 +++
 bsd-user/netbsd/target_os_signal.h    |   70 +++
 bsd-user/openbsd/target_os_siginfo.h  |   82 +++
 bsd-user/openbsd/target_os_signal.h   |   70 +++
 bsd-user/qemu.h                       |   33 +-
 bsd-user/signal.c                     |  907 ++++++++++++++++++++++++++++++++-
 bsd-user/sparc/target_arch_signal.h   |   77 +++
 bsd-user/sparc64/target_arch_signal.h |   94 ++++
 bsd-user/syscall.c                    |   59 +++
 bsd-user/x86_64/target_arch_signal.h  |   94 ++++
 19 files changed, 2830 insertions(+), 17 deletions(-)
 create mode 100644 bsd-user/arm/target_arch_signal.h
 create mode 100644 bsd-user/bsd-signal.h
 create mode 100644 bsd-user/freebsd/os-signal.h
 create mode 100644 bsd-user/freebsd/target_os_siginfo.h
 create mode 100644 bsd-user/freebsd/target_os_signal.h
 create mode 100644 bsd-user/i386/target_arch_signal.h
 create mode 100644 bsd-user/mips/target_arch_signal.h
 create mode 100644 bsd-user/mips64/target_arch_signal.h
 create mode 100644 bsd-user/netbsd/target_os_siginfo.h
 create mode 100644 bsd-user/netbsd/target_os_signal.h
 create mode 100644 bsd-user/openbsd/target_os_siginfo.h
 create mode 100644 bsd-user/openbsd/target_os_signal.h
 create mode 100644 bsd-user/sparc/target_arch_signal.h
 create mode 100644 bsd-user/sparc64/target_arch_signal.h
 create mode 100644 bsd-user/x86_64/target_arch_signal.h

diff --git a/bsd-user/arm/target_arch_signal.h b/bsd-user/arm/target_arch_signal.h
new file mode 100644
index 0000000..048bd4f
--- /dev/null
+++ b/bsd-user/arm/target_arch_signal.h
@@ -0,0 +1,257 @@
+/*
+ *  arm signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+#define TARGET_REG_R0   0
+#define TARGET_REG_R1   1
+#define TARGET_REG_R2   2
+#define TARGET_REG_R3   3
+#define TARGET_REG_R4   4
+#define TARGET_REG_R5   5
+#define TARGET_REG_R6   6
+#define TARGET_REG_R7   7
+#define TARGET_REG_R8   8
+#define TARGET_REG_R9   9
+#define TARGET_REG_R10  10
+#define TARGET_REG_R11  11
+#define TARGET_REG_R12  12
+#define TARGET_REG_R13  13
+#define TARGET_REG_R14  14
+#define TARGET_REG_R15  15
+#define TARGET_REG_CPSR 16
+#define TARGET__NGREG   17
+/* Convenience synonyms */
+#define TARGET_REG_FP   TARGET_REG_R11
+#define TARGET_REG_SP   TARGET_REG_R13
+#define TARGET_REG_LR   TARGET_REG_R14
+#define TARGET_REG_PC   TARGET_REG_R15
+
+#define TARGET_INSN_SIZE    4       /* arm instruction size */
+
+/* Size of the signal trampolin code. See _sigtramp(). */
+#define TARGET_SZSIGCODE    ((abi_ulong)(8 * TARGET_INSN_SIZE))
+
+/* compare to arm/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (1024 * 4)                  /* min sig stack size */
+#define TARGET_SIGSTKSZ     (TARGET_MINSIGSTKSZ + 32768)  /* recommended size */
+
+/* arm/arm/machdep.c */
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC     0x0002
+#define TARGET_MC_SET_ONSTACK   0x0004
+
+struct target_sigcontext {
+    target_sigset_t sc_mask;    /* signal mask to retstore */
+    int32_t     sc_onstack;     /* sigstack state to restore */
+    abi_long    sc_pc;          /* pc at time of signal */
+    abi_long    sc_reg[32];     /* processor regs 0 to 31 */
+    abi_long    mullo, mulhi;   /* mullo and mulhi registers */
+    int32_t     sc_fpused;      /* fp has been used */
+    abi_long    sc_fpregs[33];  /* fp regs 0 to 31 & csr */
+    abi_long    sc_fpc_eir;     /* fp exception instr reg */
+    /* int32_t reserved[8]; */
+};
+
+typedef struct {
+    uint32_t    __fp_fpsr;
+    struct {
+        uint32_t    __fp_exponent;
+        uint32_t    __fp_mantissa_hi;
+        uint32_t    __fp_mantissa_lo;
+    }       __fp_fr[8];
+} target__fpregset_t;
+
+typedef struct {
+    uint32_t    __vfp_fpscr;
+    uint32_t    __vfp_fstmx[33];
+    uint32_t    __vfp_fpsid;
+} target__vfpregset_t;
+
+typedef struct target_mcontext {
+    uint32_t        __gregs[TARGET__NGREG];
+    union {
+        target__fpregset_t  __fpregs;
+        target__vfpregset_t __vfpregs;
+    } __fpu;
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t     uc_sigmask;
+    target_mcontext_t   uc_mcontext;
+    abi_ulong           uc_link;
+    target_stack_t      uc_stack;
+    int32_t             uc_flags;
+    int32_t             __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    target_siginfo_t    sf_si;  /* saved siginfo */
+    target_ucontext_t   sf_uc;  /* saved ucontext */
+};
+
+
+/* compare to sys/arm/include/frame.h */
+struct target_trapframe {
+    abi_ulong tf_spsr; /* Zero on arm26 */
+    abi_ulong tf_r0;
+    abi_ulong tf_r1;
+    abi_ulong tf_r2;
+    abi_ulong tf_r3;
+    abi_ulong tf_r4;
+    abi_ulong tf_r5;
+    abi_ulong tf_r6;
+    abi_ulong tf_r7;
+    abi_ulong tf_r8;
+    abi_ulong tf_r9;
+    abi_ulong tf_r10;
+    abi_ulong tf_r11;
+    abi_ulong tf_r12;
+    abi_ulong tf_usr_sp;
+    abi_ulong tf_usr_lr;
+    abi_ulong tf_svc_sp; /* Not used on arm26 */
+    abi_ulong tf_svc_lr; /* Not used on arm26 */
+    abi_ulong tf_pc;
+};
+
+/*
+ * Compare to arm/arm/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUARMState *regs, int sig, struct target_sigframe *frame,
+    abi_ulong frame_addr, struct target_sigaction *ka)
+{
+    /*
+     * Arguments to signal handler:
+     *  r0 = signal number
+     *  r1 = siginfo pointer
+     *  r2 = ucontext pointer
+     *  r5 = ucontext pointer
+     *  pc = signal handler pointer
+     *  sp = sigframe struct pointer
+     *  lr = sigtramp at base of user stack
+     */
+
+    regs->regs[0] = sig;
+    regs->regs[1] = frame_addr +
+        offsetof(struct target_sigframe, sf_si);
+    regs->regs[2] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+
+    /* the trampoline uses r5 as the uc address */
+    regs->regs[5] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+    regs->regs[TARGET_REG_PC] = ka->_sa_handler;
+    regs->regs[TARGET_REG_SP] = frame_addr;
+    regs->regs[TARGET_REG_LR] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+
+    return 0;
+}
+
+/*
+ * Compare to arm/arm/machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long get_mcontext(CPUARMState *regs, target_mcontext_t *mcp,
+        int flags)
+{
+    int err = 0;
+    uint32_t *gr = mcp->__gregs;
+
+
+    if (flags & TARGET_MC_GET_CLEAR_RET) {
+        gr[TARGET_REG_R0] = 0;
+    } else {
+        gr[TARGET_REG_R0] = tswap32(regs->regs[0]);
+    }
+
+    gr[TARGET_REG_R1] = tswap32(regs->regs[1]);
+    gr[TARGET_REG_R2] = tswap32(regs->regs[2]);
+    gr[TARGET_REG_R3] = tswap32(regs->regs[3]);
+    gr[TARGET_REG_R4] = tswap32(regs->regs[4]);
+    gr[TARGET_REG_R5] = tswap32(regs->regs[5]);
+    gr[TARGET_REG_R6] = tswap32(regs->regs[6]);
+    gr[TARGET_REG_R7] = tswap32(regs->regs[7]);
+    gr[TARGET_REG_R8] = tswap32(regs->regs[8]);
+    gr[TARGET_REG_R9] = tswap32(regs->regs[9]);
+    gr[TARGET_REG_R10] = tswap32(regs->regs[10]);
+    gr[TARGET_REG_R11] = tswap32(regs->regs[11]);
+    gr[TARGET_REG_R12] = tswap32(regs->regs[12]);
+
+    gr[TARGET_REG_SP] = tswap32(regs->regs[13]);
+    gr[TARGET_REG_LR] = tswap32(regs->regs[14]);
+    gr[TARGET_REG_PC] = tswap32(regs->regs[15]);
+    gr[TARGET_REG_CPSR] = tswap32(cpsr_read(regs));
+
+    return err;
+}
+
+/* Compare to arm/arm/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUARMState *regs, target_mcontext_t *mcp,
+        int srflag)
+{
+    int err = 0;
+    const uint32_t *gr = mcp->__gregs;
+    uint32_t cpsr;
+
+    regs->regs[0] = tswap32(gr[TARGET_REG_R0]);
+    regs->regs[1] = tswap32(gr[TARGET_REG_R1]);
+    regs->regs[2] = tswap32(gr[TARGET_REG_R2]);
+    regs->regs[3] = tswap32(gr[TARGET_REG_R3]);
+    regs->regs[4] = tswap32(gr[TARGET_REG_R4]);
+    regs->regs[5] = tswap32(gr[TARGET_REG_R5]);
+    regs->regs[6] = tswap32(gr[TARGET_REG_R6]);
+    regs->regs[7] = tswap32(gr[TARGET_REG_R7]);
+    regs->regs[8] = tswap32(gr[TARGET_REG_R8]);
+    regs->regs[9] = tswap32(gr[TARGET_REG_R9]);
+    regs->regs[10] = tswap32(gr[TARGET_REG_R10]);
+    regs->regs[11] = tswap32(gr[TARGET_REG_R11]);
+    regs->regs[12] = tswap32(gr[TARGET_REG_R12]);
+
+    regs->regs[13] = tswap32(gr[TARGET_REG_SP]);
+    regs->regs[14] = tswap32(gr[TARGET_REG_LR]);
+    regs->regs[15] = tswap32(gr[TARGET_REG_PC]);
+    cpsr = tswap32(gr[TARGET_REG_CPSR]);
+    cpsr_write(regs, cpsr, CPSR_USER | CPSR_EXEC);
+
+    return err;
+}
+
+/* Compare to arm/arm/machdep.c sys_sigreturn() */
+static inline abi_long get_ucontext_sigreturn(CPUARMState *regs,
+        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    uint32_t cpsr = cpsr_read(regs);
+
+    *target_uc = 0;
+
+    if ((cpsr & CPSR_M) != ARM_CPU_MODE_USR ||
+            (cpsr & (CPSR_I | CPSR_F)) != 0) {
+        return -TARGET_EINVAL;
+    }
+
+    *target_uc = target_sf + offsetof(struct target_sigframe, sf_uc);
+
+    return 0;
+}
+
+
+#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/bsd-signal.h b/bsd-user/bsd-signal.h
new file mode 100644
index 0000000..48a8b56
--- /dev/null
+++ b/bsd-user/bsd-signal.h
@@ -0,0 +1,232 @@
+/*
+ *  signal related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_SIGNAL_H_
+#define __BSD_SIGNAL_H_
+
+/* sigaction(2) */
+static inline abi_long do_bsd_sigaction(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    struct target_sigaction *old_act, act, oact, *pact;
+
+    if (arg2) {
+        if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) {
+            return -TARGET_EFAULT;
+        }
+        act._sa_handler = old_act->_sa_handler;
+        act.sa_flags = old_act->sa_flags;
+        memcpy(&act.sa_mask, &old_act->sa_mask, sizeof(target_sigset_t));
+        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)) {
+            return -TARGET_EFAULT;
+        }
+        old_act->_sa_handler = oact._sa_handler;
+        old_act->sa_flags = oact.sa_flags;
+        memcpy(&old_act->sa_mask, &oact.sa_mask, sizeof(target_sigset_t));
+        unlock_user_struct(old_act, arg3, 1);
+    }
+    return ret;
+}
+
+
+/* sigprocmask(2) */
+static inline abi_long do_bsd_sigprocmask(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set, oldset, *set_ptr;
+    int how;
+
+    if (arg2) {
+        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:
+            return -TARGET_EFAULT;
+        }
+        p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        target_to_host_sigset(&set, p);
+        unlock_user(p, arg2, 0);
+        set_ptr = &set;
+    } else {
+        how = 0;
+        set_ptr = NULL;
+    }
+    ret = get_errno(sigprocmask(how, set_ptr, &oldset));
+    if (!is_error(ret) && arg3) {
+        p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_sigset(p, &oldset);
+        unlock_user(p, arg3, sizeof(target_sigset_t));
+    }
+    return ret;
+}
+
+/* sigpending(2) */
+static inline abi_long do_bsd_sigpending(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+
+    ret = get_errno(sigpending(&set));
+    if (!is_error(ret)) {
+        p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_sigset(p, &set);
+        unlock_user(p, arg1, sizeof(target_sigset_t));
+    }
+    return ret;
+}
+
+/* sigsuspend(2) */
+static inline abi_long do_bsd_sigsuspend(abi_long arg1, abi_long arg2)
+{
+    void *p;
+    sigset_t set;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+
+    return get_errno(sigsuspend(&set));
+}
+
+/* sigreturn(2) */
+static inline abi_long do_bsd_sigreturn(void *cpu_env, abi_long arg1)
+{
+
+    return do_sigreturn(cpu_env, arg1);
+}
+
+/* sigvec(2) - not defined */
+/* sigblock(2) - not defined */
+/* sigsetmask(2) - not defined */
+/* sigstack(2) - not defined */
+
+/* sigwait(2) */
+static inline abi_long do_bsd_sigwait(abi_ulong arg1, abi_ulong arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    int sig;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    ret = get_errno(sigwait(&set, &sig));
+    if (!is_error(ret) && arg2) {
+        ret = put_user_s32(sig, arg2);
+    }
+    return ret;
+}
+
+/* sigwaitinfo(2) */
+static inline abi_long do_bsd_sigwaitinfo(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    siginfo_t uinfo;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    ret = get_errno(sigwaitinfo(&set, &uinfo));
+    if (!is_error(ret) && arg2) {
+        p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_siginfo(p, &uinfo);
+        unlock_user(p, arg2, sizeof(target_siginfo_t));
+    }
+    return ret;
+}
+
+/* sigqueue(2) */
+static inline abi_long do_bsd_sigqueue(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    union sigval value;
+
+    value.sival_ptr = (void *)(uintptr_t)arg3;
+    return get_errno(sigqueue(arg1, target_to_host_signal(arg2), value));
+}
+
+/* sigaltstck(2) */
+static inline abi_long do_bsd_sigaltstack(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    return do_sigaltstack(arg1, arg2, get_sp_from_cpustate(cpu_env));
+}
+
+/* kill(2) */
+static inline abi_long do_bsd_kill(abi_long pid, abi_long sig)
+{
+
+    return get_errno(kill(pid, target_to_host_signal(sig)));
+}
+
+/* killpg(2) */
+static inline abi_long do_bsd_killpg(abi_long pg, abi_long sig)
+{
+
+    return get_errno(killpg(pg, target_to_host_signal(sig)));
+}
+
+#endif /* !  __BSD_SIGNAL_H_ */
diff --git a/bsd-user/errno_defs.h b/bsd-user/errno_defs.h
index 1efa502..f01181d 100644
--- a/bsd-user/errno_defs.h
+++ b/bsd-user/errno_defs.h
@@ -1,6 +1,3 @@
-/*      $OpenBSD: errno.h,v 1.20 2007/09/03 14:37:52 millert Exp $      */
-/*      $NetBSD: errno.h,v 1.10 1996/01/20 01:33:53 jtc Exp $   */
-
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
  *      The Regents of the University of California.  All rights reserved.
@@ -37,6 +34,9 @@
  *      @(#)errno.h     8.5 (Berkeley) 1/21/94
  */
 
+#ifndef _ERRNO_DEFS_H_
+#define _ERRNO_DEFS_H_
+
 #define TARGET_EPERM            1               /* Operation not permitted */
 #define TARGET_ENOENT           2               /* No such file or directory */
 #define TARGET_ESRCH            3               /* No such process */
@@ -147,3 +147,10 @@
 #define TARGET_EIDRM            89              /* Identifier removed */
 #define TARGET_ENOMSG           90              /* No message of desired type */
 #define TARGET_ELAST            90              /* Must be equal largest errno */
+
+/* Internal errors: */
+#define TARGET_EJUSTRETURN      254             /* Just return without
+                                                   modifing regs */
+#define TARGET_ERESTART         255             /* Restart syscall */
+
+#endif /* !  _ERRNO_DEFS_H_ */
diff --git a/bsd-user/freebsd/os-signal.h b/bsd-user/freebsd/os-signal.h
new file mode 100644
index 0000000..d4a26da
--- /dev/null
+++ b/bsd-user/freebsd/os-signal.h
@@ -0,0 +1,43 @@
+/*
+ *  FreeBSD signal system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_OS_SIGNAL_H_
+#define __FREEBSD_OS_SIGNAL_H_
+
+#include <sys/procdesc.h>
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+/* pdkill(2) */
+static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(pdkill(arg1, arg2));
+}
+
+#else
+
+static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdkill()\n");
+    return -TARGET_ENOSYS;
+}
+#endif /* ! __FreeBSD_version > 900000 */
+
+#endif /* ! __FREEBSD_OS_SIGNAL_H_ */
diff --git a/bsd-user/freebsd/target_os_siginfo.h b/bsd-user/freebsd/target_os_siginfo.h
new file mode 100644
index 0000000..39180ec
--- /dev/null
+++ b/bsd-user/freebsd/target_os_siginfo.h
@@ -0,0 +1,110 @@
+/*
+ *  FreeBSD siginfo related definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_OS_SIGINFO_H_
+#define _TARGET_OS_SIGINFO_H_
+
+#define TARGET_NSIG         128
+#define TARGET_NSIG_BPW     (sizeof(uint32_t) * 8)
+#define TARGET_NSIG_WORDS   (TARGET_NSIG / TARGET_NSIG_BPW)
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+    abi_long    ss_sp;
+    abi_ulong   ss_size;
+    abi_long    ss_flags;
+} target_stack_t;
+
+typedef struct {
+    uint32_t __bits[TARGET_NSIG_WORDS];
+} target_sigset_t;
+
+struct target_sigaction {
+    abi_ulong   _sa_handler;
+    int32_t     sa_flags;
+    target_sigset_t sa_mask;
+};
+
+union target_sigval {
+    int32_t sival_int;
+    abi_ulong sival_ptr;
+    int32_t sigval_int;
+    abi_ulong sigval_ptr;
+};
+
+typedef struct target_siginfo {
+    int32_t si_signo;   /* signal number */
+    int32_t si_errno;   /* errno association */
+    int32_t si_code;    /* signal code */
+    int32_t si_pid;     /* sending process */
+    int32_t si_uid;     /* sender's ruid */
+    int32_t si_status;  /* exit value */
+    abi_ulong si_addr;  /* faulting instruction */
+    union target_sigval si_value;   /* signal value */
+    union {
+        struct {
+            int32_t _trapno;    /* machine specific trap code */
+        } _fault;
+
+        /* POSIX.1b timers */
+        struct {
+            int32_t _timerid;
+            int32_t _overrun;
+        } _timer;
+
+        struct {
+            int32_t _mqd;
+        } _mesgp;
+
+        /* SIGPOLL */
+        struct {
+            int _band;  /* POLL_IN, POLL_OUT, POLL_MSG */
+        } _poll;
+
+        struct {
+            abi_long __spare1__;
+            int32_t  __spare2_[7];
+        } __spare__;
+    } _reason;
+} target_siginfo_t;
+
+#define target_si_signo     si_signo
+#define target_si_code      si_code
+#define target_si_errno     si_errno
+#define target_si_addr      si_addr
+
+/* SIGILL si_codes */
+#define TARGET_ILL_ILLOPC   (1) /* Illegal opcode. */
+#define TARGET_ILL_ILLOPN   (2) /* Illegal operand. */
+#define TARGET_ILL_ILLADR   (3) /* Illegal addressing mode. */
+#define TARGET_ILL_ILLTRP   (4) /* Illegal trap. */
+#define TARGET_ILL_PRVOPC   (5) /* Privileged opcode. */
+#define TARGET_ILL_PRVREG   (6) /* Privileged register. */
+#define TARGET_ILL_COPROC   (7) /* Coprocessor error. */
+#define TARGET_ILL_BADSTK   (8) /* Internal stack error. */
+
+/* SIGSEGV si_codes */
+#define TARGET_SEGV_MAPERR  (1) /* address not mapped to object */
+#define TARGET_SEGV_ACCERR  (2) /* invalid permissions for mapped
+                                           object */
+
+/* SIGTRAP si_codes */
+#define TARGET_TRAP_BRKPT   (1) /* process beakpoint */
+#define TARGET_TRAP_TRACE   (2) /* process trace trap */
+
+#endif /* !_TARGET_OS_SIGINFO_H_ */
diff --git a/bsd-user/freebsd/target_os_signal.h b/bsd-user/freebsd/target_os_signal.h
new file mode 100644
index 0000000..d7004c8
--- /dev/null
+++ b/bsd-user/freebsd/target_os_signal.h
@@ -0,0 +1,79 @@
+#ifndef _TARGET_OS_SIGNAL_H_
+#define _TARGET_OS_SIGNAL_H_
+
+#include "target_os_siginfo.h"
+#include "target_arch_signal.h"
+
+/* Compare to sys/signal.h */
+#define TARGET_SIGHUP  1       /* hangup */
+#define TARGET_SIGINT  2       /* interrupt */
+#define TARGET_SIGQUIT 3       /* quit */
+#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
+#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
+#define TARGET_SIGABRT 6       /* abort() */
+#define TARGET_SIGIOT  SIGABRT /* compatibility */
+#define TARGET_SIGEMT  7       /* EMT instruction */
+#define TARGET_SIGFPE  8       /* floating point exception */
+#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
+#define TARGET_SIGBUS  10      /* bus error */
+#define TARGET_SIGSEGV 11      /* segmentation violation */
+#define TARGET_SIGSYS  12      /* bad argument to system call */
+#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
+#define TARGET_SIGALRM 14      /* alarm clock */
+#define TARGET_SIGTERM 15      /* software termination signal from kill */
+#define TARGET_SIGURG  16      /* urgent condition on IO channel */
+#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
+#define TARGET_SIGTSTP 18      /* stop signal from tty */
+#define TARGET_SIGCONT 19      /* continue a stopped process */
+#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
+#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
+#define TARGET_SIGTTOU 22      /* like TTIN for output if(tp->t_local&LTOSTOP)*/
+#define TARGET_SIGIO   23      /* input/output possible signal */
+#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
+#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
+#define TARGET_SIGVTALRM 26    /* virtual time alarm */
+#define TARGET_SIGPROF 27      /* profiling time alarm */
+#define TARGET_SIGWINCH 28     /* window size changes */
+#define TARGET_SIGINFO  29     /* information request */
+#define TARGET_SIGUSR1 30      /* user defined signal 1 */
+#define TARGET_SIGUSR2 31      /* user defined signal 2 */
+#define TARGET_SIGTHR 32       /* reserved by thread library */
+#define TARGET_SIGLWP SIGTHR   /* compatibility */
+#define TARGET_SIGLIBRT 33     /* reserved by the real-time library */
+#define TARGET_SIGRTMIN 65
+#define TARGET_SIGRTMAX 126
+#define TARGET_QEMU_ESIGRETURN  255 /* fake errno value for use by sigreturn */
+
+/*
+ * Language spec says we must list exactly one parameter, even though we
+ * actually supply three.  Ugh!
+ */
+#define TARGET_SIG_DFL      ((abi_long)0)   /* default signal handling */
+#define TARGET_SIG_IGN      ((abi_long)1)   /* ignore signal */
+#define TARGET_SIG_ERR      ((abi_long)-1)  /* error return from signal */
+
+#define TARGET_SA_ONSTACK   0x0001  /* take signal on signal stack */
+#define TARGET_SA_RESTART   0x0002  /* restart system on signal return */
+#define TARGET_SA_RESETHAND 0x0004  /* reset to SIG_DFL when taking signal */
+#define TARGET_SA_NODEFER   0x0010  /* don't mask the signal we're delivering */
+#define TARGET_SA_NOCLDWAIT 0x0020  /* don't create zombies (assign to pid 1) */
+#define TARGET_SA_USERTRAMP 0x0100  /* do not bounce off kernel's sigtramp */
+#define TARGET_SA_NOCLDSTOP 0x0008  /* do not generate SIGCHLD on child stop */
+#define TARGET_SA_SIGINFO   0x0040  /* generate siginfo_t */
+
+/*
+ * Flags for sigprocmask:
+ */
+#define TARGET_SIG_BLOCK        1   /* block specified signal set */
+#define TARGET_SIG_UNBLOCK      2   /* unblock specified signal set */
+#define TARGET_SIG_SETMASK      3   /* set specified signal set */
+
+#define TARGET_BADSIG           SIG_ERR
+
+/*
+ * sigaltstack control
+ */
+#define TARGET_SS_ONSTACK 0x0001  /* take signals on alternate stack */
+#define TARGET_SS_DISABLE 0x0004  /* disable taking signals on alternate stack*/
+
+#endif /* !_TARGET_OS_SIGNAL_H_ */
diff --git a/bsd-user/i386/target_arch_signal.h b/bsd-user/i386/target_arch_signal.h
new file mode 100644
index 0000000..e2387b2
--- /dev/null
+++ b/bsd-user/i386/target_arch_signal.h
@@ -0,0 +1,94 @@
+/*
+ *  i386 dependent signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef TARGET_ARCH_SIGNAL_H
+#define TARGET_ARCH_SIGNAL_H
+
+#include "cpu.h"
+
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE    (0) */      /* XXX to be added. */
+
+/* compare to  x86/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (512 * 4)               /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to i386/i386/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long set_sigtramp_args(CPUX86State *regs,
+        int sig, struct target_sigframe *frame, abi_ulong frame_addr,
+        struct target_sigaction *ka)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to i386/i386/machdep.c get_mcontext() */
+static inline abi_long get_mcontext(CPUX86State *regs,
+        target_mcontext_t *mcp, int flags)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to i386/i386/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUX86State *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUX86State *regs,
+                        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    /* XXX */
+    *target_uc = 0;
+    return -TARGET_EOPNOTSUPP;
+}
+
+#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/mips/target_arch_signal.h b/bsd-user/mips/target_arch_signal.h
new file mode 100644
index 0000000..79d6f65
--- /dev/null
+++ b/bsd-user/mips/target_arch_signal.h
@@ -0,0 +1,237 @@
+/*
+ *  mips signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+#define TARGET_INSN_SIZE    4       /* mips instruction size */
+
+/* Size of the signal trampolin code. See insall_sigtramp(). */
+#define TARGET_SZSIGCODE    ((abi_ulong)(4 * TARGET_INSN_SIZE))
+
+/* compare to mips/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (512 * 4)                   /* min sig stack size */
+#define TARGET_SIGSTKSZ     (TARGET_MINSIGSTKSZ + 32768)  /* recommended size */
+
+/* compare to sys/mips/include/asm.h */
+#define TARGET_SZREG        8
+#define TARGET_CALLFRAME_SIZ    (TARGET_SZREG * 4)
+
+/* mips/mips/pm_machdep.c */
+#define TARGET_UCONTEXT_MAGIC   0xACEDBADE
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC     0x0002
+#define TARGET_MC_SET_ONSTACK   0x0004
+
+struct target_sigcontext {
+    target_sigset_t sc_mask;    /* signal mask to retstore */
+    int32_t     sc_onstack;     /* sigstack state to restore */
+    abi_long    sc_pc;          /* pc at time of signal */
+    abi_long    sc_reg[32];     /* processor regs 0 to 31 */
+    abi_long    mullo, mulhi;   /* mullo and mulhi registers */
+    int32_t     sc_fpused;      /* fp has been used */
+    abi_long    sc_fpregs[33];  /* fp regs 0 to 31 & csr */
+    abi_long    sc_fpc_eir;     /* fp exception instr reg */
+    /* int32_t reserved[8]; */
+};
+
+typedef struct target_mcontext {
+    int32_t     mc_onstack;     /* sigstack state to restore */
+    abi_long    mc_pc;          /* pc at time of signal */
+    abi_long    mc_regs[32];    /* process regs 0 to 31 */
+    abi_long    sr;             /* status register */
+    abi_long    mullo, mulhi;
+    int32_t     mc_fpused;      /* fp has been used */
+    abi_long    mc_fpregs[33];  /* fp regs 0 to 32 & csr */
+    abi_long    mc_fpc_eir;     /* fp exception instr reg */
+    abi_ulong   mc_tls;         /* pointer to TLS area */
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to mips/mips/pm_machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
+    abi_ulong frame_addr, struct target_sigaction *ka)
+{
+
+    /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */
+
+    /* MIPS only struct target_sigframe members: */
+    frame->sf_signum = sig;
+    frame->sf_siginfo = frame_addr + offsetof(struct target_sigframe, sf_si);
+    frame->sf_ucontext = frame_addr + offsetof(struct target_sigframe, sf_uc);
+
+    /*
+     * Arguments to signal handler:
+     *  a0 ($4) = signal number
+     *  a1 ($5) = siginfo pointer
+     *  a2 ($6) = ucontext pointer
+     *  PC = signal handler pointer
+     *  t9 ($25) = signal handler pointer
+     *  $29 = point to sigframe struct
+     *  ra ($31) = sigtramp at base of user stack
+     */
+    regs->active_tc.gpr[4] = sig;
+    regs->active_tc.gpr[5] = frame_addr +
+        offsetof(struct target_sigframe, sf_si);
+    regs->active_tc.gpr[6] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+    regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler;
+    regs->active_tc.gpr[29] = frame_addr;
+    regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+
+    return 0;
+}
+
+/*
+ * Compare to mips/mips/pm_machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
+        int flags)
+{
+    int i, err = 0;
+
+    if (flags & TARGET_MC_ADD_MAGIC) {
+        mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC);
+    } else {
+        mcp->mc_regs[0] = 0;
+    }
+
+    if (flags & TARGET_MC_SET_ONSTACK) {
+        mcp->mc_onstack = tswapal(1);
+    } else {
+        mcp->mc_onstack = 0;
+    }
+
+    for (i = 1; i < 32; i++) {
+        mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]);
+    }
+
+#if 0 /* XXX FP is not used right now */
+    abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0;
+
+    mcp->mc_fpused = used_fp;
+    if (used_fp) {
+        preempt_disable();
+        if (!is_fpu_owner()) {
+            own_fpu();
+            for (i = 0; i < 33; i++) {
+                mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]);
+            }
+        }
+        preempt_enable();
+    }
+#else
+    mcp->mc_fpused = 0;
+#endif
+
+    if (flags & TARGET_MC_GET_CLEAR_RET) {
+        mcp->mc_regs[2] = 0;    /* v0 = 0 */
+        mcp->mc_regs[3] = 0;    /* v1 = 0 */
+        mcp->mc_regs[7] = 0;    /* a3 = 0 */
+    }
+
+    mcp->mc_pc = tswapal(regs->active_tc.PC);
+    mcp->mullo = tswapal(regs->active_tc.LO[0]);
+    mcp->mulhi = tswapal(regs->active_tc.HI[0]);
+    mcp->mc_tls = tswapal(regs->tls_value);
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+/* Compare to mips/mips/pm_machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
+        int srflag)
+{
+    int i, err = 0;
+
+    for (i = 1; i < 32; i++) {
+        regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]);
+    }
+
+#if 0  /* XXX FP is not used right now */
+    abi_ulong used_fp = 0;
+
+    used_fp = tswapal(mcp->mc_fpused)
+    conditional_used_math(used_fp);
+
+    preempt_disabled();
+    if (used_math()) {
+        /* restore fpu context if we have used it before */
+        own_fpu();
+        for (i = 0; i < 32; i++) {
+            regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]);
+        }
+    } else {
+        /* Signal handler may have used FPU.  Give it up. */
+        lose_fpu();
+    }
+    preempt_enable();
+#endif
+
+    regs->CP0_EPC = tswapal(mcp->mc_pc);
+    regs->active_tc.LO[0] = tswapal(mcp->mullo);
+    regs->active_tc.HI[0] = tswapal(mcp->mulhi);
+    regs->tls_value = tswapal(mcp->mc_tls);
+
+    if (srflag) {
+        /* doing sigreturn() */
+        regs->active_tc.PC = regs->CP0_EPC;
+        regs->CP0_EPC = 0;  /* XXX  for nested signals ? */
+    }
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUMIPSState *regs,
+                abi_ulong target_sf, abi_ulong *target_uc)
+{
+
+    *target_uc = target_sf;
+    return 0;
+}
+
+
+#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/mips64/target_arch_signal.h b/bsd-user/mips64/target_arch_signal.h
new file mode 100644
index 0000000..2f79a24
--- /dev/null
+++ b/bsd-user/mips64/target_arch_signal.h
@@ -0,0 +1,214 @@
+/*
+ *  mips64 signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+#define TARGET_INSN_SIZE     4  /* mips64 instruction size */
+
+/* Size of the signal trampolin code placed on the stack. */
+#define TARGET_SZSIGCODE    ((abi_ulong)(4 * TARGET_INSN_SIZE))
+
+#define TARGET_MINSIGSTKSZ  (512 * 4)
+#define TARGET_SIGSTKSZ     (TARGET_MINSIGSTKSZ + 32768)
+
+/* compare to sys/mips/include/asm.h */
+#define TARGET_SZREG        8
+#define TARGET_CALLFRAME_SIZ    (TARGET_SZREG * 4)
+
+/* mips/mips/pm_machdep.c */
+#define TARGET_UCONTEXT_MAGIC   0xACEDBADE
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC     0x0002
+#define TARGET_MC_SET_ONSTACK   0x0004
+
+struct target_sigcontext {
+    target_sigset_t sc_mask;    /* signal mask to retstore */
+    int32_t     sc_onstack;     /* sigstack state to restore */
+    abi_long    sc_pc;          /* pc at time of signal */
+    abi_long    sc_reg[32];     /* processor regs 0 to 31 */
+    abi_long    mullo, mulhi;   /* mullo and mulhi registers */
+    int32_t     sc_fpused;      /* fp has been used */
+    abi_long    sc_fpregs[33];  /* fp regs 0 to 31 & csr */
+    abi_long    sc_fpc_eir;     /* fp exception instr reg */
+    /* int32_t reserved[8]; */
+};
+
+typedef struct target_mcontext {
+    int32_t     mc_onstack;     /* sigstack state to restore */
+    abi_long    mc_pc;          /* pc at time of signal */
+    abi_long    mc_regs[32];    /* process regs 0 to 31 */
+    abi_long    sr;             /* status register */
+    abi_long    mullo, mulhi;
+    int32_t     mc_fpused;      /* fp has been used */
+    abi_long    mc_fpregs[33];  /* fp regs 0 to 32 & csr */
+    abi_long    mc_fpc_eir;     /* fp exception instr reg */
+    abi_ulong   mc_tls;         /* pointer to TLS area */
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to mips/mips/pm_machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
+    abi_ulong frame_addr, struct target_sigaction *ka)
+{
+
+    /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */
+
+    /* MIPS only struct target_sigframe members: */
+    frame->sf_signum = sig;
+    frame->sf_siginfo = frame_addr + offsetof(struct target_sigframe, sf_si);
+    frame->sf_ucontext = frame_addr + offsetof(struct target_sigframe, sf_uc);
+
+    /*
+     * Arguments to signal handler:
+     *  a0 ($4) = signal number
+     *  a1 ($5) = siginfo pointer
+     *  a2 ($6) = ucontext pointer
+     *  PC = signal handler pointer
+     *  t9 ($25) = signal handler pointer
+     *  $29 = point to sigframe struct
+     *  ra ($31) = sigtramp at base of user stack
+     */
+    regs->active_tc.gpr[4] = sig;
+    regs->active_tc.gpr[5] = frame_addr +
+        offsetof(struct target_sigframe, sf_si);
+    regs->active_tc.gpr[6] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+    regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler;
+    regs->active_tc.gpr[29] = frame_addr;
+    regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+
+    return 0;
+}
+
+/*
+ * Compare to mips/mips/pm_machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
+        int flags)
+{
+    int i, err = 0;
+
+    if (flags & TARGET_MC_ADD_MAGIC) {
+        mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC);
+    } else {
+        mcp->mc_regs[0] = 0;
+    }
+
+    if (flags & TARGET_MC_SET_ONSTACK) {
+        mcp->mc_onstack = tswapal(1);
+    } else {
+        mcp->mc_onstack = 0;
+    }
+
+    for (i = 1; i < 32; i++) {
+        mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]);
+    }
+
+    mcp->mc_fpused = 1;
+    for (i = 0; i < 32; i++) {
+        mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i].d);
+    }
+    mcp->mc_fpregs[32] = tswapal(regs->active_fpu.fcr0);
+    mcp->mc_fpc_eir = tswapal(regs->active_fpu.fcr31);
+
+    if (flags & TARGET_MC_GET_CLEAR_RET) {
+        mcp->mc_regs[2] = 0;    /* v0 = 0 */
+        mcp->mc_regs[3] = 0;    /* v1 = 0 */
+        mcp->mc_regs[7] = 0;    /* a3 = 0 */
+    }
+
+    mcp->mc_pc = tswapal(regs->active_tc.PC);
+    mcp->mullo = tswapal(regs->active_tc.LO[0]);
+    mcp->mulhi = tswapal(regs->active_tc.HI[0]);
+    mcp->mc_tls = tswapal(regs->tls_value);
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+/* Compare to mips/mips/pm_machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
+        int srflag)
+{
+    int i, err = 0;
+
+    for (i = 1; i < 32; i++) {
+        regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]);
+    }
+
+    if (mcp->mc_fpused) {
+        /* restore fpu context if we have used it before */
+        for (i = 0; i < 32; i++) {
+            regs->active_fpu.fpr[i].d = tswapal(mcp->mc_fpregs[i]);
+        }
+        regs->active_fpu.fcr0 = tswapal(mcp->mc_fpregs[32]);
+        regs->active_fpu.fcr31 = tswapal(mcp->mc_fpc_eir);
+    }
+
+    regs->CP0_EPC = tswapal(mcp->mc_pc);
+    regs->active_tc.LO[0] = tswapal(mcp->mullo);
+    regs->active_tc.HI[0] = tswapal(mcp->mulhi);
+    regs->tls_value = tswapal(mcp->mc_tls);
+
+    if (srflag) {
+        /* doing sigreturn() */
+        regs->active_tc.PC = regs->CP0_EPC;
+        regs->CP0_EPC = 0;  /* XXX  for nested signals ? */
+    }
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUMIPSState *regs,
+                        abi_ulong target_sf, abi_ulong *target_uc)
+{
+
+    /* mips passes ucontext struct as the stack frame */
+    *target_uc = target_sf;
+    return 0;
+}
+
+#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/netbsd/target_os_siginfo.h b/bsd-user/netbsd/target_os_siginfo.h
new file mode 100644
index 0000000..667c19c
--- /dev/null
+++ b/bsd-user/netbsd/target_os_siginfo.h
@@ -0,0 +1,82 @@
+#ifndef _TARGET_OS_SIGINFO_H_
+#define _TARGET_OS_SIGINFO_H_
+
+#define TARGET_NSIG     32  /* counting 0; could be 33 (mask is 1-32) */
+#define TARGET_NSIG_BPW     (sizeof(uint32_t) * 8)
+#define TARGET_NSIG_WORDS   (TARGET_NSIG / TARGET_NSIG_BPW)
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+    abi_long    ss_sp;
+    abi_ulong   ss_size;
+    abi_long    ss_flags;
+} target_stack_t;
+
+typedef struct {
+    uint32_t __bits[TARGET_NSIG_WORDS];
+} target_sigset_t
+
+struct target_sigaction {
+    abi_ulong   _sa_handler;
+    int32_t     sa_flags;
+    target_sigset_t sa_mask;
+};
+
+/* Compare to sys/siginfo.h */
+typedef union target_sigval {
+    int         sival_int;
+    abi_ulong   sival_ptr;
+} target_sigval_t;
+
+struct target_ksiginfo {
+    int32_t     _signo;
+    int32_t     _code;
+    int32_t     _errno;
+#if TARGET_ABI_BITS == 64
+    int32_t     _pad;
+#endif
+    union {
+        struct {
+            int32_t             _pid;
+            int32_t             _uid;
+            target_sigval_t    _value;
+        } _rt;
+
+        struct {
+            int32_t             _pid;
+            int32_t             _uid;
+            int32_t             _struct;
+            /* clock_t          _utime; */
+            /* clock_t          _stime; */
+        } _child;
+
+        struct {
+            abi_ulong           _addr;
+            int32_t             _trap;
+        } _fault;
+
+        struct {
+            long                _band;
+            int                 _fd;
+        } _poll;
+    } _reason;
+};
+
+typedef union target_siginfo {
+    int8_t     si_pad[128];
+    struct     target_ksiginfo  _info;
+} target_siginfo_t;
+
+#define target_si_signo     _info._signo
+#define target_si_code      _info._code
+#define target_si_errno     _info._errno
+#define target_si_addr      _info._reason._fault._addr
+
+#define TARGET_SEGV_MAPERR  1
+#define TARGET_SEGV_ACCERR  2
+
+#define TARGET_TRAP_BRKPT   1
+#define TARGET_TRAP_TRACE   2
+
+
+#endif /* ! _TARGET_OS_SIGINFO_H_ */
diff --git a/bsd-user/netbsd/target_os_signal.h b/bsd-user/netbsd/target_os_signal.h
new file mode 100644
index 0000000..d39a26f
--- /dev/null
+++ b/bsd-user/netbsd/target_os_signal.h
@@ -0,0 +1,70 @@
+#ifndef _TARGET_OS_SIGNAL_H_
+#define _TARGET_OS_SIGNAL_H_
+
+#include "target_os_siginfo.h"
+#include "target_arch_signal.h"
+
+#define TARGET_SIGHUP  1       /* hangup */
+#define TARGET_SIGINT  2       /* interrupt */
+#define TARGET_SIGQUIT 3       /* quit */
+#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
+#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
+#define TARGET_SIGABRT 6       /* abort() */
+#define TARGET_SIGIOT  SIGABRT /* compatibility */
+#define TARGET_SIGEMT  7       /* EMT instruction */
+#define TARGET_SIGFPE  8       /* floating point exception */
+#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
+#define TARGET_SIGBUS  10      /* bus error */
+#define TARGET_SIGSEGV 11      /* segmentation violation */
+#define TARGET_SIGSYS  12      /* bad argument to system call */
+#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
+#define TARGET_SIGALRM 14      /* alarm clock */
+#define TARGET_SIGTERM 15      /* software termination signal from kill */
+#define TARGET_SIGURG  16      /* urgent condition on IO channel */
+#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
+#define TARGET_SIGTSTP 18      /* stop signal from tty */
+#define TARGET_SIGCONT 19      /* continue a stopped process */
+#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
+#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
+#define TARGET_SIGTTOU 22      /* like TTIN for output if
+                                  (tp->t_local&LTOSTOP) */
+#define TARGET_SIGIO   23      /* input/output possible signal */
+#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
+#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
+#define TARGET_SIGVTALRM 26    /* virtual time alarm */
+#define TARGET_SIGPROF   27    /* profiling time alarm */
+#define TARGET_SIGWINCH  28    /* window size changes */
+#define TARGET_SIGINFO   29    /* information request */
+#define TARGET_SIGUSR1   30    /* user defined signal 1 */
+#define TARGET_SIGUSR2   31    /* user defined signal 2 */
+
+/*
+ * Language spec says we must list exactly one parameter, even though we
+ * actually supply three.  Ugh!
+ */
+#define TARGET_SIG_DFL         ((void (*)(int))0)
+#define TARGET_SIG_IGN         ((void (*)(int))1)
+#define TARGET_SIG_ERR         ((void (*)(int))-1)
+
+#define TARGET_SA_ONSTACK   0x0001  /* take signal on signal stack */
+#define TARGET_SA_RESTART   0x0002  /* restart system on signal return */
+#define TARGET_SA_RESETHAND 0x0004  /* reset to SIG_DFL when taking signal */
+#define TARGET_SA_NODEFER   0x0010  /* don't mask the signal we're delivering */
+#define TARGET_SA_NOCLDWAIT 0x0020  /* don't create zombies (assign to pid 1) */
+#define TARGET_SA_USERTRAMP 0x0100  /* do not bounce off kernel's sigtramp */
+#define TARGET_SA_NOCLDSTOP 0x0008  /* do not generate SIGCHLD on child stop */
+#define TARGET_SA_SIGINFO   0x0040  /* generate siginfo_t */
+
+/*
+ * Flags for sigprocmask:
+ */
+#define TARGET_SIG_BLOCK       1       /* block specified signal set */
+#define TARGET_SIG_UNBLOCK     2       /* unblock specified signal set */
+#define TARGET_SIG_SETMASK     3       /* set specified signal set */
+
+#define TARGET_BADSIG       SIG_ERR
+
+#define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */
+#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */
+
+#endif /* !_TARGET_OS_SIGNAL_H_ */
diff --git a/bsd-user/openbsd/target_os_siginfo.h b/bsd-user/openbsd/target_os_siginfo.h
new file mode 100644
index 0000000..baf646a
--- /dev/null
+++ b/bsd-user/openbsd/target_os_siginfo.h
@@ -0,0 +1,82 @@
+#ifndef _TARGET_OS_SIGINFO_H_
+#define _TARGET_OS_SIGINFO_H_
+
+#define TARGET_NSIG     32   /* counting 0; could be 33 (mask is 1-32) */
+#define TARGET_NSIG_BPW     (sizeof(uint32_t) * 8)
+#define TARGET_NSIG_WORDS   (TARGET_NSIG / TARGET_NSIG_BPW)
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+    abi_long    ss_sp;
+    abi_ulong   ss_size;
+    abi_long    ss_flags;
+} target_stack_t;
+
+typedef struct {
+    uint32_t __bits[TARGET_NSIG_WORDS];
+} target_sigset_t
+
+struct target_sigaction {
+    abi_ulong   _sa_handler;
+    int32_t     sa_flags;
+    target_sigset_t sa_mask;
+};
+
+/* Compare to sys/siginfo.h */
+typedef union target_sigval {
+    int         sival_int;
+    abi_ulong   sival_ptr;
+} target_sigval_t;
+
+struct target_ksiginfo {
+    int32_t     _signo;
+    int32_t     _code;
+    int32_t     _errno;
+#if TARGET_ABI_BITS == 64
+    int32_t     _pad;
+#endif
+    union {
+        struct {
+            int32_t             _pid;
+            int32_t             _uid;
+            target_sigval_t    _value;
+        } _rt;
+
+        struct {
+            int32_t             _pid;
+            int32_t             _uid;
+            int32_t             _struct;
+            /* clock_t          _utime; */
+            /* clock_t          _stime; */
+        } _child;
+
+        struct {
+            abi_ulong           _addr;
+            int32_t             _trap;
+        } _fault;
+
+        struct {
+            long                _band;
+            int                 _fd;
+        } _poll;
+    } _reason;
+};
+
+typedef union target_siginfo {
+    int8_t     si_pad[128];
+    struct     target_ksiginfo  _info;
+} target_siginfo_t;
+
+#define target_si_signo     _info._signo
+#define target_si_code      _info._code
+#define target_si_errno     _info._errno
+#define target_si_addr      _info._reason._fault._addr
+
+#define TARGET_SEGV_MAPERR  1
+#define TARGET_SEGV_ACCERR  2
+
+#define TARGET_TRAP_BRKPT   1
+#define TARGET_TRAP_TRACE   2
+
+
+#endif /* ! _TARGET_OS_SIGINFO_H_ */
diff --git a/bsd-user/openbsd/target_os_signal.h b/bsd-user/openbsd/target_os_signal.h
new file mode 100644
index 0000000..d39a26f
--- /dev/null
+++ b/bsd-user/openbsd/target_os_signal.h
@@ -0,0 +1,70 @@
+#ifndef _TARGET_OS_SIGNAL_H_
+#define _TARGET_OS_SIGNAL_H_
+
+#include "target_os_siginfo.h"
+#include "target_arch_signal.h"
+
+#define TARGET_SIGHUP  1       /* hangup */
+#define TARGET_SIGINT  2       /* interrupt */
+#define TARGET_SIGQUIT 3       /* quit */
+#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
+#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
+#define TARGET_SIGABRT 6       /* abort() */
+#define TARGET_SIGIOT  SIGABRT /* compatibility */
+#define TARGET_SIGEMT  7       /* EMT instruction */
+#define TARGET_SIGFPE  8       /* floating point exception */
+#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
+#define TARGET_SIGBUS  10      /* bus error */
+#define TARGET_SIGSEGV 11      /* segmentation violation */
+#define TARGET_SIGSYS  12      /* bad argument to system call */
+#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
+#define TARGET_SIGALRM 14      /* alarm clock */
+#define TARGET_SIGTERM 15      /* software termination signal from kill */
+#define TARGET_SIGURG  16      /* urgent condition on IO channel */
+#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
+#define TARGET_SIGTSTP 18      /* stop signal from tty */
+#define TARGET_SIGCONT 19      /* continue a stopped process */
+#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
+#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
+#define TARGET_SIGTTOU 22      /* like TTIN for output if
+                                  (tp->t_local&LTOSTOP) */
+#define TARGET_SIGIO   23      /* input/output possible signal */
+#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
+#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
+#define TARGET_SIGVTALRM 26    /* virtual time alarm */
+#define TARGET_SIGPROF   27    /* profiling time alarm */
+#define TARGET_SIGWINCH  28    /* window size changes */
+#define TARGET_SIGINFO   29    /* information request */
+#define TARGET_SIGUSR1   30    /* user defined signal 1 */
+#define TARGET_SIGUSR2   31    /* user defined signal 2 */
+
+/*
+ * Language spec says we must list exactly one parameter, even though we
+ * actually supply three.  Ugh!
+ */
+#define TARGET_SIG_DFL         ((void (*)(int))0)
+#define TARGET_SIG_IGN         ((void (*)(int))1)
+#define TARGET_SIG_ERR         ((void (*)(int))-1)
+
+#define TARGET_SA_ONSTACK   0x0001  /* take signal on signal stack */
+#define TARGET_SA_RESTART   0x0002  /* restart system on signal return */
+#define TARGET_SA_RESETHAND 0x0004  /* reset to SIG_DFL when taking signal */
+#define TARGET_SA_NODEFER   0x0010  /* don't mask the signal we're delivering */
+#define TARGET_SA_NOCLDWAIT 0x0020  /* don't create zombies (assign to pid 1) */
+#define TARGET_SA_USERTRAMP 0x0100  /* do not bounce off kernel's sigtramp */
+#define TARGET_SA_NOCLDSTOP 0x0008  /* do not generate SIGCHLD on child stop */
+#define TARGET_SA_SIGINFO   0x0040  /* generate siginfo_t */
+
+/*
+ * Flags for sigprocmask:
+ */
+#define TARGET_SIG_BLOCK       1       /* block specified signal set */
+#define TARGET_SIG_UNBLOCK     2       /* unblock specified signal set */
+#define TARGET_SIG_SETMASK     3       /* set specified signal set */
+
+#define TARGET_BADSIG       SIG_ERR
+
+#define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */
+#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */
+
+#endif /* !_TARGET_OS_SIGNAL_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 594de5c..0e332af 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -39,7 +39,7 @@ extern enum BSDType bsd_type;
 #include "syscall_defs.h"
 #include "syscall.h"
 #include "target_os_vmparam.h"
-#include "target_signal.h"
+#include "target_os_signal.h"
 #include "exec/gdbstub.h"
 
 #if defined(CONFIG_USE_NPTL)
@@ -72,16 +72,16 @@ struct image_info {
 
 #define MAX_SIGQUEUE_SIZE 1024
 
-struct sigqueue {
-    struct sigqueue *next;
-    //target_siginfo_t info;
+struct qemu_sigqueue {
+    struct qemu_sigqueue *next;
+    target_siginfo_t info;
 };
 
 struct emulated_sigtable {
     int pending; /* true if signal is pending */
-    struct sigqueue *first;
-    struct sigqueue info; /* in order to always have memory for the
-                             first signal, we put it here */
+    struct qemu_sigqueue *first;
+    struct qemu_sigqueue info; /* in order to always have memory for the
+                                  first signal, we put it here */
 };
 
 /* NOTE: we force a big alignment so that the stack stored after is
@@ -93,8 +93,8 @@ typedef struct TaskState {
     struct bsd_binprm *bprm;
 
     struct emulated_sigtable sigtab[TARGET_NSIG];
-    struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
-    struct sigqueue *first_free; /* first free siginfo queue entry */
+    struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
+    struct qemu_sigqueue *first_free; /* first free siginfo queue entry */
     int signal_pending; /* non zero if a signal may be pending */
 
     uint8_t stack[0];
@@ -202,12 +202,19 @@ extern int do_strace;
 /* signal.c */
 void process_pending_signals(CPUArchState *cpu_env);
 void signal_init(void);
-//int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
-//void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
-//void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
-long do_sigreturn(CPUArchState *env);
+int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
+int target_to_host_signal(int sig);
+int host_to_target_signal(int sig);
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
+long do_sigreturn(CPUArchState *env, abi_ulong addr);
 long do_rt_sigreturn(CPUArchState *env);
 abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
+int do_sigaction(int sig, const struct target_sigaction *act,
+                struct target_sigaction *oact);
+void QEMU_NORETURN force_sig(int target_sig);
 
 /* mmap.c */
 int target_mprotect(abi_ulong start, abi_ulong len, int prot);
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index 445f69e..3619b00 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -2,6 +2,7 @@
  *  Emulation of BSD signals
  *
  *  Copyright (c) 2003 - 2008 Fabrice Bellard
+ *  Copyright (c) 2013 Stacey Son
  *
  *  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
@@ -23,16 +24,920 @@
 #include <unistd.h>
 #include <signal.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 
 #include "qemu.h"
-#include "target_signal.h"
 
 //#define DEBUG_SIGNAL
 
+static target_stack_t target_sigaltstack_used = {
+    .ss_sp = 0,
+    .ss_size = 0,
+    .ss_flags = TARGET_SS_DISABLE,
+};
+
+static uint8_t host_to_target_signal_table[TARGET_NSIG] = {
+    [SIGHUP]    =   TARGET_SIGHUP,
+    [SIGINT]    =   TARGET_SIGINT,
+    [SIGQUIT]   =   TARGET_SIGQUIT,
+    [SIGILL]    =   TARGET_SIGILL,
+    [SIGTRAP]   =   TARGET_SIGTRAP,
+    [SIGABRT]   =   TARGET_SIGABRT,
+    [SIGEMT]    =   TARGET_SIGEMT,
+    [SIGFPE]    =   TARGET_SIGFPE,
+    [SIGKILL]   =   TARGET_SIGKILL,
+    [SIGBUS]    =   TARGET_SIGBUS,
+    [SIGSEGV]   =   TARGET_SIGSEGV,
+    [SIGSYS]    =   TARGET_SIGSYS,
+    [SIGPIPE]   =   TARGET_SIGPIPE,
+    [SIGALRM]   =   TARGET_SIGALRM,
+    [SIGTERM]   =   TARGET_SIGTERM,
+    [SIGURG]    =   TARGET_SIGURG,
+    [SIGSTOP]   =   TARGET_SIGSTOP,
+    [SIGTSTP]   =   TARGET_SIGTSTP,
+    [SIGCONT]   =   TARGET_SIGCONT,
+    [SIGCHLD]   =   TARGET_SIGCHLD,
+    [SIGTTIN]   =   TARGET_SIGTTIN,
+    [SIGTTOU]   =   TARGET_SIGTTOU,
+    [SIGIO]     =   TARGET_SIGIO,
+    [SIGXCPU]   =   TARGET_SIGXCPU,
+    [SIGXFSZ]   =   TARGET_SIGXFSZ,
+    [SIGVTALRM] =   TARGET_SIGVTALRM,
+    [SIGPROF]   =   TARGET_SIGPROF,
+    [SIGWINCH]  =   TARGET_SIGWINCH,
+    [SIGINFO]   =   TARGET_SIGINFO,
+    [SIGUSR1]   =   TARGET_SIGUSR1,
+    [SIGUSR2]   =   TARGET_SIGUSR2,
+#ifdef SIGTHR
+    [SIGTHR + 3]    =   TARGET_SIGTHR,
+#endif
+    /* [SIGLWP] =   TARGET_SIGLWP, */
+#ifdef SIGLIBRT
+    [SIGLIBRT]  =   TARGET_SIGLIBRT,
+#endif
+
+    /*
+     * The following signals stay the same.
+     * Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
+     * host libpthread signals.  This assumes no one actually uses
+     * SIGRTMAX.  To fix this properly we need to manual signal delivery
+     * multiplexed over a single host signal.
+     */
+    [SIGRTMIN]  =   SIGRTMAX,
+    [SIGRTMAX]  =   SIGRTMIN,
+};
+
+static uint8_t target_to_host_signal_table[TARGET_NSIG];
+static struct target_sigaction sigact_table[TARGET_NSIG];
+static void host_signal_handler(int host_signum, siginfo_t *info, void *puc);
+static void target_to_host_sigset_internal(sigset_t *d,
+        const target_sigset_t *s);
+
+static inline int on_sig_stack(unsigned long sp)
+{
+    return sp - target_sigaltstack_used.ss_sp < target_sigaltstack_used.ss_size;
+}
+
+static inline int sas_ss_flags(unsigned long sp)
+{
+    return target_sigaltstack_used.ss_size == 0 ? SS_DISABLE : on_sig_stack(sp)
+        ? SS_ONSTACK : 0;
+}
+
+int host_to_target_signal(int sig)
+{
+
+    if (sig < 0 || sig >= TARGET_NSIG) {
+        return sig;
+    }
+
+    return host_to_target_signal_table[sig];
+}
+
+int target_to_host_signal(int sig)
+{
+
+    if (sig >= TARGET_NSIG) {
+        return sig;
+    }
+
+    return target_to_host_signal_table[sig];
+}
+
+static inline void target_sigemptyset(target_sigset_t *set)
+{
+
+    memset(set, 0, sizeof(*set));
+}
+
+static inline void target_sigaddset(target_sigset_t *set, int signum)
+{
+
+    signum--;
+    uint32_t mask = (uint32_t)1 << (signum % TARGET_NSIG_BPW);
+    set->__bits[signum / TARGET_NSIG_BPW] |= mask;
+}
+
+static inline int target_sigismember(const target_sigset_t *set, int signum)
+{
+
+    signum--;
+    abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
+    return (set->__bits[signum / TARGET_NSIG_BPW] & mask) != 0;
+}
+
+static void host_to_target_sigset_internal(target_sigset_t *d,
+        const sigset_t *s)
+{
+    int i;
+
+    target_sigemptyset(d);
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        if (sigismember(s, i)) {
+            target_sigaddset(d, host_to_target_signal(i));
+        }
+    }
+}
+
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
+{
+    target_sigset_t d1;
+    int i;
+
+    host_to_target_sigset_internal(&d1, s);
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        d->__bits[i] = tswap32(d1.__bits[i]);
+    }
+}
+
+static void target_to_host_sigset_internal(sigset_t *d,
+        const target_sigset_t *s)
+{
+    int i;
+
+    sigemptyset(d);
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        if (target_sigismember(s, i)) {
+            sigaddset(d, target_to_host_signal(i));
+        }
+    }
+}
+
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
+{
+    target_sigset_t s1;
+    int i;
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        s1.__bits[i] = tswap32(s->__bits[i]);
+    }
+    target_to_host_sigset_internal(d, &s1);
+}
+
+/* Siginfo conversion. */
+static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
+        const siginfo_t *info)
+{
+    int sig, code;
+
+    sig = host_to_target_signal(info->si_signo);
+    /* XXX should have host_to_target_si_code() */
+    code = tswap32(info->si_code);
+    tinfo->si_signo = sig;
+    tinfo->si_errno = info->si_errno;
+    tinfo->si_code = info->si_code;
+    tinfo->si_pid = info->si_pid;
+    tinfo->si_uid = info->si_uid;
+    tinfo->si_addr = (abi_ulong)(unsigned long)info->si_addr;
+    /* si_value is opaque to kernel */
+    tinfo->si_value.sival_ptr =
+        (abi_ulong)(unsigned long)info->si_value.sival_ptr;
+    if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig ||
+            SIGTRAP == sig) {
+        tinfo->_reason._fault._trapno = info->_reason._fault._trapno;
+    }
+#ifdef SIGPOLL
+    if (SIGPOLL == sig) {
+        tinfo->_reason._poll._band = info->_reason._poll._band;
+    }
+#endif
+    if (SI_TIMER == code) {
+        tinfo->_reason._timer._timerid = info->_reason._timer._timerid;
+        tinfo->_reason._timer._overrun = info->_reason._timer._overrun;
+    }
+}
+
+static void tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info)
+{
+    int sig, code;
+
+    sig = info->si_signo;
+    code = info->si_code;
+    tinfo->si_signo = tswap32(sig);
+    tinfo->si_errno = tswap32(info->si_errno);
+    tinfo->si_code = tswap32(info->si_code);
+    tinfo->si_pid = tswap32(info->si_pid);
+    tinfo->si_uid = tswap32(info->si_uid);
+    tinfo->si_addr = tswapal(info->si_addr);
+    if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig ||
+            SIGTRAP == sig) {
+        tinfo->_reason._fault._trapno = tswap32(info->_reason._fault._trapno);
+    }
+#ifdef SIGPOLL
+    if (SIGPOLL == sig) {
+        tinfo->_reason._poll._band = tswap32(info->_reason._poll._band);
+    }
+#endif
+    if (SI_TIMER == code) {
+        tinfo->_reason._timer._timerid = tswap32(info->_reason._timer._timerid);
+        tinfo->_reason._timer._overrun = tswap32(info->_reason._timer._overrun);
+    }
+}
+
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
+{
+
+    host_to_target_siginfo_noswap(tinfo, info);
+    tswap_siginfo(tinfo, tinfo);
+}
+
+/* Returns 1 if given signal should dump core if not handled. */
+static int core_dump_signal(int sig)
+{
+    switch (sig) {
+    case TARGET_SIGABRT:
+    case TARGET_SIGFPE:
+    case TARGET_SIGILL:
+    case TARGET_SIGQUIT:
+    case TARGET_SIGSEGV:
+    case TARGET_SIGTRAP:
+    case TARGET_SIGBUS:
+        return 1;
+    default:
+        return 0;
+    }
+}
+
+/* Signal queue handling. */
+static inline struct qemu_sigqueue *alloc_sigqueue(CPUArchState *env)
+{
+    TaskState *ts = env->opaque;
+    struct qemu_sigqueue *q = ts->first_free;
+
+    if (!q) {
+        return NULL;
+    }
+    ts->first_free = q->next;
+    return q;
+}
+
+static inline void free_sigqueue(CPUArchState *env, struct qemu_sigqueue *q)
+{
+
+    TaskState *ts = env->opaque;
+    q->next = ts->first_free;
+    ts->first_free = q;
+}
+
+/* Abort execution with signal. */
+void QEMU_NORETURN force_sig(int target_sig)
+{
+    CPUArchState *env = thread_cpu->env_ptr;
+    TaskState *ts = (TaskState *)env->opaque;
+    int core_dumped = 0;
+    int host_sig;
+    struct sigaction act;
+
+    host_sig = target_to_host_signal(target_sig);
+    gdb_signalled(env, target_sig);
+
+    /* Dump core if supported by target binary format */
+    if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
+        stop_all_tasks();
+        core_dumped =
+            ((*ts->bprm->core_dump)(target_sig, env) == 0);
+    }
+    if (core_dumped) {
+        struct rlimit nodump;
+
+        /*
+         * We already dumped the core of target process, we don't want
+         * a coredump of qemu itself.
+         */
+         getrlimit(RLIMIT_CORE, &nodump);
+         nodump.rlim_cur = 0;
+         setrlimit(RLIMIT_CORE, &nodump);
+         (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) "
+             "- %s\n", target_sig, strsignal(host_sig), "core dumped");
+    }
+
+    /*
+     * The proper exit code for dying from an uncaught signal is
+     * -<signal>.  The kernel doesn't allow exit() or _exit() to pass
+     * a negative value.  To get the proper exit code we need to
+     * actually die from an uncaught signal.  Here the default signal
+     * handler is installed, we send ourself a signal and we wait for
+     * it to arrive.
+     */
+    memset(&act, 0, sizeof(act));
+    sigfillset(&act.sa_mask);
+    act.sa_handler = SIG_DFL;
+    sigaction(host_sig, &act, NULL);
+
+    kill(getpid(), host_sig);
+
+    /*
+     * Make sure the signal isn't masked (just reuse the mask inside
+     * of act).
+     */
+    sigdelset(&act.sa_mask, host_sig);
+    sigsuspend(&act.sa_mask);
+
+    /* unreachable */
+    abort();
+}
+
+/*
+ * Queue a signal so that it will be send to the virtual CPU as soon as
+ * possible.
+ */
+int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
+{
+    TaskState *ts = env->opaque;
+    struct emulated_sigtable *k;
+    struct qemu_sigqueue *q, **pq;
+    abi_ulong handler;
+    int queue;
+
+    k = &ts->sigtab[sig - 1];
+    queue = gdb_queuesig();
+    handler = sigact_table[sig - 1]._sa_handler;
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "queue_signal: sig=%d handler=0x%lx flags=0x%x\n", sig,
+        handler, (uint32_t)sigact_table[sig - 1].sa_flags);
+#endif
+    if (!queue && (TARGET_SIG_DFL == handler)) {
+        if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN ||
+            sig == TARGET_SIGTTOU) {
+            kill(getpid(), SIGSTOP);
+            return 0;
+        } else {
+            if (sig != TARGET_SIGCHLD &&
+                sig != TARGET_SIGURG &&
+                sig != TARGET_SIGWINCH &&
+                sig != TARGET_SIGCONT) {
+                force_sig(sig);
+            } else {
+                return 0; /* The signal was ignored. */
+            }
+        }
+    } else if (!queue && (TARGET_SIG_IGN == handler)) {
+        return 0; /* Ignored signal. */
+    } else if (!queue && (TARGET_SIG_ERR == handler)) {
+        force_sig(sig);
+    } else {
+        pq = &k->first;
+
+        /*
+         * FreeBSD signals are always queued.
+         * Linux only queues real time signals.
+         * XXX this code is not thread safe.
+         */
+        if (!k->pending) {
+            /* first signal */
+            q = &k->info;
+        } else {
+            q = alloc_sigqueue(env);
+            if (!q) {
+                return -EAGAIN;
+            }
+            while (*pq != NULL) {
+                pq = &(*pq)->next;
+            }
+        }
+        *pq = q;
+        q->info = *info;
+        q->next = NULL;
+        k->pending = 1;
+        /* Signal that a new signal is pending. */
+        ts->signal_pending = 1;
+        return 1; /* Indicates that the signal was queued. */
+    }
+}
+
+static void host_signal_handler(int host_signum, siginfo_t *info, void *puc)
+{
+    CPUArchState *env = thread_cpu->env_ptr;
+    int sig;
+    target_siginfo_t tinfo;
+
+    /*
+     * The CPU emulator uses some host signal to detect exceptions so
+     * we forward to it some signals.
+     */
+    if ((host_signum == SIGSEGV || host_signum == SIGBUS) &&
+            info->si_code < 0x10000) {
+        if (cpu_signal_handler(host_signum, info, puc)) {
+            return;
+        }
+    }
+
+    /* Get the target signal number. */
+    sig = host_to_target_signal(host_signum);
+    if (sig < 1 || sig > TARGET_NSIG) {
+        return;
+    }
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: got signal %d\n", sig);
+#endif
+    host_to_target_siginfo_noswap(&tinfo, info);
+    if (queue_signal(env, sig, &tinfo) == 1) {
+        /* Interrupt the virtual CPU as soon as possible. */
+        cpu_exit(thread_cpu);
+    }
+}
+
+/* do_sigaltstack() returns target values and errnos.  */
+/* compare to kern/kern_sig.c sys_sigaltstack() and kern_sigaltstack() */
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
+{
+    int ret = 0;
+    target_stack_t ss, oss, *uss;
+
+    if (uoss_addr) {
+        /* Save current signal stack params */
+        oss.ss_sp = tswapl(target_sigaltstack_used.ss_sp);
+        oss.ss_size = tswapl(target_sigaltstack_used.ss_size);
+        oss.ss_flags = tswapl(sas_ss_flags(sp));
+    }
+
+    if (uss_addr) {
+
+        if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1) ||
+            __get_user(ss.ss_sp, &uss->ss_sp) ||
+            __get_user(ss.ss_size, &uss->ss_size) ||
+            __get_user(ss.ss_flags, &uss->ss_flags)) {
+            ret = -TARGET_EFAULT;
+            goto out;
+        }
+        unlock_user_struct(uss, uss_addr, 0);
+
+        if (on_sig_stack(sp)) {
+            ret = -TARGET_EPERM;
+            goto out;
+        }
+
+        if ((ss.ss_flags & ~TARGET_SS_DISABLE) != 0) {
+            ret = -TARGET_EINVAL;
+            goto out;
+        }
+
+        if (!(ss.ss_flags & ~TARGET_SS_DISABLE)) {
+            if (ss.ss_size < TARGET_MINSIGSTKSZ) {
+                ret = -TARGET_ENOMEM;
+                goto out;
+            }
+        } else {
+            ss.ss_size = 0;
+            ss.ss_sp = 0;
+        }
+
+        target_sigaltstack_used.ss_sp = ss.ss_sp;
+        target_sigaltstack_used.ss_size = ss.ss_size;
+    }
+
+    if (uoss_addr) {
+        /* Copy out to user saved signal stack params */
+        if (copy_to_user(uoss_addr, &oss, sizeof(oss))) {
+            ret = -TARGET_EFAULT;
+            goto out;
+        }
+    }
+
+out:
+    return ret;
+}
+
+static int fatal_signal(int sig)
+{
+
+    switch (sig) {
+    case TARGET_SIGCHLD:
+    case TARGET_SIGURG:
+    case TARGET_SIGWINCH:
+        /* Ignored by default. */
+        return 0;
+    case TARGET_SIGCONT:
+    case TARGET_SIGSTOP:
+    case TARGET_SIGTSTP:
+    case TARGET_SIGTTIN:
+    case TARGET_SIGTTOU:
+        /* Job control signals.  */
+        return 0;
+    default:
+        return 1;
+    }
+}
+
+/* do_sigaction() return host values and errnos */
+int do_sigaction(int sig, const struct target_sigaction *act,
+        struct target_sigaction *oact)
+{
+    struct target_sigaction *k;
+    struct sigaction act1;
+    int host_sig;
+    int ret = 0;
+
+    if (sig < 1 || sig > TARGET_NSIG || TARGET_SIGKILL == sig ||
+            TARGET_SIGSTOP == sig) {
+        return -EINVAL;
+    }
+    k = &sigact_table[sig - 1];
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_sigaction sig=%d act=%p, oact=%p\n",
+        sig, act, oact);
+#endif
+    if (oact) {
+        oact->_sa_handler = tswapal(k->_sa_handler);
+        oact->sa_flags = tswap32(k->sa_flags);
+        oact->sa_mask = k->sa_mask;
+    }
+    if (act) {
+        /* XXX: this is most likely not threadsafe. */
+        k->_sa_handler = tswapal(act->_sa_handler);
+        k->sa_flags = tswap32(act->sa_flags);
+        k->sa_mask = act->sa_mask;
+
+        /* Update the host signal state. */
+        host_sig = target_to_host_signal(sig);
+        if (host_sig != SIGSEGV && host_sig != SIGBUS) {
+            memset(&act1, 0, sizeof(struct sigaction));
+            sigfillset(&act1.sa_mask);
+            if (k->sa_flags & TARGET_SA_RESTART) {
+                act1.sa_flags |= SA_RESTART;
+            }
+            /*
+             *  Note: It is important to update the host kernel signal mask to
+             *  avoid getting unexpected interrupted system calls.
+             */
+            if (k->_sa_handler == TARGET_SIG_IGN) {
+                act1.sa_sigaction = (void *)SIG_IGN;
+            } else if (k->_sa_handler == TARGET_SIG_DFL) {
+                if (fatal_signal(sig)) {
+                    act1.sa_flags = SA_SIGINFO;
+                    act1.sa_sigaction = host_signal_handler;
+                } else {
+                    act1.sa_sigaction = (void *)SIG_DFL;
+                }
+            } else {
+                act1.sa_flags = SA_SIGINFO;
+                act1.sa_sigaction = host_signal_handler;
+            }
+            ret = sigaction(host_sig, &act1, NULL);
+#if defined(DEBUG_SIGNAL)
+            fprintf(stderr, "sigaction (action = %p "
+                    "(host_signal_handler = %p)) returned: %d\n",
+                    act1.sa_sigaction, host_signal_handler, ret);
+#endif
+        }
+    }
+    return ret;
+}
+
+static inline abi_ulong get_sigframe(struct target_sigaction *ka,
+        CPUArchState *regs, size_t frame_size)
+{
+    abi_ulong sp;
+
+    /* Use default user stack */
+    sp = get_sp_from_cpustate(regs);
+
+    if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
+        sp = target_sigaltstack_used.ss_sp +
+            target_sigaltstack_used.ss_size;
+    }
+
+#if defined(TARGET_MIPS) || defined(TARGET_ARM)
+    return (sp - frame_size) & ~7;
+#else
+    return sp - frame_size;
+#endif
+}
+
+/* compare to mips/mips/pm_machdep.c and sparc64/sparc64/machdep.c sendsig() */
+static void setup_frame(int sig, int code, struct target_sigaction *ka,
+    target_sigset_t *set, target_siginfo_t *tinfo, CPUArchState *regs)
+{
+    struct target_sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "setup_frame()\n");
+#endif
+    frame_addr = get_sigframe(ka, regs, sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+        goto give_sigsegv;
+    }
+
+    memset(frame, 0, sizeof(*frame));
+#if defined(TARGET_MIPS)
+    int mflags = on_sig_stack(frame_addr) ? TARGET_MC_ADD_MAGIC :
+        TARGET_MC_SET_ONSTACK | TARGET_MC_ADD_MAGIC;
+#else
+    int mflags = 0;
+#endif
+    if (get_mcontext(regs, &frame->sf_uc.uc_mcontext, mflags)) {
+        goto give_sigsegv;
+    }
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        if (__put_user(set->__bits[i], &frame->sf_uc.uc_sigmask.__bits[i])) {
+            goto give_sigsegv;
+        }
+    }
+
+    if (tinfo) {
+        frame->sf_si.si_signo = tinfo->si_signo;
+        frame->sf_si.si_errno = tinfo->si_errno;
+        frame->sf_si.si_code = tinfo->si_code;
+        frame->sf_si.si_pid = tinfo->si_pid;
+        frame->sf_si.si_uid = tinfo->si_uid;
+        frame->sf_si.si_status = tinfo->si_status;
+        frame->sf_si.si_addr = tinfo->si_addr;
+
+        if (TARGET_SIGILL == sig || TARGET_SIGFPE == sig ||
+                TARGET_SIGSEGV == sig || TARGET_SIGBUS == sig ||
+                TARGET_SIGTRAP == sig) {
+            frame->sf_si._reason._fault._trapno = tinfo->_reason._fault._trapno;
+        }
+
+        /*
+         * If si_code is one of SI_QUEUE, SI_TIMER, SI_ASYNCIO, or
+         * SI_MESGQ, then si_value contains the application-specified
+         * signal value. Otherwise, the contents of si_value are
+         * undefined.
+         */
+        if (SI_QUEUE == code || SI_TIMER == code || SI_ASYNCIO == code ||
+                SI_MESGQ == code) {
+            frame->sf_si.si_value.sival_int = tinfo->si_value.sival_int;
+        }
+
+        if (SI_TIMER == code) {
+            frame->sf_si._reason._timer._timerid =
+                tinfo->_reason._timer._timerid;
+            frame->sf_si._reason._timer._overrun =
+                tinfo->_reason._timer._overrun;
+        }
+
+#ifdef SIGPOLL
+        if (SIGPOLL == sig) {
+            frame->sf_si._reason._band = tinfo->_reason._band;
+        }
+#endif
+
+    }
+
+    if (set_sigtramp_args(regs, sig, frame, frame_addr, ka)) {
+        goto give_sigsegv;
+    }
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+static int reset_signal_mask(target_ucontext_t *ucontext)
+{
+    int i;
+    sigset_t blocked;
+    target_sigset_t target_set;
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++)
+        if (__get_user(target_set.__bits[i],
+                    &ucontext->uc_sigmask.__bits[i])) {
+            return -TARGET_EFAULT;
+        }
+    target_to_host_sigset_internal(&blocked, &target_set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    return 0;
+}
+
+long do_sigreturn(CPUArchState *regs, abi_ulong addr)
+{
+    long ret;
+    abi_ulong target_ucontext;
+    target_ucontext_t *ucontext = NULL;
+
+    /* Get the target ucontext address from the stack frame */
+    ret = get_ucontext_sigreturn(regs, addr, &target_ucontext);
+    if (is_error(ret)) {
+        return ret;
+    }
+    if (!lock_user_struct(VERIFY_READ, ucontext, target_ucontext, 0)) {
+        goto badframe;
+    }
+
+    /* Set the register state back to before the signal. */
+    if (set_mcontext(regs, &ucontext->uc_mcontext, 1)) {
+        goto badframe;
+    }
+
+    /* And reset the signal mask. */
+    if (reset_signal_mask(ucontext)) {
+        goto badframe;
+    }
+
+    unlock_user_struct(ucontext, target_ucontext, 0);
+    return -TARGET_EJUSTRETURN;
+
+badframe:
+    if (ucontext != NULL) {
+        unlock_user_struct(ucontext, target_ucontext, 0);
+    }
+    force_sig(TARGET_SIGSEGV);
+    return -TARGET_EFAULT;
+}
+
 void signal_init(void)
 {
+    struct sigaction act;
+    struct sigaction oact;
+    int i, j;
+    int host_sig;
+
+    /* Generate the signal conversion tables.  */
+    for (i = 1; i < TARGET_NSIG; i++) {
+        if (host_to_target_signal_table[i] == 0) {
+            host_to_target_signal_table[i] = i;
+        }
+    }
+    for (i = 1; i < TARGET_NSIG; i++) {
+        j = host_to_target_signal_table[i];
+        target_to_host_signal_table[j] = i;
+    }
+
+    /*
+     * Set all host signal handlers. ALL signals are blocked during the
+     * handlers to serialize them.
+     */
+    memset(sigact_table, 0, sizeof(sigact_table));
+
+    sigfillset(&act.sa_mask);
+    act.sa_sigaction = host_signal_handler;
+    act.sa_flags = SA_SIGINFO;
+
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        host_sig = target_to_host_signal(i);
+        sigaction(host_sig, NULL, &oact);
+        if (oact.sa_sigaction == (void *)SIG_IGN) {
+            sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
+        } else if (oact.sa_sigaction == (void *)SIG_DFL) {
+            sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
+        }
+        /*
+         * If there's already a handler installed then something has
+         * gone horribly wrong, so don't even try to handle that case.
+         * Install some handlers for our own use.  We need at least
+         * SIGSEGV and SIGBUS, to detect exceptions.  We can not just
+         * trap all signals because it affects syscall interrupt
+         * behavior.  But do trap all default-fatal signals.
+         */
+        if (fatal_signal(i)) {
+            sigaction(host_sig, &act, NULL);
+        }
+    }
 }
 
 void process_pending_signals(CPUArchState *cpu_env)
 {
+    CPUState *cpu = ENV_GET_CPU(cpu_env);
+    int sig, code;
+    abi_ulong handler;
+    sigset_t set, old_set;
+    target_sigset_t target_old_set;
+    target_siginfo_t tinfo;
+    struct emulated_sigtable *k;
+    struct target_sigaction *sa;
+    struct qemu_sigqueue *q;
+    TaskState *ts = cpu_env->opaque;
+
+    if (!ts->signal_pending) {
+        return;
+    }
+
+    /* FIXME: This is not threadsafe.  */
+    k  = ts->sigtab;
+    for (sig = 1; sig <= TARGET_NSIG; sig++) {
+        if (k->pending) {
+            goto handle_signal;
+        }
+        k++;
+    }
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: process_pending_signals has no signals\n");
+#endif
+    /* If no signal is pending then just return. */
+    ts->signal_pending = 0;
+    return;
+
+handle_signal:
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: process signal %d\n", sig);
+#endif
+
+    /* Dequeue signal. */
+    q = k->first;
+    k->first = q->next;
+    if (!k->first) {
+        k->pending = 0;
+    }
+
+    sig = gdb_handlesig(cpu, sig);
+    if (!sig) {
+        sa = NULL;
+        handler = TARGET_SIG_IGN;
+    } else {
+        sa = &sigact_table[sig - 1];
+        handler = sa->_sa_handler;
+    }
+
+    if (handler == TARGET_SIG_DFL) {
+#ifdef DEBUG_SIGNAL
+        fprintf(stderr, "qemu: TARGET_SIG_DFL\n");
+#endif
+        /*
+         * default handler : ignore some signal. The other are job
+         * control or fatal.
+         */
+        if (TARGET_SIGTSTP == sig || TARGET_SIGTTIN == sig ||
+                TARGET_SIGTTOU == sig) {
+            kill(getpid(), SIGSTOP);
+        } else if (TARGET_SIGCHLD != sig && TARGET_SIGURG != sig &&
+            TARGET_SIGWINCH != sig && TARGET_SIGCONT != sig) {
+            force_sig(sig);
+        }
+    } else if (TARGET_SIG_IGN == handler) {
+        /* ignore sig */
+#ifdef DEBUG_SIGNAL
+        fprintf(stderr, "qemu: TARGET_SIG_IGN\n");
+#endif
+    } else if (TARGET_SIG_ERR == handler) {
+#ifdef DEBUG_SIGNAL
+        fprintf(stderr, "qemu: TARGET_SIG_ERR\n");
+#endif
+        force_sig(sig);
+    } else {
+        /* compute the blocked signals during the handler execution */
+        target_to_host_sigset(&set, &sa->sa_mask);
+        /*
+         * SA_NODEFER indicates that the current signal should not be
+         * blocked during the handler.
+         */
+        if (!(sa->sa_flags & TARGET_SA_NODEFER)) {
+            sigaddset(&set, target_to_host_signal(sig));
+        }
+
+        /* block signals in the handler */
+        sigprocmask(SIG_BLOCK, &set, &old_set);
+
+        /*
+         * Save the previous blocked signal state to restore it at the
+         * end of the signal execution (see do_sigreturn).
+         */
+        host_to_target_sigset_internal(&target_old_set, &old_set);
+
+#if 0  /* not yet */
+#if defined(TARGET_I386) && !defined(TARGET_X86_64)
+        /* if the CPU is in VM86 mode, we restore the 32 bit values */
+        {
+            CPUX86State *env = cpu_env;
+            if (env->eflags & VM_MASK) {
+                save_v86_state(env);
+            }
+        }
+#endif
+#endif /* not yet */
+
+        code = q->info.si_code;
+        /* prepare the stack frame of the virtual CPU */
+        if (sa->sa_flags & TARGET_SA_SIGINFO) {
+            tswap_siginfo(&tinfo, &q->info);
+            setup_frame(sig, code, sa, &target_old_set, &tinfo, cpu_env);
+        } else {
+            setup_frame(sig, code, sa, &target_old_set, NULL, cpu_env);
+        }
+        if (sa->sa_flags & TARGET_SA_RESETHAND) {
+            sa->_sa_handler = TARGET_SIG_DFL;
+        }
+    }
+    if (q != &k->info) {
+        free_sigqueue(cpu_env, q);
+    }
 }
diff --git a/bsd-user/sparc/target_arch_signal.h b/bsd-user/sparc/target_arch_signal.h
new file mode 100644
index 0000000..f934f8c
--- /dev/null
+++ b/bsd-user/sparc/target_arch_signal.h
@@ -0,0 +1,77 @@
+#ifndef TARGET_ARCH_SIGNAL_H
+#define TARGET_ARCH_SIGNAL_H
+
+#include "cpu.h"
+
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE   (0) */       /* XXX to be added. */
+
+/* compare to  sparc64/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (1024 * 4)              /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to sparc64/sparc64/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long set_sigtramp_args(CPUSPARCState *regs,
+        int sig, struct target_sigframe *frame, abi_ulong frame_addr,
+        struct target_sigaction *ka)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to sparc64/sparc64/machdep.c get_mcontext() */
+static inline abi_long get_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int flags)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to sparc64/space64/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUSPARCState *regs,
+        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    /* XXX */
+    *target_uc = 0;
+    return -TARGET_EOPNOTSUPP;
+}
+
+#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/sparc64/target_arch_signal.h b/bsd-user/sparc64/target_arch_signal.h
new file mode 100644
index 0000000..1529b0f
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_signal.h
@@ -0,0 +1,94 @@
+/*
+ *  sparc64 dependent signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE    (0) */      /* XXX to be added. */
+
+/* compare to  sparc64/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (1024 * 4)              /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to sparc64/sparc64/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long set_sigtramp_args(CPUSPARCState *regs,
+        int sig, struct target_sigframe *frame, abi_ulong frame_addr,
+        struct target_sigaction *ka)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to sparc64/sparc64/machdep.c get_mcontext() */
+static inline abi_long get_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int flags)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to sparc64/space64/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUSPARCState *regs,
+        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    /* XXX */
+    *target_uc = 0;
+    return -TARGET_EOPNOTSUPP;
+}
+
+#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 0996787..bc4a7e4 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -39,8 +39,12 @@
 
 #define target_to_host_bitmask(x, tbl) (x)
 
+/* BSD independent syscall shims */
+#include "bsd-signal.h"
+
 /* *BSD dependent syscall shims */
 #include "os-time.h"
+#include "os-signal.h"
 
 /* #define DEBUG */
 
@@ -326,6 +330,61 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * signal system calls
+         */
+    case TARGET_FREEBSD_NR_sigtimedwait: /* sigtimedwait(2) */
+        ret = do_freebsd_sigtimedwait(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigaction: /* sigaction(2) */
+        ret = do_bsd_sigaction(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigprocmask: /* sigprocmask(2) */
+        ret = do_bsd_sigprocmask(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigpending: /* sigpending(2) */
+        ret = do_bsd_sigpending(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sigsuspend: /* sigsuspend(2) */
+        ret = do_bsd_sigsuspend(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sigreturn: /* sigreturn(2) */
+        ret = do_bsd_sigreturn(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sigwait: /* sigwait(2) */
+        ret = do_bsd_sigwait(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigwaitinfo: /* sigwaitinfo(2) */
+        ret = do_bsd_sigwaitinfo(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sigqueue: /* sigqueue(2) */
+        ret = do_bsd_sigqueue(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigaltstack: /* sigaltstack(2) */
+        ret = do_bsd_sigaltstack(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kill: /* kill(2) */
+        ret = do_bsd_kill(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_killpg: /* killpg(2) */
+        ret = do_bsd_killpg(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_pdkill: /* pdkill(2) */
+        ret = do_freebsd_pdkill(arg1, arg2);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
diff --git a/bsd-user/x86_64/target_arch_signal.h b/bsd-user/x86_64/target_arch_signal.h
new file mode 100644
index 0000000..1998570
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_signal.h
@@ -0,0 +1,94 @@
+/*
+ *  x86_64 signal definitions
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_SIGNAL_H_
+#define _TARGET_ARCH_SIGNAL_H_
+
+#include "cpu.h"
+
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE    (0) */   /* XXX to be added */
+
+/* compare to  x86/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (512 * 4)               /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+/*
+ * Compare to amd64/amd64/machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long set_sigtramp_args(CPUX86State *regs,
+        int sig, struct target_sigframe *frame, abi_ulong frame_addr,
+        struct target_sigaction *ka)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to amd64/amd64/machdep.c get_mcontext() */
+static inline abi_long get_mcontext(CPUX86State *regs,
+                target_mcontext_t *mcp, int flags)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+/* Compare to amd64/amd64/machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUX86State *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    /* XXX */
+    return -TARGET_EOPNOTSUPP;
+}
+
+static inline abi_long get_ucontext_sigreturn(CPUX86State *regs,
+        abi_ulong target_sf, abi_ulong *target_uc)
+{
+    /* XXX */
+    *target_uc = 0;
+    return -TARGET_EOPNOTSUPP;
+}
+
+#endif /* !TARGET_ARCH_SIGNAL_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 08/19] bsd-user: move arch/OS dependent code out of elfload.c
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (8 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 07/19] bsd-user: add support for freebsd signal " Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 09/19] bsd-user: add support for freebsd process related system calls Stacey Son
                     ` (10 subsequent siblings)
  20 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change moves ELF and thread start up code from elfload.c to
the host OS and arch dependent directories.  This eliminates many
of the #ifdef's in elfload.c and moves the target arch and OS
dependent code into its own directories.
---
 bsd-user/arm/target_arch_elf.h        |   54 ++
 bsd-user/arm/target_arch_thread.h     |   67 +++
 bsd-user/elfload.c                    |  947 +++++++--------------------------
 bsd-user/freebsd/target_os_elf.h      |  145 +++++
 bsd-user/freebsd/target_os_thread.h   |    6 +
 bsd-user/i386/target_arch_elf.h       |   62 +++
 bsd-user/i386/target_arch_thread.h    |   45 ++
 bsd-user/mips/target_arch_elf.h       |   36 ++
 bsd-user/mips/target_arch_thread.h    |   54 ++
 bsd-user/mips64/target_arch_elf.h     |   36 ++
 bsd-user/mips64/target_arch_thread.h  |   54 ++
 bsd-user/netbsd/target_os_elf.h       |  226 ++++++++
 bsd-user/netbsd/target_os_thread.h    |    6 +
 bsd-user/openbsd/target_os_elf.h      |  226 ++++++++
 bsd-user/openbsd/target_os_thread.h   |    6 +
 bsd-user/sparc/target_arch_elf.h      |   30 +
 bsd-user/sparc/target_arch_thread.h   |   39 ++
 bsd-user/sparc64/target_arch_elf.h    |   34 ++
 bsd-user/sparc64/target_arch_thread.h |   55 ++
 bsd-user/syscall_defs.h               |   64 +++
 bsd-user/x86_64/target_arch_elf.h     |   55 ++
 bsd-user/x86_64/target_arch_thread.h  |   40 ++
 22 files changed, 1530 insertions(+), 757 deletions(-)
 create mode 100644 bsd-user/arm/target_arch_elf.h
 create mode 100644 bsd-user/arm/target_arch_thread.h
 create mode 100644 bsd-user/freebsd/target_os_elf.h
 create mode 100644 bsd-user/freebsd/target_os_thread.h
 create mode 100644 bsd-user/i386/target_arch_elf.h
 create mode 100644 bsd-user/i386/target_arch_thread.h
 create mode 100644 bsd-user/mips/target_arch_elf.h
 create mode 100644 bsd-user/mips/target_arch_thread.h
 create mode 100644 bsd-user/mips64/target_arch_elf.h
 create mode 100644 bsd-user/mips64/target_arch_thread.h
 create mode 100644 bsd-user/netbsd/target_os_elf.h
 create mode 100644 bsd-user/netbsd/target_os_thread.h
 create mode 100644 bsd-user/openbsd/target_os_elf.h
 create mode 100644 bsd-user/openbsd/target_os_thread.h
 create mode 100644 bsd-user/sparc/target_arch_elf.h
 create mode 100644 bsd-user/sparc/target_arch_thread.h
 create mode 100644 bsd-user/sparc64/target_arch_elf.h
 create mode 100644 bsd-user/sparc64/target_arch_thread.h
 create mode 100644 bsd-user/x86_64/target_arch_elf.h
 create mode 100644 bsd-user/x86_64/target_arch_thread.h

diff --git a/bsd-user/arm/target_arch_elf.h b/bsd-user/arm/target_arch_elf.h
new file mode 100644
index 0000000..c408cea
--- /dev/null
+++ b/bsd-user/arm/target_arch_elf.h
@@ -0,0 +1,54 @@
+/*
+ *  arm ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_ARM )
+
+#define ELF_CLASS       ELFCLASS32
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+#define ELF_ARCH        EM_ARM
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+enum
+{
+  ARM_HWCAP_ARM_SWP       = 1 << 0,
+  ARM_HWCAP_ARM_HALF      = 1 << 1,
+  ARM_HWCAP_ARM_THUMB     = 1 << 2,
+  ARM_HWCAP_ARM_26BIT     = 1 << 3,
+  ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
+  ARM_HWCAP_ARM_FPA       = 1 << 5,
+  ARM_HWCAP_ARM_VFP       = 1 << 6,
+  ARM_HWCAP_ARM_EDSP      = 1 << 7,
+};
+
+#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
+                    | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
+                    | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
+
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/arm/target_arch_thread.h b/bsd-user/arm/target_arch_thread.h
new file mode 100644
index 0000000..e69f612
--- /dev/null
+++ b/bsd-user/arm/target_arch_thread.h
@@ -0,0 +1,67 @@
+/*
+ *  arm thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to arm/arm/vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUARMState *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    abi_ulong sp;
+
+    /*
+     * Make sure the stack is properly aligned.
+     * arm/include/param.h (STACKLIGN() macro)
+     */
+    sp = ((u_int)(stack_base + stack_size) & ~(8-1)) -
+        sizeof(struct target_trapframe);
+
+    /* sp = stack base */
+    regs->regs[13] = sp;
+    /* pc = start function entry */
+    regs->regs[15] = entry & 0xfffffffe;
+    /* r0 = arg */
+    regs->regs[0] = arg;
+    regs->spsr = ARM_CPU_MODE_USR;
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    abi_long stack = infop->start_stack;
+    memset(regs, 0, sizeof(*regs));
+    regs->ARM_cpsr = 0x10;
+    if (infop->entry & 1)
+      regs->ARM_cpsr |= CPSR_T;
+    regs->ARM_pc = infop->entry & 0xfffffffe;
+    regs->ARM_sp = infop->start_stack;
+    if (bsd_type == target_freebsd) {
+        regs->ARM_lr = infop->entry & 0xfffffffe;
+    }
+    /* FIXME - what to for failure of get_user()? */
+    get_user_ual(regs->ARM_r2, stack + 8); /* envp */
+    get_user_ual(regs->ARM_r1, stack + 4); /* envp */
+    /* XXX: it seems that r0 is zeroed after ! */
+    regs->ARM_r0 = 0;
+    /* For uClinux PIC binaries.  */
+    /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
+    regs->ARM_r10 = infop->start_data;
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 68d0209..ef96b8c 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -1,4 +1,20 @@
-/* This is the Linux kernel elf-loading code, ported into user space */
+/*
+ *  ELF loading code
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
 
 #include <stdio.h>
 #include <sys/types.h>
@@ -11,548 +27,13 @@
 
 #include "qemu.h"
 #include "disas/disas.h"
-
-#ifdef _ARCH_PPC64
-#undef ARCH_DLINFO
-#undef ELF_PLATFORM
-#undef ELF_HWCAP
-#undef ELF_CLASS
-#undef ELF_DATA
-#undef ELF_ARCH
-#endif
-
-/* from personality.h */
-
-/*
- * Flags for bug emulation.
- *
- * These occupy the top three bytes.
- */
-enum {
-        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA space */
-        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs point to descriptors
-                                                 * (signal handling)
-                                                 */
-        MMAP_PAGE_ZERO =        0x0100000,
-        ADDR_COMPAT_LAYOUT =    0x0200000,
-        READ_IMPLIES_EXEC =     0x0400000,
-        ADDR_LIMIT_32BIT =      0x0800000,
-        SHORT_INODE =           0x1000000,
-        WHOLE_SECONDS =         0x2000000,
-        STICKY_TIMEOUTS =       0x4000000,
-        ADDR_LIMIT_3GB =        0x8000000,
-};
-
-/*
- * Personality types.
- *
- * These go in the low byte.  Avoid using the top bit, it will
- * conflict with error returns.
- */
-enum {
-        PER_LINUX =             0x0000,
-        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
-        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
-        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
-        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
-        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
-                                         WHOLE_SECONDS | SHORT_INODE,
-        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
-        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
-        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
-        PER_BSD =               0x0006,
-        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
-        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
-        PER_LINUX32 =           0x0008,
-        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
-        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
-        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
-        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
-        PER_RISCOS =            0x000c,
-        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
-        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
-        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
-        PER_HPUX =              0x0010,
-        PER_MASK =              0x00ff,
-};
-
-/*
- * Return the base personality without flags.
- */
-#define personality(pers)       (pers & PER_MASK)
-
-/* this flag is uneffective under linux too, should be deleted */
-#ifndef MAP_DENYWRITE
-#define MAP_DENYWRITE 0
-#endif
-
-/* should probably go in elf.h */
-#ifndef ELIBBAD
-#define ELIBBAD 80
-#endif
+#include "target_os_elf.h"
+#include "target_os_stack.h"
+#include "target_os_thread.h"
 
 abi_ulong target_stksiz;
 abi_ulong target_stkbas;
 
-#ifdef TARGET_I386
-
-#define ELF_PLATFORM get_elf_platform()
-
-static const char *get_elf_platform(void)
-{
-    static char elf_platform[] = "i386";
-    int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
-    if (family > 6)
-        family = 6;
-    if (family >= 3)
-        elf_platform[1] = '0' + family;
-    return elf_platform;
-}
-
-#define ELF_HWCAP get_elf_hwcap()
-
-static uint32_t get_elf_hwcap(void)
-{
-    X86CPU *cpu = X86_CPU(thread_cpu);
-
-    return cpu->env.features[FEAT_1_EDX];
-}
-
-#ifdef TARGET_X86_64
-#define ELF_START_MMAP 0x2aaaaab000ULL
-#define elf_check_arch(x) ( ((x) == ELF_ARCH) )
-
-#define ELF_CLASS      ELFCLASS64
-#define ELF_DATA       ELFDATA2LSB
-#define ELF_ARCH       EM_X86_64
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->rax = 0;
-    regs->rsp = infop->start_stack;
-    regs->rip = infop->entry;
-    if (bsd_type == target_freebsd) {
-        regs->rdi = infop->start_stack;
-    }
-}
-
-#else
-
-#define ELF_START_MMAP 0x80000000
-
-/*
- * This is used to ensure we don't load something for the wrong architecture.
- */
-#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
-
-/*
- * These are used to set parameters in the core dumps.
- */
-#define ELF_CLASS       ELFCLASS32
-#define ELF_DATA        ELFDATA2LSB
-#define ELF_ARCH        EM_386
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->esp = infop->start_stack;
-    regs->eip = infop->entry;
-
-    /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
-       starts %edx contains a pointer to a function which might be
-       registered using `atexit'.  This provides a mean for the
-       dynamic linker to call DT_FINI functions for shared libraries
-       that have been loaded before the code runs.
-
-       A value of 0 tells we have no such handler.  */
-    regs->edx = 0;
-}
-#endif
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       4096
-
-#endif
-
-#ifdef TARGET_ARM
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_ARM )
-
-#define ELF_CLASS       ELFCLASS32
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA        ELFDATA2MSB
-#else
-#define ELF_DATA        ELFDATA2LSB
-#endif
-#define ELF_ARCH        EM_ARM
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    abi_long stack = infop->start_stack;
-    memset(regs, 0, sizeof(*regs));
-    regs->ARM_cpsr = 0x10;
-    if (infop->entry & 1)
-      regs->ARM_cpsr |= CPSR_T;
-    regs->ARM_pc = infop->entry & 0xfffffffe;
-    regs->ARM_sp = infop->start_stack;
-    /* FIXME - what to for failure of get_user()? */
-    get_user_ual(regs->ARM_r2, stack + 8); /* envp */
-    get_user_ual(regs->ARM_r1, stack + 4); /* envp */
-    /* XXX: it seems that r0 is zeroed after ! */
-    regs->ARM_r0 = 0;
-    /* For uClinux PIC binaries.  */
-    /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
-    regs->ARM_r10 = infop->start_data;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       4096
-
-enum
-{
-  ARM_HWCAP_ARM_SWP       = 1 << 0,
-  ARM_HWCAP_ARM_HALF      = 1 << 1,
-  ARM_HWCAP_ARM_THUMB     = 1 << 2,
-  ARM_HWCAP_ARM_26BIT     = 1 << 3,
-  ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
-  ARM_HWCAP_ARM_FPA       = 1 << 5,
-  ARM_HWCAP_ARM_VFP       = 1 << 6,
-  ARM_HWCAP_ARM_EDSP      = 1 << 7,
-};
-
-#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
-                    | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
-                    | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
-
-#endif
-
-#ifdef TARGET_SPARC
-#ifdef TARGET_SPARC64
-
-#define ELF_START_MMAP 0x80000000
-
-#ifndef TARGET_ABI32
-#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
-#else
-#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
-#endif
-
-#define ELF_CLASS   ELFCLASS64
-#define ELF_DATA    ELFDATA2MSB
-#define ELF_ARCH    EM_SPARCV9
-
-#define STACK_BIAS              2047
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-#ifndef TARGET_ABI32
-    regs->tstate = 0;
-#endif
-    regs->pc = infop->entry;
-    regs->npc = regs->pc + 4;
-    regs->y = 0;
-#ifdef TARGET_ABI32
-    regs->u_regs[14] = infop->start_stack - 16 * 4;
-#else
-    if (personality(infop->personality) == PER_LINUX32)
-        regs->u_regs[14] = infop->start_stack - 16 * 4;
-    else {
-        regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
-        if (bsd_type == target_freebsd) {
-            regs->u_regs[8] = infop->start_stack;
-            regs->u_regs[11] = infop->start_stack;
-        }
-    }
-#endif
-}
-
-#else
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_SPARC )
-
-#define ELF_CLASS   ELFCLASS32
-#define ELF_DATA    ELFDATA2MSB
-#define ELF_ARCH    EM_SPARC
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->psr = 0;
-    regs->pc = infop->entry;
-    regs->npc = regs->pc + 4;
-    regs->y = 0;
-    regs->u_regs[14] = infop->start_stack - 16 * 4;
-}
-
-#endif
-#endif
-
-#ifdef TARGET_PPC
-
-#define ELF_START_MMAP 0x80000000
-
-#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-
-#define elf_check_arch(x) ( (x) == EM_PPC64 )
-
-#define ELF_CLASS       ELFCLASS64
-
-#else
-
-#define elf_check_arch(x) ( (x) == EM_PPC )
-
-#define ELF_CLASS       ELFCLASS32
-
-#endif
-
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA        ELFDATA2MSB
-#else
-#define ELF_DATA        ELFDATA2LSB
-#endif
-#define ELF_ARCH        EM_PPC
-
-/*
- * We need to put in some extra aux table entries to tell glibc what
- * the cache block size is, so it can use the dcbz instruction safely.
- */
-#define AT_DCACHEBSIZE          19
-#define AT_ICACHEBSIZE          20
-#define AT_UCACHEBSIZE          21
-/* A special ignored type value for PPC, for glibc compatibility.  */
-#define AT_IGNOREPPC            22
-/*
- * The requirements here are:
- * - keep the final alignment of sp (sp & 0xf)
- * - make sure the 32-bit value at the first 16 byte aligned position of
- *   AUXV is greater than 16 for glibc compatibility.
- *   AT_IGNOREPPC is used for that.
- * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
- *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
- */
-#define DLINFO_ARCH_ITEMS       5
-#define ARCH_DLINFO                                                     \
-do {                                                                    \
-        NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);                              \
-        NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);                              \
-        NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                                 \
-        /*                                                              \
-         * Now handle glibc compatibility.                              \
-         */                                                             \
-        NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);                        \
-        NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);                        \
- } while (0)
-
-static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
-{
-    abi_ulong pos = infop->start_stack;
-    abi_ulong tmp;
-#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-    abi_ulong entry, toc;
-#endif
-
-    _regs->gpr[1] = infop->start_stack;
-#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-    entry = ldq_raw(infop->entry) + infop->load_addr;
-    toc = ldq_raw(infop->entry + 8) + infop->load_addr;
-    _regs->gpr[2] = toc;
-    infop->entry = entry;
-#endif
-    _regs->nip = infop->entry;
-    /* Note that isn't exactly what regular kernel does
-     * but this is what the ABI wants and is needed to allow
-     * execution of PPC BSD programs.
-     */
-    /* FIXME - what to for failure of get_user()? */
-    get_user_ual(_regs->gpr[3], pos);
-    pos += sizeof(abi_ulong);
-    _regs->gpr[4] = pos;
-    for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong))
-        tmp = ldl(pos);
-    _regs->gpr[5] = pos;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       4096
-
-#endif
-
-#ifdef TARGET_MIPS
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_MIPS )
-
-#ifdef TARGET_MIPS64
-#define ELF_CLASS   ELFCLASS64
-#else
-#define ELF_CLASS   ELFCLASS32
-#endif
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA        ELFDATA2MSB
-#else
-#define ELF_DATA        ELFDATA2LSB
-#endif
-#define ELF_ARCH    EM_MIPS
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->cp0_status = 2 << CP0St_KSU;
-    regs->cp0_epc = infop->entry;
-    regs->regs[29] = infop->start_stack;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE        4096
-
-#endif /* TARGET_MIPS */
-
-#ifdef TARGET_SH4
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_SH )
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA  ELFDATA2LSB
-#define ELF_ARCH  EM_SH
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-  /* Check other registers XXXXX */
-  regs->pc = infop->entry;
-  regs->regs[15] = infop->start_stack;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE        4096
-
-#endif
-
-#ifdef TARGET_CRIS
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_CRIS )
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA  ELFDATA2LSB
-#define ELF_ARCH  EM_CRIS
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-  regs->erp = infop->entry;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE        8192
-
-#endif
-
-#ifdef TARGET_M68K
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_68K )
-
-#define ELF_CLASS       ELFCLASS32
-#define ELF_DATA        ELFDATA2MSB
-#define ELF_ARCH        EM_68K
-
-/* ??? Does this need to do anything?
-#define ELF_PLAT_INIT(_r) */
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->usp = infop->start_stack;
-    regs->sr = 0;
-    regs->pc = infop->entry;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       8192
-
-#endif
-
-#ifdef TARGET_ALPHA
-
-#define ELF_START_MMAP (0x30000000000ULL)
-
-#define elf_check_arch(x) ( (x) == ELF_ARCH )
-
-#define ELF_CLASS      ELFCLASS64
-#define ELF_DATA       ELFDATA2MSB
-#define ELF_ARCH       EM_ALPHA
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
-    regs->pc = infop->entry;
-    regs->ps = 8;
-    regs->usp = infop->start_stack;
-    regs->unique = infop->start_data; /* ? */
-    printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n",
-           regs->unique, infop->start_data);
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE        8192
-
-#endif /* TARGET_ALPHA */
-
-#ifndef ELF_PLATFORM
-#define ELF_PLATFORM (NULL)
-#endif
-
-#ifndef ELF_HWCAP
-#define ELF_HWCAP 0
-#endif
-
-#ifdef TARGET_ABI32
-#undef ELF_CLASS
-#define ELF_CLASS ELFCLASS32
-#undef bswaptls
-#define bswaptls(ptr) bswap32s(ptr)
-#endif
-
-#include "elf.h"
-
-struct exec
-{
-  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
-  unsigned int a_text;   /* length of text, in bytes */
-  unsigned int a_data;   /* length of data, in bytes */
-  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
-  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
-  unsigned int a_entry;  /* start address */
-  unsigned int a_trsize; /* length of relocation info for text, in bytes */
-  unsigned int a_drsize; /* length of relocation info for data, in bytes */
-};
-
-
-#define N_MAGIC(exec) ((exec).a_info & 0xffff)
-#define OMAGIC 0407
-#define NMAGIC 0410
-#define ZMAGIC 0413
-#define QMAGIC 0314
-
-/* max code+data+bss space allocated to elf interpreter */
-#define INTERP_MAP_SIZE (32 * 1024 * 1024)
-
-/* max code+data+bss+brk space allocated to ET_DYN executables */
-#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
-
-/* Necessary parameters */
-#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
-#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
-#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
-
-#define INTERPRETER_NONE 0
-#define INTERPRETER_AOUT 1
-#define INTERPRETER_ELF 2
-
-#define DLINFO_ITEMS 12
-
 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
 {
         memcpy(to, from, n);
@@ -563,7 +44,7 @@ static int load_aout_interp(void * exptr, int interp_fd);
 #ifdef BSWAP_NEEDED
 static void bswap_ehdr(struct elfhdr *ehdr)
 {
-    bswap16s(&ehdr->e_type);                    /* Object file type */
+    bswap16s(&ehdr->e_type);            /* Object file type */
     bswap16s(&ehdr->e_machine);         /* Architecture */
     bswap32s(&ehdr->e_version);         /* Object file version */
     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
@@ -571,37 +52,45 @@ static void bswap_ehdr(struct elfhdr *ehdr)
     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
-    bswap16s(&ehdr->e_phentsize);               /* Program header table entry size */
+    bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
-    bswap16s(&ehdr->e_shentsize);               /* Section header table entry size */
+    bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
-    bswap16s(&ehdr->e_shstrndx);                /* Section header string table index */
+    bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
 }
 
-static void bswap_phdr(struct elf_phdr *phdr)
+static void bswap_phdr(struct elf_phdr *phdr, int phnum)
 {
-    bswap32s(&phdr->p_type);                    /* Segment type */
-    bswaptls(&phdr->p_offset);          /* Segment file offset */
-    bswaptls(&phdr->p_vaddr);           /* Segment virtual address */
-    bswaptls(&phdr->p_paddr);           /* Segment physical address */
-    bswaptls(&phdr->p_filesz);          /* Segment size in file */
-    bswaptls(&phdr->p_memsz);           /* Segment size in memory */
-    bswap32s(&phdr->p_flags);           /* Segment flags */
-    bswaptls(&phdr->p_align);           /* Segment alignment */
+    int i;
+
+    for (i = 0; i < phnum; i++, phdr++) {
+        bswap32s(&phdr->p_type);        /* Segment type */
+        bswaptls(&phdr->p_offset);      /* Segment file offset */
+        bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
+        bswaptls(&phdr->p_paddr);       /* Segment physical address */
+        bswaptls(&phdr->p_filesz);      /* Segment size in file */
+        bswaptls(&phdr->p_memsz);       /* Segment size in memory */
+        bswap32s(&phdr->p_flags);       /* Segment flags */
+        bswaptls(&phdr->p_align);       /* Segment alignment */
+    }
 }
 
-static void bswap_shdr(struct elf_shdr *shdr)
+static void bswap_shdr(struct elf_shdr *shdr, int shnum)
 {
-    bswap32s(&shdr->sh_name);
-    bswap32s(&shdr->sh_type);
-    bswaptls(&shdr->sh_flags);
-    bswaptls(&shdr->sh_addr);
-    bswaptls(&shdr->sh_offset);
-    bswaptls(&shdr->sh_size);
-    bswap32s(&shdr->sh_link);
-    bswap32s(&shdr->sh_info);
-    bswaptls(&shdr->sh_addralign);
-    bswaptls(&shdr->sh_entsize);
+    int i;
+
+    for (i = 0; i < shnum; i++, shdr++) {
+        bswap32s(&shdr->sh_name);
+        bswap32s(&shdr->sh_type);
+        bswaptls(&shdr->sh_flags);
+        bswaptls(&shdr->sh_addr);
+        bswaptls(&shdr->sh_offset);
+        bswaptls(&shdr->sh_size);
+        bswap32s(&shdr->sh_link);
+        bswap32s(&shdr->sh_info);
+        bswaptls(&shdr->sh_addralign);
+        bswaptls(&shdr->sh_entsize);
+    }
 }
 
 static void bswap_sym(struct elf_sym *sym)
@@ -611,7 +100,15 @@ static void bswap_sym(struct elf_sym *sym)
     bswaptls(&sym->st_size);
     bswap16s(&sym->st_shndx);
 }
-#endif
+
+#else /* ! BSWAP_NEEDED */
+
+static void bswap_ehdr(struct elfhdr *ehdr) { }
+static void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
+static void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
+static void bswap_sym(struct elf_sym *sym) { }
+
+#endif /* ! BSWAP_NEEDED */
 
 /*
  * 'copy_elf_strings()' copies argument/envelope strings from user
@@ -671,39 +168,31 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
 static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm,
                                  struct image_info *info)
 {
-    abi_ulong stack_base, size, error;
-    int i;
+    abi_ulong stack_base, size;
+    abi_long addr;
 
     /* Create enough stack to hold everything.  If we don't use
      * it for args, we'll use it for something else...
      */
     size = target_dflssiz;
-    if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
-        size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
-    error = target_mmap(0,
-                        size + qemu_host_page_size,
-                        PROT_READ | PROT_WRITE,
-                        MAP_PRIVATE | MAP_ANON,
-                        -1, 0);
-    if (error == -1) {
+    stack_base = TARGET_USRSTACK - size;
+    addr = target_mmap(stack_base , size + qemu_host_page_size,
+            PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+    if (addr == -1) {
         perror("stk mmap");
         exit(-1);
     }
     /* we reserve one extra page at the top of the stack as guard */
-    target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
+    target_mprotect(addr + size, qemu_host_page_size, PROT_NONE);
 
-    stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
-    p += stack_base;
+    target_stksiz = size;
+    target_stkbas = addr;
 
-    for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-        if (bprm->page[i]) {
-            info->rss++;
-            /* FIXME - check return value of memcpy_to_target() for failure */
-            memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
-            g_free(bprm->page[i]);
-        }
-        stack_base += TARGET_PAGE_SIZE;
+    if (setup_initial_stack(bprm, &p) != 0) {
+        perror("stk setup");
+        exit(-1);
     }
+
     return p;
 }
 
@@ -761,86 +250,6 @@ static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
         }
 }
 
-
-static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
-                                   struct elfhdr * exec,
-                                   abi_ulong load_addr,
-                                   abi_ulong load_bias,
-                                   abi_ulong interp_load_addr, int ibcs,
-                                   struct image_info *info)
-{
-        abi_ulong sp;
-        int size;
-        abi_ulong u_platform;
-        const char *k_platform;
-        const int n = sizeof(elf_addr_t);
-
-        sp = p;
-        u_platform = 0;
-        k_platform = ELF_PLATFORM;
-        if (k_platform) {
-            size_t len = strlen(k_platform) + 1;
-            sp -= (len + n - 1) & ~(n - 1);
-            u_platform = sp;
-            /* FIXME - check return value of memcpy_to_target() for failure */
-            memcpy_to_target(sp, k_platform, len);
-        }
-        /*
-         * Force 16 byte _final_ alignment here for generality.
-         */
-        sp = sp &~ (abi_ulong)15;
-        size = (DLINFO_ITEMS + 1) * 2;
-        if (k_platform)
-          size += 2;
-#ifdef DLINFO_ARCH_ITEMS
-        size += DLINFO_ARCH_ITEMS * 2;
-#endif
-        size += envc + argc + 2;
-        size += (!ibcs ? 3 : 1);        /* argc itself */
-        size *= n;
-        if (size & 15)
-            sp -= 16 - (size & 15);
-
-        /* This is correct because Linux defines
-         * elf_addr_t as Elf32_Off / Elf64_Off
-         */
-#define NEW_AUX_ENT(id, val) do {               \
-            sp -= n; put_user_ual(val, sp);     \
-            sp -= n; put_user_ual(id, sp);      \
-          } while(0)
-
-        NEW_AUX_ENT (AT_NULL, 0);
-
-        /* There must be exactly DLINFO_ITEMS entries here.  */
-        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
-        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
-        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
-        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
-        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
-        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
-        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
-        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
-        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
-        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
-        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
-        NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
-        NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
-        if (k_platform)
-            NEW_AUX_ENT(AT_PLATFORM, u_platform);
-#ifdef ARCH_DLINFO
-        /*
-         * ARCH_DLINFO must come last so platform specific code can enforce
-         * special alignment requirements on the AUXV if necessary (eg. PPC).
-         */
-        ARCH_DLINFO;
-#endif
-#undef NEW_AUX_ENT
-
-        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
-        return sp;
-}
-
-
 static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                                  int interpreter_fd,
                                  abi_ulong *interp_load_addr)
@@ -858,9 +267,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
         last_bss = 0;
         error = 0;
 
-#ifdef BSWAP_NEEDED
         bswap_ehdr(interp_elf_ex);
-#endif
         /* First of all, some simple consistency checks */
         if ((interp_elf_ex->e_type != ET_EXEC &&
              interp_elf_ex->e_type != ET_DYN) ||
@@ -901,12 +308,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                 free (elf_phdata);
                 return retval;
         }
-#ifdef BSWAP_NEEDED
-        eppnt = elf_phdata;
-        for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
-            bswap_phdr(eppnt);
-        }
-#endif
+        bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
 
         if (interp_elf_ex->e_type == ET_DYN) {
             /* in order to avoid hardcoding the interpreter load
@@ -923,54 +325,57 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
         }
 
         eppnt = elf_phdata;
-        for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
-          if (eppnt->p_type == PT_LOAD) {
-            int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
-            int elf_prot = 0;
-            abi_ulong vaddr = 0;
-            abi_ulong k;
-
-            if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
-            if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-            if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-            if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
-                elf_type |= MAP_FIXED;
-                vaddr = eppnt->p_vaddr;
-            }
-            error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
-                 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
-                 elf_prot,
-                 elf_type,
-                 interpreter_fd,
-                 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
-
-            if (error == -1) {
-              /* Real error */
-              close(interpreter_fd);
-              free(elf_phdata);
-              return ~((abi_ulong)0UL);
-            }
-
-            if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
-              load_addr = error;
-              load_addr_set = 1;
+        for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++)
+            if (eppnt->p_type == PT_LOAD) {
+                int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+                int elf_prot = 0;
+                abi_ulong vaddr = 0;
+                abi_ulong k;
+
+                if (eppnt->p_flags & PF_R) {
+                    elf_prot =  PROT_READ;
+                }
+                if (eppnt->p_flags & PF_W) {
+                    elf_prot |= PROT_WRITE;
+                }
+                if (eppnt->p_flags & PF_X) {
+                    elf_prot |= PROT_EXEC;
+                }
+                if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
+                    elf_type |= MAP_FIXED;
+                    vaddr = eppnt->p_vaddr;
+                }
+                error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
+                        eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
+                        elf_prot, elf_type, interpreter_fd, eppnt->p_offset -
+                        TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
+                if (error == -1) {
+                    /* Real error */
+                    close(interpreter_fd);
+                    free(elf_phdata);
+                    return ~((abi_ulong)0UL);
+                }
+                if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+                    load_addr = error;
+                    load_addr_set = 1;
+                }
+                /*
+                 * Find the end of the file  mapping for this phdr, and keep
+                 * track of the largest address we see for this.
+                 */
+                k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
+                if (k > elf_bss) {
+                    elf_bss = k;
+                }
+                /*
+                 * Do the same thing for the memory mapping - between
+                 * elf_bss and last_bss is the bss section.
+                 */
+                k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+                if (k > last_bss) {
+                    last_bss = k;
+                }
             }
-
-            /*
-             * Find the end of the file  mapping for this phdr, and keep
-             * track of the largest address we see for this.
-             */
-            k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
-            if (k > elf_bss) elf_bss = k;
-
-            /*
-             * Do the same thing for the memory mapping - between
-             * elf_bss and last_bss is the bss section.
-             */
-            k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
-            if (k > last_bss) last_bss = k;
-          }
-
         /* Now use mmap to map the library into memory. */
 
         close(interpreter_fd);
@@ -982,7 +387,8 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
          * bss page.
          */
         padzero(elf_bss, last_bss);
-        elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
+        /* What we have mapped so far */
+        elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1);
 
         /* Map the last of the bss segment */
         if (last_bss > elf_bss) {
@@ -1051,9 +457,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
     for (i = 0; i < hdr->e_shnum; i++) {
         if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
             return;
-#ifdef BSWAP_NEEDED
-        bswap_shdr(&sechdr);
-#endif
+        bswap_shdr(&sechdr, 1);
         if (sechdr.sh_type == SHT_SYMTAB) {
             symtab = sechdr;
             lseek(fd, hdr->e_shoff
@@ -1061,9 +465,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
             if (read(fd, &strtab, sizeof(strtab))
                 != sizeof(strtab))
                 return;
-#ifdef BSWAP_NEEDED
-            bswap_shdr(&strtab);
-#endif
+            bswap_shdr(&strtab, 1);
             goto found;
         }
     }
@@ -1096,9 +498,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
 
     i = 0;
     while (i < nsyms) {
-#ifdef BSWAP_NEEDED
         bswap_sym(syms + i);
-#endif
         // Throw away entries which we do not need.
         if (syms[i].st_shndx == SHN_UNDEF ||
                 syms[i].st_shndx >= SHN_LORESERVE ||
@@ -1150,6 +550,30 @@ static void load_symbols(struct elfhdr *hdr, int fd)
     syminfos = s;
 }
 
+/* Check the elf header and see if this a target elf binary. */
+int is_target_elf_binary(int fd)
+{
+    uint8_t buf[128];
+    struct elfhdr elf_ex;
+
+    if (lseek(fd, 0L, SEEK_SET) < 0) {
+        return 0;
+    }
+    if (read(fd, buf, sizeof(buf)) < 0) {
+        return 0;
+    }
+
+    elf_ex = *((struct elfhdr *)buf);
+    bswap_ehdr(&elf_ex);
+
+    if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
+        (!elf_check_arch(elf_ex.e_machine))) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
 int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
                     struct image_info *info)
 {
@@ -1169,20 +593,18 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
     int retval;
     char * elf_interpreter;
     abi_ulong elf_entry, interp_load_addr = 0;
-    int status;
     abi_ulong start_code, end_code, start_data, end_data;
     abi_ulong reloc_func_desc = 0;
+#ifdef LOW_ELF_STACK
     abi_ulong elf_stack;
+#endif
     char passed_fileno[6];
 
     ibcs2_interpreter = 0;
-    status = 0;
     load_addr = 0;
     load_bias = 0;
     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
-#ifdef BSWAP_NEEDED
     bswap_ehdr(&elf_ex);
-#endif
 
     /* First of all, some simple consistency checks */
     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
@@ -1190,12 +612,14 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
             return -ENOEXEC;
     }
 
+#ifndef __FreeBSD__
     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
     if (!bprm->p) {
         retval = -E2BIG;
     }
+#endif /* ! __FreeBSD__ */
 
     /* Now read in all of the header information */
     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
@@ -1216,19 +640,16 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
         return -errno;
     }
 
-#ifdef BSWAP_NEEDED
-    elf_ppnt = elf_phdata;
-    for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
-        bswap_phdr(elf_ppnt);
-    }
-#endif
+    bswap_phdr(elf_phdata, elf_ex.e_phnum);
     elf_ppnt = elf_phdata;
 
     elf_bss = 0;
     elf_brk = 0;
 
 
+#ifdef LOW_ELF_STACK
     elf_stack = ~((abi_ulong)0UL);
+#endif
     elf_interpreter = NULL;
     start_code = ~((abi_ulong)0UL);
     end_code = 0;
@@ -1236,7 +657,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
     end_data = 0;
     interp_ex.a_info = 0;
 
-    for(i=0;i < elf_ex.e_phnum; i++) {
+    for (i = 0; i < elf_ex.e_phnum; i++) {
         if (elf_ppnt->p_type == PT_INTERP) {
             if ( elf_interpreter != NULL )
             {
@@ -1274,9 +695,9 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
 
             /* JRP - Need to add X86 lib dir stuff here... */
 
-            if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
-                strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
-              ibcs2_interpreter = 1;
+            if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0 ||
+                    strcmp(elf_interpreter, "/usr/lib/ld-elf.so.1") == 0) {
+                ibcs2_interpreter = 1;
             }
 
 #if 0
@@ -1406,7 +827,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
      * address.
      */
 
-    for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+    for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
         int elf_prot = 0;
         int elf_flags = 0;
         abi_ulong error;
@@ -1423,7 +844,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
         } else if (elf_ex.e_type == ET_DYN) {
             /* Try and get dynamic programs out of the way of the default mmap
                base, as well as whatever program they might try to exec.  This
-               is because the brk will follow the loader, and is not movable.  */
+               is because the brk will follow the loader, and is not movable. */
             /* NOTE: for qemu, we do a big mmap to get enough space
                without hardcoding any address */
             error = target_mmap(0, ET_DYN_MAP_SIZE,
@@ -1520,7 +941,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
 #ifdef LOW_ELF_STACK
     info->start_stack = bprm->p = elf_stack - 4;
 #endif
-    bprm->p = create_elf_tables(bprm->p,
+    bprm->p = target_create_elf_tables(bprm->p,
                     bprm->argc,
                     bprm->envc,
                     &elf_ex,
@@ -1536,19 +957,22 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
     info->end_data = end_data;
     info->start_stack = bprm->p;
 
-    /* Calling set_brk effectively mmaps the pages that we need for the bss and break
-       sections */
+    /*
+     * Calling set_brk effectively mmaps the pages that we need for the bss
+     * and break sections.
+     */
     set_brk(elf_bss, elf_brk);
 
     padzero(elf_bss, elf_brk);
 
 #if 0
-    printf("(start_brk) %x\n" , info->start_brk);
-    printf("(end_code) %x\n" , info->end_code);
-    printf("(start_code) %x\n" , info->start_code);
-    printf("(end_data) %x\n" , info->end_data);
-    printf("(start_stack) %x\n" , info->start_stack);
-    printf("(brk) %x\n" , info->brk);
+    printf("(start_brk) 0x" TARGET_FMT_lx "\n" , info->start_brk);
+    printf("(end_code) 0x" TARGET_FMT_lx "\n" , info->end_code);
+    printf("(start_code) 0x" TARGET_FMT_lx "\n" , info->start_code);
+    printf("(start_data) 0x" TARGET_FMT_lx "\n" , info->start_data);
+    printf("(end_data) 0x" TARGET_FMT_lx "\n" , info->end_data);
+    printf("(start_stack) 0x" TARGET_FMT_lx "\n" , info->start_stack);
+    printf("(brk) 0x" TARGET_FMT_lx "\n" , info->brk);
 #endif
 
     if ( info->personality == PER_SVR4 )
@@ -1557,12 +981,21 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
                and some applications "depend" upon this behavior.
                Since we do not have the power to recompile these, we
                emulate the SVr4 behavior.  Sigh.  */
-            mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
-                                      MAP_FIXED | MAP_PRIVATE, -1, 0);
+            mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ |
+                    PROT_EXEC, MAP_FIXED | MAP_PRIVATE, -1, 0);
+	    if (mapped_addr == -1) {
+		    return -1;
+	    }
     }
 
     info->entry = elf_entry;
 
+#ifdef USE_ELF_CORE_DUMP
+    /* not yet */
+    /* bprm->core_dump = &elf_core_dump; */
+    bprm->core_dump = NULL;
+#endif
+
     return 0;
 }
 
@@ -1574,5 +1007,5 @@ static int load_aout_interp(void * exptr, int interp_fd)
 
 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
 {
-    init_thread(regs, infop);
+    target_thread_init(regs, infop);
 }
diff --git a/bsd-user/freebsd/target_os_elf.h b/bsd-user/freebsd/target_os_elf.h
new file mode 100644
index 0000000..67637a0
--- /dev/null
+++ b/bsd-user/freebsd/target_os_elf.h
@@ -0,0 +1,145 @@
+/*
+ *  freebsd ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_OS_ELF_H_
+#define _TARGET_OS_ELF_H_
+
+#include "target_arch_elf.h"
+#include "elf.h"
+
+/* this flag is uneffective under linux too, should be deleted */
+#ifndef MAP_DENYWRITE
+#define MAP_DENYWRITE 0
+#endif
+
+/* should probably go in elf.h */
+#ifndef ELIBBAD
+#define ELIBBAD 80
+#endif
+
+#ifndef ELF_PLATFORM
+#define ELF_PLATFORM (NULL)
+#endif
+
+#ifndef ELF_HWCAP
+#define ELF_HWCAP 0
+#endif
+
+#ifdef TARGET_ABI32
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+#undef bswaptls
+#define bswaptls(ptr) bswap32s(ptr)
+#endif
+
+struct exec
+{
+  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
+  unsigned int a_text;   /* length of text, in bytes */
+  unsigned int a_data;   /* length of data, in bytes */
+  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
+  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
+  unsigned int a_entry;  /* start address */
+  unsigned int a_trsize; /* length of relocation info for text, in bytes */
+  unsigned int a_drsize; /* length of relocation info for data, in bytes */
+};
+
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+
+/* max code+data+bss space allocated to elf interpreter */
+#define INTERP_MAP_SIZE (32 * 1024 * 1024)
+
+/* max code+data+bss+brk space allocated to ET_DYN executables */
+#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
+
+/* Necessary parameters */
+#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
+#define TARGET_ELF_PAGESTART(_v) ((_v) & \
+        ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+#define DLINFO_ITEMS 12
+
+static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc,
+                                   struct elfhdr * exec,
+                                   abi_ulong load_addr,
+                                   abi_ulong load_bias,
+                                   abi_ulong interp_load_addr, int ibcs,
+                                   struct image_info *info)
+{
+        abi_ulong sp;
+        int size;
+        const int n = sizeof(elf_addr_t);
+
+        sp = p;
+        /*
+         * Force 16 byte _final_ alignment here for generality.
+         */
+        sp = sp &~ (abi_ulong)15;
+        size = (DLINFO_ITEMS + 1) * 2;
+        size += envc + argc + 2;
+        size += (!ibcs ? 3 : 1);        /* argc itself */
+        size *= n;
+        if (size & 15)
+            sp -= 16 - (size & 15);
+
+        /* This is correct because Linux defines
+         * elf_addr_t as Elf32_Off / Elf64_Off
+         */
+#define NEW_AUX_ENT(id, val) do {               \
+            sp -= n; put_user_ual(val, sp);     \
+            sp -= n; put_user_ual(id, sp);      \
+          } while(0)
+
+        NEW_AUX_ENT (AT_NULL, 0);
+
+        /* There must be exactly DLINFO_ITEMS entries here.  */
+        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+#ifdef ARCH_DLINFO
+        /*
+         * ARCH_DLINFO must come last so platform specific code can enforce
+         * special alignment requirements on the AUXV if necessary (eg. PPC).
+         */
+        ARCH_DLINFO;
+#endif
+#undef NEW_AUX_ENT
+
+        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+        return sp;
+}
+
+#endif /* _TARGET_OS_ELF_H_ */
diff --git a/bsd-user/freebsd/target_os_thread.h b/bsd-user/freebsd/target_os_thread.h
new file mode 100644
index 0000000..519aad8
--- /dev/null
+++ b/bsd-user/freebsd/target_os_thread.h
@@ -0,0 +1,6 @@
+#ifndef _TARGET_OS_THREAD_H_
+#define _TARGET_OS_THREAD_H_
+
+#include "target_arch_thread.h"
+
+#endif /* !_TARGET_OS_THREAD_H_ */
diff --git a/bsd-user/i386/target_arch_elf.h b/bsd-user/i386/target_arch_elf.h
new file mode 100644
index 0000000..83b2197
--- /dev/null
+++ b/bsd-user/i386/target_arch_elf.h
@@ -0,0 +1,62 @@
+/*
+ *  i386 ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x80000000
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS       ELFCLASS32
+#define ELF_DATA        ELFDATA2LSB
+#define ELF_ARCH        EM_386
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+/* XXX */
+#ifndef __FreeBSD__
+#define ELF_PLATFORM target_elf_get_platform()
+
+static const char *target_elf_get_platform(void)
+{
+    static char elf_platform[] = "i386";
+    int family = (thread_env->cpuid_version >> 8) & 0xff;
+    if (family > 6)
+        family = 6;
+    if (family >= 3)
+        elf_platform[1] = '0' + family;
+    return elf_platform;
+}
+
+#define ELF_HWCAP target_elf_get_hwcap()
+
+static uint32_t target_elf_get_hwcap(void)
+{
+    return thread_env->features[FEAT_1_EDX];
+}
+#endif /* ! __FreeBSD__ */
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/i386/target_arch_thread.h b/bsd-user/i386/target_arch_thread.h
new file mode 100644
index 0000000..407aa6c
--- /dev/null
+++ b/bsd-user/i386/target_arch_thread.h
@@ -0,0 +1,45 @@
+/*
+ *  i386 thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUX86State *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    /* XXX */
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    regs->esp = infop->start_stack;
+    regs->eip = infop->entry;
+
+    /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
+       starts %edx contains a pointer to a function which might be
+       registered using `atexit'.  This provides a mean for the
+       dynamic linker to call DT_FINI functions for shared libraries
+       that have been loaded before the code runs.
+
+       A value of 0 tells we have no such handler.  */
+    regs->edx = 0;
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/mips/target_arch_elf.h b/bsd-user/mips/target_arch_elf.h
new file mode 100644
index 0000000..8630f34
--- /dev/null
+++ b/bsd-user/mips/target_arch_elf.h
@@ -0,0 +1,36 @@
+/*
+ *  mips ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define elf_check_arch(x) ( (x) == EM_MIPS )
+#define ELF_START_MMAP 0x80000000
+#define ELF_CLASS   ELFCLASS32
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+#define ELF_ARCH    EM_MIPS
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        4096
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/mips/target_arch_thread.h b/bsd-user/mips/target_arch_thread.h
new file mode 100644
index 0000000..c76b0d6
--- /dev/null
+++ b/bsd-user/mips/target_arch_thread.h
@@ -0,0 +1,54 @@
+/*
+ *  mips thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to mips/mips/vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUMIPSState *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    abi_ulong sp;
+
+    /*
+     * At the point where a function is called, sp must be 8
+     * byte aligned[for compatibility with 64-bit CPUs]
+     * in ``See MIPS Run'' by D. Sweetman, p. 269
+     * align stack
+     */
+    sp = ((stack_base + stack_size) & ~0x7) - TARGET_CALLFRAME_SIZ;
+
+    /* t9 = pc = start function entry */
+    regs->active_tc.gpr[25] = regs->active_tc.PC = entry;
+    /* a0 = arg */
+    regs->active_tc.gpr[4] = arg;
+    /* sp = top of the stack */
+    regs->active_tc.gpr[29] = sp;
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    regs->cp0_status = 2 << CP0St_KSU;
+    regs->regs[25] = regs->cp0_epc = infop->entry & ~3;  /* t9/pc = entry */
+    regs->regs[4] = regs->regs[29] = infop->start_stack; /* a0/sp = stack */
+    regs->regs[5] = regs->regs[6] = 0;                   /* a1/a2 = 0 */
+    regs->regs[7] = TARGET_PS_STRINGS;                   /* a3 = ps_strings */
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/mips64/target_arch_elf.h b/bsd-user/mips64/target_arch_elf.h
new file mode 100644
index 0000000..ca0da03
--- /dev/null
+++ b/bsd-user/mips64/target_arch_elf.h
@@ -0,0 +1,36 @@
+/*
+ *  mips64 ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define elf_check_arch(x) ( (x) == EM_MIPS )
+#define ELF_START_MMAP 0x2aaaaab000ULL
+#define ELF_CLASS   ELFCLASS64
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+#define ELF_ARCH    EM_MIPS
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        4096
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/mips64/target_arch_thread.h b/bsd-user/mips64/target_arch_thread.h
new file mode 100644
index 0000000..7fcd866
--- /dev/null
+++ b/bsd-user/mips64/target_arch_thread.h
@@ -0,0 +1,54 @@
+/*
+ *  mips64 thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _MIPS64_ARCH_THREAD_H_
+#define _MIPS64_ARCH_THREAD_H_
+
+/* Compare to mips/mips/vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUMIPSState *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    abi_ulong sp;
+
+    /*
+     * At the point where a function is called, sp must be 8
+     * byte aligned[for compatibility with 64-bit CPUs]
+     * in ``See MIPS Run'' by D. Sweetman, p. 269
+     * align stack
+     */
+    sp = ((stack_base + stack_size) & ~0x7) - TARGET_CALLFRAME_SIZ;
+
+    /* t9 = pc = start function entry */
+    regs->active_tc.gpr[25] = regs->active_tc.PC = entry;
+    /* a0 = arg */
+    regs->active_tc.gpr[4] = arg;
+    /* sp = top of the stack */
+    regs->active_tc.gpr[29] = sp;
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    regs->cp0_status = 2 << CP0St_KSU;
+    regs->regs[25] = regs->cp0_epc = infop->entry & ~3;  /* t9/pc = entry */
+    regs->regs[4] = regs->regs[29] = infop->start_stack; /* a0/sp = stack */
+    regs->regs[5] = regs->regs[6] = 0;                   /* a1/a2 = 0 */
+    regs->regs[7] = TARGET_PS_STRINGS;                   /* a3 = ps_strings */
+}
+
+#endif /* !_MIPS64_ARCH_THREAD_H_ */
diff --git a/bsd-user/netbsd/target_os_elf.h b/bsd-user/netbsd/target_os_elf.h
new file mode 100644
index 0000000..bf663d2
--- /dev/null
+++ b/bsd-user/netbsd/target_os_elf.h
@@ -0,0 +1,226 @@
+/*
+ *  netbsd ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_OS_ELF_H_
+#define _TARGET_OS_ELF_H_
+
+#include "target_arch_elf.h"
+#include "elf.h"
+
+/* from personality.h */
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA
+                                                   space */
+        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs
+                                                   point to descriptors
+                                                   (signal handling) */
+        MMAP_PAGE_ZERO =        0x0100000,
+        ADDR_COMPAT_LAYOUT =    0x0200000,
+        READ_IMPLIES_EXEC =     0x0400000,
+        ADDR_LIMIT_32BIT =      0x0800000,
+        SHORT_INODE =           0x1000000,
+        WHOLE_SECONDS =         0x2000000,
+        STICKY_TIMEOUTS =       0x4000000,
+        ADDR_LIMIT_3GB =        0x8000000,
+};
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+        PER_LINUX =             0x0000,
+        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
+        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
+        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
+                                         WHOLE_SECONDS | SHORT_INODE,
+        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
+        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
+        PER_BSD =               0x0006,
+        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
+        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_LINUX32 =           0x0008,
+        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
+        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
+        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
+        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
+        PER_RISCOS =            0x000c,
+        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
+        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
+        PER_HPUX =              0x0010,
+        PER_MASK =              0x00ff,
+};
+
+/*
+ * Return the base personality without flags.
+ */
+#define personality(pers)       (pers & PER_MASK)
+
+/* this flag is uneffective under linux too, should be deleted */
+#ifndef MAP_DENYWRITE
+#define MAP_DENYWRITE 0
+#endif
+
+/* should probably go in elf.h */
+#ifndef ELIBBAD
+#define ELIBBAD 80
+#endif
+
+#ifndef ELF_PLATFORM
+#define ELF_PLATFORM (NULL)
+#endif
+
+#ifndef ELF_HWCAP
+#define ELF_HWCAP 0
+#endif
+
+#ifdef TARGET_ABI32
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+#undef bswaptls
+#define bswaptls(ptr) bswap32s(ptr)
+#endif
+
+struct exec
+{
+  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
+  unsigned int a_text;   /* length of text, in bytes */
+  unsigned int a_data;   /* length of data, in bytes */
+  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
+  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
+  unsigned int a_entry;  /* start address */
+  unsigned int a_trsize; /* length of relocation info for text, in bytes */
+  unsigned int a_drsize; /* length of relocation info for data, in bytes */
+};
+
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+
+/* max code+data+bss space allocated to elf interpreter */
+#define INTERP_MAP_SIZE (32 * 1024 * 1024)
+
+/* max code+data+bss+brk space allocated to ET_DYN executables */
+#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
+
+/* Necessary parameters */
+#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
+#define TARGET_ELF_PAGESTART(_v) ((_v) & \
+        ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+#define DLINFO_ITEMS 12
+
+static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc,
+                                   struct elfhdr * exec,
+                                   abi_ulong load_addr,
+                                   abi_ulong load_bias,
+                                   abi_ulong interp_load_addr, int ibcs,
+                                   struct image_info *info)
+{
+        abi_ulong sp;
+        int size;
+        abi_ulong u_platform;
+        const char *k_platform;
+        const int n = sizeof(elf_addr_t);
+
+        sp = p;
+        u_platform = 0;
+        k_platform = ELF_PLATFORM;
+        if (k_platform) {
+            size_t len = strlen(k_platform) + 1;
+            sp -= (len + n - 1) & ~(n - 1);
+            u_platform = sp;
+            /* FIXME - check return value of memcpy_to_target() for failure */
+            memcpy_to_target(sp, k_platform, len);
+        }
+        /*
+         * Force 16 byte _final_ alignment here for generality.
+         */
+        sp = sp &~ (abi_ulong)15;
+        size = (DLINFO_ITEMS + 1) * 2;
+        if (k_platform)
+          size += 2;
+#ifdef DLINFO_ARCH_ITEMS
+        size += DLINFO_ARCH_ITEMS * 2;
+#endif
+        size += envc + argc + 2;
+        size += (!ibcs ? 3 : 1);        /* argc itself */
+        size *= n;
+        if (size & 15)
+            sp -= 16 - (size & 15);
+
+        /* This is correct because Linux defines
+         * elf_addr_t as Elf32_Off / Elf64_Off
+         */
+#define NEW_AUX_ENT(id, val) do {               \
+            sp -= n; put_user_ual(val, sp);     \
+            sp -= n; put_user_ual(id, sp);      \
+          } while(0)
+
+        NEW_AUX_ENT (AT_NULL, 0);
+
+        /* There must be exactly DLINFO_ITEMS entries here.  */
+        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+        NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
+        NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+        if (k_platform)
+            NEW_AUX_ENT(AT_PLATFORM, u_platform);
+#ifdef ARCH_DLINFO
+        /*
+         * ARCH_DLINFO must come last so platform specific code can enforce
+         * special alignment requirements on the AUXV if necessary (eg. PPC).
+         */
+        ARCH_DLINFO;
+#endif
+#undef NEW_AUX_ENT
+
+        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+        return sp;
+}
+
+#endif /* _TARGET_OS_ELF_H_ */
diff --git a/bsd-user/netbsd/target_os_thread.h b/bsd-user/netbsd/target_os_thread.h
new file mode 100644
index 0000000..519aad8
--- /dev/null
+++ b/bsd-user/netbsd/target_os_thread.h
@@ -0,0 +1,6 @@
+#ifndef _TARGET_OS_THREAD_H_
+#define _TARGET_OS_THREAD_H_
+
+#include "target_arch_thread.h"
+
+#endif /* !_TARGET_OS_THREAD_H_ */
diff --git a/bsd-user/openbsd/target_os_elf.h b/bsd-user/openbsd/target_os_elf.h
new file mode 100644
index 0000000..978d944
--- /dev/null
+++ b/bsd-user/openbsd/target_os_elf.h
@@ -0,0 +1,226 @@
+/*
+ *  openbsd ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_OS_ELF_H_
+#define _TARGET_OS_ELF_H_
+
+#include "target_arch_elf.h"
+#include "elf.h"
+
+/* from personality.h */
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA
+                                                   space */
+        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs
+                                                   point to descriptors
+                                                   (signal handling) */
+        MMAP_PAGE_ZERO =        0x0100000,
+        ADDR_COMPAT_LAYOUT =    0x0200000,
+        READ_IMPLIES_EXEC =     0x0400000,
+        ADDR_LIMIT_32BIT =      0x0800000,
+        SHORT_INODE =           0x1000000,
+        WHOLE_SECONDS =         0x2000000,
+        STICKY_TIMEOUTS =       0x4000000,
+        ADDR_LIMIT_3GB =        0x8000000,
+};
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+        PER_LINUX =             0x0000,
+        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
+        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
+        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
+                                         WHOLE_SECONDS | SHORT_INODE,
+        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
+        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
+        PER_BSD =               0x0006,
+        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
+        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_LINUX32 =           0x0008,
+        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
+        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
+        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
+        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
+        PER_RISCOS =            0x000c,
+        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
+        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
+        PER_HPUX =              0x0010,
+        PER_MASK =              0x00ff,
+};
+
+/*
+ * Return the base personality without flags.
+ */
+#define personality(pers)       (pers & PER_MASK)
+
+/* this flag is uneffective under linux too, should be deleted */
+#ifndef MAP_DENYWRITE
+#define MAP_DENYWRITE 0
+#endif
+
+/* should probably go in elf.h */
+#ifndef ELIBBAD
+#define ELIBBAD 80
+#endif
+
+#ifndef ELF_PLATFORM
+#define ELF_PLATFORM (NULL)
+#endif
+
+#ifndef ELF_HWCAP
+#define ELF_HWCAP 0
+#endif
+
+#ifdef TARGET_ABI32
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+#undef bswaptls
+#define bswaptls(ptr) bswap32s(ptr)
+#endif
+
+struct exec
+{
+  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
+  unsigned int a_text;   /* length of text, in bytes */
+  unsigned int a_data;   /* length of data, in bytes */
+  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
+  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
+  unsigned int a_entry;  /* start address */
+  unsigned int a_trsize; /* length of relocation info for text, in bytes */
+  unsigned int a_drsize; /* length of relocation info for data, in bytes */
+};
+
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+
+/* max code+data+bss space allocated to elf interpreter */
+#define INTERP_MAP_SIZE (32 * 1024 * 1024)
+
+/* max code+data+bss+brk space allocated to ET_DYN executables */
+#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
+
+/* Necessary parameters */
+#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
+#define TARGET_ELF_PAGESTART(_v) ((_v) & \
+        ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+#define DLINFO_ITEMS 12
+
+static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc,
+                                   struct elfhdr * exec,
+                                   abi_ulong load_addr,
+                                   abi_ulong load_bias,
+                                   abi_ulong interp_load_addr, int ibcs,
+                                   struct image_info *info)
+{
+        abi_ulong sp;
+        int size;
+        abi_ulong u_platform;
+        const char *k_platform;
+        const int n = sizeof(elf_addr_t);
+
+        sp = p;
+        u_platform = 0;
+        k_platform = ELF_PLATFORM;
+        if (k_platform) {
+            size_t len = strlen(k_platform) + 1;
+            sp -= (len + n - 1) & ~(n - 1);
+            u_platform = sp;
+            /* FIXME - check return value of memcpy_to_target() for failure */
+            memcpy_to_target(sp, k_platform, len);
+        }
+        /*
+         * Force 16 byte _final_ alignment here for generality.
+         */
+        sp = sp &~ (abi_ulong)15;
+        size = (DLINFO_ITEMS + 1) * 2;
+        if (k_platform)
+          size += 2;
+#ifdef DLINFO_ARCH_ITEMS
+        size += DLINFO_ARCH_ITEMS * 2;
+#endif
+        size += envc + argc + 2;
+        size += (!ibcs ? 3 : 1);        /* argc itself */
+        size *= n;
+        if (size & 15)
+            sp -= 16 - (size & 15);
+
+        /* This is correct because Linux defines
+         * elf_addr_t as Elf32_Off / Elf64_Off
+         */
+#define NEW_AUX_ENT(id, val) do {               \
+            sp -= n; put_user_ual(val, sp);     \
+            sp -= n; put_user_ual(id, sp);      \
+          } while(0)
+
+        NEW_AUX_ENT (AT_NULL, 0);
+
+        /* There must be exactly DLINFO_ITEMS entries here.  */
+        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+        NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
+        NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+        if (k_platform)
+            NEW_AUX_ENT(AT_PLATFORM, u_platform);
+#ifdef ARCH_DLINFO
+        /*
+         * ARCH_DLINFO must come last so platform specific code can enforce
+         * special alignment requirements on the AUXV if necessary (eg. PPC).
+         */
+        ARCH_DLINFO;
+#endif
+#undef NEW_AUX_ENT
+
+        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+        return sp;
+}
+
+#endif /* _TARGET_OS_ELF_H_ */
diff --git a/bsd-user/openbsd/target_os_thread.h b/bsd-user/openbsd/target_os_thread.h
new file mode 100644
index 0000000..519aad8
--- /dev/null
+++ b/bsd-user/openbsd/target_os_thread.h
@@ -0,0 +1,6 @@
+#ifndef _TARGET_OS_THREAD_H_
+#define _TARGET_OS_THREAD_H_
+
+#include "target_arch_thread.h"
+
+#endif /* !_TARGET_OS_THREAD_H_ */
diff --git a/bsd-user/sparc/target_arch_elf.h b/bsd-user/sparc/target_arch_elf.h
new file mode 100644
index 0000000..b93e2ed
--- /dev/null
+++ b/bsd-user/sparc/target_arch_elf.h
@@ -0,0 +1,30 @@
+/*
+ *  sparc ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_SPARC )
+
+#define ELF_CLASS   ELFCLASS32
+#define ELF_DATA    ELFDATA2MSB
+#define ELF_ARCH    EM_SPARC
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/sparc/target_arch_thread.h b/bsd-user/sparc/target_arch_thread.h
new file mode 100644
index 0000000..fe607be
--- /dev/null
+++ b/bsd-user/sparc/target_arch_thread.h
@@ -0,0 +1,39 @@
+/*
+ *  sparc thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUSPARCState *regs,
+    abi_ulong entry, abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    /* XXX */
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    regs->psr = 0;
+    regs->pc = infop->entry;
+    regs->npc = regs->pc + 4;
+    regs->y = 0;
+    regs->u_regs[14] = infop->start_stack - 16 * 4;
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/sparc64/target_arch_elf.h b/bsd-user/sparc64/target_arch_elf.h
new file mode 100644
index 0000000..f2b8e12
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_elf.h
@@ -0,0 +1,34 @@
+/*
+ *  sparc64 ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x80000000
+
+#ifndef TARGET_ABI32
+#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
+#else
+#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
+#endif
+
+#define ELF_CLASS   ELFCLASS64
+#define ELF_DATA    ELFDATA2MSB
+#define ELF_ARCH    EM_SPARCV9
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/sparc64/target_arch_thread.h b/bsd-user/sparc64/target_arch_thread.h
new file mode 100644
index 0000000..2e5585a
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_thread.h
@@ -0,0 +1,55 @@
+/*
+ *  sparc64 thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+#define STACK_BIAS              2047
+
+/* Compare to vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUSPARCState *regs,
+    abi_ulong entry, abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    /* XXX */
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+#ifndef TARGET_ABI32
+    regs->tstate = 0;
+#endif
+    regs->pc = infop->entry;
+    regs->npc = regs->pc + 4;
+    regs->y = 0;
+#ifdef TARGET_ABI32
+    regs->u_regs[14] = infop->start_stack - 16 * 4;
+#else
+    if (personality(infop->personality) == PER_LINUX32)
+        regs->u_regs[14] = infop->start_stack - 16 * 4;
+    else {
+        regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
+        if (bsd_type == target_freebsd) {
+            regs->u_regs[8] = infop->start_stack;
+            regs->u_regs[11] = infop->start_stack;
+        }
+    }
+#endif
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index ad84d33..13678d4 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -703,4 +703,68 @@ struct target_uuid {
     uint8_t     node[TARGET_UUID_NODE_LEN];
 };
 
+
+/*
+ * from personality.h
+ */
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA
+                                                   space */
+        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs
+                                                   point to descriptors
+                                                   (signal handling) */
+        MMAP_PAGE_ZERO =        0x0100000,
+        ADDR_COMPAT_LAYOUT =    0x0200000,
+        READ_IMPLIES_EXEC =     0x0400000,
+        ADDR_LIMIT_32BIT =      0x0800000,
+        SHORT_INODE =           0x1000000,
+        WHOLE_SECONDS =         0x2000000,
+        STICKY_TIMEOUTS =       0x4000000,
+        ADDR_LIMIT_3GB =        0x8000000,
+};
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+        PER_LINUX =             0x0000,
+        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
+        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
+        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
+                                         WHOLE_SECONDS | SHORT_INODE,
+        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
+        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
+        PER_BSD =               0x0006,
+        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
+        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_LINUX32 =           0x0008,
+        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
+        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
+        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
+        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
+        PER_RISCOS =            0x000c,
+        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
+        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
+        PER_HPUX =              0x0010,
+        PER_MASK =              0x00ff,
+};
+
+/*
+ * Return the base personality without flags.
+ */
+#define personality(pers)       (pers & PER_MASK)
+
 #endif /* ! _SYSCALL_DEFS_H_ */
diff --git a/bsd-user/x86_64/target_arch_elf.h b/bsd-user/x86_64/target_arch_elf.h
new file mode 100644
index 0000000..bc7c6a1
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_elf.h
@@ -0,0 +1,55 @@
+/*
+ *  x86_64 ELF definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_ELF_H_
+#define _TARGET_ARCH_ELF_H_
+
+#define ELF_START_MMAP 0x2aaaaab000ULL
+#define elf_check_arch(x) ( ((x) == ELF_ARCH) )
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_DATA       ELFDATA2LSB
+#define ELF_ARCH       EM_X86_64
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+/* XXX */
+#ifndef __FreeBSD__
+#define ELF_PLATFORM target_elf_get_platform()
+
+static const char *target_elf_get_platform(void)
+{
+    static char elf_platform[] = "i386";
+    int family = (thread_env->cpuid_version >> 8) & 0xff;
+    if (family > 6)
+        family = 6;
+    if (family >= 3)
+        elf_platform[1] = '0' + family;
+    return elf_platform;
+}
+
+#define ELF_HWCAP target_elf_get_hwcap()
+
+static uint32_t target_elf_get_hwcap(void)
+{
+    return thread_env->features[FEAT_1_EDX];
+}
+#endif /* ! __FreeBSD__ */
+
+#endif /* _TARGET_ARCH_ELF_H_ */
diff --git a/bsd-user/x86_64/target_arch_thread.h b/bsd-user/x86_64/target_arch_thread.h
new file mode 100644
index 0000000..d105e43
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_thread.h
@@ -0,0 +1,40 @@
+/*
+ *  x86_64 thread support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _TARGET_ARCH_THREAD_H_
+#define _TARGET_ARCH_THREAD_H_
+
+/* Compare to vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUX86State *regs, abi_ulong entry,
+    abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+    /* XXX */
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+    struct image_info *infop)
+{
+    regs->rax = 0;
+    regs->rsp = infop->start_stack;
+    regs->rip = infop->entry;
+    if (bsd_type == target_freebsd) {
+        regs->rdi = infop->start_stack;
+    }
+}
+
+#endif /* !_TARGET_ARCH_THREAD_H_ */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 09/19] bsd-user: add support for freebsd process related system calls
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (9 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 08/19] bsd-user: move arch/OS dependent code out of elfload.c Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 10/19] bsd-user: add support for file system " Stacey Son
                     ` (9 subsequent siblings)
  20 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change add support or stubs for process related system calls
including fork(2), vfork(2), rfork(2), pdfork(2), execve(2),
fexecve(2), wait4(2), exit(2), getgroups(2), setgroups(2),
umask(2), setlogin(2), getlogin(2), getrusage(2), getrlimit(2),
setrlimit(2), getpid(2), getppid(2), getuid(2), geteuid(2),
getgid(2), getegid(2), setuid(2), seteuid(2), setgid(2),
setegid(2), getpgrp(2), setreuid(2), setregid(2), getresuid(2),
getresgid(2), getsid(2), setsid(2), issetugid(2), profil(2),
ktrace(2), setloginclass(2), getloginclass(2), pdgetpid(2),
jail*(2), cap_*(2), *audit*(2), utrace(2), ptrace(2),
getpriority(2), and setpriority(2).
---
 bsd-user/Makefile.objs     |    4 +-
 bsd-user/bsd-proc.c        |  160 ++++++++++++++++
 bsd-user/bsd-proc.h        |  434 ++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-proc.c |  309 +++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-proc.h |  428 +++++++++++++++++++++++++++++++++++++++++++
 bsd-user/netbsd/os-proc.c  |   11 +
 bsd-user/netbsd/os-proc.h  |  243 +++++++++++++++++++++++++
 bsd-user/openbsd/os-proc.c |   11 +
 bsd-user/openbsd/os-proc.h |  243 +++++++++++++++++++++++++
 bsd-user/qemu-bsd.h        |   43 +++++
 bsd-user/qemu.h            |    4 +
 bsd-user/syscall.c         |  262 ++++++++++++++++++++++++++-
 12 files changed, 2144 insertions(+), 8 deletions(-)
 create mode 100644 bsd-user/bsd-proc.c
 create mode 100644 bsd-user/bsd-proc.h
 create mode 100644 bsd-user/freebsd/os-proc.c
 create mode 100644 bsd-user/freebsd/os-proc.h
 create mode 100644 bsd-user/netbsd/os-proc.c
 create mode 100644 bsd-user/netbsd/os-proc.h
 create mode 100644 bsd-user/openbsd/os-proc.c
 create mode 100644 bsd-user/openbsd/os-proc.h
 create mode 100644 bsd-user/qemu-bsd.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index ac69be7..fac11bb 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,3 +1,5 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o $(HOST_VARIANT_DIR)/os-sys.o \
+	        uaccess.o bsd-proc.o \
+			$(HOST_VARIANT_DIR)/os-proc.o \
+			$(HOST_VARIANT_DIR)/os-sys.o \
 			$(HOST_VARIANT_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/bsd-proc.c b/bsd-user/bsd-proc.c
new file mode 100644
index 0000000..a4bcdc8
--- /dev/null
+++ b/bsd-user/bsd-proc.c
@@ -0,0 +1,160 @@
+/*
+ *  BSD process related system call helpers
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+/*
+ * resource/rusage conversion
+ */
+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_MEMLOCK:
+        return RLIMIT_MEMLOCK;
+
+    case TARGET_RLIMIT_NOFILE:
+        return RLIMIT_NOFILE;
+
+    case TARGET_RLIMIT_NPROC:
+        return RLIMIT_NPROC;
+
+    case TARGET_RLIMIT_RSS:
+        return RLIMIT_RSS;
+
+    case TARGET_RLIMIT_SBSIZE:
+        return RLIMIT_SBSIZE;
+
+    case TARGET_RLIMIT_STACK:
+        return RLIMIT_STACK;
+
+    case TARGET_RLIMIT_SWAP:
+        return RLIMIT_SWAP;
+
+    case TARGET_RLIMIT_NPTS:
+        return RLIMIT_NPTS;
+
+    default:
+        return code;
+    }
+}
+
+rlim_t target_to_host_rlim(abi_ulong target_rlim)
+{
+    abi_ulong target_rlim_swap;
+    rlim_t result;
+
+    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;
+    }
+
+    return result;
+}
+
+abi_ulong host_to_target_rlim(rlim_t rlim)
+{
+    abi_ulong target_rlim_swap;
+    abi_ulong result;
+
+    if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim) {
+        target_rlim_swap = TARGET_RLIM_INFINITY;
+    } else {
+        target_rlim_swap = rlim;
+    }
+    result = tswapal(target_rlim_swap);
+
+    return result;
+}
+
+abi_long host_to_target_rusage(abi_ulong target_addr,
+        const struct rusage *rusage)
+{
+    struct target_freebsd_rusage *target_rusage;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(rusage->ru_utime.tv_sec, &target_rusage->ru_utime.tv_sec);
+    __put_user(rusage->ru_utime.tv_usec, &target_rusage->ru_utime.tv_usec);
+
+    __put_user(rusage->ru_stime.tv_sec, &target_rusage->ru_stime.tv_sec);
+    __put_user(rusage->ru_stime.tv_usec, &target_rusage->ru_stime.tv_usec);
+
+    __put_user(rusage->ru_maxrss, &target_rusage->ru_maxrss);
+    __put_user(rusage->ru_idrss, &target_rusage->ru_idrss);
+    __put_user(rusage->ru_idrss, &target_rusage->ru_idrss);
+    __put_user(rusage->ru_isrss, &target_rusage->ru_isrss);
+    __put_user(rusage->ru_minflt, &target_rusage->ru_minflt);
+    __put_user(rusage->ru_majflt, &target_rusage->ru_majflt);
+    __put_user(rusage->ru_nswap, &target_rusage->ru_nswap);
+    __put_user(rusage->ru_inblock, &target_rusage->ru_inblock);
+    __put_user(rusage->ru_oublock, &target_rusage->ru_oublock);
+    __put_user(rusage->ru_msgsnd, &target_rusage->ru_msgsnd);
+    __put_user(rusage->ru_msgrcv, &target_rusage->ru_msgrcv);
+    __put_user(rusage->ru_nsignals, &target_rusage->ru_nsignals);
+    __put_user(rusage->ru_nvcsw, &target_rusage->ru_nvcsw);
+    __put_user(rusage->ru_nivcsw, &target_rusage->ru_nivcsw);
+    unlock_user_struct(target_rusage, target_addr, 1);
+
+    return 0;
+}
+
+/*
+ * wait status conversion.
+ *
+ * Map host to target signal numbers for the wait family of syscalls.
+ * Assume all other status bits are the same.
+ */
+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;
+}
+
diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h
new file mode 100644
index 0000000..d1c732a
--- /dev/null
+++ b/bsd-user/bsd-proc.h
@@ -0,0 +1,434 @@
+/*
+ *  process related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_PROC_H_
+#define __BSD_PROC_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#include "qemu-bsd.h"
+
+extern int _getlogin(char*, int);
+
+/* exit(2) */
+static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1)
+{
+#ifdef TARGET_GPROF
+    _mcleanup();
+#endif
+    gdb_exit(cpu_env, arg1);
+    /* XXX: should free thread stack and CPU env here  */
+    _exit(arg1);
+
+    return 0;
+}
+
+/* getgroups(2) */
+static inline abi_long do_bsd_getgroups(abi_long gidsetsize, abi_long arg2)
+{
+    abi_long ret;
+    uint32_t *target_grouplist;
+    gid_t *grouplist;
+    int i;
+
+    grouplist = alloca(gidsetsize * sizeof(gid_t));
+    ret = get_errno(getgroups(gidsetsize, grouplist));
+    if (gidsetsize != 0) {
+        if (!is_error(ret)) {
+            target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
+            if (!target_grouplist) {
+                return -TARGET_EFAULT;
+            }
+            for (i = 0; i < ret; i++) {
+                target_grouplist[i] = tswap32(grouplist[i]);
+            }
+            unlock_user(target_grouplist, arg2, gidsetsize * 2);
+        }
+    }
+    return ret;
+}
+
+/* setgroups(2) */
+static inline abi_long do_bsd_setgroups(abi_long gidsetsize, abi_long arg2)
+{
+    uint32_t *target_grouplist;
+    gid_t *grouplist;
+    int i;
+
+    grouplist = alloca(gidsetsize * sizeof(gid_t));
+    target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
+    if (!target_grouplist) {
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < gidsetsize; i++) {
+        grouplist[i] = tswap32(target_grouplist[i]);
+    }
+    unlock_user(target_grouplist, arg2, 0);
+    return get_errno(setgroups(gidsetsize, grouplist));
+}
+
+/* umask(2) */
+static inline abi_long do_bsd_umask(abi_long arg1)
+{
+
+    return get_errno(umask(arg1));
+}
+
+/* setlogin(2) */
+static inline abi_long do_bsd_setlogin(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(setlogin(p));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* getlogin(2) */
+static inline abi_long do_bsd_getlogin(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(_getlogin(p, arg2));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* getrusage(2) */
+static inline abi_long do_bsd_getrusage(abi_long who, abi_ulong target_addr)
+{
+    abi_long ret;
+    struct rusage rusage;
+
+    ret = get_errno(getrusage(who, &rusage));
+    if (!is_error(ret)) {
+        host_to_target_rusage(target_addr, &rusage);
+    }
+    return ret;
+}
+
+/* getrlimit(2) */
+static inline abi_long do_bsd_getrlimit(abi_long arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    int resource = target_to_host_resource(arg1);
+    struct target_rlimit *target_rlim;
+    struct rlimit rlim;
+
+    switch (resource) {
+    case RLIMIT_STACK:
+        rlim.rlim_cur = target_dflssiz;
+        rlim.rlim_max = target_maxssiz;
+        ret = 0;
+        break;
+
+    case RLIMIT_DATA:
+        rlim.rlim_cur = target_dfldsiz;
+        rlim.rlim_max = target_maxdsiz;
+        ret = 0;
+        break;
+
+    default:
+        ret = get_errno(getrlimit(resource, &rlim));
+        break;
+    }
+    if (!is_error(ret)) {
+        if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) {
+            return -TARGET_EFAULT;
+        }
+        target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
+        target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
+        unlock_user_struct(target_rlim, arg2, 1);
+    }
+    return ret;
+}
+
+/* setrlimit(2) */
+static inline abi_long do_bsd_setrlimit(abi_long arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    int resource = target_to_host_resource(arg1);
+    struct target_rlimit *target_rlim;
+    struct rlimit rlim;
+
+    if (RLIMIT_STACK == resource) {
+        /* XXX We should, maybe, allow the stack size to shrink */
+        ret = -TARGET_EPERM;
+    } else {
+        if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) {
+            return -TARGET_EFAULT;
+        }
+        rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
+        rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
+        unlock_user_struct(target_rlim, arg2, 0);
+        ret = get_errno(setrlimit(resource, &rlim));
+    }
+    return ret;
+}
+
+/* getpid(2) */
+static inline abi_long do_bsd_getpid(void)
+{
+
+    return get_errno(getpid());
+}
+
+/* getppid(2) */
+static inline abi_long do_bsd_getppid(void)
+{
+
+    return get_errno(getppid());
+}
+
+/* getuid(2) */
+static inline abi_long do_bsd_getuid(void)
+{
+
+    return get_errno(getuid());
+}
+
+/* geteuid(2) */
+static inline abi_long do_bsd_geteuid(void)
+{
+
+    return get_errno(geteuid());
+}
+
+/* getgid(2) */
+static inline abi_long do_bsd_getgid(void)
+{
+
+    return get_errno(getgid());
+}
+
+/* getegid(2) */
+static inline abi_long do_bsd_getegid(void)
+{
+
+    return get_errno(getegid());
+}
+
+/* setuid(2) */
+static inline abi_long do_bsd_setuid(abi_long arg1)
+{
+
+    return get_errno(setuid(arg1));
+}
+
+/* seteuid(2) */
+static inline abi_long do_bsd_seteuid(abi_long arg1)
+{
+
+    return get_errno(seteuid(arg1));
+}
+
+/* setgid(2) */
+static inline abi_long do_bsd_setgid(abi_long arg1)
+{
+
+    return get_errno(setgid(arg1));
+}
+
+/* setegid(2) */
+static inline abi_long do_bsd_setegid(abi_long arg1)
+{
+
+    return get_errno(setegid(arg1));
+}
+
+/* getpgrp(2) */
+static inline abi_long do_bsd_getpgrp(void)
+{
+
+    return get_errno(getpgrp());
+}
+
+/* setreuid(2) */
+static inline abi_long do_bsd_setreuid(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(setreuid(arg1, arg2));
+}
+
+/* setregid(2) */
+static inline abi_long do_bsd_setregid(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(setregid(arg1, arg2));
+}
+
+/* setresuid(2) */
+static inline abi_long do_bsd_setresuid(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    return get_errno(setresuid(arg1, arg2, arg3));
+}
+
+/* getresuid(2) */
+static inline abi_long do_bsd_getresuid(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    uid_t ruid, euid, suid;
+
+    ret = get_errno(getresuid(&ruid, &euid, &suid));
+    if (is_error(ret)) {
+            return ret;
+    }
+    if (put_user_s32(ruid, arg1)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(euid, arg2)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(suid, arg3)) {
+        return -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+/* getresgid(2) */
+static inline abi_long do_bsd_getresgid(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    uid_t ruid, euid, suid;
+
+    ret = get_errno(getresgid(&ruid, &euid, &suid));
+    if (is_error(ret)) {
+            return ret;
+    }
+    if (put_user_s32(ruid, arg1)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(euid, arg2)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(suid, arg3)) {
+        return -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+/* getsid(2) */
+static inline abi_long do_bsd_getsid(abi_long arg1)
+{
+
+    return get_errno(getsid(arg1));
+}
+
+/* setsid(2) */
+static inline abi_long do_bsd_setsid(void)
+{
+
+    return get_errno(setsid());
+}
+
+/* issetugid(2) */
+static inline abi_long do_bsd_issetugid(void)
+{
+
+    return get_errno(issetugid());
+}
+
+/* profil(2) */
+static inline abi_long do_bsd_profil(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall profil()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* ktrace(2) */
+static inline abi_long do_bsd_ktrace(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall ktrace()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* utrace(2) */
+static inline abi_long do_bsd_utrace(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall ptrace()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* ptrace(2) */
+static inline abi_long do_bsd_ptrace(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall ptrace()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getpriority(2) */
+static inline abi_long do_bsd_getpriority(abi_long which, abi_long who)
+{
+    abi_long ret;
+    /*
+     * Note that negative values are valid for getpriority, so we must
+     * differentiate based on errno settings.
+     */
+    errno = 0;
+    ret = getpriority(which, who);
+    if (ret == -1 && errno != 0) {
+        ret = -host_to_target_errno(errno);
+        return ret;
+    }
+    /* Return value is a biased priority to avoid negative numbers. */
+    ret = 20 - ret;
+
+    return ret;
+}
+
+/* setpriority(2) */
+static inline abi_long do_bsd_setpriority(abi_long which, abi_long who,
+        abi_long prio)
+{
+
+    return get_errno(setpriority(which, who, prio));
+}
+
+
+#endif /* !__BSD_PROC_H_ */
+
diff --git a/bsd-user/freebsd/os-proc.c b/bsd-user/freebsd/os-proc.c
new file mode 100644
index 0000000..05df37f
--- /dev/null
+++ b/bsd-user/freebsd/os-proc.c
@@ -0,0 +1,309 @@
+/*
+ *  FreeBSD process related emulation code
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#include <libprocstat.h>
+#endif
+#include <string.h>
+
+#include "qemu.h"
+
+/*
+ * Get the filename for the given file descriptor.
+ * Note that this may return NULL (fail) if no longer cached in the kernel.
+ */
+static char *
+get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len)
+{
+    char *ret = NULL;
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+    unsigned int cnt;
+    struct procstat *procstat = NULL;
+    struct kinfo_proc *kipp = NULL;
+    struct filestat_list *head = NULL;
+    struct filestat *fst;
+
+    procstat = procstat_open_sysctl();
+    if (NULL == procstat) {
+        goto out;
+    }
+
+    kipp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt);
+    if (NULL == kipp) {
+        goto out;
+    }
+
+    head = procstat_getfiles(procstat, kipp, 0);
+    if (NULL == head) {
+        goto out;
+    }
+
+    STAILQ_FOREACH(fst, head, next) {
+        if (fd == fst->fs_fd) {
+            if (fst->fs_path != NULL) {
+                (void)strlcpy(filename, fst->fs_path, len);
+                ret = filename;
+            }
+            break;
+        }
+    }
+
+out:
+    if (head != NULL) {
+        procstat_freefiles(procstat, head);
+    }
+    if (kipp != NULL) {
+        procstat_freeprocs(procstat, kipp);
+    }
+    if (procstat != NULL) {
+        procstat_close(procstat);
+    }
+#endif
+    return ret;
+}
+
+static int
+is_target_shell_script(int fd, char *interp, size_t size)
+{
+    char buf[2], *p, *b;
+    ssize_t n;
+
+    if (fd < 0) {
+        return 0;
+    }
+    (void)lseek(fd, 0L, SEEK_SET);
+    if (read(fd, buf, 2) != 2) {
+        return 0;
+    }
+    if (buf[0] != '#' && buf[1] != '!') {
+        return 0;
+    }
+    if (size == 0) {
+        return 0;
+    }
+    b = interp;
+    /* Remove the trailing whitespace after "#!", if any. */
+    while (size != 0) {
+        n = read(fd, b, 1);
+        if (n < 0 || n == 0) {
+            return 0;
+        }
+        if ((*b != ' ') && (*b != '\t')) {
+            b++;
+            size--;
+            break;
+        }
+    }
+    while (size != 0) {
+        n = read(fd, b, size);
+        if (n < 0 || n == 0) {
+            return 0;
+        }
+        if ((p = memchr(b, '\n', size)) != NULL) {
+            *p = 0;
+            return 1;
+        }
+        b += n;
+        size -= n;
+    }
+
+    return 0;
+}
+
+/*
+ * execve/fexecve
+ */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec)
+{
+    char **argp, **envp, **qargp, **qarg1, **qarg0;
+    int argc, envc;
+    abi_ulong gp;
+    abi_ulong addr;
+    char **q;
+    int total_size = 0;
+    void *p;
+    abi_long ret;
+
+    argc = 0;
+    for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
+        if (get_user_ual(addr, gp)) {
+            return -TARGET_EFAULT;
+        }
+        if (!addr) {
+            break;
+        }
+        argc++;
+    }
+    envc = 0;
+    for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
+        if (get_user_ual(addr, gp)) {
+            return -TARGET_EFAULT;
+        }
+        if (!addr) {
+            break;
+        }
+        envc++;
+    }
+
+    qarg0 = argp =  alloca((argc + 4) * sizeof(void *));
+    /* save the first agrument for the emulator */
+    *argp++ = (char *)getprogname();
+    qargp = argp;
+    *argp++ = (char *)getprogname();
+    qarg1 = argp;
+    envp = alloca((envc + 1) * sizeof(void *));
+    for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp)) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+        if (!addr) {
+            break;
+        }
+        *q = lock_user_string(addr);
+        if (*q == NULL) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+        total_size += strlen(*q) + 1;
+    }
+    *q = NULL;
+
+    for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp)) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+        if (!addr) {
+            break;
+        }
+        *q = lock_user_string(addr);
+        if (*q == NULL) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+        total_size += strlen(*q) + 1;
+    }
+    *q = NULL;
+
+    /*
+     * 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;
+    }
+
+    if (do_fexec) {
+        char execpath[PATH_MAX];
+
+        if (((int)path_or_fd > 0 &&
+            is_target_elf_binary((int)path_or_fd)) == 1) {
+            char execpath[PATH_MAX];
+
+            /*
+             * The executable is an elf binary for the target
+             * arch.  execve() it using the emulator if we can
+             * determine the filename path from the fd.
+             */
+            if (get_filename_from_fd(getpid(), (int)path_or_fd, execpath,
+                        sizeof(execpath)) != NULL) {
+                *qarg1 = execpath;
+                ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
+            } else {
+                /* Getting the filename path failed. */
+                ret = -TARGET_EBADF;
+                goto execve_end;
+            }
+        } else if (is_target_shell_script((int)path_or_fd, execpath,
+                    sizeof(execpath)) != 0) {
+            char scriptpath[PATH_MAX];
+
+            /* execve() as a target script using emulator. */
+            if (get_filename_from_fd(getpid(), (int)path_or_fd, scriptpath,
+                        sizeof(scriptpath)) != NULL) {
+                *qargp = execpath;
+                *qarg1 = scriptpath;
+                ret = get_errno(execve(qemu_proc_pathname, qarg0, envp));
+            } else {
+                ret = -TARGET_EBADF;
+                goto execve_end;
+            }
+        } else {
+            ret = get_errno(fexecve((int)path_or_fd, argp, envp));
+        }
+    } else {
+        int fd;
+        char execpath[PATH_MAX];
+
+        p = lock_user_string(path_or_fd);
+        if (p == NULL) {
+            ret = -TARGET_EFAULT;
+            goto execve_end;
+        }
+
+        /*
+         * Check the header and see if it a target elf binary.  If so
+         * then execute using qemu user mode emulator.
+         */
+        fd = open(p, O_RDONLY | O_CLOEXEC);
+        if (fd > 0 && is_target_elf_binary(fd) == 1) {
+            close(fd);
+            /* execve() as a target binary using emulator. */
+            *qarg1 = (char *)p;
+            ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
+        } else if (is_target_shell_script(fd, execpath,
+                    sizeof(execpath)) != 0) {
+            close(fd);
+            /* execve() as a target script using emulator. */
+            *qargp = execpath;
+            *qarg1 = (char *)p;
+            ret = get_errno(execve(qemu_proc_pathname, qarg0, envp));
+        } else {
+            close(fd);
+            /* Execve() as a host native binary. */
+            ret = get_errno(execve(p, argp, envp));
+        }
+        unlock_user(p, path_or_fd, 0);
+    }
+
+execve_end:
+    for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp) || !addr) {
+            break;
+        }
+        unlock_user(*q, addr, 0);
+    }
+
+    for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp) || !addr) {
+            break;
+        }
+        unlock_user(*q, addr, 0);
+    }
+    return ret;
+}
+
+
diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h
new file mode 100644
index 0000000..b31f7c4
--- /dev/null
+++ b/bsd-user/freebsd/os-proc.h
@@ -0,0 +1,428 @@
+/*
+ *  process related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_PROC_H_
+#define __FREEBSD_PROC_H_
+
+#include <sys/types.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#include <sys/procdesc.h>
+#endif
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "target_arch_cpu.h"
+
+extern int __setugid(int flag);
+extern int pdwait4(int fd, int *status, int options, struct rusage *rusage);
+
+/* execve(2) */
+static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    return freebsd_exec_common(path_or_fd, argp, envp, 0);
+}
+
+/* fexecve(2) */
+static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    return freebsd_exec_common(path_or_fd, argp, envp, 1);
+}
+
+/* wait4(2) */
+static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
+        abi_long arg3, abi_ulong target_rusage)
+{
+    abi_long ret;
+    int status;
+    struct rusage rusage, *rusage_ptr = NULL;
+
+    if (target_rusage) {
+        rusage_ptr = &rusage;
+    }
+    ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
+    if (!is_error(ret)) {
+        status = host_to_target_waitstatus(status);
+        if (put_user_s32(status, target_status) != 0) {
+            return -TARGET_EFAULT;
+        }
+        if (target_rusage != 0) {
+            host_to_target_rusage(target_rusage, &rusage);
+        }
+    }
+    return ret;
+}
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(setloginclass(p));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(getloginclass(p, arg2));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+    abi_long ret;
+    int status;
+    struct rusage rusage, *rusage_ptr = NULL;
+
+    if (target_rusage) {
+        rusage_ptr = &rusage;
+    }
+    ret = get_errno(pdwait4(arg1, &status, arg3, rusage_ptr));
+    if (!is_error(ret)) {
+        status = host_to_target_waitstatus(status);
+        if (put_user_s32(status, target_status) != 0) {
+            return -TARGET_EFAULT;
+        }
+        if (target_rusage != 0) {
+            host_to_target_rusage(target_rusage, &rusage);
+        }
+    }
+    return ret;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+    abi_long ret;
+    pid_t pid;
+
+    ret = get_errno(pdgetpid(fd, &pid));
+    if (!is_error(ret)) {
+        if (put_user_u32(pid, target_pidp)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+#else
+
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall pdwait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+
+    qemu_log("qemu: Unsupported syscall pdgetpid()\n");
+    return -TARGET_ENOSYS;
+}
+#endif /* !  __FreeBSD_version > 900000 */
+
+/* undocumented __setugid */
+static inline abi_long do_freebsd___setugid(abi_long arg1)
+{
+
+    return get_errno(__setugid(arg1));
+}
+
+/* fork(2) */
+static inline abi_long do_freebsd_fork(void *cpu_env)
+{
+    abi_long ret;
+    abi_ulong child_flag = 0;
+
+    fork_start();
+    ret = fork();
+    if (ret == 0) {
+        /* child */
+        child_flag = 1;
+        target_cpu_clone_regs(cpu_env, 0);
+    } else {
+        /* parent */
+        fork_end(0);
+    }
+
+    /*
+     * The fork system call sets a child flag in the second return
+     * value: 0 for parent process, 1 for child process.
+     */
+    set_second_rval(cpu_env, child_flag);
+
+    return ret;
+}
+
+/* vfork(2) */
+static inline abi_long do_freebsd_vfork(void *cpu_env)
+{
+
+    return do_freebsd_fork(cpu_env);
+}
+
+/* rfork(2) */
+static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+{
+    abi_long ret;
+    abi_ulong child_flag = 0;
+
+    fork_start();
+    ret = rfork(flags);
+    if (ret == 0) {
+        /* child */
+        child_flag = 1;
+        target_cpu_clone_regs(cpu_env, 0);
+    } else {
+        /* parent */
+        fork_end(0);
+    }
+
+    /*
+     * The fork system call sets a child flag in the second return
+     * value: 0 for parent process, 1 for child process.
+     */
+    set_second_rval(cpu_env, child_flag);
+
+    return ret;
+
+}
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp,
+        abi_long flags)
+{
+    abi_long ret;
+    abi_ulong child_flag = 0;
+    int fd;
+
+    fork_start();
+    ret = pdfork(&fd, flags);
+    if (ret == 0) {
+        /* child */
+        child_flag = 1;
+        target_cpu_clone_regs(cpu_env, 0);
+    } else {
+        /* parent */
+        fork_end(0);
+    }
+    if (put_user_s32(fd, target_fdp)) {
+        return -TARGET_EFAULT;
+    }
+
+    /*
+     * The fork system call sets a child flag in the second return
+     * value: 0 for parent process, 1 for child process.
+     */
+    set_second_rval(cpu_env, child_flag);
+
+    return ret;
+}
+
+#else
+
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* __FreeBSD_version > 900000 */
+
+/* jail(2) */
+static inline abi_long do_freebsd_jail(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_attach(2) */
+static inline abi_long do_freebsd_jail_attach(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_attach()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_remove(2) */
+static inline abi_long do_freebsd_jail_remove(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_remove()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_get(2) */
+static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_get()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_set(2) */
+static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_set()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_enter(2) */
+static inline abi_long do_freebsd_cap_enter(void)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_enter()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_new(2) */
+static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getrights(2) */
+static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getrights()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getmode(2) */
+static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getmode()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* audit(2) */
+static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall audit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditon(2) */
+static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall auditon()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit(2) */
+static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit(2) */
+static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit_addr(2) */
+static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit_addr(2) */
+static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditctl(2) */
+static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall auditctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __FREEBSD_PROC_H_ */
diff --git a/bsd-user/netbsd/os-proc.c b/bsd-user/netbsd/os-proc.c
new file mode 100644
index 0000000..bc11d29
--- /dev/null
+++ b/bsd-user/netbsd/os-proc.c
@@ -0,0 +1,11 @@
+/*
+ * XXX To support FreeBSD binaries on NetBSD the following will need to be
+ * emulated.
+ */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec)
+{
+
+    qemu_log("qemu: Unsupported %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/netbsd/os-proc.h b/bsd-user/netbsd/os-proc.h
new file mode 100644
index 0000000..f34d616
--- /dev/null
+++ b/bsd-user/netbsd/os-proc.h
@@ -0,0 +1,243 @@
+#ifndef __NETBSD_PROC_H_
+#define __NETBSD_PROC_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* execve(2) */
+static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall execve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fexecve(2) */
+static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall fexecve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* wait4(2) */
+static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
+        abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall wait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall pdwait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+
+    qemu_log("qemu: Unsupported syscall pdgetpid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocumented __setugid */
+static inline abi_long do_freebsd___setugid(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall __setugid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fork(2) */
+static inline abi_long do_freebsd_fork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall fork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* vfork(2) */
+static inline abi_long do_freebsd_vfork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall vfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rfork(2) */
+static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall rfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdfork()\n");
+    return -TARGET_ENOSYS
+}
+
+/* jail(2) */
+static inline abi_long do_freebsd_jail(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_attach(2) */
+static inline abi_long do_freebsd_jail_attach(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_attach()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_remove(2) */
+static inline abi_long do_freebsd_jail_remove(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_remove()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_get(2) */
+static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_get()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_set(2) */
+static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_set()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_enter(2) */
+static inline abi_long do_freebsd_cap_enter(void)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_enter()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_new(2) */
+static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getrights(2) */
+static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getrights()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getmode(2) */
+static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getmode()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* audit(2) */
+static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall audit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditon(2) */
+static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall auditon()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit(2) */
+static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit(2) */
+static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit_addr(2) */
+static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit_addr(2) */
+static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditctl(2) */
+static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall auditctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __NETBSD_PROC_H_ */
diff --git a/bsd-user/openbsd/os-proc.c b/bsd-user/openbsd/os-proc.c
new file mode 100644
index 0000000..bc11d29
--- /dev/null
+++ b/bsd-user/openbsd/os-proc.c
@@ -0,0 +1,11 @@
+/*
+ * XXX To support FreeBSD binaries on NetBSD the following will need to be
+ * emulated.
+ */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec)
+{
+
+    qemu_log("qemu: Unsupported %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/openbsd/os-proc.h b/bsd-user/openbsd/os-proc.h
new file mode 100644
index 0000000..9cce719
--- /dev/null
+++ b/bsd-user/openbsd/os-proc.h
@@ -0,0 +1,243 @@
+#ifndef __OPENBSD_PROC_H_
+#define __OPENBSD_PROC_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* execve(2) */
+static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall execve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fexecve(2) */
+static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall fexecve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* wait4(2) */
+static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
+        abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall wait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall pdwait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+
+    qemu_log("qemu: Unsupported syscall pdgetpid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocumented __setugid */
+static inline abi_long do_freebsd___setugid(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall __setugid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fork(2) */
+static inline abi_long do_freebsd_fork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall fork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* vfork(2) */
+static inline abi_long do_freebsd_vfork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall vfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rfork(2) */
+static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall rfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdfork()\n");
+    return -TARGET_ENOSYS
+}
+
+/* jail(2) */
+static inline abi_long do_freebsd_jail(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_attach(2) */
+static inline abi_long do_freebsd_jail_attach(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_attach()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_remove(2) */
+static inline abi_long do_freebsd_jail_remove(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_remove()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_get(2) */
+static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_get()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_set(2) */
+static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_set()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_enter(2) */
+static inline abi_long do_freebsd_cap_enter(void)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_enter()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_new(2) */
+static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
+{
+
+        qemu_log("qemu: Unsupported syscall cap_new()\n");
+            return -TARGET_ENOSYS;
+}
+
+/* cap_getrights(2) */
+static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
+{
+
+        qemu_log("qemu: Unsupported syscall cap_getrights()\n");
+            return -TARGET_ENOSYS;
+}
+
+/* cap_getmode(2) */
+static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getmode()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* audit(2) */
+static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall audit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditon(2) */
+static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall auditon()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit(2) */
+static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit(2) */
+static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit_addr(2) */
+static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit_addr(2) */
+static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditctl(2) */
+static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall auditctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_PROC_H_ */
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
new file mode 100644
index 0000000..590c36b
--- /dev/null
+++ b/bsd-user/qemu-bsd.h
@@ -0,0 +1,43 @@
+/*
+ *  BSD conversion extern declarations
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _QEMU_BSD_H_
+#define _QEMU_BSD_H_
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/resource.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uuid.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+
+/* bsd-proc.c */
+int target_to_host_resource(int code);
+rlim_t target_to_host_rlim(abi_ulong target_rlim);
+abi_ulong host_to_target_rlim(rlim_t rlim);
+abi_long host_to_target_rusage(abi_ulong target_addr,
+        const struct rusage *rusage);
+int host_to_target_waitstatus(int status);
+
+#endif /* !_QEMU_BSD_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 0e332af..a9f5666 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -248,6 +248,10 @@ extern char qemu_proc_pathname[];
 abi_long get_errno(abi_long ret);
 int is_error(abi_long ret);
 
+/* os-proc.c */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec);
+
 /* os-sys.c */
 abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
         abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen);
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index bc4a7e4..f8a40f0 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -38,12 +38,15 @@
 #include "qemu-common.h"
 
 #define target_to_host_bitmask(x, tbl) (x)
+static int host_to_target_errno(int err);
 
 /* BSD independent syscall shims */
+#include "bsd-proc.h"
 #include "bsd-signal.h"
 
 /* *BSD dependent syscall shims */
 #include "os-time.h"
+#include "os-proc.h"
 #include "os-signal.h"
 
 /* #define DEBUG */
@@ -63,6 +66,12 @@ abi_long get_errno(abi_long ret)
         return ret;
 }
 
+static int host_to_target_errno(int err)
+{
+    /* XXX need to translate host errnos here */
+    return err;
+}
+
 int is_error(abi_long ret)
 {
     return (abi_ulong)ret >= (abi_ulong)(-4096);
@@ -176,15 +185,254 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
 
     switch(num) {
-    case TARGET_FREEBSD_NR_exit:
-#ifdef TARGET_GPROF
-        _mcleanup();
+        /*
+         * process system calls
+         */
+    case TARGET_FREEBSD_NR_fork: /* fork(2) */
+        ret = do_freebsd_fork(cpu_env);
+        break;
+
+    case TARGET_FREEBSD_NR_vfork: /* vfork(2) */
+        ret = do_freebsd_vfork(cpu_env);
+        break;
+
+    case TARGET_FREEBSD_NR_rfork: /* rfork(2) */
+        ret = do_freebsd_rfork(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_pdfork: /* pdfork(2) */
+        ret = do_freebsd_pdfork(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_execve: /* execve(2) */
+        ret = do_freebsd_execve(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_fexecve: /* fexecve(2) */
+        ret = do_freebsd_fexecve(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_wait4: /* wait4(2) */
+        ret = do_freebsd_wait4(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_exit: /* exit(2) */
+        ret = do_bsd_exit(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getgroups: /* getgroups(2) */
+        ret = do_bsd_getgroups(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setgroups: /* setgroups(2) */
+        ret = do_bsd_setgroups(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_umask: /* umask(2) */
+        ret = do_bsd_umask(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setlogin: /* setlogin(2) */
+        ret = do_bsd_setlogin(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getlogin: /* getlogin(2) */
+        ret = do_bsd_getlogin(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getrusage: /* getrusage(2) */
+        ret = do_bsd_getrusage(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getrlimit: /* getrlimit(2) */
+        ret = do_bsd_getrlimit(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setrlimit: /* setrlimit(2) */
+        ret = do_bsd_setrlimit(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getpid: /* getpid(2) */
+        ret = do_bsd_getpid();
+        break;
+
+    case TARGET_FREEBSD_NR_getppid: /* getppid(2) */
+        ret = do_bsd_getppid();
+        break;
+
+    case TARGET_FREEBSD_NR_getuid: /* getuid(2) */
+        ret = do_bsd_getuid();
+        break;
+
+    case TARGET_FREEBSD_NR_geteuid: /* geteuid(2) */
+        ret = do_bsd_geteuid();
+        break;
+
+    case TARGET_FREEBSD_NR_getgid: /* getgid(2) */
+        ret = do_bsd_getgid();
+        break;
+
+    case TARGET_FREEBSD_NR_getegid: /* getegid(2) */
+        ret = do_bsd_getegid();
+        break;
+
+    case TARGET_FREEBSD_NR_setuid: /* setuid(2) */
+        ret = do_bsd_setuid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_seteuid: /* seteuid(2) */
+        ret = do_bsd_seteuid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setgid: /* setgid(2) */
+        ret = do_bsd_setgid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setegid: /* setegid(2) */
+        ret = do_bsd_setegid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getpgrp: /* getpgrp(2) */
+        ret = do_bsd_getpgrp();
+        break;
+
+    case TARGET_FREEBSD_NR_setreuid: /* setreuid(2) */
+        ret = do_bsd_setreuid(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setregid: /* setregid(2) */
+        ret = do_bsd_setregid(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getresuid: /* getresuid(2) */
+        ret = do_bsd_getresuid(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getresgid: /* getresgid(2) */
+        ret = do_bsd_getresgid(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getsid: /* getsid(2) */
+        ret = do_bsd_getsid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setsid: /* setsid(2) */
+        ret = do_bsd_setsid();
+        break;
+
+    case TARGET_FREEBSD_NR_issetugid: /* issetugid(2) */
+        ret = do_bsd_issetugid();
+        break;
+
+    case TARGET_FREEBSD_NR_profil: /* profil(2) */
+        ret = do_bsd_profil(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ktrace: /* ktrace(2) */
+        ret = do_bsd_ktrace(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_setloginclass: /* setloginclass(2) */
+        ret = do_freebsd_setloginclass(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getloginclass: /* getloginclass(2) */
+        ret = do_freebsd_getloginclass(arg1, arg2);
+        break;
+#if 0
+    case TARGET_FREEBSD_NR_pdwait4: /* pdwait4(2) */
+        ret = do_freebsd_pdwait4(arg1, arg2, arg3, arg4);
+        break;
 #endif
-        gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
-        _exit(arg1);
-        ret = 0; /* avoid warning */
+
+    case TARGET_FREEBSD_NR_pdgetpid: /* pdgetpid(2) */
+        ret = do_freebsd_pdgetpid(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___setugid: /* undocumented */
+        ret = do_freebsd___setugid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail: /* jail(2) */
+        ret = do_freebsd_jail(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_attach: /* jail_attach(2) */
+        ret = do_freebsd_jail_attach(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_remove: /* jail_remove(2) */
+        ret = do_freebsd_jail_remove(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_get: /* jail_get(2) */
+        ret = do_freebsd_jail_get(arg1, arg2, arg3);
         break;
+
+    case TARGET_FREEBSD_NR_jail_set: /* jail_set(2) */
+        ret = do_freebsd_jail_set(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_cap_enter: /* cap_enter(2) */
+        ret = do_freebsd_cap_enter();
+        break;
+
+    case TARGET_FREEBSD_NR_cap_new: /* cap_new(2) */
+        ret = do_freebsd_cap_new(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_cap_getrights: /* cap_getrights(2) */
+        ret = do_freebsd_cap_getrights(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_cap_getmode: /* cap_getmode(2) */
+        ret = do_freebsd_cap_getmode(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_audit: /* audit(2) */
+        ret = do_freebsd_audit(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_auditon: /* auditon(2) */
+        ret = do_freebsd_auditon(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getaudit: /* getaudit(2) */
+        ret = do_freebsd_getaudit(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setaudit: /* setaudit(2) */
+        ret = do_freebsd_setaudit(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getaudit_addr: /* getaudit_addr(2) */
+        ret = do_freebsd_getaudit_addr(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setaudit_addr: /* setaudit_addr(2) */
+        ret = do_freebsd_setaudit_addr(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_auditctl: /* auditctl(2) */
+        ret = do_freebsd_auditctl(arg1);
+        break;
+    case TARGET_FREEBSD_NR_utrace: /* utrace(2) */
+        ret = do_bsd_utrace(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_ptrace: /* ptrace(2) */
+        ret = do_bsd_ptrace(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_getpriority: /* getpriority(2) */
+        ret = do_bsd_getpriority(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setpriority: /* setpriority(2) */
+        ret = do_bsd_setpriority(arg1, arg2, arg3);
+        break;
+
+
     case TARGET_FREEBSD_NR_read:
         if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
             goto efault;
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 10/19] bsd-user: add support for file system related system calls
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (10 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 09/19] bsd-user: add support for freebsd process related system calls Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 11/19] bsd-user: add support for stat, dir, and fcntl related syscalls Stacey Son
                     ` (8 subsequent siblings)
  20 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for file system (except stat)
related system calls including read(2), pread(2), readv(2),
write(2), pwrite(2), writev(2), pwritev(2),  open(2), openat(2),
close(2), closefrom(2), revoke(2), access(2), eaccess(2),
faccessat(2), chdir(2), fchdir(2), rename(2), renameat(2), link(2),
linkat(2), unlink(2), unlinkat(2), mkdir(2), mkdirat(2), rmdir(2),
__getcwd(), dup(2), dup2(2), truncate(2), ftruncate(2), acct(2),
sync(2), mount(2), nmount(2), symlink(2), symlinkat(2), readlink(2),
readlinkat(2), chmod(2), fchmod(2), lchmod(2), fchmodat(2), mknod(2),
mknodat(2), chown(2), fchown(2), lchown(2), fchownat(2), chflags(2),
lchflags(2), fchflags(2), chroot(2), flock(2), mkfifo(2),
mkfifoat(2), pathconf(2), lpathconf(2), fpathconf(2), undelete(2),
poll(2), lseek(2), pipe(2), swapon(2), swapoff(2),
the undocumented openbsd_poll() and freebsd6_*() system calls.
---
 bsd-user/bsd-file.h | 1111 +++++++++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/qemu.h     |   36 ++
 bsd-user/syscall.c  |  391 ++++++++++++++----
 3 files changed, 1454 insertions(+), 84 deletions(-)
 create mode 100644 bsd-user/bsd-file.h

diff --git a/bsd-user/bsd-file.h b/bsd-user/bsd-file.h
new file mode 100644
index 0000000..fc279a8
--- /dev/null
+++ b/bsd-user/bsd-file.h
@@ -0,0 +1,1111 @@
+/*
+ *  file related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_FILE_H_
+#define __BSD_FILE_H_
+
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define target_to_host_bitmask(x, tbl) (x)
+
+#define LOCK_PATH(p, arg)  do {             \
+    (p) =  lock_user_string(arg);           \
+    if ((p) == NULL) {                      \
+        return -TARGET_EFAULT;              \
+    }                                       \
+} while (0)
+
+#define UNLOCK_PATH(p, arg)   unlock_user((p), (arg), 0)
+
+struct target_pollfd {
+    int32_t fd;         /* file descriptor */
+    int16_t events;     /* requested events */
+    int16_t revents;    /* returned events */
+};
+
+static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
+        int count, int copy);
+static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
+        int count, int copy);
+extern int __getcwd(char *path, size_t len);
+
+/* read(2) */
+static inline abi_long do_bsd_read(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(read(arg1, p, arg3));
+    unlock_user(p, arg2, ret);
+
+    return ret;
+}
+
+/* pread(2) */
+static inline abi_long do_bsd_pread(void *cpu_env, abi_long arg1,
+    abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg4 = arg5;
+        arg5 = arg6;
+    }
+    ret = get_errno(pread(arg1, p, arg3, target_offset64(arg4, arg5)));
+    unlock_user(p, arg2, ret);
+
+    return ret;
+}
+
+/* readv(2) */
+static inline abi_long do_bsd_readv(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    int count = arg3;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (vec == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(readv(arg1, vec, count));
+    unlock_iovec(vec, arg2, count, 1);
+
+    return ret;
+}
+
+/* write(2) */
+static inline abi_long do_bsd_write(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_READ, arg2, arg3, 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(write(arg1, p, arg3));
+    unlock_user(p, arg2, 0);
+
+    return ret;
+}
+
+/* pwrite(2) */
+static inline abi_long do_bsd_pwrite(void *cpu_env, abi_long arg1,
+    abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_READ, arg2, arg3, 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg4 = arg5;
+        arg5 = arg6;
+    }
+    ret = get_errno(pwrite(arg1, p, arg3, target_offset64(arg4, arg5)));
+    unlock_user(p, arg2, 0);
+
+    return ret;
+}
+
+/* writev(2) */
+static inline abi_long do_bsd_writev(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    int count = arg3;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (vec == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(writev(arg1, vec, count));
+    unlock_iovec(vec, arg2, count, 0);
+
+    return ret;
+}
+
+/* pwritev(2) */
+static inline abi_long do_bsd_pwritev(void *cpu_env, abi_long arg1,
+    abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    int count = arg3;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (vec == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) {
+        return -TARGET_EFAULT;
+    }
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg4 = arg5;
+        arg5 = arg6;
+    }
+    ret = get_errno(pwritev(arg1, vec, count, target_offset64(arg4, arg5)));
+    unlock_iovec(vec, arg2, count, 0);
+
+    return ret;
+}
+
+/* open(2) */
+static inline abi_long do_bsd_open(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(open(path(p), target_to_host_bitmask(arg2, fcntl_flags_tbl),
+                arg3));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* openat(2) */
+static inline abi_long do_bsd_openat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(openat(arg1, path(p),
+                target_to_host_bitmask(arg3, fcntl_flags_tbl), arg4));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* close(2) */
+static inline abi_long do_bsd_close(abi_long arg1)
+{
+
+    return get_errno(close(arg1));
+}
+
+/* closefrom(2) */
+static inline abi_long do_bsd_closefrom(abi_long arg1)
+{
+
+    closefrom(arg1);  /* returns void */
+    return get_errno(0);
+}
+
+/* revoke(2) */
+static inline abi_long do_bsd_revoke(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(revoke(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* creat(2) (obsolete) */
+static inline abi_long do_bsd_creat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(open(path(p), O_CREAT | O_TRUNC | O_WRONLY, arg2));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+
+/* access(2) */
+static inline abi_long do_bsd_access(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(access(path(p), arg2));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* eaccess(2) */
+static inline abi_long do_bsd_eaccess(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(eaccess(path(p), arg2));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* faccessat(2) */
+static inline abi_long do_bsd_faccessat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(faccessat(arg1, p, arg3, arg4)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* chdir(2) */
+static inline abi_long do_bsd_chdir(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chdir(p)); /* XXX  path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchdir(2) */
+static inline abi_long do_bsd_fchdir(abi_long arg1)
+{
+
+    return get_errno(fchdir(arg1));
+}
+
+/* rename(2) */
+static inline abi_long do_bsd_rename(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(rename(p1, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* renameat(2) */
+static inline abi_long do_bsd_renameat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(renameat(arg1, p1, arg3, p2));
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* link(2) */
+static inline abi_long do_bsd_link(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(link(p1, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* linkat(2) */
+static inline abi_long do_bsd_linkat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg2);
+    LOCK_PATH(p2, arg4);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(linkat(arg1, p1, arg3, p2, arg5));
+    }
+    UNLOCK_PATH(p2, arg4);
+    UNLOCK_PATH(p1, arg2);
+
+    return ret;
+}
+
+/* unlink(2) */
+static inline abi_long do_bsd_unlink(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(unlink(p)); /* XXX path(p) */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* unlinkat(2) */
+static inline abi_long do_bsd_unlinkat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(unlinkat(arg1, p, arg3)); /* XXX path(p) */
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* mkdir(2) */
+static inline abi_long do_bsd_mkdir(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(mkdir(p, arg2)); /* XXX path(p) */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+
+/* mkdirat(2) */
+static inline abi_long do_bsd_mkdirat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(mkdirat(arg1, p, arg3));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+
+/* rmdir(2) */
+static inline abi_long do_bsd_rmdir(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(rmdir(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* undocumented __getcwd(char *buf, size_t len)  system call */
+static inline abi_long do_bsd___getcwd(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__getcwd(p, arg2));
+    unlock_user(p, arg1, ret);
+
+    return ret;
+}
+
+/* dup(2) */
+static inline abi_long do_bsd_dup(abi_long arg1)
+{
+
+    return get_errno(dup(arg1));
+}
+
+/* dup2(2) */
+static inline abi_long do_bsd_dup2(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(dup2(arg1, arg2));
+}
+
+/* truncate(2) */
+static inline abi_long do_bsd_truncate(void *cpu_env, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg2 = arg3;
+        arg3 = arg4;
+    }
+    ret = get_errno(truncate(p, target_offset64(arg2, arg3)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* ftruncate(2) */
+static inline abi_long do_bsd_ftruncate(void *cpu_env, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4)
+{
+
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg2 = arg3;
+        arg3 = arg4;
+    }
+    return get_errno(ftruncate(arg1, target_offset64(arg2, arg3)));
+}
+
+/* acct(2) */
+static inline abi_long do_bsd_acct(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    if (arg1 == 0) {
+        ret = get_errno(acct(NULL));
+    } else {
+        LOCK_PATH(p, arg1);
+        ret = get_errno(acct(path(p)));
+        UNLOCK_PATH(p, arg1);
+    }
+    return ret;
+}
+
+/* sync(2) */
+static inline abi_long do_bsd_sync(void)
+{
+
+    sync();
+    return 0;
+}
+
+/* mount(2) */
+static inline abi_long do_bsd_mount(abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        /*
+         * XXX arg4 should be locked, but it isn't clear how to do that
+         * since it's it may be not be a NULL-terminated string.
+         */
+        if (arg4 == 0) {
+            ret = get_errno(mount(p1, p2, arg3, NULL)); /* XXX path(p2)? */
+        } else {
+            ret = get_errno(mount(p1, p2, arg3, g2h(arg4))); /* XXX path(p2)? */
+        }
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* unmount(2) */
+static inline abi_long do_bsd_unmount(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(unmount(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* nmount(2) */
+static inline abi_long do_bsd_nmount(abi_long arg1, abi_long count,
+        abi_long flags)
+{
+    abi_long ret;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (lock_iovec(VERIFY_READ, vec, arg1, count, 1) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(nmount(vec, count, flags));
+    unlock_iovec(vec, arg1, count, 0);
+
+    return ret;
+}
+
+/* symlink(2) */
+static inline abi_long do_bsd_symlink(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(symlink(p1, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* symlinkat(2) */
+static inline abi_long do_bsd_symlinkat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg3);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(symlinkat(p1, arg2, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg3);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* readlink(2) */
+static inline abi_long do_bsd_readlink(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(readlink(path(p1), p2, arg3));
+    }
+    unlock_user(p2, arg2, ret);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* readlinkat(2) */
+static inline abi_long do_bsd_readlinkat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg2);
+    p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(readlinkat(arg1, p1, p2, arg4));
+    }
+    unlock_user(p2, arg3, ret);
+    UNLOCK_PATH(p1, arg2);
+
+    return ret;
+}
+
+/* chmod(2) */
+static inline abi_long do_bsd_chmod(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chmod(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchmod(2) */
+static inline abi_long do_bsd_fchmod(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(fchmod(arg1, arg2));
+}
+
+/* lchmod(2) */
+static inline abi_long do_bsd_lchmod(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lchmod(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchmodat(2) */
+static inline abi_long do_bsd_fchmodat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(fchmodat(arg1, p, arg3, arg4));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* mknod(2) */
+static inline abi_long do_bsd_mknod(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(mknod(p, arg2, arg3)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* mknodat(2) */
+static inline abi_long do_bsd_mknodat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(mknodat(arg1, p, arg3, arg4));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* chown(2) */
+static inline abi_long do_bsd_chown(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chown(p, arg2, arg3)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchown(2) */
+static inline abi_long do_bsd_fchown(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    return get_errno(fchown(arg1, arg2, arg3));
+}
+
+/* lchown(2) */
+static inline abi_long do_bsd_lchown(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lchown(p, arg2, arg3)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchownat(2) */
+static inline abi_long do_bsd_fchownat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(fchownat(arg1, p, arg3, arg4, arg5)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* chflags(2) */
+static inline abi_long do_bsd_chflags(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chflags(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* lchflags(2) */
+static inline abi_long do_bsd_lchflags(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lchflags(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchflags(2) */
+static inline abi_long do_bsd_fchflags(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(fchflags(arg1, arg2));
+}
+
+/* chroot(2) */
+static inline abi_long do_bsd_chroot(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chroot(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* flock(2) */
+static abi_long do_bsd_flock(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(flock(arg1, arg2));
+}
+
+/* mkfifo(2) */
+static inline abi_long do_bsd_mkfifo(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(mkfifo(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* mkfifoat(2) */
+static inline abi_long do_bsd_mkfifoat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(mkfifoat(arg1, p, arg3));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* pathconf(2) */
+static inline abi_long do_bsd_pathconf(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(pathconf(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* lpathconf(2) */
+static inline abi_long do_bsd_lpathconf(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lpathconf(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fpathconf(2) */
+static inline abi_long do_bsd_fpathconf(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(fpathconf(arg1, arg2));
+}
+
+/* undelete(2) */
+static inline abi_long do_bsd_undelete(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(undelete(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* poll(2) */
+static abi_long do_bsd_poll(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    nfds_t i, nfds = arg2;
+    int timeout = arg3;
+    struct pollfd *pfd;
+    struct target_pollfd *target_pfd;
+
+    target_pfd = lock_user(VERIFY_WRITE, arg1,
+            sizeof(struct target_pollfd) * nfds, 1);
+    if (!target_pfd) {
+        return -TARGET_EFAULT;
+    }
+    pfd = alloca(sizeof(struct pollfd) * nfds);
+    for (i = 0; i < nfds; i++) {
+        pfd[i].fd = tswap32(target_pfd[i].fd);
+        pfd[i].events = tswap16(target_pfd[i].events);
+    } ret = get_errno(poll(pfd, nfds, timeout));
+    if (!is_error(ret)) {
+        for (i = 0; i < nfds; i++) {
+            target_pfd[i].revents = tswap16(pfd[i].revents);
+        }
+    }
+    unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
+
+    return ret;
+}
+
+/*
+ * undocumented openbsd_poll(struct pollfd *fds, u_int nfds, int
+ * timeout) system call.
+ */
+static abi_long do_bsd_openbsd_poll(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall openbsd_poll()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* lseek(2) */
+static abi_long do_bsd_lseek(void *cpu_env, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+#if TARGET_ABI_BITS == 32
+    int64_t res;
+
+    /* 32-bit arch's use two 32 registers for 64 bit return value */
+    if (regpairs_aligned(cpu_env) != 0) {
+    	res = lseek(arg1, target_offset64(arg3, arg4), arg5);
+    } else {
+        res = lseek(arg1, target_offset64(arg2, arg3), arg4);
+    }
+    if (res == -1) {
+        ret = get_errno(res);
+    } else {
+        ret = res & 0xFFFFFFFF;
+        set_second_rval(cpu_env, (res >> 32) & 0xFFFFFFFF);
+    }
+#else
+    ret = get_errno(lseek(arg1, arg2, arg3));
+#endif
+    return ret;
+}
+
+/* pipe(2) */
+static abi_long do_bsd_pipe(void *cpu_env, abi_long arg1)
+{
+    abi_long ret;
+    int host_pipe[2];
+    int host_ret = pipe(host_pipe);
+
+    if (host_ret != -1) {
+        set_second_rval(cpu_env, host_pipe[1]);
+        ret = host_pipe[0];
+    } else {
+        ret = get_errno(host_ret);
+    }
+    return ret;
+}
+
+/* swapon(2) */
+static abi_long do_bsd_swapon(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(swapon(path(p)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* swapoff(2) */
+static abi_long do_bsd_swapoff(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(swapoff(path(p)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/*
+ * undocumented freebsd6_pread(int fd, void *buf, size_t nbyte, int pad,
+ * off_t offset) system call.
+ */
+static abi_long do_bsd_freebsd6_pread(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_pread()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_pwrite(int fd, void *buf, size_t nbyte, int pad,
+ * off_t offset) system call.
+ */
+static abi_long do_bsd_freebsd6_pwrite(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_pwrite()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_lseek(int fd, int pad, off_t offset, int whence)
+ * system call.
+ */
+static abi_long do_bsd_freebsd6_lseek(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_lseek()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_truncate(char *path, int pad, off_t offset) system
+ * call.
+ */
+static abi_long do_bsd_freebsd6_truncate(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_truncate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_ftruncate(int fd, int pad, off_t offset) system
+ * call.
+ */
+static abi_long do_bsd_freebsd6_ftruncate(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_ftruncate()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__BSD_FILE_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index a9f5666..e668a67 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -446,6 +446,42 @@ static inline void *lock_user_string(abi_ulong guest_addr)
 #define unlock_user_struct(host_ptr, guest_addr, copy)          \
     unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
 
+#if TARGET_ABI_BITS == 32
+static inline uint64_t
+target_offset64(uint32_t word0, uint32_t word1)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    return ((uint64_t)word0 << 32) | word1;
+#else
+    return ((uint64_t)word1 << 32) | word0;
+#endif
+}
+#else /* TARGET_ABI_BITS != 32 */
+static inline uint64_t
+target_offset64(uint64_t word0, uint64_t word1)
+{
+    return word0;
+}
+#endif /* TARGET_ABI_BITS != 32 */
+
+/* ARM EABI and MIPS expect 64bit types aligned even on pairs of registers */
+#ifdef TARGET_ARM
+static inline int
+regpairs_aligned(void *cpu_env) {
+    return ((((CPUARMState *)cpu_env)->eabi) == 1);
+}
+#elif defined(TARGET_MIPS) && TARGET_ABI_BITS == 32
+static inline int regpairs_aligned(void *cpu_env)
+{
+    return 1;
+}
+#else
+static inline int regpairs_aligned(void *cpu_env)
+{
+    return 0;
+}
+#endif
+
 #if defined(CONFIG_USE_NPTL)
 #include <pthread.h>
 #endif
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index f8a40f0..15780af 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -41,6 +41,7 @@
 static int host_to_target_errno(int err);
 
 /* BSD independent syscall shims */
+#include "bsd-file.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
 
@@ -176,7 +177,6 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                             abi_long arg8)
 {
     abi_long ret;
-    void *p;
 
 #ifdef DEBUG
     gemu_log("freebsd syscall %d\n", num);
@@ -433,38 +433,305 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
 
-    case TARGET_FREEBSD_NR_read:
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-            goto efault;
-        ret = get_errno(read(arg1, p, arg3));
-        unlock_user(p, arg2, ret);
+        /*
+         * File system calls.
+         */
+    case TARGET_FREEBSD_NR_read: /* read(2) */
+        ret = do_bsd_read(arg1, arg2, arg3);
         break;
-    case TARGET_FREEBSD_NR_write:
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            goto efault;
-        ret = get_errno(write(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
+
+    case TARGET_FREEBSD_NR_pread: /* pread(2) */
+        ret = do_bsd_pread(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
-    case TARGET_FREEBSD_NR_writev:
-        {
-            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(writev(arg1, vec, count));
-            unlock_iovec(vec, arg2, count, 0);
-        }
+    case TARGET_FREEBSD_NR_readv: /* readv(2) */
+        ret = do_bsd_read(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_write: /* write(2) */
+        ret = do_bsd_write(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pwrite: /* pwrite(2) */
+        ret = do_bsd_pwrite(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_writev: /* writev(2) */
+        ret = do_bsd_writev(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pwritev: /* pwritev(2) */
+        ret = do_bsd_pwritev(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_open: /* open(2) */
+        ret = do_bsd_open(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_openat: /* openat(2) */
+        ret = do_bsd_openat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_close: /* close(2) */
+        ret = do_bsd_close(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_closefrom: /* closefrom(2) */
+        ret = do_bsd_closefrom(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_revoke: /* revoke(2) */
+        ret = do_bsd_revoke(arg1);
+        break;
+
+#ifdef TARGET_FREEBSD_NR_creat
+    case TARGET_FREEBSD_NR_creat: /* creat(2) (obsolete) */
+        ret = do_bsd_creat(arg1);
+        break;
+#endif
+
+    case TARGET_FREEBSD_NR_access: /* access(2) */
+        ret = do_bsd_access(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_eaccess: /* eaccess(2) */
+        ret = do_bsd_eaccess(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_faccessat: /* faccessat(2) */
+        ret = do_bsd_faccessat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_chdir: /* chdir(2) */
+        ret = do_bsd_chdir(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_fchdir: /* fchdir(2) */
+        ret = do_bsd_fchdir(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_rename: /* rename(2) */
+        ret = do_bsd_rename(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_renameat: /* renameat(2) */
+        ret = do_bsd_renameat(arg1, arg2, arg3, arg4);
         break;
-    case TARGET_FREEBSD_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
-        unlock_user(p, arg1, 0);
+
+    case TARGET_FREEBSD_NR_link: /* link(2) */
+        ret = do_bsd_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_linkat: /* linkat(2) */
+        ret = do_bsd_linkat(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_unlink: /* unlink(2) */
+        ret = do_bsd_unlink(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_unlinkat: /* unlinkat(2) */
+        ret = do_bsd_unlinkat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mkdir: /* mkdir(2) */
+        ret = do_bsd_mkdir(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mkdirat: /* mkdirat(2) */
+        ret = do_bsd_mkdirat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_rmdir: /* rmdir(2) (XXX no rmdirat()?) */
+        ret = do_bsd_rmdir(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___getcwd: /* undocumented __getcwd() */
+        ret = do_bsd___getcwd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_dup: /* dup(2) */
+        ret = do_bsd_dup(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_dup2: /* dup2(2) */
+        ret = do_bsd_dup2(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_truncate: /* truncate(2) */
+        ret = do_bsd_truncate(cpu_env, arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ftruncate: /* ftruncate(2) */
+        ret = do_bsd_ftruncate(cpu_env, arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_acct: /* acct(2) */
+        ret = do_bsd_acct(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sync: /* sync(2) */
+        ret = do_bsd_sync();
+        break;
+
+    case TARGET_FREEBSD_NR_mount: /* mount(2) */
+        ret = do_bsd_mount(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_unmount: /* unmount(2) */
+        ret = do_bsd_unmount(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_nmount: /* nmount(2) */
+        ret = do_bsd_nmount(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_symlink: /* symlink(2) */
+        ret = do_bsd_symlink(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_symlinkat: /* symlinkat(2) */
+        ret = do_bsd_symlinkat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_readlink: /* readlink(2) */
+        ret = do_bsd_readlink(arg1, arg2, arg3);
         break;
+
+    case TARGET_FREEBSD_NR_readlinkat: /* readlinkat(2) */
+        ret = do_bsd_readlinkat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_chmod: /* chmod(2) */
+        ret = do_bsd_chmod(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fchmod: /* fchmod(2) */
+        ret = do_bsd_fchmod(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lchmod: /* lchmod(2) */
+        ret = do_bsd_lchmod(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fchmodat: /* fchmodat(2) */
+        ret = do_bsd_fchmodat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_mknod: /* mknod(2) */
+        ret = do_bsd_mknod(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mknodat: /* mknodat(2) */
+        ret = do_bsd_mknodat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_chown: /* chown(2) */
+        ret = do_bsd_chown(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_fchown: /* fchown(2) */
+        ret = do_bsd_fchown(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_lchown: /* lchown(2) */
+        ret = do_bsd_lchown(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_fchownat: /* fchownat(2) */
+        ret = do_bsd_fchownat(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_chflags: /* chflags(2) */
+        ret = do_bsd_chflags(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lchflags: /* lchflags(2) */
+        ret = do_bsd_lchflags(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fchflags: /* fchflags(2) */
+        ret = do_bsd_fchflags(arg2, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_chroot: /* chroot(2) */
+        ret = do_bsd_chroot(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_flock: /* flock(2) */
+        ret = do_bsd_flock(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mkfifo: /* mkfifo(2) */
+        ret = do_bsd_mkfifo(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mkfifoat: /* mkfifoat(2) */
+        ret = do_bsd_mkfifoat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pathconf: /* pathconf(2) */
+        ret = do_bsd_pathconf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lpathconf: /* lpathconf(2) */
+        ret = do_bsd_lpathconf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fpathconf: /* fpathconf(2) */
+        ret = do_bsd_fpathconf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_undelete: /* undelete(2) */
+        ret = do_bsd_undelete(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_poll: /* poll(2) */
+        ret = do_bsd_poll(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_openbsd_poll:  /* undocumented openbsd_poll() */
+        ret = do_bsd_openbsd_poll(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_lseek: /* lseek(2) */
+        ret = do_bsd_lseek(cpu_env, arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_pipe: /* pipe(2) */
+        ret = do_bsd_pipe(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_swapon: /* swapon(2) */
+        ret = do_bsd_swapon(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_swapoff: /* swapoff(2) */
+        ret = do_bsd_swapoff(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_pread: /* undocumented freebsd6_pread() */
+        ret = do_bsd_freebsd6_pread(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_pwrite: /* undocumented freebsd6_pwrite() */
+        ret = do_bsd_freebsd6_pwrite(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_lseek: /* undocumented freebsd6_lseek() */
+        ret = do_bsd_freebsd6_lseek(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_truncate: /* undocumented */
+        ret = do_bsd_freebsd6_truncate(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_ftruncate: /* undocumented */
+        ret = do_bsd_freebsd6_ftruncate(arg1, arg2, arg3);
+        break;
+
+
+
     case TARGET_FREEBSD_NR_mmap:
         ret = get_errno(target_mmap(arg1, arg2, arg3,
                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
@@ -654,16 +921,12 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                     arg8));
         break;
     }
- fail:
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
     if (do_strace)
         print_freebsd_syscall_ret(num, ret);
     return ret;
- efault:
-    ret = -TARGET_EFAULT;
-    goto fail;
 }
 
 abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
@@ -671,7 +934,6 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
                            abi_long arg5, abi_long arg6)
 {
     abi_long ret;
-    void *p;
 
 #ifdef DEBUG
     gemu_log("netbsd syscall %d\n", num);
@@ -681,34 +943,19 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
 
     switch(num) {
     case TARGET_NETBSD_NR_exit:
-#ifdef TARGET_GPROF
-        _mcleanup();
-#endif
-        gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
-        _exit(arg1);
-        ret = 0; /* avoid warning */
+        ret = do_bsd_exit(cpu_env, arg1);
         break;
+
     case TARGET_NETBSD_NR_read:
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-            goto efault;
-        ret = get_errno(read(arg1, p, arg3));
-        unlock_user(p, arg2, ret);
+        ret = do_bsd_read(arg1, arg2, arg3);
         break;
     case TARGET_NETBSD_NR_write:
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            goto efault;
-        ret = get_errno(write(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
+        ret = do_bsd_write(arg1, arg2, arg3);
         break;
     case TARGET_NETBSD_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
-        unlock_user(p, arg1, 0);
+        ret = do_bsd_open(arg1, arg2, arg3);
         break;
+
     case TARGET_NETBSD_NR_mmap:
         ret = get_errno(target_mmap(arg1, arg2, arg3,
                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
@@ -727,16 +974,12 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
     }
- fail:
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
     if (do_strace)
         print_netbsd_syscall_ret(num, ret);
     return ret;
- efault:
-    ret = -TARGET_EFAULT;
-    goto fail;
 }
 
 abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
@@ -744,7 +987,6 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
                             abi_long arg5, abi_long arg6)
 {
     abi_long ret;
-    void *p;
 
 #ifdef DEBUG
     gemu_log("openbsd syscall %d\n", num);
@@ -754,34 +996,19 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
 
     switch(num) {
     case TARGET_OPENBSD_NR_exit:
-#ifdef TARGET_GPROF
-        _mcleanup();
-#endif
-        gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
-        _exit(arg1);
-        ret = 0; /* avoid warning */
+        ret = do_bsd_exit(cpu_env, arg1);
         break;
+
     case TARGET_OPENBSD_NR_read:
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-            goto efault;
-        ret = get_errno(read(arg1, p, arg3));
-        unlock_user(p, arg2, ret);
+        ret = do_bsd_read(arg1, arg2, arg3);
         break;
     case TARGET_OPENBSD_NR_write:
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            goto efault;
-        ret = get_errno(write(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
+        ret = do_bsd_write(arg1, arg2, arg3);
         break;
     case TARGET_OPENBSD_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
-        unlock_user(p, arg1, 0);
+        ret = do_bsd_open(arg1, arg2, arg3);
         break;
+
     case TARGET_OPENBSD_NR_mmap:
         ret = get_errno(target_mmap(arg1, arg2, arg3,
                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
@@ -800,16 +1027,12 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
     }
- fail:
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
     if (do_strace)
         print_openbsd_syscall_ret(num, ret);
     return ret;
- efault:
-    ret = -TARGET_EFAULT;
-    goto fail;
 }
 
 void syscall_init(void)
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 11/19] bsd-user: add support for stat, dir, and fcntl related syscalls
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (11 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 10/19] bsd-user: add support for file system " Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 12/19] bsd-user: add support for memory management " Stacey Son
                     ` (7 subsequent siblings)
  20 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for stat, directory, and file
control related system calls including stat(2), lstat(2),
fstat(2), fstatat(2), nstat(), nfstat(), nlstat(), getfh(2),
lgetfh(2), fhopen(2), fhstat(2), fhstatfs(2), statfs(2),
fstatfs(2), getfsstat(2), getdents(2), getdirentries(2), and
fcntl(2).
---
 bsd-user/Makefile.objs     |    1 +
 bsd-user/freebsd/os-stat.c |  234 +++++++++++++++++++++++
 bsd-user/freebsd/os-stat.h |  437 ++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h |    8 +
 bsd-user/netbsd/os-stat.c  |    1 +
 bsd-user/netbsd/os-stat.h  |    1 +
 bsd-user/openbsd/os-stat.c |    1 +
 bsd-user/openbsd/os-stat.h |  176 ++++++++++++++++++
 bsd-user/syscall.c         |   76 ++++++++
 9 files changed, 935 insertions(+), 0 deletions(-)
 create mode 100644 bsd-user/freebsd/os-stat.c
 create mode 100644 bsd-user/freebsd/os-stat.h
 create mode 100644 bsd-user/netbsd/os-stat.c
 create mode 100644 bsd-user/netbsd/os-stat.h
 create mode 100644 bsd-user/openbsd/os-stat.c
 create mode 100644 bsd-user/openbsd/os-stat.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index fac11bb..caf95ed 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,5 +1,6 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
 	        uaccess.o bsd-proc.o \
 			$(HOST_VARIANT_DIR)/os-proc.o \
+			$(HOST_VARIANT_DIR)/os-stat.o \
 			$(HOST_VARIANT_DIR)/os-sys.o \
 			$(HOST_VARIANT_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/freebsd/os-stat.c b/bsd-user/freebsd/os-stat.c
new file mode 100644
index 0000000..50885d1
--- /dev/null
+++ b/bsd-user/freebsd/os-stat.c
@@ -0,0 +1,234 @@
+/*
+ *  FreeBSD stat related conversion routines
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+/*
+ * stat conversion
+ */
+abi_long h2t_freebsd_stat(abi_ulong target_addr, struct stat *host_st)
+{
+    struct target_freebsd_stat *target_st;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    memset(target_st, 0, sizeof(*target_st));
+    __put_user(host_st->st_dev, &target_st->st_dev);
+    __put_user(host_st->st_ino, &target_st->st_ino);
+    __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_atim.tv_sec, &target_st->st_atim.tv_sec);
+    __put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec);
+    __put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec);
+    __put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec);
+    __put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec);
+    __put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec);
+    __put_user(host_st->st_size, &target_st->st_size);
+    __put_user(host_st->st_blocks, &target_st->st_blocks);
+    __put_user(host_st->st_blksize, &target_st->st_blksize);
+    __put_user(host_st->st_flags, &target_st->st_flags);
+    __put_user(host_st->st_gen, &target_st->st_gen);
+    /* st_lspare not used */
+    __put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec);
+    __put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec);
+    unlock_user_struct(target_st, target_addr, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_nstat(abi_ulong target_addr, struct stat *host_st)
+{
+    struct target_freebsd_nstat *target_st;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    memset(target_st, 0, sizeof(*target_st));
+    __put_user(host_st->st_dev, &target_st->st_dev);
+    __put_user(host_st->st_ino, &target_st->st_ino);
+    __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_atim.tv_sec, &target_st->st_atim.tv_sec);
+    __put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec);
+    __put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec);
+    __put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec);
+    __put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec);
+    __put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec);
+    __put_user(host_st->st_size, &target_st->st_size);
+    __put_user(host_st->st_blocks, &target_st->st_blocks);
+    __put_user(host_st->st_blksize, &target_st->st_blksize);
+    __put_user(host_st->st_flags, &target_st->st_flags);
+    __put_user(host_st->st_gen, &target_st->st_gen);
+    __put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec);
+    __put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec);
+    unlock_user_struct(target_st, target_addr, 1);
+
+    return 0;
+}
+
+/*
+ * file handle conversion
+ */
+abi_long t2h_freebsd_fhandle(fhandle_t *host_fh, abi_ulong target_addr)
+{
+    target_freebsd_fhandle_t *target_fh;
+
+    if (!lock_user_struct(VERIFY_READ, target_fh, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]);
+    __get_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]);
+    __get_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len);
+    /* u_short         fid_data0; */
+    memcpy(host_fh->fh_fid.fid_data, target_fh->fh_fid.fid_data,
+        TARGET_MAXFIDSZ);
+    unlock_user_struct(target_fh, target_addr, 0);
+    return 0;
+}
+
+abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh)
+{
+    target_freebsd_fhandle_t *target_fh;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_fh, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]);
+    __put_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]);
+    __put_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len);
+    /* u_short         fid_data0; */
+    memcpy(target_fh->fh_fid.fid_data, host_fh->fh_fid.fid_data,
+            TARGET_MAXFIDSZ);
+    unlock_user_struct(target_fh, target_addr, 1);
+    return 0;
+}
+
+/*
+ *  file system stat
+ */
+abi_long h2t_freebsd_statfs(abi_ulong target_addr, struct statfs *host_statfs)
+{
+    struct target_freebsd_statfs *target_statfs;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_statfs, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_statfs->f_version, &target_statfs->f_version);
+    __put_user(host_statfs->f_type, &target_statfs->f_type);
+    __put_user(host_statfs->f_flags, &target_statfs->f_flags);
+    __put_user(host_statfs->f_bsize, &target_statfs->f_bsize);
+    __put_user(host_statfs->f_iosize, &target_statfs->f_iosize);
+    __put_user(host_statfs->f_blocks, &target_statfs->f_blocks);
+    __put_user(host_statfs->f_bfree, &target_statfs->f_bfree);
+    __put_user(host_statfs->f_bavail, &target_statfs->f_bavail);
+    __put_user(host_statfs->f_files, &target_statfs->f_files);
+    __put_user(host_statfs->f_ffree, &target_statfs->f_ffree);
+    __put_user(host_statfs->f_syncwrites, &target_statfs->f_syncwrites);
+    __put_user(host_statfs->f_asyncwrites, &target_statfs->f_asyncwrites);
+    __put_user(host_statfs->f_syncreads, &target_statfs->f_syncreads);
+    __put_user(host_statfs->f_asyncreads, &target_statfs->f_asyncreads);
+    /* uint64_t f_spare[10]; */
+    __put_user(host_statfs->f_namemax, &target_statfs->f_namemax);
+    __put_user(host_statfs->f_owner, &target_statfs->f_owner);
+    __put_user(host_statfs->f_fsid.val[0], &target_statfs->f_fsid.val[0]);
+    __put_user(host_statfs->f_fsid.val[1], &target_statfs->f_fsid.val[1]);
+    /* char f_charspace[80]; */
+    strncpy(&target_statfs->f_fstypename[0], host_statfs->f_fstypename,
+        TARGET_MFSNAMELEN);
+    strncpy(&target_statfs->f_mntfromname[0], host_statfs->f_mntfromname,
+        TARGET_MNAMELEN);
+    strncpy(&target_statfs->f_mntonname[0], host_statfs->f_mntonname,
+        TARGET_MNAMELEN);
+    unlock_user_struct(target_statfs, target_addr, 1);
+    return 0;
+}
+
+/*
+ * fcntl cmd conversion
+ */
+abi_long target_to_host_fcntl_cmd(int cmd)
+{
+
+    switch (cmd) {
+    case TARGET_F_DUPFD:
+        return F_DUPFD;
+
+    case TARGET_F_DUP2FD:
+        return F_DUP2FD;
+
+    case TARGET_F_GETFD:
+        return F_GETFD;
+
+    case TARGET_F_SETFD:
+        return F_SETFD;
+
+    case TARGET_F_GETFL:
+        return F_GETFL;
+
+    case TARGET_F_SETFL:
+        return F_SETFL;
+
+    case TARGET_F_GETOWN:
+        return F_GETOWN;
+
+    case TARGET_F_SETOWN:
+        return F_SETOWN;
+
+    case TARGET_F_GETLK:
+        return F_GETLK;
+
+    case TARGET_F_SETLK:
+        return F_SETLK;
+
+    case TARGET_F_SETLKW:
+        return F_SETLKW;
+
+    case TARGET_F_READAHEAD:
+        return F_READAHEAD;
+
+    case TARGET_F_RDAHEAD:
+        return F_RDAHEAD;
+
+#ifdef F_DUPFD_CLOEXEC
+    case TARGET_F_DUPFD_CLOEXEC:
+        return F_DUPFD_CLOEXEC;
+#endif
+
+#ifdef F_DUP2FD_CLOEXEC
+    case TARGET_F_DUP2FD_CLOEXEC:
+        return F_DUP2FD_CLOEXEC;
+#endif
+
+    default:
+        return -TARGET_EINVAL;
+    }
+}
+
diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h
new file mode 100644
index 0000000..ed6bcab
--- /dev/null
+++ b/bsd-user/freebsd/os-stat.h
@@ -0,0 +1,437 @@
+/*
+ *  stat related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_STAT_H_
+#define __FREEBSD_STAT_H_
+
+#include <sys/types.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include "qemu-os.h"
+
+/* undocumented nstat system calls */
+int nstat(const char *path, struct stat *sb);
+int nlstat(const char *path, struct stat *sb);
+int nfstat(int fd, struct stat *sb);
+
+/* stat(2) */
+static inline abi_long do_freebsd_stat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(stat(path(p), &st));
+    UNLOCK_PATH(p, arg1);
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_stat(arg2, &st);
+    }
+    return ret;
+}
+
+/* lstat(2) */
+static inline abi_long do_freebsd_lstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lstat(path(p), &st));
+    UNLOCK_PATH(p, arg1);
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_stat(arg2, &st);
+    }
+    return ret;
+}
+
+/* fstat(2) */
+static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct stat st;
+
+    ret = get_errno(fstat(arg1, &st));
+    if (!is_error(ret))  {
+        ret = h2t_freebsd_stat(arg2, &st);
+    }
+    return ret;
+}
+
+/* fstatat(2) */
+static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(fstatat(arg1, p, &st, arg4));
+    UNLOCK_PATH(p, arg2);
+    if (!is_error(ret) && arg3) {
+        ret = h2t_freebsd_stat(arg3, &st);
+    }
+    return ret;
+}
+
+/* undocummented nstat(char *path, struct nstat *ub) syscall */
+static abi_long do_freebsd_nstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(nstat(path(p), &st));
+    UNLOCK_PATH(p, arg1);
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_nstat(arg2, &st);
+    }
+    return ret;
+}
+
+/* undocummented nfstat(int fd, struct nstat *sb) syscall */
+static abi_long do_freebsd_nfstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct stat st;
+
+    ret = get_errno(nfstat(arg1, &st));
+    if (!is_error(ret))  {
+        ret = h2t_freebsd_nstat(arg2, &st);
+    }
+    return ret;
+}
+
+/* undocummented nlstat(char *path, struct nstat *ub) syscall */
+static abi_long do_freebsd_nlstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct stat st;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(nlstat(path(p), &st));
+    UNLOCK_PATH(p, arg1);
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_nstat(arg2, &st);
+    }
+    return ret;
+}
+
+/* getfh(2) */
+static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    fhandle_t host_fh;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(getfh(path(p), &host_fh));
+    UNLOCK_PATH(p, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+    return h2t_freebsd_fhandle(arg2, &host_fh);
+}
+
+/* lgetfh(2) */
+static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    fhandle_t host_fh;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lgetfh(path(p), &host_fh));
+    UNLOCK_PATH(p, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+    return h2t_freebsd_fhandle(arg2, &host_fh);
+}
+
+/* fhopen(2) */
+static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    fhandle_t host_fh;
+
+    ret = t2h_freebsd_fhandle(&host_fh, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(fhopen(&host_fh, arg2));
+}
+
+/* fhstat(2) */
+static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    fhandle_t host_fh;
+    struct stat host_sb;
+
+    ret = t2h_freebsd_fhandle(&host_fh, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = get_errno(fhstat(&host_fh, &host_sb));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return h2t_freebsd_stat(arg2, &host_sb);
+}
+
+/* fhstatfs(2) */
+static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr,
+        abi_ulong target_stfs_addr)
+{
+    abi_long ret;
+    fhandle_t host_fh;
+    struct statfs host_stfs;
+
+    ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = get_errno(fhstatfs(&host_fh, &host_stfs));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return h2t_freebsd_statfs(target_stfs_addr, &host_stfs);
+}
+
+/* statfs(2) */
+static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct statfs host_stfs;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(statfs(path(p), &host_stfs));
+    UNLOCK_PATH(p, arg1);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return h2t_freebsd_statfs(arg2, &host_stfs);
+}
+
+/* fstatfs(2) */
+static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr)
+{
+    abi_long ret;
+    struct statfs host_stfs;
+
+    ret = get_errno(fstatfs(fd, &host_stfs));
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return h2t_freebsd_statfs(target_addr, &host_stfs);
+}
+
+/* getfsstat(2) */
+static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr,
+        abi_long bufsize, abi_long flags)
+{
+    abi_long ret;
+    struct statfs *host_stfs;
+    int count;
+    long host_bufsize;
+
+    count = bufsize / sizeof(struct target_freebsd_statfs);
+
+    /* if user buffer is NULL then return number of mounted FS's */
+    if (target_addr == 0 || count == 0) {
+        return get_errno(getfsstat(NULL, 0, flags));
+    }
+
+    /* XXX check count to be reasonable */
+    host_bufsize = sizeof(struct statfs) * count;
+    host_stfs = alloca(host_bufsize);
+    if (!host_stfs) {
+        return -TARGET_EINVAL;
+    }
+
+    ret = count = get_errno(getfsstat(host_stfs, host_bufsize, flags));
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    while (count--) {
+        if (h2t_freebsd_statfs((target_addr +
+                        (count * sizeof(struct target_freebsd_statfs))),
+                    &host_stfs[count])) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getdents(2) */
+static inline abi_long do_freebsd_getdents(abi_long arg1, abi_ulong arg2,
+        abi_long nbytes)
+{
+    abi_long ret;
+    struct dirent *dirp;
+
+    dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
+    if (dirp == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(getdents(arg1, (char *)dirp, nbytes));
+    if (!is_error(ret)) {
+        struct dirent *de;
+        int len = ret;
+        int reclen;
+
+        de = dirp;
+        while (len > 0) {
+            reclen = de->d_reclen;
+            if (reclen > len) {
+                return -TARGET_EFAULT;
+            }
+            de->d_reclen = tswap16(reclen);
+            de->d_fileno = tswap32(de->d_fileno);
+            len -= reclen;
+        }
+    }
+    return ret;
+}
+
+/* getdirecentries(2) */
+static inline abi_long do_freebsd_getdirentries(abi_long arg1, abi_ulong arg2,
+        abi_long nbytes, abi_ulong arg4)
+{
+    abi_long ret;
+    struct dirent *dirp;
+    long basep;
+
+    dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
+    if (dirp == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(getdirentries(arg1, (char *)dirp, nbytes, &basep));
+    if (!is_error(ret)) {
+        struct dirent *de;
+        int len = ret;
+        int reclen;
+
+        de = dirp;
+        while (len > 0) {
+            reclen = de->d_reclen;
+            if (reclen > len) {
+                return -TARGET_EFAULT;
+            }
+            de->d_reclen = tswap16(reclen);
+            de->d_fileno = tswap32(de->d_fileno);
+            len -= reclen;
+            de = (struct dirent *)((void *)de + reclen);
+        }
+    }
+    unlock_user(dirp, arg2, ret);
+    if (arg4) {
+        if (put_user(basep, arg4, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* fcntl(2) */
+static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    int host_cmd;
+    struct flock fl;
+    struct target_freebsd_flock *target_fl;
+
+    host_cmd = target_to_host_fcntl_cmd(arg2);
+    if (host_cmd < 0) {
+        return host_cmd;
+    }
+    switch (arg2) {
+    case TARGET_F_GETLK:
+        if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(fl.l_type, &target_fl->l_type);
+        __get_user(fl.l_whence, &target_fl->l_whence);
+        __get_user(fl.l_start, &target_fl->l_start);
+        __get_user(fl.l_len, &target_fl->l_len);
+        __get_user(fl.l_pid, &target_fl->l_pid);
+        __get_user(fl.l_sysid, &target_fl->l_sysid);
+        unlock_user_struct(target_fl, arg3, 0);
+        ret = get_errno(fcntl(arg1, host_cmd, &fl));
+        if (!is_error(ret)) {
+            if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) {
+                return -TARGET_EFAULT;
+            }
+            __put_user(fl.l_type, &target_fl->l_type);
+            __put_user(fl.l_whence, &target_fl->l_whence);
+            __put_user(fl.l_start, &target_fl->l_start);
+            __put_user(fl.l_len, &target_fl->l_len);
+            __put_user(fl.l_pid, &target_fl->l_pid);
+            __put_user(fl.l_sysid, &target_fl->l_sysid);
+            unlock_user_struct(target_fl, arg3, 1);
+        }
+        break;
+
+    case TARGET_F_SETLK:
+    case TARGET_F_SETLKW:
+        if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(fl.l_type, &target_fl->l_type);
+        __get_user(fl.l_whence, &target_fl->l_whence);
+        __get_user(fl.l_start, &target_fl->l_start);
+        __get_user(fl.l_len, &target_fl->l_len);
+        __get_user(fl.l_pid, &target_fl->l_pid);
+        __get_user(fl.l_sysid, &target_fl->l_sysid);
+        unlock_user_struct(target_fl, arg3, 0);
+        ret = get_errno(fcntl(arg1, host_cmd, &fl));
+        break;
+
+    case TARGET_F_DUPFD:
+    case TARGET_F_DUP2FD:
+    case TARGET_F_GETOWN:
+    case TARGET_F_SETOWN:
+    case TARGET_F_GETFD:
+    case TARGET_F_SETFD:
+    case TARGET_F_GETFL:
+    case TARGET_F_SETFL:
+    case TARGET_F_READAHEAD:
+    case TARGET_F_RDAHEAD:
+    default:
+        ret = get_errno(fcntl(arg1, host_cmd, arg3));
+        break;
+    }
+    return ret;
+}
+
+#endif /* ! __FREEBSD_STAT_H_ */
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index bde610e..e915246 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -50,4 +50,12 @@ abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
 abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds,
         int n);
 
+/* os-stat.c */
+abi_long h2t_freebsd_stat(abi_ulong target_addr, struct stat *host_st);
+abi_long h2t_freebsd_nstat(abi_ulong target_addr, struct stat *host_st);
+abi_long t2h_freebsd_fhandle(fhandle_t *host_fh, abi_ulong target_addr);
+abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh);
+abi_long h2t_freebsd_statfs(abi_ulong target_addr, struct statfs *host_statfs);
+abi_long target_to_host_fcntl_cmd(int cmd);
+
 #endif /* !_QEMU_OS_H_ */
diff --git a/bsd-user/netbsd/os-stat.c b/bsd-user/netbsd/os-stat.c
new file mode 100644
index 0000000..11ea122
--- /dev/null
+++ b/bsd-user/netbsd/os-stat.c
@@ -0,0 +1 @@
+/* XXX NetBSD stat related helpers */
diff --git a/bsd-user/netbsd/os-stat.h b/bsd-user/netbsd/os-stat.h
new file mode 100644
index 0000000..11ea122
--- /dev/null
+++ b/bsd-user/netbsd/os-stat.h
@@ -0,0 +1 @@
+/* XXX NetBSD stat related helpers */
diff --git a/bsd-user/openbsd/os-stat.c b/bsd-user/openbsd/os-stat.c
new file mode 100644
index 0000000..de4e3f5
--- /dev/null
+++ b/bsd-user/openbsd/os-stat.c
@@ -0,0 +1 @@
+/* XXX OpenBSD stat related helpers */
diff --git a/bsd-user/openbsd/os-stat.h b/bsd-user/openbsd/os-stat.h
new file mode 100644
index 0000000..1d3850d
--- /dev/null
+++ b/bsd-user/openbsd/os-stat.h
@@ -0,0 +1,176 @@
+/*
+ *  OpenBSD stat related system call shims and definitions
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OPENBSD_STAT_H_
+#define __OPENBSD_STAT_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* stat(2) */
+static inline abi_long do_freebsd_stat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall stat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* lstat(2) */
+static inline abi_long do_freebsd_lstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall lstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fstat(2) */
+static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall fstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fstatat(2) */
+static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall fstatat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocummented nstat(char *path, struct nstat *ub) syscall */
+static abi_long do_freebsd_nstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall nstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocummented nfstat(int fd, struct nstat *sb) syscall */
+static abi_long do_freebsd_nfstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall nfstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocummented nlstat(char *path, struct nstat *ub) syscall */
+static abi_long do_freebsd_nlstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall nlstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getfh(2) */
+static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getfh()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* lgetfh(2) */
+static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall lgetfh()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fhopen(2) */
+static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall fhopen()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fhstat(2) */
+static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall fhstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fhstatfs(2) */
+static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr,
+        abi_ulong target_stfs_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall fhstatfs()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* statfs(2) */
+static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall statfs()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fstatfs(2) */
+static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall fstatfs()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getfsstat(2) */
+static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr,
+        abi_long bufsize, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall getfsstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getdents(2) */
+static inline abi_long do_freebsd_getdents(abi_long arg1, abi_ulong arg2,
+        abi_long nbytes)
+{
+
+    qemu_log("qemu: Unsupported syscall getdents()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getdirecentries(2) */
+static inline abi_long do_freebsd_getdirentries(abi_long arg1, abi_ulong arg2,
+        abi_long nbytes, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall getdirecentries()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fcntl(2) */
+static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall fcntl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_STAT_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 15780af..633d638 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -49,6 +49,7 @@ static int host_to_target_errno(int err);
 #include "os-time.h"
 #include "os-proc.h"
 #include "os-signal.h"
+#include "os-stat.h"
 
 /* #define DEBUG */
 
@@ -730,6 +731,81 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = do_bsd_freebsd6_ftruncate(arg1, arg2, arg3);
         break;
 
+        /*
+         * stat system calls
+         */
+    case TARGET_FREEBSD_NR_stat: /* stat(2) */
+        ret = do_freebsd_stat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lstat: /* lstat(2) */
+        ret = do_freebsd_lstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fstat: /* fstat(2) */
+        ret = do_freebsd_fstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fstatat: /* fstatat(2) */
+        ret = do_freebsd_fstatat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_nstat: /* undocumented */
+        ret = do_freebsd_nstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_nfstat: /* undocumented */
+        ret = do_freebsd_nfstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_nlstat: /* undocumented */
+        ret = do_freebsd_nlstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getfh: /* getfh(2) */
+        ret = do_freebsd_getfh(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lgetfh: /* lgetfh(2) */
+        ret = do_freebsd_lgetfh(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fhopen: /* fhopen(2) */
+        ret = do_freebsd_fhopen(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fhstat: /* fhstat(2) */
+        ret = do_freebsd_fhstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fhstatfs: /* fhstatfs(2) */
+        ret = do_freebsd_fhstatfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_statfs: /* statfs(2) */
+        ret = do_freebsd_statfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fstatfs: /* fstatfs(2) */
+        ret = do_freebsd_fstatfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getfsstat: /* getfsstat(2) */
+        ret = do_freebsd_getfsstat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getdents: /* getdents(2) */
+        ret = do_freebsd_getdents(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getdirentries: /* getdirentries(2) */
+        ret = do_freebsd_getdirentries(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_fcntl: /* fcntl(2) */
+        ret = do_freebsd_fcntl(arg1, arg2, arg3);
+        break;
+
 
 
     case TARGET_FREEBSD_NR_mmap:
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 12/19] bsd-user: add support for memory management related syscalls
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (12 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 11/19] bsd-user: add support for stat, dir, and fcntl related syscalls Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 13/19] bsd-user: add support for socket related system calls Stacey Son
                     ` (6 subsequent siblings)
  20 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for memory management related
system calls including mmap(2), munmap(2), mprotect(2), msync(2),
mlock(2), munlock(2), mlockall(2), munlockall(2), madvise(2),
minherit(2), mincore(2), shm_open(2), shm_unlink(2), shmget(2),
shmctl(2), shmat(2), shmdt(2), vadvise(), sbrk(), sstk(), and
freebsd6_mmap().
---
 bsd-user/Makefile.objs |    2 +-
 bsd-user/bsd-mem.c     |  122 +++++++++++++++
 bsd-user/bsd-mem.h     |  393 ++++++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/mmap.c        |  178 ++++++++--------------
 bsd-user/qemu-bsd.h    |   10 ++
 bsd-user/qemu.h        |    3 +-
 bsd-user/syscall.c     |  174 +++++++++++++---------
 7 files changed, 700 insertions(+), 182 deletions(-)
 create mode 100644 bsd-user/bsd-mem.c
 create mode 100644 bsd-user/bsd-mem.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index caf95ed..77709cd 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,5 +1,5 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-proc.o \
+	        uaccess.o bsd-mem.o bsd-proc.o \
 			$(HOST_VARIANT_DIR)/os-proc.o \
 			$(HOST_VARIANT_DIR)/os-stat.o \
 			$(HOST_VARIANT_DIR)/os-sys.o \
diff --git a/bsd-user/bsd-mem.c b/bsd-user/bsd-mem.c
new file mode 100644
index 0000000..bfe03aa
--- /dev/null
+++ b/bsd-user/bsd-mem.c
@@ -0,0 +1,122 @@
+/*
+ *  memory management system conversion routines
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+struct bsd_shm_regions bsd_shm_regions[N_BSD_SHM_REGIONS];
+
+abi_ulong bsd_target_brk;
+abi_ulong bsd_target_original_brk;
+
+void target_set_brk(abi_ulong new_brk)
+{
+
+    bsd_target_original_brk = bsd_target_brk = HOST_PAGE_ALIGN(new_brk);
+}
+
+abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
+        abi_ulong target_addr)
+{
+    struct target_ipc_perm *target_ip;
+
+    if (!lock_user_struct(VERIFY_READ, target_ip, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_ip->cuid, &target_ip->cuid);
+    __get_user(host_ip->cgid, &target_ip->cgid);
+    __get_user(host_ip->uid, &target_ip->uid);
+    __get_user(host_ip->gid, &target_ip->gid);
+    __get_user(host_ip->mode, &target_ip->mode);
+    __get_user(host_ip->seq, &target_ip->seq);
+    __get_user(host_ip->key, &target_ip->key);
+    unlock_user_struct(target_ip, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_ipc_perm(abi_ulong target_addr,
+        struct ipc_perm *host_ip)
+{
+    struct target_ipc_perm *target_ip;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ip, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_ip->cuid, &target_ip->cuid);
+    __put_user(host_ip->cgid, &target_ip->cgid);
+    __put_user(host_ip->uid, &target_ip->uid);
+    __put_user(host_ip->gid, &target_ip->gid);
+    __put_user(host_ip->mode, &target_ip->mode);
+    __put_user(host_ip->seq, &target_ip->seq);
+    __put_user(host_ip->key, &target_ip->key);
+    unlock_user_struct(target_ip, target_addr, 1);
+
+    return 0;
+}
+
+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_lpid, &target_sd->shm_lpid);
+    __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    __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);
+    unlock_user_struct(target_sd, target_addr, 0);
+
+    return 0;
+}
+
+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_lpid, &target_sd->shm_lpid);
+    __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    __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);
+    unlock_user_struct(target_sd, target_addr, 1);
+
+    return 0;
+}
+
diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h
new file mode 100644
index 0000000..88c01ec
--- /dev/null
+++ b/bsd-user/bsd-mem.h
@@ -0,0 +1,393 @@
+/*
+ *  memory management system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*--
+ * Copyright (c) 1982, 1986, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BSD_MMAN_H_
+#define _BSD_MMAN_H_
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <fcntl.h>
+
+#include "qemu-bsd.h"
+
+extern struct bsd_shm_regions bsd_shm_regions[];
+extern abi_ulong bsd_target_brk;
+extern abi_ulong bsd_target_original_brk;
+
+/* mmap(2) */
+static inline abi_long do_bsd_mmap(void *cpu_env, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7,
+    abi_long arg8)
+{
+
+    if (regpairs_aligned(cpu_env) != 0) {
+       arg6 = arg7;
+       arg7 = arg8;
+    }
+    return get_errno(target_mmap(arg1, arg2, arg3,
+                target_to_host_bitmask(arg4, mmap_flags_tbl), arg5,
+		target_offset64(arg6, arg7)));
+}
+
+/* munmap(2) */
+static inline abi_long do_bsd_munmap(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(target_munmap(arg1, arg2));
+}
+
+/* mprotect(2) */
+static inline abi_long do_bsd_mprotect(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    return get_errno(target_mprotect(arg1, arg2, arg3));
+}
+
+/* msync(2) */
+static inline abi_long do_bsd_msync(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+
+    return get_errno(msync(g2h(arg1), arg2, arg3));
+}
+
+/* mlock(2) */
+static inline abi_long do_bsd_mlock(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(mlock(g2h(arg1), arg2));
+}
+
+/* munlock(2) */
+static inline abi_long do_bsd_munlock(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(munlock(g2h(arg1), arg2));
+}
+
+/* mlockall(2) */
+static inline abi_long do_bsd_mlockall(abi_long arg1)
+{
+
+    return get_errno(mlockall(arg1));
+}
+
+/* munlockall(2) */
+static inline abi_long do_bsd_munlockall(void)
+{
+
+    return get_errno(munlockall());
+}
+
+/* madvise(2) */
+static inline abi_long do_bsd_madvise(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    /*
+     * A straight passthrough may not be safe because qemu sometimes
+     * turns private file-backed mapping into anonymous mappings. This
+     * will break MADV_DONTNEED.  This is a hint, so ignoring and returing
+     * success is ok.
+     */
+    return get_errno(0);
+}
+
+/* minherit(2) */
+static inline abi_long do_bsd_minherit(abi_long addr, abi_long len,
+        abi_long inherit)
+{
+
+    return get_errno(minherit(g2h(addr), len, inherit));
+}
+
+/* mincore(2) */
+static inline abi_long do_bsd_mincore(abi_ulong target_addr, abi_ulong len,
+        abi_ulong target_vec)
+{
+    abi_long ret;
+    void *p, *a;
+
+    a = lock_user(VERIFY_WRITE, target_addr, len, 0);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+    p = lock_user_string(target_vec);
+    if (p == NULL) {
+        unlock_user(a, target_addr, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(mincore(a, len, p));
+    unlock_user(p, target_vec, ret);
+    unlock_user(a, target_addr, 0);
+
+    return ret;
+}
+
+/* break() XXX this needs some more work. */
+static inline abi_long do_obreak(abi_ulong new_brk)
+{
+    abi_ulong brk_page;
+    abi_long mapped_addr;
+    int new_alloc_size;
+
+    return -TARGET_EINVAL;
+
+    if (!new_brk) {
+        return 0;
+    }
+    if (new_brk < bsd_target_original_brk) {
+        return -TARGET_EINVAL;
+    }
+
+    brk_page = HOST_PAGE_ALIGN(bsd_target_brk);
+
+    /* If the new brk is less than this, set it and we're done... */
+    if (new_brk < brk_page) {
+        bsd_target_brk = new_brk;
+        return 0;
+    }
+
+    /* We need to allocate more memory after the brk... */
+    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
+    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
+                PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0));
+
+    if (!is_error(mapped_addr)) {
+        bsd_target_brk = new_brk;
+    } else {
+        return mapped_addr;
+    }
+
+    return 0;
+}
+
+/* shm_open(2) */
+static inline abi_long do_bsd_shm_open(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+    int ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(shm_open(path(p),
+                target_to_host_bitmask(arg2, fcntl_flags_tbl), arg3));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* shm_unlink(2) */
+static inline abi_long do_bsd_shm_unlink(abi_ulong arg1)
+{
+    int ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(shm_unlink(p)); /* XXX path(p)? */
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* shmget(2) */
+static inline abi_long do_bsd_shmget(abi_long arg1, abi_ulong arg2,
+        abi_long arg3)
+{
+
+    return get_errno(shmget(arg1, arg2, arg3));
+}
+
+/* shmctl(2) */
+static inline abi_long do_bsd_shmctl(abi_long shmid, abi_long cmd,
+        abi_ulong buff)
+{
+    struct shmid_ds dsarg;
+    abi_long ret = -TARGET_EINVAL;
+
+    cmd &= 0xff;
+
+    switch (cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+        if (target_to_host_shmid_ds(&dsarg, buff)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(shmctl(shmid, cmd, &dsarg));
+        if (host_to_target_shmid_ds(buff, &dsarg)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    case IPC_RMID:
+        ret = get_errno(shmctl(shmid, cmd, NULL));
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+/* shmat(2) */
+static inline abi_long do_bsd_shmat(int shmid, abi_ulong shmaddr, int shmflg)
+{
+    abi_ulong raddr;
+    abi_long ret;
+    void *host_raddr;
+    struct shmid_ds shm_info;
+    int i;
+
+    /* 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 the length */
+        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_BSD_SHM_REGIONS; i++) {
+        if (bsd_shm_regions[i].start == 0) {
+            bsd_shm_regions[i].start = raddr;
+            bsd_shm_regions[i].size = shm_info.shm_segsz;
+            break;
+        }
+    }
+
+    mmap_unlock();
+    return raddr;
+}
+
+/* shmdt(2) */
+static inline abi_long do_bsd_shmdt(abi_ulong shmaddr)
+{
+    int i;
+
+    for (i = 0; i < N_BSD_SHM_REGIONS; ++i) {
+        if (bsd_shm_regions[i].start == shmaddr) {
+            bsd_shm_regions[i].start = 0;
+            page_set_flags(shmaddr,
+                shmaddr + bsd_shm_regions[i].size, 0);
+            break;
+        }
+    }
+
+    return get_errno(shmdt(g2h(shmaddr)));
+}
+
+
+static inline abi_long do_bsd_vadvise(void)
+{
+    /* See sys_ovadvise() in vm_unix.c */
+    qemu_log("qemu: Unsupported syscall vadvise()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_bsd_sbrk(void)
+{
+    /* see sys_sbrk() in vm_mmap.c */
+    qemu_log("qemu: Unsupported syscall sbrk()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_bsd_sstk(void)
+{
+    /* see sys_sstk() in vm_mmap.c */
+    qemu_log("qemu: Unsupported syscall sstk()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_mmap(caddr_t addr, size_t len, int prot, int
+ * flags, int fd, int pad, off_t pos) system call.
+ */
+static inline abi_long do_bsd_freebsd6_mmap(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6,
+        abi_long arg7)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_mmap()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !_BSD_MMAN_H_ */
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index aae8ea1..96a09f3 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -1,4 +1,4 @@
-/*
+/**
  *  mmap support for qemu
  *
  *  Copyright (c) 2003 - 2008 Fabrice Bellard
@@ -26,13 +26,11 @@
 
 #include "qemu.h"
 #include "qemu-common.h"
-#include "bsd-mman.h"
 
-//#define DEBUG_MMAP
+// #define DEBUG_MMAP
 
-#if defined(CONFIG_USE_NPTL)
-pthread_mutex_t mmap_mutex;
-static int __thread mmap_lock_count;
+pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
+static __thread int mmap_lock_count;
 
 void mmap_lock(void)
 {
@@ -63,76 +61,6 @@ void mmap_fork_end(int child)
     else
         pthread_mutex_unlock(&mmap_mutex);
 }
-#else
-/* We aren't threadsafe to start with, so no need to worry about locking.  */
-void mmap_lock(void)
-{
-}
-
-void mmap_unlock(void)
-{
-}
-#endif
-
-static void *bsd_vmalloc(size_t size)
-{
-    void *p;
-    mmap_lock();
-    /* Use map and mark the pages as used.  */
-    p = mmap(NULL, size, PROT_READ | PROT_WRITE,
-             MAP_PRIVATE | MAP_ANON, -1, 0);
-
-    if (h2g_valid(p)) {
-        /* Allocated region overlaps guest address space.
-           This may recurse.  */
-        abi_ulong addr = h2g(p);
-        page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size),
-                       PAGE_RESERVED);
-    }
-
-    mmap_unlock();
-    return p;
-}
-
-void *g_malloc(size_t size)
-{
-    char * p;
-    size += 16;
-    p = bsd_vmalloc(size);
-    *(size_t *)p = size;
-    return p + 16;
-}
-
-/* We use map, which is always zero initialized.  */
-void * g_malloc0(size_t size)
-{
-    return g_malloc(size);
-}
-
-void g_free(void *ptr)
-{
-    /* FIXME: We should unmark the reserved pages here.  However this gets
-       complicated when one target page spans multiple host pages, so we
-       don't bother.  */
-    size_t *p;
-    p = (size_t *)((char *)ptr - 16);
-    munmap(p, *p);
-}
-
-void *g_realloc(void *ptr, size_t size)
-{
-    size_t old_size, copy;
-    void *new_ptr;
-
-    if (!ptr)
-        return g_malloc(size);
-    old_size = *(size_t *)((char *)ptr - 16);
-    copy = old_size < size ? old_size : size;
-    new_ptr = g_malloc(size);
-    memcpy(new_ptr, ptr, copy);
-    g_free(ptr);
-    return new_ptr;
-}
 
 /* NOTE: all the constants are the HOST ones, but addresses are target. */
 int target_mprotect(abi_ulong start, abi_ulong len, int prot)
@@ -164,11 +92,11 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
     if (start > host_start) {
         /* handle host page containing start */
         prot1 = prot;
-        for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
+        for (addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
             prot1 |= page_get_flags(addr);
         }
         if (host_end == host_start + qemu_host_page_size) {
-            for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+            for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
                 prot1 |= page_get_flags(addr);
             }
             end = host_end;
@@ -180,7 +108,7 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
     }
     if (end < host_end) {
         prot1 = prot;
-        for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+        for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
             prot1 |= page_get_flags(addr);
         }
         ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size,
@@ -218,7 +146,7 @@ static int mmap_frag(abi_ulong real_start,
 
     /* get the protection of the target pages outside the mapping */
     prot1 = 0;
-    for(addr = real_start; addr < real_end; addr++) {
+    for (addr = real_start; addr < real_end; addr++) {
         if (addr < start || addr >= end)
             prot1 |= page_get_flags(addr);
     }
@@ -238,15 +166,19 @@ static int mmap_frag(abi_ulong real_start,
         /* msync() won't work here, so we return an error if write is
            possible while it is a shared mapping */
         if ((flags & TARGET_BSD_MAP_FLAGMASK) == MAP_SHARED &&
-            (prot & PROT_WRITE))
+            (prot & PROT_WRITE)) {
             return -1;
+        }
 
         /* adjust protection to be able to read */
-        if (!(prot1 & PROT_WRITE))
+        if (!(prot1 & PROT_WRITE)) {
             mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
+        }
 
         /* read the corresponding file data */
-        pread(fd, g2h(start), end - start, offset);
+        if (pread(fd, g2h(start), end - start, offset) == -1) {
+            return -1;
+        }
 
         /* put final protection */
         if (prot_new != (prot1 | PROT_WRITE))
@@ -269,13 +201,14 @@ static abi_ulong mmap_next_start = 0x40000000;
 
 unsigned long last_brk;
 
-/* find a free memory area of size 'size'. The search starts at
-   'start'. If 'start' == 0, then a default start address is used.
-   Return -1 if error.
-*/
+/*
+ * Find a free memory area of size 'size'. The search starts at
+ * 'start'. If 'start' == 0, then a default start address is used.
+ * Return -1 if error.
+ */
 /* page_init() marks pages used by the host as reserved to be sure not
    to use them. */
-static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
 {
     abi_ulong addr, addr1, addr_start;
     int prot;
@@ -300,9 +233,9 @@ static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
     if (addr == 0)
         addr = mmap_next_start;
     addr_start = addr;
-    for(;;) {
+    for (;;) {
         prot = 0;
-        for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
+        for (addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
             prot |= page_get_flags(addr1);
         }
         if (prot == 0)
@@ -319,9 +252,10 @@ static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
 
 /* NOTE: all the constants are the HOST ones */
 abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
-                     int flags, int fd, abi_ulong offset)
+                     int flags, int fd, off_t offset)
 {
-    abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
+    abi_ulong ret, end, real_start, real_end, retaddr, host_len;
+    off_t host_offset;
     unsigned long host_start;
 
     mmap_lock();
@@ -337,21 +271,38 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
             printf("MAP_FIXED ");
         if (flags & MAP_ANON)
             printf("MAP_ANON ");
-        switch(flags & TARGET_BSD_MAP_FLAGMASK) {
-        case MAP_PRIVATE:
-            printf("MAP_PRIVATE ");
-            break;
-        case MAP_SHARED:
-            printf("MAP_SHARED ");
-            break;
-        default:
-            printf("[MAP_FLAGMASK=0x%x] ", flags & TARGET_BSD_MAP_FLAGMASK);
-            break;
-        }
-        printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset);
+	if (flags & MAP_PRIVATE)
+	    printf("MAP_PRIVATE ");
+	if (flags & MAP_SHARED)
+	    printf("MAP_SHARED ");
+	if (flags & MAP_NOCORE)
+	    printf("MAP_NOCORE ");
+#ifdef MAP_STACK
+	if (flags & MAP_STACK)
+	    printf("MAP_STACK ");
+#endif
+        printf("fd=%d offset=0x%llx\n", fd, offset);
     }
 #endif
 
+    /*
+     * Enforce the constraints.
+     */
+    if (len == 0 && fd != -1) {
+            errno = EINVAL;
+            goto fail;
+    }
+
+#ifdef MAP_STACK
+    if (flags & MAP_STACK) {
+        if ((fd != -1) || ((prot & (PROT_READ | PROT_WRITE)) !=
+                    (PROT_READ | PROT_WRITE))) {
+            errno = EINVAL;
+            goto fail;
+        }
+    }
+#endif /* MAP_STACK */
+
     if (offset & ~TARGET_PAGE_MASK) {
         errno = EINVAL;
         goto fail;
@@ -378,8 +329,9 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
            qemu_real_host_page_size */
         p = mmap(g2h(mmap_start),
                  host_len, prot, flags | MAP_FIXED, fd, host_offset);
-        if (p == MAP_FAILED)
+        if (p == MAP_FAILED) {
             goto fail;
+        }
         /* update start so that it points to the file position at 'offset' */
         host_start = (unsigned long)p;
         if (!(flags & MAP_ANON))
@@ -396,7 +348,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
         end = start + len;
         real_end = HOST_PAGE_ALIGN(end);
 
-        for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) {
+        for (addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) {
             flg = page_get_flags(addr);
             if (flg & PAGE_RESERVED) {
                 errno = ENXIO;
@@ -493,7 +445,9 @@ int target_munmap(abi_ulong start, abi_ulong len)
     int prot, ret;
 
 #ifdef DEBUG_MMAP
-    printf("munmap: start=0x%lx len=0x%lx\n", start, len);
+    printf("munmap: start=0x" TARGET_ABI_FMT_lx " len=0x"
+            TARGET_ABI_FMT_lx "\n",
+            start, len);
 #endif
     if (start & ~TARGET_PAGE_MASK)
         return -EINVAL;
@@ -508,11 +462,11 @@ int target_munmap(abi_ulong start, abi_ulong len)
     if (start > real_start) {
         /* handle host page containing start */
         prot = 0;
-        for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
+        for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
             prot |= page_get_flags(addr);
         }
         if (real_end == real_start + qemu_host_page_size) {
-            for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+            for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
                 prot |= page_get_flags(addr);
             }
             end = real_end;
@@ -522,7 +476,7 @@ int target_munmap(abi_ulong start, abi_ulong len)
     }
     if (end < real_end) {
         prot = 0;
-        for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+        for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
             prot |= page_get_flags(addr);
         }
         if (prot != 0)
@@ -535,8 +489,10 @@ int target_munmap(abi_ulong start, abi_ulong len)
         ret = munmap(g2h(real_start), real_end - real_start);
     }
 
-    if (ret == 0)
+    if (ret == 0) {
         page_set_flags(start, start + len, 0);
+        tb_invalidate_phys_range(start, start + len, 0);
+    }
     mmap_unlock();
     return ret;
 }
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
index 590c36b..f562aad 100644
--- a/bsd-user/qemu-bsd.h
+++ b/bsd-user/qemu-bsd.h
@@ -32,6 +32,16 @@
 #include <sys/wait.h>
 #include <netinet/in.h>
 
+/* bsd-mem.c */
+abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
+        abi_ulong target_addr);
+abi_long host_to_target_ipc_perm(abi_ulong target_addr,
+        struct ipc_perm *host_ip);
+abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
+        abi_ulong target_addr);
+abi_long host_to_target_shmid_ds(abi_ulong target_addr,
+        struct shmid_ds *host_sd);
+
 /* bsd-proc.c */
 int target_to_host_resource(int code);
 rlim_t target_to_host_rlim(abi_ulong target_rlim);
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index e668a67..613a89e 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -219,7 +219,7 @@ void QEMU_NORETURN force_sig(int target_sig);
 /* mmap.c */
 int target_mprotect(abi_ulong start, abi_ulong len, int prot);
 abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
-                     int flags, int fd, abi_ulong offset);
+                     int flags, int fd, off_t offset);
 int target_munmap(abi_ulong start, abi_ulong len);
 abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
                        abi_ulong new_size, unsigned long flags,
@@ -228,6 +228,7 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
 extern unsigned long last_brk;
 void mmap_lock(void);
 void mmap_unlock(void);
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
 void cpu_list_lock(void);
 void cpu_list_unlock(void);
 #if defined(CONFIG_USE_NPTL)
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 633d638..e3967fa 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -17,22 +17,16 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
-#include <stdlib.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdarg.h>
 #include <string.h>
 #include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <time.h>
-#include <limits.h>
 #include <sys/types.h>
-#include <sys/mman.h>
 #include <sys/syscall.h>
 #include <sys/param.h>
 #include <sys/sysctl.h>
-#include <utime.h>
 
 #include "qemu.h"
 #include "qemu-common.h"
@@ -42,6 +36,7 @@ static int host_to_target_errno(int err);
 
 /* BSD independent syscall shims */
 #include "bsd-file.h"
+#include "bsd-mem.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
 
@@ -53,19 +48,18 @@ static int host_to_target_errno(int err);
 
 /* #define DEBUG */
 
-static abi_ulong target_brk;
-static abi_ulong target_original_brk;
-
 /*
  * errno conversion.
  */
 abi_long get_errno(abi_long ret)
 {
-    if (ret == -1)
+
+    if (ret == -1) {
         /* XXX need to translate host -> target errnos here */
         return -(errno);
-    else
+    } else {
         return ret;
+    }
 }
 
 static int host_to_target_errno(int err)
@@ -76,46 +70,8 @@ static int host_to_target_errno(int err)
 
 int is_error(abi_long ret)
 {
-    return (abi_ulong)ret >= (abi_ulong)(-4096);
-}
 
-void target_set_brk(abi_ulong new_brk)
-{
-    target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
-}
-
-/* do_obreak() must return target errnos. */
-static abi_long do_obreak(abi_ulong new_brk)
-{
-    abi_ulong brk_page;
-    abi_long mapped_addr;
-    int new_alloc_size;
-
-    if (!new_brk)
-        return 0;
-    if (new_brk < target_original_brk)
-        return -TARGET_EINVAL;
-
-    brk_page = HOST_PAGE_ALIGN(target_brk);
-
-    /* If the new brk is less than this, set it and we're done... */
-    if (new_brk < brk_page) {
-        target_brk = new_brk;
-        return 0;
-    }
-
-    /* We need to allocate more memory after the brk... */
-    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
-    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
-                                        PROT_READ|PROT_WRITE,
-                                        MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0));
-
-    if (!is_error(mapped_addr))
-        target_brk = new_brk;
-    else
-        return mapped_addr;
-
-    return 0;
+    return (abi_ulong)ret >= (abi_ulong)(-4096);
 }
 
 /* FIXME
@@ -169,6 +125,13 @@ static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
     return 0;
 }
 
+
+/* stub for arm semihosting support */
+abi_long do_brk(abi_ulong new_brk)
+{
+    return do_obreak(new_brk);
+}
+
 /* 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>. */
@@ -340,6 +303,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_FREEBSD_NR_getloginclass: /* getloginclass(2) */
         ret = do_freebsd_getloginclass(arg1, arg2);
         break;
+
 #if 0
     case TARGET_FREEBSD_NR_pdwait4: /* pdwait4(2) */
         ret = do_freebsd_pdwait4(arg1, arg2, arg3, arg4);
@@ -417,6 +381,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_FREEBSD_NR_auditctl: /* auditctl(2) */
         ret = do_freebsd_auditctl(arg1);
         break;
+
     case TARGET_FREEBSD_NR_utrace: /* utrace(2) */
         ret = do_bsd_utrace(arg1, arg2);
         break;
@@ -434,6 +399,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
 
+
         /*
          * File system calls.
          */
@@ -807,20 +773,95 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
 
+        /*
+         * Memory management system calls.
+         */
+    case TARGET_FREEBSD_NR_mmap: /* mmap(2) */
+        ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+           arg8);
+        break;
+
+    case TARGET_FREEBSD_NR_munmap: /* munmap(2) */
+        ret = do_bsd_munmap(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mprotect: /* mprotect(2) */
+        ret = do_bsd_mprotect(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_msync: /* msync(2) */
+        ret = do_bsd_msync(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mlock: /* mlock(2) */
+        ret = do_bsd_mlock(arg1, arg2);
+        break;
 
-    case TARGET_FREEBSD_NR_mmap:
-        ret = get_errno(target_mmap(arg1, arg2, arg3,
-                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
-                                    arg5,
-                                    arg6));
+    case TARGET_FREEBSD_NR_munlock: /* munlock(2) */
+        ret = do_bsd_munlock(arg1, arg2);
         break;
-    case TARGET_FREEBSD_NR_mprotect:
-        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+
+    case TARGET_FREEBSD_NR_mlockall: /* mlockall(2) */
+        ret = do_bsd_mlockall(arg1);
         break;
-    case TARGET_FREEBSD_NR_break:
-        ret = do_obreak(arg1);
+
+    case TARGET_FREEBSD_NR_munlockall: /* munlockall(2) */
+        ret = do_bsd_munlockall();
+        break;
+
+    case TARGET_FREEBSD_NR_madvise: /* madvise(2) */
+        ret = do_bsd_madvise(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_minherit: /* minherit(2) */
+        ret = do_bsd_minherit(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mincore: /* mincore(2) */
+        ret = do_bsd_mincore(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_shm_open: /* shm_open(2) */
+        ret = do_bsd_shm_open(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_shm_unlink: /* shm_unlink(2) */
+        ret = do_bsd_shm_unlink(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_shmget: /* shmget(2) */
+        ret = do_bsd_shmget(arg1, arg2, arg3);
         break;
 
+    case TARGET_FREEBSD_NR_shmctl: /* shmctl(2) */
+        ret = do_bsd_shmctl(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_shmat: /* shmat(2) */
+        ret = do_bsd_shmat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_shmdt: /* shmdt(2) */
+        ret = do_bsd_shmdt(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_vadvise:
+        ret = do_bsd_vadvise();
+        break;
+
+    case TARGET_FREEBSD_NR_sbrk:
+        ret = do_bsd_sbrk();
+        break;
+
+    case TARGET_FREEBSD_NR_sstk:
+        ret = do_bsd_sstk();
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_mmap: /* undocumented */
+        ret = do_bsd_freebsd6_mmap(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+        break;
+
+
         /*
          * time related system calls.
          */
@@ -997,6 +1038,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                     arg8));
         break;
     }
+
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
@@ -1033,13 +1075,10 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_NETBSD_NR_mmap:
-        ret = get_errno(target_mmap(arg1, arg2, arg3,
-                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
-                                    arg5,
-                                    arg6));
+        ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
         break;
     case TARGET_NETBSD_NR_mprotect:
-        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+        ret = do_bsd_mprotect(arg1, arg2, arg3);
         break;
 
     case TARGET_NETBSD_NR_syscall:
@@ -1086,13 +1125,10 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_OPENBSD_NR_mmap:
-        ret = get_errno(target_mmap(arg1, arg2, arg3,
-                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
-                                    arg5,
-                                    arg6));
+        ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
         break;
     case TARGET_OPENBSD_NR_mprotect:
-        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+        ret = do_bsd_mprotect(arg1, arg2, arg3);
         break;
 
     case TARGET_OPENBSD_NR_syscall:
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 13/19] bsd-user: add support for socket related system calls
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (13 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 12/19] bsd-user: add support for memory management " Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 14/19] bsd-user: add support for thread " Stacey Son
                     ` (5 subsequent siblings)
  20 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for socket related system calls
including accept(2), bind(2), connect(2), getpeername(2),
getsockname(2), getsockopt(2), setsockopt(2), listen(2),
recvfrom(2), recvmsg(2), sendmsg(2), sendto(2), socket(2),
socketpair(2), shutdown(2), setfib(2), sctp_peeloff(2),
sctp_generic_sendmsg(2), sctp_generic_recvmsg(2), sendfile(2), and
freebsd4_sendfile(2).
---
 bsd-user/Makefile.objs       |    4 +-
 bsd-user/bsd-socket.c        |  108 +++++++++
 bsd-user/bsd-socket.h        |  266 ++++++++++++++++++++
 bsd-user/freebsd/os-socket.c |  149 ++++++++++++
 bsd-user/freebsd/os-socket.h |  548 ++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h   |    6 +
 bsd-user/netbsd/os-socket.c  |    1 +
 bsd-user/netbsd/os-socket.h  |   98 ++++++++
 bsd-user/openbsd/os-socket.c |    1 +
 bsd-user/openbsd/os-socket.h |   98 ++++++++
 bsd-user/qemu-bsd.h          |    8 +
 bsd-user/syscall.c           |   93 +++++++
 12 files changed, 1378 insertions(+), 2 deletions(-)
 create mode 100644 bsd-user/bsd-socket.c
 create mode 100644 bsd-user/bsd-socket.h
 create mode 100644 bsd-user/freebsd/os-socket.c
 create mode 100644 bsd-user/freebsd/os-socket.h
 create mode 100644 bsd-user/netbsd/os-socket.c
 create mode 100644 bsd-user/netbsd/os-socket.h
 create mode 100644 bsd-user/openbsd/os-socket.c
 create mode 100644 bsd-user/openbsd/os-socket.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 77709cd..635d879 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,6 +1,6 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-mem.o bsd-proc.o \
+	        uaccess.o bsd-mem.o bsd-proc.o bsd-socket.o \
 			$(HOST_VARIANT_DIR)/os-proc.o \
-			$(HOST_VARIANT_DIR)/os-stat.o \
+			$(HOST_VARIANT_DIR)/os-socket.o $(HOST_VARIANT_DIR)/os-stat.o \
 			$(HOST_VARIANT_DIR)/os-sys.o \
 			$(HOST_VARIANT_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/bsd-socket.c b/bsd-user/bsd-socket.c
new file mode 100644
index 0000000..c1a3b49
--- /dev/null
+++ b/bsd-user/bsd-socket.c
@@ -0,0 +1,108 @@
+/*
+ *  BSD socket system call related helpers
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+/*
+ * socket conversion
+ */
+abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr,
+        socklen_t len)
+{
+    const socklen_t unix_maxlen = sizeof(struct sockaddr_un);
+    sa_family_t sa_family;
+    struct target_sockaddr *target_saddr;
+
+    target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
+    if (target_saddr == 0) {
+        return -TARGET_EFAULT;
+    }
+
+    sa_family = 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 will
+     * fix that here if needed.
+     */
+    if (target_saddr->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;
+        }
+    }
+
+    memcpy(addr, target_saddr, len);
+    addr->sa_family = sa_family;        /* type uint8_t */
+    addr->sa_len = target_saddr->sa_len;    /* type uint8_t */
+    unlock_user(target_saddr, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
+        socklen_t len)
+{
+    struct target_sockaddr *target_saddr;
+
+    target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
+    if (target_saddr == 0) {
+        return -TARGET_EFAULT;
+    }
+    memcpy(target_saddr, addr, len);
+    target_saddr->sa_family = addr->sa_family;  /* type uint8_t */
+    target_saddr->sa_len = addr->sa_len;        /* type uint8_t */
+    unlock_user(target_saddr, target_addr, len);
+
+    return 0;
+}
+
+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 == 0) {
+        return -TARGET_EFAULT;
+    }
+    mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
+    mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
+    if (len == sizeof(struct target_ip_mreqn)) {
+        mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
+    }
+    unlock_user(target_smreqn, target_addr, 0);
+
+    return 0;
+}
+
diff --git a/bsd-user/bsd-socket.h b/bsd-user/bsd-socket.h
new file mode 100644
index 0000000..f5d1ac8
--- /dev/null
+++ b/bsd-user/bsd-socket.h
@@ -0,0 +1,266 @@
+/*
+ *  socket related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __BSD_SOCKET_H_
+#define __BSD_SOCKET_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu-bsd.h"
+
+/* bind(2) */
+static inline abi_long do_bsd_bind(int sockfd, abi_ulong target_addr,
+        socklen_t addrlen)
+{
+    abi_long ret;
+    void *addr;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+
+    addr = alloca(addrlen + 1);
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(bind(sockfd, addr, addrlen));
+}
+
+/* connect(2) */
+static inline abi_long do_bsd_connect(int sockfd, abi_ulong target_addr,
+        socklen_t addrlen)
+{
+    abi_long ret;
+    void *addr;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    addr = alloca(addrlen);
+
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(connect(sockfd, addr, addrlen));
+}
+
+/* accept(2) */
+static inline abi_long do_bsd_accept(int fd, abi_ulong target_addr,
+        abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (target_addr == 0) {
+        return get_errno(accept(fd, NULL, NULL));
+    }
+    /* return EINVAL if addrlen pointer is invalid */
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EINVAL;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EINVAL;
+    }
+    addr = alloca(addrlen);
+
+    ret = get_errno(accept(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getpeername(2) */
+static inline abi_long do_bsd_getpeername(int fd, abi_ulong target_addr,
+        abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EFAULT;
+    }
+    addr = alloca(addrlen);
+    ret = get_errno(getpeername(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getsockname(2) */
+static inline abi_long do_bsd_getsockname(int fd, abi_ulong target_addr,
+        abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EFAULT;
+    }
+    addr = alloca(addrlen);
+
+    ret = get_errno(getsockname(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* socketpair(2) */
+static inline abi_long do_bsd_socketpair(int domain, int type, int protocol,
+        abi_ulong target_tab_addr)
+{
+    int tab[2];
+    abi_long ret;
+
+    ret = get_errno(socketpair(domain, type, protocol, tab));
+    if (!is_error(ret)) {
+        if (put_user_s32(tab[0], target_tab_addr) ||
+                put_user_s32(tab[1], target_tab_addr + sizeof(tab[0]))) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* sendto(2) */
+static inline abi_long do_bsd_sendto(int fd, abi_ulong msg, size_t len,
+        int flags, abi_ulong target_addr, socklen_t addrlen)
+{
+    struct sockaddr *saddr;
+    void *host_msg;
+    abi_long ret;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    host_msg = lock_user(VERIFY_READ, msg, len, 1);
+    if (!host_msg) {
+        return -TARGET_EFAULT;
+    }
+    if (target_addr) {
+        saddr = alloca(addrlen);
+        ret = target_to_host_sockaddr(saddr, target_addr, addrlen);
+        if (is_error(ret)) {
+            unlock_user(host_msg, msg, 0);
+            return ret;
+        }
+        ret = get_errno(sendto(fd, host_msg, len, flags, saddr, addrlen));
+    } else {
+        ret = get_errno(send(fd, host_msg, len, flags));
+    }
+    unlock_user(host_msg, msg, 0);
+    return ret;
+}
+
+/* recvfrom(2) */
+static inline abi_long do_bsd_recvfrom(int fd, abi_ulong msg, size_t len,
+        int flags, abi_ulong target_addr, abi_ulong target_addrlen)
+{
+    socklen_t addrlen;
+    struct sockaddr *saddr;
+    void *host_msg;
+    abi_long ret;
+
+    host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
+    if (!host_msg) {
+        return -TARGET_EFAULT;
+    }
+    if (target_addr) {
+        if (get_user_u32(addrlen, target_addrlen)) {
+            ret = -TARGET_EFAULT;
+            goto fail;
+        }
+        if ((int)addrlen < 0) {
+            ret = -TARGET_EINVAL;
+            goto fail;
+        }
+        saddr = alloca(addrlen);
+        ret = get_errno(recvfrom(fd, host_msg, len, flags, saddr, &addrlen));
+    } else {
+        saddr = NULL; /* To keep compiler quiet.  */
+        ret = get_errno(qemu_recv(fd, host_msg, len, flags));
+    }
+    if (!is_error(ret)) {
+        if (target_addr) {
+            host_to_target_sockaddr(target_addr, saddr, addrlen);
+            if (put_user_u32(addrlen, target_addrlen)) {
+                ret = -TARGET_EFAULT;
+                goto fail;
+            }
+        }
+        unlock_user(host_msg, msg, len);
+    } else {
+fail:
+        unlock_user(host_msg, msg, 0);
+    }
+    return ret;
+}
+
+/* socket(2) */
+static inline abi_long do_bsd_socket(abi_long domain, abi_long type,
+        abi_long protocol)
+{
+
+    return get_errno(socket(domain, type, protocol));
+}
+
+/* shutdown(2) */
+static inline abi_long do_bsd_shutdown(abi_long s, abi_long how)
+{
+
+    return get_errno(shutdown(s, how));
+}
+
+#endif /* !__BSD_SOCKET_H_ */
diff --git a/bsd-user/freebsd/os-socket.c b/bsd-user/freebsd/os-socket.c
new file mode 100644
index 0000000..949af28
--- /dev/null
+++ b/bsd-user/freebsd/os-socket.c
@@ -0,0 +1,149 @@
+/*
+ *  FreeBSD socket related system call helpers
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+abi_long t2h_freebsd_cmsg(struct msghdr *msgh,
+        struct target_msghdr *target_msgh)
+{
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
+    abi_long msg_controllen;
+    abi_ulong target_cmsg_addr;
+    struct target_cmsghdr *target_cmsg;
+    socklen_t space = 0;
+
+
+    msg_controllen = tswapal(target_msgh->msg_controllen);
+    if (msg_controllen < sizeof(struct target_cmsghdr)) {
+        goto the_end;
+    }
+    target_cmsg_addr = tswapal(target_msgh->msg_control);
+    target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
+    if (target_cmsg == 0) {
+        return -TARGET_EFAULT;
+    }
+    while (cmsg && target_cmsg) {
+        void *data = CMSG_DATA(cmsg);
+        void *target_data = TARGET_CMSG_DATA(target_cmsg);
+        int len = tswapal(target_cmsg->cmsg_len) -
+            TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr));
+        space += CMSG_SPACE(len);
+        if (space > msgh->msg_controllen) {
+            space -= CMSG_SPACE(len);
+            gemu_log("Host cmsg overflow\n");
+            break;
+        }
+        cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
+        cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
+        cmsg->cmsg_len = CMSG_LEN(len);
+
+        if (cmsg->cmsg_level != TARGET_SOL_SOCKET ||
+            cmsg->cmsg_type != SCM_RIGHTS) {
+            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);
+    }
+    unlock_user(target_cmsg, target_cmsg_addr, 0);
+
+the_end:
+    msgh->msg_controllen = space;
+    return 0;
+}
+
+abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh,
+        struct msghdr *msgh)
+{
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
+    abi_long msg_controllen;
+    abi_ulong target_cmsg_addr;
+    struct target_cmsghdr *target_cmsg;
+    socklen_t space = 0;
+
+    msg_controllen = tswapal(target_msgh->msg_controllen);
+    if (msg_controllen < sizeof(struct target_cmsghdr)) {
+        goto the_end;
+    }
+    target_cmsg_addr = tswapal(target_msgh->msg_control);
+    target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr,
+        msg_controllen, 0);
+    if (target_cmsg == 0) {
+        return -TARGET_EFAULT;
+    }
+    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);
+        if (space > msg_controllen) {
+            space -= TARGET_CMSG_SPACE(len);
+            gemu_log("Target cmsg overflow\n");
+            break;
+        }
+        target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
+        target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
+        target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
+        if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
+            (cmsg->cmsg_type == SCM_RIGHTS)) {
+            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]);
+            }
+        } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
+            (cmsg->cmsg_type == SO_TIMESTAMP) &&
+            (len == sizeof(struct timeval))) {
+            /* copy struct timeval to target */
+            struct timeval *tv = (struct timeval *)data;
+            struct target_freebsd_timeval *target_tv =
+                (struct target_freebsd_timeval *)target_data;
+            __put_user(tv->tv_sec, &target_tv->tv_sec);
+            __put_user(tv->tv_usec, &target_tv->tv_usec);
+        } else {
+            gemu_log("Unsupported ancillary data: %d/%d\n",
+                cmsg->cmsg_level, cmsg->cmsg_type);
+            memcpy(target_data, data, len);
+        }
+        cmsg = CMSG_NXTHDR(msgh, cmsg);
+        target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
+    }
+    unlock_user(target_cmsg, target_cmsg_addr, space);
+
+the_end:
+    target_msgh->msg_controllen = tswapal(space);
+    return 0;
+}
+
diff --git a/bsd-user/freebsd/os-socket.h b/bsd-user/freebsd/os-socket.h
new file mode 100644
index 0000000..9339ffb
--- /dev/null
+++ b/bsd-user/freebsd/os-socket.h
@@ -0,0 +1,548 @@
+/*
+ *  FreeBSD socket related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __FREEBSD_SOCKET_H_
+#define __FREEBSD_SOCKET_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu-os.h"
+
+/* sendmsg(2) */
+static inline abi_long do_freebsd_sendmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+    abi_long ret;
+    struct target_msghdr *msgp;
+    struct msghdr msg;
+    int count;
+    struct iovec *vec;
+    abi_ulong target_vec;
+
+    if (!lock_user_struct(VERIFY_READ, msgp, target_msg, 1)) {
+        return -TARGET_EFAULT;
+    }
+    if (msgp->msg_name) {
+        msg.msg_namelen = tswap32(msgp->msg_namelen);
+        msg.msg_name = alloca(msg.msg_namelen);
+        ret = target_to_host_sockaddr(msg.msg_name,
+            tswapal(msgp->msg_name), msg.msg_namelen);
+
+        if (is_error(ret)) {
+            unlock_user_struct(msgp, target_msg, 0);
+            return ret;
+        }
+    } else {
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+    }
+    msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
+    msg.msg_control = alloca(msg.msg_controllen);
+    msg.msg_flags = tswap32(msgp->msg_flags);
+
+    count = tswapal(msgp->msg_iovlen);
+    vec = alloca(count * sizeof(struct iovec));
+    target_vec = tswapal(msgp->msg_iov);
+    lock_iovec(VERIFY_READ, vec, target_vec, count, 1);
+    msg.msg_iovlen = count;
+    msg.msg_iov = vec;
+
+    ret = t2h_freebsd_cmsg(&msg, msgp);
+    if (!is_error(ret)) {
+        ret = get_errno(sendmsg(fd, &msg, flags));
+    }
+    unlock_iovec(vec, target_vec, count, 0);
+    unlock_user_struct(msgp, target_msg, 0);
+    return ret;
+}
+
+/* recvmsg(2) */
+static inline abi_long do_freebsd_recvmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+    abi_long ret, len;
+    struct target_msghdr *msgp;
+    struct msghdr msg;
+    int count;
+    struct iovec *vec;
+    abi_ulong target_vec;
+
+    if (!lock_user_struct(VERIFY_WRITE, msgp, target_msg, 0)) {
+        return -TARGET_EFAULT;
+    }
+    if (msgp->msg_name) {
+        msg.msg_namelen = tswap32(msgp->msg_namelen);
+        msg.msg_name = alloca(msg.msg_namelen);
+        ret = target_to_host_sockaddr(msg.msg_name,
+            tswapal(msgp->msg_name), msg.msg_namelen);
+
+        if (is_error(ret)) {
+            unlock_user_struct(msgp, target_msg, 1);
+            return ret;
+        }
+    } else {
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+    }
+    msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
+    msg.msg_control = alloca(msg.msg_controllen);
+    msg.msg_flags = tswap32(msgp->msg_flags);
+
+    count = tswapal(msgp->msg_iovlen);
+    vec = alloca(count * sizeof(struct iovec));
+    target_vec = tswapal(msgp->msg_iov);
+    lock_iovec(VERIFY_WRITE, vec, target_vec, count, 0);
+    msg.msg_iovlen = count;
+    msg.msg_iov = vec;
+
+    ret = get_errno(recvmsg(fd, &msg, flags));
+    if (!is_error(ret)) {
+        len = ret;
+        ret = h2t_freebsd_cmsg(msgp, &msg);
+        if (!is_error(ret)) {
+            msgp->msg_namelen = tswap32(msg.msg_namelen);
+            if (msg.msg_name != NULL) {
+                ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
+                        msg.msg_name, msg.msg_namelen);
+                if (is_error(ret)) {
+                    goto out;
+                }
+            }
+        }
+        ret = len;
+    }
+out:
+    unlock_iovec(vec, target_vec, count, 1);
+    unlock_user_struct(msgp, target_msg, 1);
+    return ret;
+}
+
+/* setsockopt(2) */
+static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, socklen_t optlen)
+{
+    abi_long ret;
+    int val;
+    struct ip_mreqn *ip_mreq;
+
+    switch (level) {
+    case IPPROTO_TCP:
+        /* TCP options all take an 'int' value. */
+        if (optlen < sizeof(uint32_t)) {
+            return -TARGET_EINVAL;
+        }
+        if (get_user_u32(val, optval_addr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
+        break;
+
+    case IPPROTO_IP:
+        switch (optname) {
+        case IP_HDRINCL:/* int; header is included with data */
+        case IP_TOS:    /* int; IP type of service and preced. */
+        case IP_TTL:    /* int; IP time to live */
+        case IP_RECVOPTS: /* bool; receive all IP opts w/dgram */
+        case IP_RECVRETOPTS: /* bool; receive IP opts for response */
+        case IP_RECVDSTADDR: /* bool; receive IP dst addr w/dgram */
+        case IP_MULTICAST_IF:/* u_char; set/get IP multicast i/f  */
+        case IP_MULTICAST_TTL:/* u_char; set/get IP multicast ttl */
+        case IP_MULTICAST_LOOP:/*u_char;set/get IP multicast loopback */
+        case IP_PORTRANGE: /* int; range to choose for unspec port */
+        case IP_RECVIF: /* bool; receive reception if w/dgram */
+        case IP_IPSEC_POLICY:   /* int; set/get security policy */
+        case IP_FAITH:  /* bool; accept FAITH'ed connections */
+        case IP_RECVTTL: /* bool; receive reception TTL w/dgram */
+            val = 0;
+            if (optlen >= sizeof(uint32_t)) {
+                if (get_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            } else if (optlen >= 1) {
+                if (get_user_u8(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            }
+            ret = get_errno(setsockopt(sockfd, level, optname, &val,
+                        sizeof(val)));
+            break;
+
+        case IP_ADD_MEMBERSHIP: /*ip_mreq; add an IP group membership */
+        case IP_DROP_MEMBERSHIP:/*ip_mreq; drop an IP group 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;
+
+        default:
+            goto unimplemented;
+        }
+        break;
+
+    case TARGET_SOL_SOCKET:
+        switch (optname) {
+        /* Options with 'int' argument.  */
+        case TARGET_SO_DEBUG:
+            optname = SO_DEBUG;
+            break;
+
+        case TARGET_SO_REUSEADDR:
+            optname = SO_REUSEADDR;
+            break;
+
+        case TARGET_SO_REUSEPORT:
+            optname = SO_REUSEADDR;
+            break;
+
+        case TARGET_SO_KEEPALIVE:
+            optname = SO_KEEPALIVE;
+            break;
+
+        case TARGET_SO_DONTROUTE:
+            optname = SO_DONTROUTE;
+            break;
+
+        case TARGET_SO_LINGER:
+            optname = SO_LINGER;
+            break;
+
+        case TARGET_SO_BROADCAST:
+            optname = SO_BROADCAST;
+            break;
+
+        case TARGET_SO_OOBINLINE:
+            optname = SO_OOBINLINE;
+            break;
+
+        case TARGET_SO_SNDBUF:
+            optname = SO_SNDBUF;
+            break;
+
+        case TARGET_SO_RCVBUF:
+            optname = SO_RCVBUF;
+            break;
+
+        case TARGET_SO_SNDLOWAT:
+            optname = SO_RCVLOWAT;
+            break;
+
+        case TARGET_SO_RCVLOWAT:
+            optname = SO_RCVLOWAT;
+            break;
+
+        case TARGET_SO_SNDTIMEO:
+            optname = SO_SNDTIMEO;
+            break;
+
+        case TARGET_SO_RCVTIMEO:
+            optname = SO_RCVTIMEO;
+            break;
+
+        case TARGET_SO_ACCEPTFILTER:
+            goto unimplemented;
+
+        case TARGET_SO_NOSIGPIPE:
+            optname = SO_NOSIGPIPE;
+            break;
+
+        case TARGET_SO_TIMESTAMP:
+            optname = SO_TIMESTAMP;
+            break;
+
+        case TARGET_SO_BINTIME:
+            optname = SO_BINTIME;
+            break;
+
+        case TARGET_SO_ERROR:
+            optname = SO_ERROR;
+            break;
+
+        case TARGET_SO_SETFIB:
+            optname = SO_ERROR;
+            break;
+
+#ifdef SO_USER_COOKIE
+        case TARGET_SO_USER_COOKIE:
+            optname = SO_USER_COOKIE;
+            break;
+#endif
+        default:
+            goto unimplemented;
+        }
+        if (optlen < sizeof(uint32_t)) {
+            return -TARGET_EINVAL;
+        }
+        if (get_user_u32(val, optval_addr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val,
+                    sizeof(val)));
+        break;
+    default:
+unimplemented:
+    gemu_log("Unsupported setsockopt level=%d optname=%d\n",
+        level, optname);
+    ret = -TARGET_ENOPROTOOPT;
+    }
+
+    return ret;
+}
+
+/* getsockopt(2) */
+static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, abi_ulong optlen)
+{
+    abi_long ret;
+    int len, val;
+    socklen_t lv;
+
+    switch (level) {
+    case TARGET_SOL_SOCKET:
+        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_ACCEPTFILTER:
+            goto unimplemented;
+
+        /* 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_REUSEPORT:
+            optname = SO_REUSEPORT;
+            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_TIMESTAMP:
+            optname = SO_TIMESTAMP;
+            goto int_case;
+
+        case TARGET_SO_RCVLOWAT:
+            optname = SO_RCVLOWAT;
+            goto int_case;
+
+        case TARGET_SO_LISTENINCQLEN:
+            optname = SO_LISTENINCQLEN;
+            goto int_case;
+
+        default:
+int_case:
+            if (get_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            if (len < 0) {
+                return -TARGET_EINVAL;
+            }
+            lv = sizeof(lv);
+            ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len > lv) {
+                len = lv;
+            }
+            if (len == 4) {
+                if (put_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            } else {
+                if (put_user_u8(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            }
+            if (put_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            break;
+
+        }
+        break;
+
+    case IPPROTO_TCP:
+        /* TCP options all take an 'int' value. */
+        goto int_case;
+
+    case IPPROTO_IP:
+        switch (optname) {
+        case IP_HDRINCL:
+        case IP_TOS:
+        case IP_TTL:
+        case IP_RECVOPTS:
+        case IP_RECVRETOPTS:
+        case IP_RECVDSTADDR:
+
+        case IP_RETOPTS:
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 && defined(IP_RECVTOS)
+        case IP_RECVTOS:
+#endif
+        case IP_MULTICAST_TTL:
+        case IP_MULTICAST_LOOP:
+        case IP_PORTRANGE:
+        case IP_IPSEC_POLICY:
+        case IP_FAITH:
+        case IP_ONESBCAST:
+        case IP_BINDANY:
+            if (get_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            if (len < 0) {
+                return -TARGET_EINVAL;
+            }
+            lv = sizeof(lv);
+            ret = get_errno(getsockopt(sockfd, level, optname,
+                &val, &lv));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len < sizeof(int) && len > 0 && val >= 0 &&
+                val < 255) {
+                len = 1;
+                if (put_user_u32(len, optlen) ||
+                        put_user_u8(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            } else {
+                if (len > sizeof(int)) {
+                    len = sizeof(int);
+                }
+                if (put_user_u32(len, optlen) ||
+                        put_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            }
+            break;
+
+        default:
+            goto unimplemented;
+        }
+        break;
+
+    default:
+unimplemented:
+        gemu_log("getsockopt level=%d optname=%d not yet supported\n",
+            level, optname);
+        ret = -TARGET_EOPNOTSUPP;
+        break;
+    }
+    return ret;
+}
+
+/* setfib(2) */
+static inline abi_long do_freebsd_setfib(abi_long fib)
+{
+
+    return get_errno(setfib(fib));
+}
+
+/* sctp_peeloff(2) */
+static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_peeloff()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_sendmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s,
+        abi_ulong target_msg, abi_long msglen, abi_ulong target_to,
+        abi_ulong len, abi_ulong target_sinfo, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_recvmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s,
+        abi_ulong target_iov, abi_long iovlen, abi_ulong target_from,
+        abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* freebsd4_sendfile(2) */
+static inline abi_long do_freebsd_freebsd4_sendfile(abi_long fd, abi_long s,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong nbytes, abi_ulong target_hdtr,
+        abi_ulong target_sbytes, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd4_sendfile()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sendfile(2) */
+static inline abi_long do_freebsd_sendfile(abi_long fd, abi_long s,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong nbytes, abi_ulong target_hdtr,
+        abi_ulong target_sbytes, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sendfile()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__FREEBSD_SOCKET_H_ */
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index e915246..90d8eb4 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -50,6 +50,12 @@ abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
 abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds,
         int n);
 
+/* os-socket.c */
+abi_long t2h_freebsd_cmsg(struct msghdr *msgh,
+                struct target_msghdr *target_msgh);
+abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh,
+                struct msghdr *msgh);
+
 /* os-stat.c */
 abi_long h2t_freebsd_stat(abi_ulong target_addr, struct stat *host_st);
 abi_long h2t_freebsd_nstat(abi_ulong target_addr, struct stat *host_st);
diff --git a/bsd-user/netbsd/os-socket.c b/bsd-user/netbsd/os-socket.c
new file mode 100644
index 0000000..d983c34
--- /dev/null
+++ b/bsd-user/netbsd/os-socket.c
@@ -0,0 +1 @@
+/* XXX NetBSD socket related helpers */
diff --git a/bsd-user/netbsd/os-socket.h b/bsd-user/netbsd/os-socket.h
new file mode 100644
index 0000000..a49c41d
--- /dev/null
+++ b/bsd-user/netbsd/os-socket.h
@@ -0,0 +1,98 @@
+/*
+ *  NetBSD socket related system call shims
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __NETBSD_SOCKET_H_
+#define __NETBSD_SOCKET_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* sendmsg(2) */
+static inline abi_long do_freebsd_sendmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* recvmsg(2) */
+static inline abi_long do_freebsd_recvmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setsockopt(2) */
+static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, socklen_t optlen)
+{
+
+    qemu_log("qemu: Unsupported syscall setsockopt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getsockopt(2) */
+static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, abi_ulong optlen)
+{
+
+    qemu_log("qemu: Unsupported syscall getsockopt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setfib(2) */
+static inline abi_long do_freebsd_setfib(abi_long fib)
+{
+
+    qemu_log("qemu: Unsupported syscall setfib()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_peeloff(2) */
+static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_peeloff()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_sendmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s,
+        abi_ulong target_msg, abi_long msglen, abi_ulong target_to,
+        abi_ulong len, abi_ulong target_sinfo, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_recvmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s,
+        abi_ulong target_iov, abi_long iovlen, abi_ulong target_from,
+        abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__NETBSD_SOCKET_H_ */
diff --git a/bsd-user/openbsd/os-socket.c b/bsd-user/openbsd/os-socket.c
new file mode 100644
index 0000000..183002d
--- /dev/null
+++ b/bsd-user/openbsd/os-socket.c
@@ -0,0 +1 @@
+/* XXX OpenBSD socket related helpers */
diff --git a/bsd-user/openbsd/os-socket.h b/bsd-user/openbsd/os-socket.h
new file mode 100644
index 0000000..b8b1e99
--- /dev/null
+++ b/bsd-user/openbsd/os-socket.h
@@ -0,0 +1,98 @@
+/*
+ *  OpenBSD socket related system call shims
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __OPENBSD_SOCKET_H_
+#define __OPENBSD_SOCKET_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* sendmsg(2) */
+static inline abi_long do_freebsd_sendmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* recvmsg(2) */
+static inline abi_long do_freebsd_recvmsg(int fd, abi_ulong target_msg,
+        int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setsockopt(2) */
+static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, socklen_t optlen)
+{
+
+    qemu_log("qemu: Unsupported syscall setsockopt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getsockopt(2) */
+static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, abi_ulong optlen)
+{
+
+    qemu_log("qemu: Unsupported syscall getsockopt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setfib(2) */
+static inline abi_long do_freebsd_setfib(abi_long fib)
+{
+
+    qemu_log("qemu: Unsupported syscall setfib()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_peeloff(2) */
+static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_peeloff()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_sendmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s,
+        abi_ulong target_msg, abi_long msglen, abi_ulong target_to,
+        abi_ulong len, abi_ulong target_sinfo, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sctp_generic_recvmsg(2) */
+static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s,
+        abi_ulong target_iov, abi_long iovlen, abi_ulong target_from,
+        abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags)
+{
+
+    qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__OPENBSD_SOCKET_H_ */
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
index f562aad..09b99ef 100644
--- a/bsd-user/qemu-bsd.h
+++ b/bsd-user/qemu-bsd.h
@@ -50,4 +50,12 @@ abi_long host_to_target_rusage(abi_ulong target_addr,
         const struct rusage *rusage);
 int host_to_target_waitstatus(int status);
 
+/* bsd-socket.c */
+abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr,
+        socklen_t len);
+abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
+        socklen_t len);
+abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr,
+        socklen_t len);
+
 #endif /* !_QEMU_BSD_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index e3967fa..286c71e 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -39,11 +39,13 @@ static int host_to_target_errno(int err);
 #include "bsd-mem.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
+#include "bsd-socket.h"
 
 /* *BSD dependent syscall shims */
 #include "os-time.h"
 #include "os-proc.h"
 #include "os-signal.h"
+#include "os-socket.h"
 #include "os-stat.h"
 
 /* #define DEBUG */
@@ -1017,6 +1019,97 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * socket related system calls
+         */
+    case TARGET_FREEBSD_NR_accept: /* accept(2) */
+        ret = do_bsd_accept(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_bind: /* bind(2) */
+        ret = do_bsd_bind(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_connect: /* connect(2) */
+        ret = do_bsd_connect(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getpeername: /* getpeername(2) */
+        ret = do_bsd_getpeername(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getsockname: /* getsockname(2) */
+        ret = do_bsd_getsockname(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getsockopt: /* getsockopt(2) */
+        ret = do_bsd_getsockopt(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_setsockopt: /* setsockopt(2) */
+        ret = do_bsd_setsockopt(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_listen: /* listen(2) */
+        ret = get_errno(listen(arg1, arg2));
+        break;
+
+    case TARGET_FREEBSD_NR_recvfrom: /* recvfrom(2) */
+        ret = do_bsd_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_recvmsg: /* recvmsg(2) */
+        ret = do_freebsd_recvmsg(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sendmsg: /* sendmsg(2) */
+        ret = do_freebsd_sendmsg(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sendto: /* sendto(2) */
+        ret = do_bsd_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_socket: /* socket(2) */
+        ret = do_bsd_socket(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_socketpair: /* socketpair(2) */
+        ret = do_bsd_socketpair(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_shutdown: /* shutdown(2) */
+        ret = do_bsd_shutdown(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setfib: /* setfib(2) */
+        ret = do_freebsd_setfib(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sctp_peeloff: /* sctp_peeloff(2) */
+        ret = do_freebsd_sctp_peeloff(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sctp_generic_sendmsg: /* sctp_generic_sendmsg(2) */
+        ret = do_freebsd_sctp_generic_sendmsg(arg1, arg2, arg2, arg4, arg5,
+                arg6, arg7);
+        break;
+
+    case TARGET_FREEBSD_NR_sctp_generic_recvmsg: /* sctp_generic_recvmsg(2) */
+        ret = do_freebsd_sctp_generic_recvmsg(arg1, arg2, arg2, arg4, arg5,
+                arg6, arg7);
+        break;
+
+    case TARGET_FREEBSD_NR_sendfile: /* sendfile(2) */
+        ret = do_freebsd_sendfile(arg1, arg2, arg2, arg4, arg5, arg6, arg7,
+                arg8);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd4_sendfile: /* freebsd4_sendfile(2) */
+        ret = do_freebsd_freebsd4_sendfile(arg1, arg2, arg2, arg4, arg5,
+                arg6, arg7, arg8);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 14/19] bsd-user: add support for thread related system calls
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (14 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 13/19] bsd-user: add support for socket related system calls Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 15/19] bsd-user: add support for the ioctl system call Stacey Son
                     ` (4 subsequent siblings)
  20 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for thread related system calls
including thr_create(), thr_new(), thr_set_name(), thr_self(),
thr_suspend(), thr_wake(), thr_kill(), thr_kill2(),
rtprio_thread(2), getcontext(2), setcontext(2), swapcontext(2),
_umtx_lock(), _umtx_unlock(), and _umtx_op().
---
 bsd-user/Makefile.objs       |    2 +-
 bsd-user/freebsd/os-thread.c | 1001 ++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-thread.h |  511 +++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h   |    6 +
 bsd-user/netbsd/os-thread.c  |    1 +
 bsd-user/netbsd/os-thread.h  |  133 ++++++
 bsd-user/openbsd/os-thread.c |    1 +
 bsd-user/openbsd/os-thread.h |  133 ++++++
 bsd-user/qemu.h              |   59 +++-
 bsd-user/syscall.c           |   71 +++-
 include/qemu/tls.h           |    2 +-
 11 files changed, 1908 insertions(+), 12 deletions(-)
 create mode 100644 bsd-user/freebsd/os-thread.c
 create mode 100644 bsd-user/freebsd/os-thread.h
 create mode 100644 bsd-user/netbsd/os-thread.c
 create mode 100644 bsd-user/netbsd/os-thread.h
 create mode 100644 bsd-user/openbsd/os-thread.c
 create mode 100644 bsd-user/openbsd/os-thread.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 635d879..fdc1c9a 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -2,5 +2,5 @@ obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
 	        uaccess.o bsd-mem.o bsd-proc.o bsd-socket.o \
 			$(HOST_VARIANT_DIR)/os-proc.o \
 			$(HOST_VARIANT_DIR)/os-socket.o $(HOST_VARIANT_DIR)/os-stat.o \
-			$(HOST_VARIANT_DIR)/os-sys.o \
+			$(HOST_VARIANT_DIR)/os-sys.o $(HOST_VARIANT_DIR)/os-thread.o \
 			$(HOST_VARIANT_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/freebsd/os-thread.c b/bsd-user/freebsd/os-thread.c
new file mode 100644
index 0000000..6bf2a9f
--- /dev/null
+++ b/bsd-user/freebsd/os-thread.c
@@ -0,0 +1,1001 @@
+/*
+ *  FreeBSD thr emulation support code
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/mman.h>
+#include <sys/thr.h>
+#include <sys/umtx.h>
+#include <sys/rtprio.h>
+
+#include <machine/atomic.h>
+
+#include <time.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+#include "target_arch_cpu.h"
+#include "target_arch_thread.h"
+
+// #define DEBUG_UMTX(...)   fprintf(stderr, __VA_ARGS__)
+#define DEBUG_UMTX(...)
+
+#define NEW_STACK_SIZE  0x40000
+
+/* sys/_umtx.h */
+struct target_umtx {
+    abi_ulong   u_owner;    /* Owner of the mutex. */
+};
+
+struct target_umutex {
+    uint32_t    m_owner;    /* Owner of the mutex */
+    uint32_t    m_flags;    /* Flags of the mutex */
+    uint32_t    m_ceiling[2];   /* Priority protect ceiling */
+    uint32_t    m_spare[4];
+};
+
+struct target_ucond {
+    uint32_t    c_has_waiters;  /* Has waiters in kernel */
+    uint32_t    c_flags;    /* Flags of the condition variable */
+    uint32_t    c_clockid;  /* Clock id */
+    uint32_t    c_spare[1];
+};
+
+struct target_urwlock {
+    uint32_t    rw_state;
+    uint32_t    rw_flags;
+    uint32_t    rw_blocked_readers;
+    uint32_t    rw_blocked_writers;
+    uint32_t    rw_spare[4];
+};
+
+struct target__usem {
+    uint32_t    _has_waiters;
+    uint32_t    _count;
+    uint32_t    _flags;
+};
+
+static pthread_mutex_t new_thread_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t *new_freebsd_thread_lock_ptr = &new_thread_lock;
+
+static pthread_mutex_t umtx_wait_lck = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t umtx_wait_cv = PTHREAD_COND_INITIALIZER;
+static abi_ulong umtx_wait_addr;
+
+static void rtp_to_schedparam(const struct rtprio *rtp, int *policy,
+        struct sched_param *param)
+{
+
+    switch (rtp->type) {
+    case RTP_PRIO_REALTIME:
+        *policy = SCHED_RR;
+        param->sched_priority = RTP_PRIO_MAX - rtp->prio;
+        break;
+
+    case RTP_PRIO_FIFO:
+        *policy = SCHED_FIFO;
+        param->sched_priority = RTP_PRIO_MAX - rtp->prio;
+        break;
+
+    default:
+        *policy = SCHED_OTHER;
+        param->sched_priority = 0;
+        break;
+    }
+}
+
+void *new_freebsd_thread_start(void *arg)
+{
+    new_freebsd_thread_info_t *info = arg;
+    CPUArchState *env;
+    CPUState *cpu;
+    // TaskState *ts;
+    long tid;
+
+    env = info->env;
+    cpu = ENV_GET_CPU(env);
+    thread_cpu = cpu;
+
+    // ts = (TaskState *)env->opaque;
+    (void)thr_self(&tid);
+    cpu->host_tid = tid;
+    // ts->ts_tid = tid;
+
+    /* copy out the TID info */
+    if (info->param.child_tid) {
+        put_user(tid, info->param.child_tid, abi_long);
+    }
+    if (info->param.parent_tid) {
+        put_user(info->parent_tid, info->param.parent_tid, abi_long);
+    }
+
+    /* Set arch dependent registers to start thread. */
+    target_thread_set_upcall(env, info->param.start_func, info->param.arg,
+        info->param.stack_base, info->param.stack_size);
+
+    /* 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 finished initializing the TLS state. */
+    pthread_mutex_lock(new_freebsd_thread_lock_ptr);
+    pthread_mutex_unlock(new_freebsd_thread_lock_ptr);
+
+    cpu_loop(env);
+    /* never exits */
+
+    return NULL;
+}
+
+/*
+ * FreeBSD user mutex (_umtx) emulation
+ */
+static int tcmpset_al(abi_ulong *addr, abi_ulong a, abi_ulong b)
+{
+    abi_ulong current = tswapal(a);
+    abi_ulong new = tswapal(b);
+
+#ifdef TARGET_ABI32
+    return atomic_cmpset_acq_32(addr, current, new);
+#else
+    return atomic_cmpset_acq_64(addr, current, new);
+#endif
+}
+
+static int tcmpset_32(uint32_t *addr, uint32_t a, uint32_t b)
+{
+    uint32_t current = tswap32(a);
+    uint32_t new = tswap32(b);
+
+    return atomic_cmpset_acq_32(addr, current, new);
+}
+
+abi_long freebsd_umtx_wait_uint(abi_ulong obj, uint32_t val,
+        struct timespec *timeout)
+{
+
+    DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x, NULL, %p)\n",
+            __func__, g2h(obj), UMTX_OP_WAIT_UINT, val, timeout);
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_WAIT_UINT, val, NULL, timeout));
+}
+
+abi_long freebsd_umtx_wait_uint_private(abi_ulong obj, uint32_t val,
+        struct timespec *timeout)
+{
+
+    DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x, NULL, %p)\n",
+            __func__, g2h(obj), UMTX_OP_WAIT_UINT_PRIVATE, val, timeout);
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_WAIT_UINT_PRIVATE, val, NULL,
+                timeout));
+}
+
+abi_long freebsd_umtx_wake_private(abi_ulong obj, uint32_t val)
+{
+
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(obj), UMTX_OP_WAKE_PRIVATE, val);
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_WAKE_PRIVATE, val, NULL, NULL));
+}
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#if defined(UMTX_OP_NWAKE_PRIVATE)
+abi_long freebsd_umtx_nwake_private(abi_ulong obj, uint32_t val)
+{
+
+    DEBUG_UMTX("<NWAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(obj), UMTX_OP_NWAKE_PRIVATE, val);
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_NWAKE_PRIVATE, val, NULL,
+                NULL));
+}
+#endif /* UMTX_OP_NWAKE_PRIVATE */
+
+#if defined(UMTX_OP_MUTEX_WAKE2)
+abi_long freebsd_umtx_mutex_wake2(abi_ulong target_addr,
+        __unused uint32_t flags)
+{
+    abi_long ret = 0;
+
+    pthread_mutex_lock(&umtx_wait_lck);
+    DEBUG_UMTX("<WAKE2 CV> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(target_addr), UMTX_OP_MUTEX_WAKE2, flags);
+    umtx_wait_addr = target_addr;
+    ret = get_errno(pthread_cond_broadcast(&umtx_wait_cv));
+    pthread_mutex_unlock(&umtx_wait_lck);
+
+    return ret;
+}
+#endif /* UMTX_OP_MUTEX_WAKE2 */
+
+abi_long freebsd_umtx_sem_wait(abi_ulong obj, struct timespec *timeout)
+{
+
+    /* XXX Assumes struct _usem is opauque to the user */
+    if (!access_ok(VERIFY_WRITE, obj, sizeof(struct target__usem))) {
+        return -TARGET_EFAULT;
+    }
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_SEM_WAIT, 0, NULL, timeout));
+}
+
+abi_long freebsd_umtx_sem_wake(abi_ulong obj, uint32_t val)
+{
+
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_SEM_WAKE, val, NULL, NULL));
+}
+#endif
+
+abi_long t2h_freebsd_rtprio(struct rtprio *host_rtp, abi_ulong target_addr)
+{
+    struct target_freebsd_rtprio *target_rtp;
+
+    if (!lock_user_struct(VERIFY_READ, target_rtp, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_rtp->type, &target_rtp->type);
+    __get_user(host_rtp->prio, &target_rtp->prio);
+    unlock_user_struct(target_rtp, target_addr, 0);
+    return 0;
+}
+
+abi_long h2t_freebsd_rtprio(abi_ulong target_addr, struct rtprio *host_rtp)
+{
+    struct target_freebsd_rtprio *target_rtp;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_rtp, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_rtp->type, &target_rtp->type);
+    __put_user(host_rtp->prio, &target_rtp->prio);
+    unlock_user_struct(target_rtp, target_addr, 1);
+    return 0;
+}
+
+abi_long freebsd_lock_umtx(abi_ulong target_addr, abi_long id,
+        struct timespec *timeout)
+{
+    abi_long ret;
+    abi_long owner;
+
+    /*
+     * XXX Note that memory at umtx_addr can change and so we need to be
+     * careful and check for faults.
+     */
+    for (;;) {
+        struct target_umtx *target_umtx;
+
+        if (!lock_user_struct(VERIFY_WRITE, target_umtx, target_addr, 0)) {
+            return -TARGET_EFAULT;
+        }
+        /* Check the simple uncontested case. */
+        if (tcmpset_al(&target_umtx->u_owner,
+                TARGET_UMTX_UNOWNED, id)) {
+            unlock_user_struct(target_umtx, target_addr, 1);
+            return 0;
+        }
+        /* Check to see if the lock is contested but free. */
+        __get_user(owner, &target_umtx->u_owner);
+
+        if (TARGET_UMTX_CONTESTED == owner) {
+            if (tcmpset_al(&target_umtx->u_owner, TARGET_UMTX_CONTESTED,
+                        id | TARGET_UMTX_CONTESTED)) {
+                unlock_user_struct(target_umtx, target_addr, 1);
+                return 0;
+            }
+            /* We failed because it changed on us, restart. */
+            unlock_user_struct(target_umtx, target_addr, 1);
+            continue;
+        }
+
+        /* Set the contested bit and sleep. */
+        do {
+            __get_user(owner, &target_umtx->u_owner);
+            if (owner & TARGET_UMTX_CONTESTED) {
+                break;
+            }
+        } while (!tcmpset_al(&target_umtx->u_owner, owner,
+                    owner | TARGET_UMTX_CONTESTED));
+
+        __get_user(owner, &target_umtx->u_owner);
+        unlock_user_struct(target_umtx, target_addr, 1);
+
+        /* Byte swap, if needed, to match what is stored in user mem. */
+        owner = tswapal(owner);
+        DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%llx, NULL, NULL)\n",
+                __func__, g2h(target_addr), UMTX_OP_WAIT, (long long)owner);
+#ifdef TARGET_ABI32
+        ret = get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAIT_UINT, owner,
+            NULL, timeout));
+#else
+        ret = get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAIT, owner,
+            NULL, timeout));
+#endif
+        if (is_error(ret)) {
+            return ret;
+        }
+    }
+}
+
+abi_long freebsd_unlock_umtx(abi_ulong target_addr, abi_long id)
+{
+    abi_ulong owner;
+    struct target_umtx *target_umtx;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_umtx, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(owner, &target_umtx->u_owner);
+    if ((owner & ~TARGET_UMTX_CONTESTED) != id) {
+        unlock_user_struct(target_umtx, target_addr, 1);
+        return -TARGET_EPERM;
+    }
+    /* Check the simple uncontested case. */
+    if ((owner & ~TARGET_UMTX_CONTESTED) == 0) {
+        if (tcmpset_al(&target_umtx->u_owner, owner,
+            TARGET_UMTX_UNOWNED)) {
+            unlock_user_struct(target_umtx, target_addr, 1);
+            return 0;
+        }
+    }
+    /* This is a contested lock. Unlock it. */
+    __put_user(TARGET_UMTX_UNOWNED, &target_umtx->u_owner);
+    unlock_user_struct(target_umtx, target_addr, 1);
+
+    /* Wake up all those contesting it. */
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(target_addr), UMTX_OP_WAKE, 0);
+    _umtx_op(g2h(target_addr), UMTX_OP_WAKE, 0, 0, 0);
+
+    return 0;
+}
+
+abi_long freebsd_umtx_wait(abi_ulong targ_addr, abi_ulong id,
+        struct timespec *ts)
+{
+
+    /* We want to check the user memory but not lock it.  We might sleep. */
+    if (!access_ok(VERIFY_READ, targ_addr, sizeof(abi_ulong))) {
+        return -TARGET_EFAULT;
+    }
+
+    DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%llx, NULL, NULL)\n",
+            __func__, g2h(targ_addr), UMTX_OP_WAIT, (long long)id);
+#ifdef TARGET_ABI32
+    return get_errno(_umtx_op(g2h(targ_addr), UMTX_OP_WAIT_UINT, id, NULL, ts));
+#else
+    return get_errno(_umtx_op(g2h(targ_addr), UMTX_OP_WAIT, id, NULL, ts));
+#endif
+}
+
+abi_long freebsd_umtx_wake(abi_ulong target_addr, uint32_t n_wake)
+{
+
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(target_addr), UMTX_OP_WAKE, n_wake);
+    return get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAKE, n_wake, NULL, 0));
+}
+
+abi_long freebsd_umtx_mutex_wake(abi_ulong obj, abi_long val)
+{
+
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%llx, NULL, NULL)\n",
+            __func__, g2h(obj), UMTX_OP_WAKE, (long long)val);
+    return get_errno(_umtx_op(g2h(obj), UMTX_OP_MUTEX_WAKE, val, NULL, NULL));
+}
+
+abi_long freebsd_lock_umutex(abi_ulong target_addr, uint32_t id,
+        struct timespec *ts, int mode)
+{
+    uint32_t owner, flags;
+    int ret = 0;
+
+    for (;;) {
+        struct target_umutex *target_umutex;
+
+        pthread_mutex_lock(&umtx_wait_lck);
+
+        if (!lock_user_struct(VERIFY_WRITE, target_umutex, target_addr, 0)) {
+            pthread_mutex_unlock(&umtx_wait_lck);
+            return -TARGET_EFAULT;
+        }
+
+        __get_user(owner, &target_umutex->m_owner);
+
+        if (TARGET_UMUTEX_WAIT == mode) {
+            if (TARGET_UMUTEX_UNOWNED == owner ||
+                    TARGET_UMUTEX_CONTESTED == owner) {
+                unlock_user_struct(target_umutex, target_addr, 1);
+                pthread_mutex_unlock(&umtx_wait_lck);
+                return 0;
+            }
+        } else {
+            if (tcmpset_32(&target_umutex->m_owner, TARGET_UMUTEX_UNOWNED,
+                        id)) {
+                /* The acquired succeeded. */
+                unlock_user_struct(target_umutex, target_addr, 1);
+                pthread_mutex_unlock(&umtx_wait_lck);
+                return 0;
+            }
+
+            /* If no one owns it but it is contested try to acquire it. */
+            if (TARGET_UMUTEX_CONTESTED == owner) {
+                if (tcmpset_32(&target_umutex->m_owner, TARGET_UMUTEX_CONTESTED,
+                            id | TARGET_UMUTEX_CONTESTED)) {
+                    unlock_user_struct(target_umutex, target_addr, 1);
+                    pthread_mutex_unlock(&umtx_wait_lck);
+                    return 0;
+                }
+                /* The lock changed so restart. */
+                unlock_user_struct(target_umutex, target_addr, 1);
+                pthread_mutex_unlock(&umtx_wait_lck);
+                continue;
+            }
+        }
+
+        __get_user(flags, &target_umutex->m_flags);
+        if ((flags & TARGET_UMUTEX_ERROR_CHECK) != 0 &&
+                (owner & ~TARGET_UMUTEX_CONTESTED) == id) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            pthread_mutex_unlock(&umtx_wait_lck);
+            return -TARGET_EDEADLK;
+        }
+
+        if (TARGET_UMUTEX_TRY == mode) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            pthread_mutex_unlock(&umtx_wait_lck);
+            return -TARGET_EBUSY;
+        }
+
+        /*
+         * If we caught a signal, we have retried and now
+         * exit immediately.
+         */
+        if (is_error(ret)) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            pthread_mutex_unlock(&umtx_wait_lck);
+            return ret;
+        }
+
+        /* Set the contested bit and sleep. */
+        if (!tcmpset_32(&target_umutex->m_owner, owner,
+                    owner | TARGET_UMUTEX_CONTESTED)) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            pthread_mutex_unlock(&umtx_wait_lck);
+            continue;
+        }
+
+        DEBUG_UMTX("<WAIT CV> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+                __func__, g2h(target_addr), UMTX_OP_WAIT_UINT,
+                tswap32(target_umutex->m_owner));
+        unlock_user_struct(target_umutex, target_addr, 1);
+
+again:
+        if (ts == NULL) {
+            ret = get_errno(pthread_cond_wait(&umtx_wait_cv,
+                        &umtx_wait_lck));
+        } else {
+            ret = get_errno(pthread_cond_timedwait(&umtx_wait_cv,
+                        &umtx_wait_lck, ts));
+        }
+        if (ret != 0) {
+            pthread_mutex_unlock(&umtx_wait_lck);
+            break;
+        }
+        if (target_addr != umtx_wait_addr) {
+            goto again;
+        }
+        pthread_mutex_unlock(&umtx_wait_lck);
+    }
+
+    return ret;
+}
+
+abi_long freebsd_unlock_umutex(abi_ulong target_addr, uint32_t id)
+{
+    struct target_umutex *target_umutex;
+    uint32_t owner;
+
+
+    if (!lock_user_struct(VERIFY_WRITE, target_umutex, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    /* Make sure we own this mutex. */
+    __get_user(owner, &target_umutex->m_owner);
+    if ((owner & ~TARGET_UMUTEX_CONTESTED) != id) {
+        unlock_user_struct(target_umutex, target_addr, 1);
+        return -TARGET_EPERM;
+    }
+    if ((owner & TARGET_UMUTEX_CONTESTED) == 0) {
+        if (tcmpset_32(&target_umutex->m_owner, owner, TARGET_UMTX_UNOWNED)) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            return 0;
+        }
+    }
+    /* This is a contested lock. Unlock it. */
+    __put_user(TARGET_UMUTEX_UNOWNED, &target_umutex->m_owner);
+    unlock_user_struct(target_umutex, target_addr, 1);
+
+    /* And wake up all those contesting it. */
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(target_addr), UMTX_OP_WAKE, 0);
+    return get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAKE, 0, 0, 0));
+}
+
+/*
+ * _cv_mutex is keeps other threads from doing a signal or broadcast until
+ * the thread is actually asleep and ready.  This is a global mutex for all
+ * condition vars so I am sure performance may be a problem if there are lots
+ * of CVs.
+ */
+static struct umutex _cv_mutex = { 0, 0, { 0, 0 }, { 0, 0, 0, 0 } };
+
+
+/*
+ * wflags CVWAIT_CHECK_UNPARKING, CVWAIT_ABSTIME, CVWAIT_CLOCKID
+ */
+abi_long freebsd_cv_wait(abi_ulong target_ucond_addr,
+        abi_ulong target_umtx_addr, struct timespec *ts, int wflags)
+{
+    abi_long ret;
+    long tid;
+
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+                sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* Check the clock ID if needed. */
+    if ((wflags & TARGET_CVWAIT_CLOCKID) != 0) {
+        struct target_ucond *target_ucond;
+        uint32_t clockid;
+
+        if (!lock_user_struct(VERIFY_WRITE, target_ucond, target_ucond_addr,
+                    0)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(clockid, &target_ucond->c_clockid);
+        unlock_user_struct(target_ucond, target_ucond_addr, 1);
+        if (clockid >= CLOCK_THREAD_CPUTIME_ID) {
+            /* Only HW clock id will work. */
+            return -TARGET_EINVAL;
+        }
+    }
+
+    thr_self(&tid);
+
+    /* Lock the _cv_mutex so we can safely unlock the user mutex */
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
+
+    /* unlock the user mutex */
+    ret = freebsd_unlock_umutex(target_umtx_addr, tid);
+    if (is_error(ret)) {
+        _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+        return ret;
+    }
+
+    /* UMTX_OP_CV_WAIT unlocks _cv_mutex */
+    DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x, %p, NULL)\n",
+            __func__, g2h(target_ucond_addr), UMTX_OP_CV_WAIT, wflags,
+            &_cv_mutex);
+    ret = get_errno(_umtx_op(g2h(target_ucond_addr), UMTX_OP_CV_WAIT, wflags,
+                &_cv_mutex, ts));
+
+    return ret;
+}
+
+abi_long freebsd_cv_signal(abi_ulong target_ucond_addr)
+{
+    abi_long ret;
+
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+                sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* Lock the _cv_mutex to prevent a race in do_cv_wait(). */
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(target_ucond_addr), UMTX_OP_CV_SIGNAL, 0);
+    ret = get_errno(_umtx_op(g2h(target_ucond_addr), UMTX_OP_CV_SIGNAL, 0,
+        NULL, NULL));
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+
+    return ret;
+}
+
+abi_long freebsd_cv_broadcast(abi_ulong target_ucond_addr)
+{
+    int ret;
+
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+                sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* Lock the _cv_mutex to prevent a race in do_cv_wait(). */
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h(target_ucond_addr), UMTX_OP_CV_BROADCAST, 0);
+    ret = get_errno(_umtx_op(g2h(target_ucond_addr), UMTX_OP_CV_BROADCAST, 0,
+                NULL, NULL));
+    _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+
+    return ret;
+}
+
+abi_long freebsd_rw_rdlock(abi_ulong target_addr, long fflag,
+        struct timespec *ts)
+{
+    struct target_urwlock *target_urwlock;
+    uint32_t flags, wrflags;
+    uint32_t state;
+    uint32_t blocked_readers;
+    abi_long ret;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    __get_user(flags, &target_urwlock->rw_flags);
+    wrflags = TARGET_URWLOCK_WRITE_OWNER;
+    if (!(fflag & TARGET_URWLOCK_PREFER_READER) &&
+            !(flags & TARGET_URWLOCK_PREFER_READER)) {
+        wrflags |= TARGET_URWLOCK_WRITE_WAITERS;
+    }
+    for (;;) {
+        __get_user(state, &target_urwlock->rw_state);
+        /* try to lock it */
+        while (!(state & wrflags)) {
+            if (TARGET_URWLOCK_READER_COUNT(state) ==
+                TARGET_URWLOCK_MAX_READERS) {
+                unlock_user_struct(target_urwlock,
+                    target_addr, 1);
+                return -TARGET_EAGAIN;
+            }
+            if (tcmpset_32(&target_urwlock->rw_state, state,
+                (state + 1))) {
+                /* The acquired succeeded. */
+                unlock_user_struct(target_urwlock,
+                    target_addr, 1);
+                return 0;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+        /* set read contention bit */
+        if (!tcmpset_32(&target_urwlock->rw_state, state,
+            state | TARGET_URWLOCK_READ_WAITERS)) {
+            /* The state has changed.  Start over. */
+            continue;
+        }
+
+        /* contention bit is set, increase read waiter count */
+        __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_readers,
+                    blocked_readers, blocked_readers + 1)) {
+            __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        }
+
+        while (state & wrflags) {
+            /* sleep/wait */
+            unlock_user_struct(target_urwlock, target_addr, 1);
+            DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x (0x%x), NULL, NULL)\n",
+                    __func__, &target_urwlock->rw_state,
+                    UMTX_OP_WAIT_UINT, tswap32(state),
+                    target_urwlock->rw_state);
+            ret = get_errno(_umtx_op(&target_urwlock->rw_state,
+                        UMTX_OP_WAIT_UINT, tswap32(state), NULL, ts));
+            if (is_error(ret)) {
+                return ret;
+            }
+            if (!lock_user_struct(VERIFY_WRITE, target_urwlock,
+                        target_addr, 0)) {
+                return -TARGET_EFAULT;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        /* decrease read waiter count */
+        __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_readers,
+                    blocked_readers, (blocked_readers - 1))) {
+            __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        }
+        if (blocked_readers == 1) {
+            /* clear read contention bit */
+            __get_user(state, &target_urwlock->rw_state);
+            while (!tcmpset_32(&target_urwlock->rw_state, state,
+                state & ~TARGET_URWLOCK_READ_WAITERS)) {
+                __get_user(state, &target_urwlock->rw_state);
+            }
+        }
+    }
+}
+
+abi_long freebsd_rw_wrlock(abi_ulong target_addr, long fflag,
+        struct timespec *ts)
+{
+    struct target_urwlock *target_urwlock;
+    uint32_t blocked_readers, blocked_writers;
+    uint32_t state;
+    abi_long ret;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    blocked_readers = 0;
+    for (;;) {
+        __get_user(state, &target_urwlock->rw_state);
+        while (!(state & TARGET_URWLOCK_WRITE_OWNER) &&
+            TARGET_URWLOCK_READER_COUNT(state) == 0) {
+            if (tcmpset_32(&target_urwlock->rw_state, state,
+                        state | TARGET_URWLOCK_WRITE_OWNER)) {
+                unlock_user_struct(target_urwlock, target_addr, 1);
+                return 0;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        if (!(state & (TARGET_URWLOCK_WRITE_OWNER |
+                        TARGET_URWLOCK_WRITE_WAITERS)) &&
+                blocked_readers != 0) {
+            DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+                __func__, &target_urwlock->rw_state, UMTX_OP_WAKE,
+                tswap32(state));
+            ret = get_errno(_umtx_op(&target_urwlock->rw_state,
+                UMTX_OP_WAKE, INT_MAX, NULL, NULL));
+            return ret;
+        }
+        /* re-read the state */
+        __get_user(state, &target_urwlock->rw_state);
+
+        /* and set TARGET_URWLOCK_WRITE_WAITERS */
+        while (((state & TARGET_URWLOCK_WRITE_OWNER) ||
+                    TARGET_URWLOCK_READER_COUNT(state) != 0) &&
+                (state & TARGET_URWLOCK_WRITE_WAITERS) == 0) {
+            if (tcmpset_32(&target_urwlock->rw_state, state,
+                        state | TARGET_URWLOCK_WRITE_WAITERS)) {
+                break;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        /* contention bit is set, increase write waiter count */
+        __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_writers,
+                    blocked_writers, blocked_writers + 1)) {
+            __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        }
+
+        /* sleep */
+        while ((state & TARGET_URWLOCK_WRITE_OWNER) ||
+                (TARGET_URWLOCK_READER_COUNT(state) != 0)) {
+            unlock_user_struct(target_urwlock, target_addr, 1);
+            DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x(0x%x), NULL, NULL)\n",
+                    __func__, &target_urwlock->rw_blocked_writers,
+                    UMTX_OP_WAIT_UINT, tswap32(state),
+                    target_urwlock->rw_state);
+            ret = get_errno(_umtx_op(&target_urwlock->rw_state,
+                        UMTX_OP_WAIT_UINT, tswap32(state), NULL, ts));
+            if (is_error(ret)) {
+                return ret;
+            }
+            if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr,
+                        0)) {
+                return -TARGET_EFAULT;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        /* decrease the write waiter count */
+        __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_writers,
+                    blocked_writers, (blocked_writers - 1))) {
+            __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        }
+        if (blocked_writers == 1) {
+            /* clear write contention bit */
+            __get_user(state, &target_urwlock->rw_state);
+            while (!tcmpset_32(&target_urwlock->rw_state, state,
+                        state & ~TARGET_URWLOCK_WRITE_WAITERS)) {
+                __get_user(state, &target_urwlock->rw_state);
+            }
+            __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        } else {
+            blocked_readers = 0;
+        }
+    }
+}
+
+abi_long freebsd_rw_unlock(abi_ulong target_addr)
+{
+    struct target_urwlock *target_urwlock;
+    uint32_t flags, state, count = 0;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    __get_user(flags, &target_urwlock->rw_flags);
+    __get_user(state, &target_urwlock->rw_state);
+
+    if (state & TARGET_URWLOCK_WRITE_OWNER) {
+        for (;;) {
+            if (!tcmpset_32(&target_urwlock->rw_state, state,
+                state & ~TARGET_URWLOCK_WRITE_OWNER)) {
+                __get_user(state, &target_urwlock->rw_state);
+                if (!(state & TARGET_URWLOCK_WRITE_OWNER)) {
+                    unlock_user_struct(target_urwlock,
+                        target_addr, 1);
+                    return -TARGET_EPERM;
+                }
+            } else {
+                break;
+            }
+        }
+    } else if (TARGET_URWLOCK_READER_COUNT(state) != 0) {
+        /* decrement reader count */
+        for (;;) {
+            if (!tcmpset_32(&target_urwlock->rw_state, state, (state  - 1))) {
+                if (TARGET_URWLOCK_READER_COUNT(state) == 0) {
+                    unlock_user_struct(target_urwlock,
+                        target_addr, 1);
+                        return -TARGET_EPERM;
+                 }
+            } else {
+                break;
+            }
+        }
+    } else {
+        unlock_user_struct(target_urwlock, target_addr, 1);
+        return -TARGET_EPERM;
+    }
+
+    if (!(flags & TARGET_URWLOCK_PREFER_READER)) {
+        if (state & TARGET_URWLOCK_WRITE_WAITERS) {
+            count = 1;
+        } else if (state & TARGET_URWLOCK_READ_WAITERS) {
+            count = INT_MAX;
+        }
+    } else {
+        if (state & TARGET_URWLOCK_READ_WAITERS) {
+            count = INT_MAX;
+        } else if (state & TARGET_URWLOCK_WRITE_WAITERS) {
+            count = 1;
+        }
+    }
+
+    unlock_user_struct(target_urwlock, target_addr, 1);
+    if (count != 0) {
+        DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+                __func__, &target_urwlock->rw_state, UMTX_OP_WAKE, count);
+        return get_errno(_umtx_op(&target_urwlock->rw_state, UMTX_OP_WAKE,
+                    count, NULL, NULL));
+    } else {
+        return 0;
+    }
+}
+
+abi_long do_freebsd_thr_new(CPUArchState *env,
+        abi_ulong target_param_addr, int32_t param_size)
+{
+    new_freebsd_thread_info_t info;
+    pthread_attr_t attr;
+    TaskState *ts;
+    CPUArchState *new_env;
+    struct target_freebsd_thr_param *target_param;
+    abi_ulong target_rtp_addr;
+    struct target_freebsd_rtprio *target_rtp;
+    struct rtprio *rtp_ptr, rtp;
+    TaskState *parent_ts = (TaskState *)env->opaque;
+    sigset_t sigmask;
+    struct sched_param sched_param;
+    int sched_policy;
+    int ret = 0;
+
+    memset(&info, 0, sizeof(info));
+
+    if (!lock_user_struct(VERIFY_READ, target_param, target_param_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    info.param.start_func = tswapal(target_param->start_func);
+    info.param.arg = tswapal(target_param->arg);
+    info.param.stack_base = tswapal(target_param->stack_base);
+    info.param.stack_size = tswapal(target_param->stack_size);
+    info.param.tls_base = tswapal(target_param->tls_base);
+    info.param.tls_size = tswapal(target_param->tls_size);
+    info.param.child_tid = tswapal(target_param->child_tid);
+    info.param.parent_tid = tswapal(target_param->parent_tid);
+    info.param.flags = tswap32(target_param->flags);
+    target_rtp_addr = info.param.rtp = tswapal(target_param->rtp);
+    unlock_user(target_param, target_param_addr, 0);
+
+    thr_self(&info.parent_tid);
+
+    if (target_rtp_addr) {
+        if (!lock_user_struct(VERIFY_READ, target_rtp, target_rtp_addr, 1)) {
+            return -TARGET_EFAULT;
+        }
+        rtp.type = tswap16(target_rtp->type);
+        rtp.prio = tswap16(target_rtp->prio);
+        unlock_user(target_rtp, target_rtp_addr, 0);
+        rtp_ptr = &rtp;
+    } else {
+        rtp_ptr = NULL;
+    }
+
+    /* Create a new CPU instance. */
+    ts = g_malloc0(sizeof(TaskState));
+    init_task_state(ts);
+    new_env = cpu_copy(env);
+    //target_cpu_reset(new_env); /* XXX called in cpu_copy()? */
+
+    /* init regs that differ from the parent thread. */
+    target_cpu_clone_regs(new_env, info.param.stack_base);
+    new_env->opaque = ts;
+    ts->bprm = parent_ts->bprm;
+    ts->info = parent_ts->info;
+
+    target_cpu_set_tls(new_env, info.param.tls_base);
+
+    /* Grab a mutex so that thread setup appears atomic. */
+    pthread_mutex_lock(new_freebsd_thread_lock_ptr);
+
+    pthread_mutex_init(&info.mutex, NULL);
+    pthread_mutex_lock(&info.mutex);
+    pthread_cond_init(&info.cond, NULL);
+    info.env = new_env;
+
+    /* XXX check return values... */
+    pthread_attr_init(&attr);
+    pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    if (rtp_ptr) {
+        rtp_to_schedparam(&rtp, &sched_policy, &sched_param);
+        pthread_attr_setschedpolicy(&attr, sched_policy);
+        pthread_attr_setschedparam(&attr, &sched_param);
+    }
+
+    /*
+     * 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, new_freebsd_thread_start, &info);
+    /* XXX Free new CPU state if thread creation fails. */
+
+    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);
+    } else {
+        /* Creation of new thread failed. */
+        ret = -host_to_target_errno(errno);
+    }
+
+    pthread_mutex_unlock(&info.mutex);
+    pthread_cond_destroy(&info.cond);
+    pthread_mutex_destroy(&info.mutex);
+    pthread_mutex_unlock(new_freebsd_thread_lock_ptr);
+
+    return ret;
+}
diff --git a/bsd-user/freebsd/os-thread.h b/bsd-user/freebsd/os-thread.h
new file mode 100644
index 0000000..5e24852
--- /dev/null
+++ b/bsd-user/freebsd/os-thread.h
@@ -0,0 +1,511 @@
+/*
+ *  FreeBSD thread and user mutex related system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __FREEBSD_OS_THREAD_H_
+#define __FREEBSD_OS_THREAD_H_
+
+#include <sys/thr.h>
+#include <sys/rtprio.h>
+#include <sys/umtx.h>
+
+#include "qemu-os.h"
+
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong target_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_self(abi_ulong target_id)
+{
+    abi_long ret;
+    long tid;
+
+    ret = get_errno(thr_self(&tid));
+    if (!is_error(ret)) {
+        if (put_user_sal(tid, target_id)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+static abi_long do_freebsd_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr)
+{
+    CPUState *cpu = ENV_GET_CPU(cpu_env);
+    TaskState *ts;
+
+    /*
+     * XXX This probably breaks if a signal arrives.
+     * We should disable signals.
+     */
+    cpu_list_lock();
+    /* Remove the CPU from the list. */
+    QTAILQ_REMOVE(&cpus, cpu, node);
+    cpu_list_unlock();
+    if (tid_addr) {
+        /* Signal target userland that it can free the stack. */
+        if (!put_user_sal(1, tid_addr)) {
+            freebsd_umtx_wake(tid_addr, INT_MAX);
+        }
+    }
+    thread_cpu = NULL;
+    object_unref(OBJECT(ENV_GET_CPU(cpu_env)));
+    ts = ((CPUArchState *)cpu_env)->opaque;
+    g_free(ts);
+    pthread_exit(NULL);
+    /* Doesn't return */
+    return 0;
+}
+
+static abi_long do_freebsd_thr_kill(long id, int sig)
+{
+
+    return get_errno(thr_kill(id, sig));
+}
+
+static abi_long do_freebsd_thr_kill2(pid_t pid, long id, int sig)
+{
+
+    return get_errno(thr_kill2(pid, id, sig));
+}
+
+static abi_long do_freebsd_thr_suspend(abi_ulong target_ts)
+{
+    abi_long ret;
+    struct timespec ts;
+
+    if (target_ts != 0) {
+        if (t2h_freebsd_timespec(&ts, target_ts)) {
+            return -TARGET_EFAULT;
+        }
+        ret = thr_suspend(&ts);
+    } else {
+        ret = thr_suspend(NULL);
+    }
+    return ret;
+}
+
+static abi_long do_freebsd_thr_wake(long tid)
+{
+
+    return get_errno(thr_wake(tid));
+}
+
+static abi_long do_freebsd_thr_set_name(long tid, abi_ulong target_name)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(target_name);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = thr_set_name(tid, p);
+    unlock_user(p, target_name, 0);
+
+    return ret;
+}
+
+static abi_long do_freebsd_rtprio_thread(int function, lwpid_t lwpid,
+        abi_ulong target_addr)
+{
+    int ret;
+    struct rtprio rtp;
+
+    ret = t2h_freebsd_rtprio(&rtp, target_addr);
+    if (!is_error(ret)) {
+        ret = get_errno(rtprio_thread(function, lwpid, &rtp));
+    }
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_rtprio(target_addr, &rtp);
+    }
+    return ret;
+}
+
+static abi_long do_freebsd_getcontext(void *cpu_env, abi_ulong arg1)
+{
+    abi_long ret;
+    target_ucontext_t *ucp;
+    sigset_t sigmask;
+
+    if (arg1 == 0) {
+        return -TARGET_EINVAL;
+    }
+    ret = get_errno(sigprocmask(0, NULL, &sigmask));
+    if (!is_error(ret)) {
+        ucp = lock_user(VERIFY_WRITE, arg1, sizeof(target_ucontext_t), 0);
+        if (ucp == 0) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_mcontext(cpu_env, &ucp->uc_mcontext, TARGET_MC_GET_CLEAR_RET);
+        host_to_target_sigset(&ucp->uc_sigmask, &sigmask);
+        memset(ucp->__spare__, 0, sizeof(ucp->__spare__));
+        unlock_user(ucp, arg1, sizeof(target_ucontext_t));
+    }
+    return ret;
+}
+
+static abi_long do_freebsd_setcontext(void *cpu_env, abi_ulong arg1)
+{
+    abi_long ret;
+    target_ucontext_t *ucp;
+    sigset_t sigmask;
+    if (arg1 == 0) {
+        return -TARGET_EINVAL;
+    }
+    ucp = lock_user(VERIFY_READ, arg1, sizeof(target_ucontext_t), 1);
+    if (ucp == 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = set_mcontext(cpu_env, &ucp->uc_mcontext, 0);
+    target_to_host_sigset(&sigmask, &ucp->uc_sigmask);
+    unlock_user(ucp, arg1, sizeof(target_ucontext_t));
+    if (!is_error(ret)) {
+        (void)sigprocmask(SIG_SETMASK, &sigmask, NULL);
+    }
+    return ret;
+}
+
+/* swapcontext(2) */
+static abi_long do_freebsd_swapcontext(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+    abi_long ret;
+    target_ucontext_t *ucp;
+    sigset_t sigmask;
+
+    if (arg1 == 0 || arg2 == 0) {
+        return -TARGET_EINVAL;
+    }
+    /* Save current context in arg1. */
+    ret = get_errno(sigprocmask(0, NULL,  &sigmask));
+    if (!is_error(ret)) {
+        ucp = lock_user(VERIFY_WRITE, arg1, sizeof(target_ucontext_t), 0);
+        if (ucp == 0) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_mcontext(cpu_env, &ucp->uc_mcontext, TARGET_MC_GET_CLEAR_RET);
+        host_to_target_sigset(&ucp->uc_sigmask, &sigmask);
+        memset(ucp->__spare__, 0, sizeof(ucp->__spare__));
+        unlock_user(ucp, arg1, sizeof(target_ucontext_t));
+    }
+    if (is_error(ret)) {
+            return ret;
+    }
+
+    /* Restore the context in arg2 to the current context. */
+    ucp = lock_user(VERIFY_READ, arg2, sizeof(target_ucontext_t), 1);
+    if (ucp == 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = set_mcontext(cpu_env, &ucp->uc_mcontext, 0);
+    target_to_host_sigset(&sigmask, &ucp->uc_sigmask);
+    unlock_user(ucp, arg2, sizeof(target_ucontext_t));
+    if (!is_error(ret)) {
+        (void)sigprocmask(SIG_SETMASK, &sigmask, NULL);
+    }
+    return ret;
+}
+
+
+/* undocumented _umtx_lock() */
+static inline abi_long do_freebsd__umtx_lock(abi_ulong target_addr)
+{
+    abi_long ret;
+    long tid;
+
+    ret = get_errno(thr_self(&tid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return freebsd_lock_umtx(target_addr, tid, NULL);
+}
+
+/* undocumented _umtx_unlock() */
+static inline abi_long do_freebsd__umtx_unlock(abi_ulong target_addr)
+{
+    abi_long ret;
+    long tid;
+
+    ret = get_errno(thr_self(&tid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return freebsd_unlock_umtx(target_addr, tid);
+}
+
+/* undocumented _umtx_op(void *obj, int op, u_long val, void *uaddr,
+                           void *target_ts); */
+static inline abi_long do_freebsd__umtx_op(abi_ulong obj, int op, abi_ulong val,
+        abi_ulong uaddr, abi_ulong target_ts)
+{
+    abi_long ret;
+    struct timespec ts;
+    long tid;
+
+    switch (op) {
+    case TARGET_UMTX_OP_LOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_lock_umtx(obj, tid, &ts);
+        } else {
+            ret = freebsd_lock_umtx(obj, tid, NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_UNLOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = freebsd_unlock_umtx(obj, tid);
+        break;
+
+    case TARGET_UMTX_OP_WAIT:
+        /* args: obj *, val, ts * */
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_wait(obj, tswapal(val), &ts);
+        } else {
+            ret = freebsd_umtx_wait(obj, tswapal(val), NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_WAKE:
+        /* args: obj *, nr_wakeup */
+        ret = freebsd_umtx_wake(obj, val);
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_LOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        if (target_ts) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_lock_umutex(obj, tid, &ts, 0);
+        } else {
+            ret = freebsd_lock_umutex(obj, tid, NULL, 0);
+        }
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_UNLOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = freebsd_unlock_umutex(obj, tid);
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_TRYLOCK:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = freebsd_lock_umutex(obj, tid, NULL, TARGET_UMUTEX_TRY);
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_WAIT:
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_lock_umutex(obj, tid, &ts, TARGET_UMUTEX_WAIT);
+        } else {
+            ret = freebsd_lock_umutex(obj, tid, NULL, TARGET_UMUTEX_WAIT);
+        }
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_WAKE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_mutex_wake(obj, val);
+        break;
+
+    case TARGET_UMTX_OP_SET_CEILING:
+        ret = 0; /* XXX quietly ignore these things for now */
+        break;
+
+    case TARGET_UMTX_OP_CV_WAIT:
+        /*
+         * Initialization of the struct conv is done by
+         * bzero'ing everything in userland.
+         */
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_cv_wait(obj, uaddr, &ts, val);
+        } else {
+            ret = freebsd_cv_wait(obj, uaddr, NULL, val);
+        }
+        break;
+
+    case TARGET_UMTX_OP_CV_SIGNAL:
+        /*
+         * XXX
+         * User code may check if c_has_waiters is zero.  Other
+         * than that it is assume that user code doesn't do
+         * much with the struct conv fields and is pretty
+         * much opauque to userland.
+         */
+        ret = freebsd_cv_signal(obj);
+        break;
+
+    case TARGET_UMTX_OP_CV_BROADCAST:
+        /*
+         * XXX
+         * User code may check if c_has_waiters is zero.  Other
+         * than that it is assume that user code doesn't do
+         * much with the struct conv fields and is pretty
+         * much opauque to userland.
+         */
+        ret = freebsd_cv_broadcast(obj);
+        break;
+
+    case TARGET_UMTX_OP_WAIT_UINT:
+        if (!access_ok(VERIFY_READ, obj, sizeof(abi_ulong))) {
+            return -TARGET_EFAULT;
+        }
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_wait_uint(obj, tswap32((uint32_t)val), &ts);
+        } else {
+            ret = freebsd_umtx_wait_uint(obj, tswap32((uint32_t)val), NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_WAIT_UINT_PRIVATE:
+        if (!access_ok(VERIFY_READ, obj, sizeof(abi_ulong))) {
+            return -TARGET_EFAULT;
+        }
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_wait_uint_private(obj, tswap32((uint32_t)val),
+                    &ts);
+        } else {
+            ret = freebsd_umtx_wait_uint_private(obj, tswap32((uint32_t)val),
+                    NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_WAKE_PRIVATE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_wake_private(obj, val);
+        break;
+
+    case TARGET_UMTX_OP_RW_RDLOCK:
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_rw_rdlock(obj, val, &ts);
+        } else {
+            ret = freebsd_rw_rdlock(obj, val, NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_RW_WRLOCK:
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_rw_wrlock(obj, val, &ts);
+        } else {
+            ret = freebsd_rw_wrlock(obj, val, NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_RW_UNLOCK:
+        ret = freebsd_rw_unlock(obj);
+        break;
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#ifdef UMTX_OP_MUTEX_WAKE2
+    case TARGET_UMTX_OP_MUTEX_WAKE2:
+        ret = freebsd_umtx_mutex_wake2(obj, val);
+        break;
+#endif /* UMTX_OP_MUTEX_WAKE2 */
+
+#ifdef UMTX_OP_NWAKE_PRIVATE
+    case TARGET_UMTX_OP_NWAKE_PRIVATE:
+        {
+            int i;
+            abi_ulong *uaddr;
+            uint32_t imax = tswap32(INT_MAX);
+
+            if (!access_ok(VERIFY_READ, obj, val * sizeof(uint32_t))) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_nwake_private(obj, val);
+
+            uaddr = (abi_ulong *)g2h(obj);
+            ret = 0;
+            for (i = 0; i < (int32_t)val; i++) {
+                ret = freebsd_umtx_wake_private(tswapal(uaddr[i]), imax);
+                if (is_error(ret)) {
+                    break;
+                }
+            }
+        }
+        break;
+#endif /* UMTX_OP_NWAKE_PRIVATE */
+
+    case TARGET_UMTX_OP_SEM_WAIT:
+        if (target_ts != 0) {
+            if (t2h_freebsd_timespec(&ts, target_ts)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_umtx_sem_wait(obj, &ts);
+        } else {
+            ret = freebsd_umtx_sem_wait(obj, NULL);
+        }
+        break;
+
+    case TARGET_UMTX_OP_SEM_WAKE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_sem_wake(obj, val);
+        break;
+#endif
+    default:
+        return -TARGET_EINVAL;
+    }
+    return ret;
+}
+
+#endif /* !__FREEBSD_OS_THREAD_H_ */
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index 90d8eb4..b5510dc 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -64,4 +64,10 @@ abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh);
 abi_long h2t_freebsd_statfs(abi_ulong target_addr, struct statfs *host_statfs);
 abi_long target_to_host_fcntl_cmd(int cmd);
 
+/* os-thread.c */
+abi_long t2h_freebsd_rtprio(struct rtprio *host_rtp, abi_ulong target_addr);
+abi_long h2t_freebsd_rtprio(abi_ulong target_addr, struct rtprio *host_rtp);
+abi_long do_freebsd_thr_new(CPUArchState *env, abi_ulong target_param_addr,
+        int32_t param_size);
+
 #endif /* !_QEMU_OS_H_ */
diff --git a/bsd-user/netbsd/os-thread.c b/bsd-user/netbsd/os-thread.c
new file mode 100644
index 0000000..a4af765
--- /dev/null
+++ b/bsd-user/netbsd/os-thread.c
@@ -0,0 +1 @@
+/* XXX NetBSD thread related helpers */
diff --git a/bsd-user/netbsd/os-thread.h b/bsd-user/netbsd/os-thread.h
new file mode 100644
index 0000000..073b0a0
--- /dev/null
+++ b/bsd-user/netbsd/os-thread.h
@@ -0,0 +1,133 @@
+#ifndef __NETBSD_OS_THREAD_H_
+#define __NETBSD_OS_THREAD_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need to
+ * be emulated.
+ */
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong target_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong thread_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_new(CPUArchState *env,
+        abi_ulong target_param_addr, int32_t param_size)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_self(abi_ulong target_id)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_self()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_exit()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_kill(long id, int sig)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_kill()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_kill2(pid_t pid, long id, int sig)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_kill2()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_suspend(abi_ulong target_ts)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_suspend()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_wake(long tid)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_wake()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_set_name(long tid, abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_set_name()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_rtprio_thread(int function, lwpid_t lwpid,
+        abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall rtprio_thread()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_getcontext(void *cpu_env, abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_setcontext(void *cpu_env, abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_swapcontext(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall swapcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_lock(abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_lock()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_unlock(abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_unlock()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_op(abi_ulong obj, int op, abi_ulong val,
+        abi_ulong uaddr, abi_ulong target_ts)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_op()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __NETBSD_OS_THREAD_H_ */
diff --git a/bsd-user/openbsd/os-thread.c b/bsd-user/openbsd/os-thread.c
new file mode 100644
index 0000000..d125281
--- /dev/null
+++ b/bsd-user/openbsd/os-thread.c
@@ -0,0 +1 @@
+/* XXX OpenBSD thread related helpers */
diff --git a/bsd-user/openbsd/os-thread.h b/bsd-user/openbsd/os-thread.h
new file mode 100644
index 0000000..962a769
--- /dev/null
+++ b/bsd-user/openbsd/os-thread.h
@@ -0,0 +1,133 @@
+#ifndef __OPENBSD_OS_THREAD_H_
+#define __OPENBSD_OS_THREAD_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need to
+ * be emulated.
+ */
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong target_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_create(CPUArchState *env, abi_ulong thread_ctx,
+        abi_ulong target_id, int flags)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_create()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_new(CPUArchState *env,
+        abi_ulong target_param_addr, int32_t param_size)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_self(abi_ulong target_id)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_self()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_exit()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_kill(long id, int sig)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_kill()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_kill2(pid_t pid, long id, int sig)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_kill2()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_suspend(abi_ulong target_ts)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_suspend()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_wake(long tid)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_wake()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_thr_set_name(long tid, abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall thr_set_name()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_rtprio_thread(int function, lwpid_t lwpid,
+        abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall rtprio_thread()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_getcontext(void *cpu_env, abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_setcontext(void *cpu_env, abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static abi_long do_freebsd_swapcontext(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall swapcontext()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_lock(abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_lock()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_unlock(abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_unlock()\n");
+    return -TARGET_ENOSYS;
+}
+
+static inline abi_long do_freebsd__umtx_op(abi_ulong obj, int op, abi_ulong val,
+        abi_ulong uaddr, abi_ulong target_ts)
+{
+
+    qemu_log("qemu: Unsupported syscall _umtx_op()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_OS_THREAD_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 613a89e..4b2add2 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -42,11 +42,7 @@ extern enum BSDType bsd_type;
 #include "target_os_signal.h"
 #include "exec/gdbstub.h"
 
-#if defined(CONFIG_USE_NPTL)
 #define THREAD __thread
-#else
-#define THREAD
-#endif
 
 /* This struct is used to hold certain information about the image.
  * Basically, it replicates in user space what would be certain
@@ -67,6 +63,8 @@ struct image_info {
     abi_ulong entry;
     abi_ulong code_offset;
     abi_ulong data_offset;
+    abi_ulong arg_start;
+    abi_ulong arg_end;
     int       personality;
 };
 
@@ -89,6 +87,15 @@ struct emulated_sigtable {
 typedef struct TaskState {
     struct TaskState *next;
     int used; /* non zero if used */
+#ifdef TARGET_ARM
+    int swi_errno;
+#endif
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
+    /* Extra fields for semihosted binaries. */
+    uint32_t heap_base;
+    uint32_t heap_limit;
+    uint32_t stack_base;
+#endif
     struct image_info *info;
     struct bsd_binprm *bprm;
 
@@ -231,10 +238,8 @@ void mmap_unlock(void);
 abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
 void cpu_list_lock(void);
 void cpu_list_unlock(void);
-#if defined(CONFIG_USE_NPTL)
 void mmap_fork_start(void);
 void mmap_fork_end(int child);
-#endif
 
 /* main.c */
 extern unsigned long target_maxtsiz;
@@ -244,10 +249,15 @@ extern unsigned long target_dflssiz;
 extern unsigned long target_maxssiz;
 extern unsigned long target_sgrowsiz;
 extern char qemu_proc_pathname[];
+void start_exclusive(void);
+void end_exclusive(void);
+void cpu_exec_start(CPUState *cpu);
+void cpu_exec_end(CPUState *cpu);
 
 /* syscall.c */
 abi_long get_errno(abi_long ret);
 int is_error(abi_long ret);
+int host_to_target_errno(int err);
 
 /* os-proc.c */
 abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
@@ -258,6 +268,41 @@ abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
         abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen);
 abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2);
 
+/* os-thread.c */
+extern pthread_mutex_t *new_freebsd_thread_lock_ptr;
+void *new_freebsd_thread_start(void *arg);
+abi_long freebsd_lock_umtx(abi_ulong target_addr, abi_long tid,
+        struct timespec *timeout);
+abi_long freebsd_unlock_umtx(abi_ulong target_addr, abi_long id);
+abi_long freebsd_umtx_wait(abi_ulong targ_addr, abi_ulong id,
+        struct timespec *ts);
+abi_long freebsd_umtx_wake(abi_ulong target_addr, uint32_t n_wake);
+abi_long freebsd_umtx_mutex_wake(abi_ulong target_addr, abi_long val);
+abi_long freebsd_umtx_wait_uint(abi_ulong obj, uint32_t val,
+                struct timespec *timeout);
+abi_long freebsd_umtx_wait_uint_private(abi_ulong obj, uint32_t val,
+                struct timespec *timeout);
+abi_long freebsd_umtx_wake_private(abi_ulong obj, uint32_t val);
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+abi_long freebsd_umtx_nwake_private(abi_ulong obj, uint32_t val);
+abi_long freebsd_umtx_mutex_wake2(abi_ulong obj, uint32_t val);
+abi_long freebsd_umtx_sem_wait(abi_ulong obj, struct timespec *timeout);
+abi_long freebsd_umtx_sem_wake(abi_ulong obj, uint32_t val);
+#endif
+abi_long freebsd_lock_umutex(abi_ulong target_addr, uint32_t id,
+        struct timespec *ts, int mode);
+abi_long freebsd_unlock_umutex(abi_ulong target_addr, uint32_t id);
+abi_long freebsd_cv_wait(abi_ulong target_ucond_addr,
+                abi_ulong target_umtx_addr, struct timespec *ts, int wflags);
+abi_long freebsd_cv_signal(abi_ulong target_ucond_addr);
+abi_long freebsd_cv_broadcast(abi_ulong target_ucond_addr);
+abi_long freebsd_rw_rdlock(abi_ulong target_addr, long fflag,
+        struct timespec *ts);
+abi_long freebsd_rw_wrlock(abi_ulong target_addr, long fflag,
+        struct timespec *ts);
+abi_long freebsd_rw_unlock(abi_ulong target_addr);
+
+
 /* user access */
 
 #define VERIFY_READ 0
@@ -483,8 +528,6 @@ static inline int regpairs_aligned(void *cpu_env)
 }
 #endif
 
-#if defined(CONFIG_USE_NPTL)
 #include <pthread.h>
-#endif
 
 #endif /* QEMU_H */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 286c71e..0a851fe 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -32,7 +32,6 @@
 #include "qemu-common.h"
 
 #define target_to_host_bitmask(x, tbl) (x)
-static int host_to_target_errno(int err);
 
 /* BSD independent syscall shims */
 #include "bsd-file.h"
@@ -47,6 +46,7 @@ static int host_to_target_errno(int err);
 #include "os-signal.h"
 #include "os-socket.h"
 #include "os-stat.h"
+#include "os-thread.h"
 
 /* #define DEBUG */
 
@@ -64,7 +64,7 @@ abi_long get_errno(abi_long ret)
     }
 }
 
-static int host_to_target_errno(int err)
+int host_to_target_errno(int err)
 {
     /* XXX need to translate host errnos here */
     return err;
@@ -1110,6 +1110,73 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * thread system calls
+         */
+    case TARGET_FREEBSD_NR_thr_create: /* thr_create(2) */
+        ret = do_freebsd_thr_create(cpu_env, arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_new: /* thr_new(2) */
+        ret = do_freebsd_thr_new(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_set_name: /* thr_set_name(2) */
+        ret = do_freebsd_thr_set_name(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_self: /* thr_self(2) */
+        ret = do_freebsd_thr_self(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_suspend: /* thr_suspend(2) */
+        ret = do_freebsd_thr_suspend(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_wake: /* thr_wake(2) */
+        ret = do_freebsd_thr_wake(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_kill: /* thr_kill(2) */
+        ret = do_freebsd_thr_kill(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_kill2: /* thr_kill2(2) */
+        ret = do_freebsd_thr_kill2(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_exit: /* thr_exit(2) */
+        ret = do_freebsd_thr_exit(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_rtprio_thread: /* rtprio_thread(2) */
+        ret = do_freebsd_rtprio_thread(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getcontext: /* getcontext(2) */
+        ret = do_freebsd_getcontext(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setcontext: /* setcontext(2) */
+        ret = do_freebsd_setcontext(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_swapcontext: /* swapcontext(2) */
+        ret = do_freebsd_swapcontext(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR__umtx_lock: /* undocumented */
+        ret = do_freebsd__umtx_lock(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR__umtx_unlock: /* undocumented */
+        ret = do_freebsd__umtx_unlock(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR__umtx_op: /* undocumented */
+        ret = do_freebsd__umtx_op(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
diff --git a/include/qemu/tls.h b/include/qemu/tls.h
index b92ea9d..ae7d79d 100644
--- a/include/qemu/tls.h
+++ b/include/qemu/tls.h
@@ -38,7 +38,7 @@
  * TODO: proper implementations via Win32 .tls sections and
  * POSIX pthread_getspecific.
  */
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
 #define DECLARE_TLS(type, x) extern DEFINE_TLS(type, x)
 #define DEFINE_TLS(type, x)  __thread __typeof__(type) tls__##x
 #define tls_var(x)           tls__##x
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 15/19] bsd-user: add support for the ioctl system call
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (15 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 14/19] bsd-user: add support for thread " Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 16/19] bsd-user: add support for extattr and ACL related syscalls Stacey Son
                     ` (3 subsequent siblings)
  20 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support for the ioctl system call.  This uses
the generic thunking code to convert data between the host and
target CPU.
---
 Makefile.target                    |    2 +-
 bsd-user/Makefile.objs             |    2 +-
 bsd-user/bsd-ioctl.c               |  448 ++++++++++++++++++++++++++++++++++++
 bsd-user/bsd-ioctl.h               |   27 +++
 bsd-user/freebsd/os-ioctl-cmds.h   |   47 ++++
 bsd-user/freebsd/os-ioctl-filio.h  |   45 ++++
 bsd-user/freebsd/os-ioctl-ioccom.h |   54 +++++
 bsd-user/freebsd/os-ioctl-ttycom.h |  257 +++++++++++++++++++++
 bsd-user/freebsd/os-ioctl-types.h  |    7 +
 bsd-user/netbsd/os-ioctl-cmds.h    |   48 ++++
 bsd-user/netbsd/os-ioctl-filio.h   |   29 +++
 bsd-user/netbsd/os-ioctl-ioccom.h  |   38 +++
 bsd-user/netbsd/os-ioctl-ttycom.h  |  240 +++++++++++++++++++
 bsd-user/netbsd/os-ioctl-types.h   |    7 +
 bsd-user/openbsd/os-ioctl-cmds.h   |   48 ++++
 bsd-user/openbsd/os-ioctl-filio.h  |   29 +++
 bsd-user/openbsd/os-ioctl-ioccom.h |   38 +++
 bsd-user/openbsd/os-ioctl-ttycom.h |  240 +++++++++++++++++++
 bsd-user/openbsd/os-ioctl-types.h  |    7 +
 bsd-user/qemu.h                    |    1 +
 bsd-user/syscall.c                 |   27 ++-
 21 files changed, 1632 insertions(+), 9 deletions(-)
 create mode 100644 bsd-user/bsd-ioctl.c
 create mode 100644 bsd-user/bsd-ioctl.h
 create mode 100644 bsd-user/freebsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/freebsd/os-ioctl-filio.h
 create mode 100644 bsd-user/freebsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/freebsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/freebsd/os-ioctl-types.h
 create mode 100644 bsd-user/netbsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/netbsd/os-ioctl-filio.h
 create mode 100644 bsd-user/netbsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/netbsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/netbsd/os-ioctl-types.h
 create mode 100644 bsd-user/openbsd/os-ioctl-cmds.h
 create mode 100644 bsd-user/openbsd/os-ioctl-filio.h
 create mode 100644 bsd-user/openbsd/os-ioctl-ioccom.h
 create mode 100644 bsd-user/openbsd/os-ioctl-ttycom.h
 create mode 100644 bsd-user/openbsd/os-ioctl-types.h

diff --git a/Makefile.target b/Makefile.target
index 1306b24..1dd9251 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -103,7 +103,7 @@ QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR) \
 			 -I$(SRC_PATH)/bsd-user/$(HOST_VARIANT_DIR)
 
 obj-y += bsd-user/
-obj-y += gdbstub.o user-exec.o
+obj-y += gdbstub.o thunk.o user-exec.o
 
 endif #CONFIG_BSD_USER
 
diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index fdc1c9a..a6dba89 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,5 +1,5 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-mem.o bsd-proc.o bsd-socket.o \
+	        uaccess.o bsd-ioctl.o bsd-mem.o bsd-proc.o bsd-socket.o \
 			$(HOST_VARIANT_DIR)/os-proc.o \
 			$(HOST_VARIANT_DIR)/os-socket.o $(HOST_VARIANT_DIR)/os-stat.o \
 			$(HOST_VARIANT_DIR)/os-sys.o $(HOST_VARIANT_DIR)/os-thread.o \
diff --git a/bsd-user/bsd-ioctl.c b/bsd-user/bsd-ioctl.c
new file mode 100644
index 0000000..95505a4
--- /dev/null
+++ b/bsd-user/bsd-ioctl.c
@@ -0,0 +1,448 @@
+/*
+ *  BSD ioctl(2) emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#include <sys/_termios.h>
+#else
+#include <sys/termios.h>
+#endif
+#include <sys/ttycom.h>
+#include <sys/filio.h>
+
+#include "qemu.h"
+#include "qemu-common.h"
+
+#include "bsd-ioctl.h"
+#include "os-ioctl-filio.h"
+#include "os-ioctl-ttycom.h"
+
+static const bitmask_transtbl iflag_tbl[] = {
+    { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
+    { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
+    { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
+    { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
+    { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
+    { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
+    { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
+    { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
+    { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
+    { TARGET_IXON, TARGET_IXON, IXON, IXON },
+    { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
+#ifdef IXANY
+    { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
+#endif
+#ifdef IMAXBEL
+    { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
+#endif
+    { 0, 0, 0, 0 }
+};
+
+static const bitmask_transtbl oflag_tbl[] = {
+    { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
+#ifdef ONLCR
+    { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
+#endif
+#ifdef TABDLY
+    { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
+    { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
+#endif
+#ifdef ONOEOT
+    { TARGET_ONOEOT, TARGET_ONOEOT, ONOEOT, ONOEOT },
+#endif
+#ifdef OCRNL
+    { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
+#endif
+#ifdef ONOCR
+    { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
+#endif
+#ifdef ONLRET
+    { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
+#endif
+    { 0, 0, 0, 0 }
+};
+
+static const bitmask_transtbl cflag_tbl[] = {
+#ifdef CIGNORE
+    { TARGET_CIGNORE, TARGET_CIGNORE, CIGNORE, CIGNORE },
+#endif
+    { 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 },
+#ifdef CCTS_OFLOW
+    { TARGET_CCTS_OFLOW, TARGET_CCTS_OFLOW, CCTS_OFLOW, CCTS_OFLOW },
+#endif
+#ifdef CRTSCTS
+    { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
+#endif
+#ifdef CRTS_IFLOW
+    { TARGET_CRTS_IFLOW, TARGET_CRTS_IFLOW, CRTS_IFLOW, CRTS_IFLOW },
+#endif
+#ifdef CDTS_IFLOW
+    { TARGET_CDTR_IFLOW, TARGET_CDTR_IFLOW, CDTR_IFLOW, CDTR_IFLOW },
+#endif
+#ifdef CDSR_OFLOW
+    { TARGET_CDSR_OFLOW, TARGET_CDSR_OFLOW, CDSR_OFLOW, CDSR_OFLOW },
+#endif
+#ifdef CCAR_OFLOW
+    { TARGET_CCAR_OFLOW, TARGET_CCAR_OFLOW, CCAR_OFLOW, CCAR_OFLOW },
+#endif
+    { 0, 0, 0, 0 }
+};
+
+static const bitmask_transtbl lflag_tbl[] = {
+#ifdef ECHOKE
+    { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
+#endif
+    { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
+    { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
+    { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
+    { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
+#ifdef ECHOPRT
+    { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
+#endif
+#ifdef ECHOCTL
+    { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
+#endif
+    { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
+    { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
+#ifdef ALTWERASE
+    { TARGET_ALTWERASE, TARGET_ALTWERASE, ALTWERASE, ALTWERASE },
+#endif
+    { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
+    { TARGET_EXTPROC, TARGET_EXTPROC, EXTPROC, EXTPROC },
+    { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
+#ifdef FLUSHO
+    { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
+#endif
+#ifdef NOKERNINFO
+    { TARGET_NOKERNINFO, TARGET_NOKERNINFO, NOKERNINFO, NOKERNINFO },
+#endif
+#ifdef PENDIN
+    { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
+#endif
+    { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
+    { 0, 0, 0, 0 }
+};
+
+static void target_to_host_termios(void *dst, const void *src)
+{
+    struct termios *host = dst;
+    const struct target_termios *target = src;
+
+    host->c_iflag = target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
+    host->c_oflag = target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
+    host->c_cflag = target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
+    host->c_lflag = target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
+
+    memset(host->c_cc, 0, sizeof(host->c_cc));
+    host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
+    host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
+#ifdef VEOL2
+    host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
+#endif
+    host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
+#ifdef VWERASE
+    host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
+#endif
+    host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
+#ifdef VREPRINT
+    host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
+#endif
+#ifdef VERASE2
+    host->c_cc[VERASE2] = target->c_cc[TARGET_VERASE2];
+#endif
+    host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
+    host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
+    host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
+#ifdef VDSUSP
+    host->c_cc[VDSUSP] = target->c_cc[TARGET_VDSUSP];
+#endif
+    host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
+    host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
+#ifdef VLNEXT
+    host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
+#endif
+#ifdef VDISCARD
+    host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
+#endif
+    host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
+    host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
+#ifdef VSTATUS
+    host->c_cc[VSTATUS] = target->c_cc[TARGET_VSTATUS];
+#endif
+
+    host->c_ispeed = tswap32(target->c_ispeed);
+    host->c_ospeed = tswap32(target->c_ospeed);
+}
+
+static void host_to_target_termios(void *dst, const void *src)
+{
+    struct target_termios *target = dst;
+    const struct termios *host = src;
+
+    target->c_iflag = tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
+    target->c_oflag = tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
+    target->c_cflag = tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
+    target->c_lflag = tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
+
+    memset(target->c_cc, 0, sizeof(target->c_cc));
+    target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
+    target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
+#ifdef VEOL2
+    target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
+#endif
+    target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
+#ifdef VWERASE
+    target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
+#endif
+    target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
+#ifdef VREPRINT
+    target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
+#endif
+#ifdef VERASE2
+    target->c_cc[TARGET_VERASE2] = host->c_cc[VERASE2];
+#endif
+    target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
+    target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
+    target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
+#ifdef VDSUSP
+    target->c_cc[TARGET_VDSUSP] = host->c_cc[VDSUSP];
+#endif
+    target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
+    target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
+#ifdef VLNEXT
+    target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
+#endif
+#ifdef VDISCARD
+    target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
+#endif
+    target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
+    target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
+#ifdef VSTATUS
+    target->c_cc[TARGET_VSTATUS] = host->c_cc[VSTATUS];
+#endif
+
+    target->c_ispeed = tswap32(host->c_ispeed);
+    target->c_ospeed = tswap32(host->c_ospeed);
+}
+
+static const StructEntry struct_termios_def = {
+    .convert = { host_to_target_termios, target_to_host_termios },
+    .size = { sizeof(struct target_termios), sizeof(struct termios) },
+    .align = { __alignof__(struct target_termios),
+        __alignof__(struct termios) },
+};
+
+
+/* ioctl structure type definitions */
+#define STRUCT(name, ...) STRUCT_ ## name,
+#define STRUCT_SPECIAL(name) STRUCT_ ## name,
+enum {
+#include "os-ioctl-types.h"
+};
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+#define STRUCT(name, ...) \
+    static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
+#define STRUCT_SPECIAL(name)
+#include "os-ioctl-types.h"
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+
+struct IOCTLEntry;
+
+typedef abi_long do_ioctl_fn(const struct IOCTLEntry *ie, uint8_t *buf_temp,
+                int fd, abi_long cmd, abi_long arg);
+
+struct IOCTLEntry {
+    unsigned int target_cmd;
+    unsigned int host_cmd;
+    const char *name;
+    int access;
+    do_ioctl_fn *do_ioctl;
+    const argtype arg_type[5];
+};
+typedef struct IOCTLEntry IOCTLEntry;
+
+#define MAX_STRUCT_SIZE 4096
+
+static IOCTLEntry ioctl_entries[] = {
+#define IOC_    0x0000
+#define IOC_R   0x0001
+#define IOC_W   0x0002
+#define IOC_RW  (IOC_R | IOC_W)
+#define IOCTL(cmd, access, ...) \
+    { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
+#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
+    { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
+#include "os-ioctl-cmds.h"
+    { 0, 0 },
+};
+
+abi_long do_bsd_ioctl(int fd, abi_long cmd, abi_long arg)
+{
+    const IOCTLEntry *ie;
+    const argtype *arg_type;
+    abi_long ret;
+    uint8_t buf_temp[MAX_STRUCT_SIZE];
+    int target_size;
+    void *argptr;
+
+    ie = ioctl_entries;
+    for (;;) {
+        if (ie->target_cmd == 0) {
+            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
+            return -TARGET_ENOSYS;
+        }
+        if (ie->target_cmd == cmd) {
+            break;
+        }
+        ie++;
+    }
+    arg_type = ie->arg_type;
+#if defined(DEBUG)
+    gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
+#endif
+    if (ie->do_ioctl) {
+        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
+    }
+
+    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 argument */
+        ret = get_errno(ioctl(fd, ie->host_cmd, arg));
+        break;
+
+    case TYPE_PTR:
+        arg_type++;
+        target_size = thunk_type_size(arg_type, 0);
+        switch (ie->access) {
+        case IOC_R:
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            if (!is_error(ret)) {
+                argptr = lock_user(VERIFY_WRITE, arg,
+                    target_size, 0);
+                if (!argptr) {
+                    return -TARGET_EFAULT;
+                }
+                thunk_convert(argptr, buf_temp, arg_type,
+                    THUNK_TARGET);
+                unlock_user(argptr, arg, target_size);
+            }
+            break;
+
+        case IOC_W:
+            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);
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            break;
+
+        case IOC_RW:
+            /* fallthrough */
+        default:
+            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);
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            if (!is_error(ret)) {
+                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+                if (!argptr) {
+                    return -TARGET_EFAULT;
+                }
+                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+                unlock_user(argptr, arg, target_size);
+            }
+            break;
+        }
+        break;
+
+    default:
+        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
+            (long)cmd, arg_type[0]);
+        ret = -TARGET_ENOSYS;
+        break;
+    }
+    return ret;
+}
+
+void init_bsd_ioctl(void)
+{
+    IOCTLEntry *ie;
+    const argtype *arg_type;
+    int size;
+
+#define STRUCT(name, ...) \
+ thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
+#define STRUCT_SPECIAL(name) \
+ thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
+#include "os-ioctl-types.h"
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+    /*
+     * Patch the ioctl size if necessary using the fact that no
+     * ioctl has all the bits at '1' in the size field
+     * (IOCPARM_MAX - 1).
+     */
+    ie = ioctl_entries;
+    while (ie->target_cmd != 0) {
+        if (((ie->target_cmd >> TARGET_IOCPARM_SHIFT) &
+                    TARGET_IOCPARM_MASK) == TARGET_IOCPARM_MASK) {
+            arg_type = ie->arg_type;
+            if (arg_type[0] != TYPE_PTR) {
+                fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
+                        ie->target_cmd);
+                exit(1);
+            }
+            arg_type++;
+            size = thunk_type_size(arg_type, 0);
+            ie->target_cmd = (ie->target_cmd &
+                    ~(TARGET_IOCPARM_MASK << TARGET_IOCPARM_SHIFT)) |
+                (size << TARGET_IOCPARM_SHIFT);
+        }
+        ie++;
+    }
+
+}
+
diff --git a/bsd-user/bsd-ioctl.h b/bsd-user/bsd-ioctl.h
new file mode 100644
index 0000000..b593c88
--- /dev/null
+++ b/bsd-user/bsd-ioctl.h
@@ -0,0 +1,27 @@
+/*
+ *  ioctl system call definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_IOCTL_H_
+#define __BSD_IOCTL_H_
+
+abi_long do_bsd_ioctl(int fd, abi_long cmd, abi_long arg);
+void init_bsd_ioctl(void);
+
+#endif /* !__BSD_IOCTL_H_ */
+
diff --git a/bsd-user/freebsd/os-ioctl-cmds.h b/bsd-user/freebsd/os-ioctl-cmds.h
new file mode 100644
index 0000000..85d3c41
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-cmds.h
@@ -0,0 +1,47 @@
+
+/* sys/ttycom.h tty(4) */
+IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCCBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCSDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCCDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR))
+IOCTL(TIOCNOTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCSTOP, IOC_, TYPE_NULL)
+IOCTL(TIOCSTART, IOC_, TYPE_NULL)
+IOCTL(TIOCSCTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCDRAIN, IOC_, TYPE_NULL)
+IOCTL(TIOCEXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCNXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
+
+/* sys/filio.h */
+IOCTL(FIOCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODTYPE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOGETLBA, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODGNAME, IOC_R, MK_PTR(STRUCT_fiodgname_arg))
+IOCTL(FIONWRITE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONSPACE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOSEEKDATA, IOC_RW, MK_PTR(TYPE_ULONG))
+IOCTL(FIOSEEKHOLE, IOC_RW, MK_PTR(TYPE_ULONG))
diff --git a/bsd-user/freebsd/os-ioctl-filio.h b/bsd-user/freebsd/os-ioctl-filio.h
new file mode 100644
index 0000000..7e1aae9
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-filio.h
@@ -0,0 +1,45 @@
+/*
+ *  FreeBSD filio definitions for ioctl(2) emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _IOCTL_FILIO_H_
+#define _IOCTL_FILIO_H_
+
+/* see sys/filio.h */
+#define TARGET_FIOCLEX      TARGET_IO('f', 1)
+#define TARGET_FIONCLEX     TARGET_IO('f', 2)
+#define TARGET_FIONREAD     TARGET_IOR('f', 127, int)
+#define TARGET_FIONBIO      TARGET_IOW('f', 126, int)
+#define TARGET_FIOASYNC     TARGET_IOW('f', 125, int)
+#define TARGET_FIOSETOWN    TARGET_IOW('f', 124, int)
+#define TARGET_FIOGETOWN    TARGET_IOR('f', 123, int)
+#define TARGET_FIODTYPE     TARGET_IOR('f', 122, int)
+#define TARGET_FIOGETLBA    TARGET_IOR('f', 121, int)
+
+struct target_fiodgname_arg {
+    int32_t     len;
+    abi_ulong   buf;
+};
+
+#define TARGET_FIODGNAME    TARGET_IOW('f', 120,    \
+                struct target_fiodgname_arg)
+#define TARGET_FIONWRITE    TARGET_IOR('f', 119, int)
+#define TARGET_FIONSPACE    TARGET_IOR('f', 118, int)
+#define TARGET_FIOSEEKDATA  TARGET_IOWR('f', 97, off_t)
+#define TARGET_FIOSEEKHOLE  TARGET_IOWR('f', 98, off_t)
+
+#endif /* !_IOCTL_FILIO_H_ */
diff --git a/bsd-user/freebsd/os-ioctl-ioccom.h b/bsd-user/freebsd/os-ioctl-ioccom.h
new file mode 100644
index 0000000..fb9456f
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-ioccom.h
@@ -0,0 +1,54 @@
+/*
+ *  FreeBSD ioccom definitions for ioctl(2) emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _IOCTL_IOCCOM_H_
+#define _IOCTL_IOCCOM_H_
+/*
+ * Ioctl's have the command encoded in the lower word, and the size of
+ * any in or out parameters in the upper word.  The high 3 bits of the
+ * upper word are used to encode the in/out status of the parameter.
+ */
+/* number of bits for ioctl size */
+#define TARGET_IOCPARM_SHIFT    13
+
+/* parameter length mask */
+#define TARGET_IOCPARM_MASK ((1 << TARGET_IOCPARM_SHIFT) - 1)
+
+#define TARGET_IOCPARM_LEN(x)   (((x) >> 16) & TARGET_IOCPARM_MASK)
+#define TARGET_IOCBASECMD(x)    ((x) & ~(TARGET_IOCPARM_MASK << 16))
+#define TARGET_IOCGROUP(x)  (((x) >> 8) & 0xff)
+
+#define TARGET_IOCPARM_MAX  (1 << TARGET_IOCPARM_SHIFT) /* max size of ioctl */
+#define TARGET_IOC_VOID     0x20000000  /* no parameters */
+#define TARGET_IOC_OUT      0x40000000  /* copy out parameters */
+#define TARGET_IOC_IN       0x80000000  /* copy in parameters */
+#define TARGET_IOC_INOUT    (TARGET_IOC_IN|TARGET_IOC_OUT)
+#define TARGET_IOC_DIRMASK  (TARGET_IOC_VOID|TARGET_IOC_OUT|TARGET_IOC_IN)
+
+#define TARGET_IOC(inout, group, num, len) ((abi_ulong) \
+    ((inout) | (((len) & TARGET_IOCPARM_MASK) << 16) | ((group) << 8) \
+     | (num)))
+#define TARGET_IO(g, n)       TARGET_IOC(IOC_VOID,    (g), (n), 0)
+#define TARGET_IOWINT(g, n)   TARGET_IOC(IOC_VOID,    (g), (n), sizeof(int))
+#define TARGET_IOR(g, n, t)   TARGET_IOC(IOC_OUT, (g), (n), sizeof(t))
+#define TARGET_IOW(g, n, t)   TARGET_IOC(IOC_IN,  (g), (n), sizeof(t))
+/* this should be _IORW, but stdio got there first */
+#define TARGET_IOWR(g, n, t)  TARGET_IOC(IOC_INOUT,   (g), (n), sizeof(t))
+
+#endif /* !_IOCTL_IOCCOM_H_ */
diff --git a/bsd-user/freebsd/os-ioctl-ttycom.h b/bsd-user/freebsd/os-ioctl-ttycom.h
new file mode 100644
index 0000000..b60db25
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-ttycom.h
@@ -0,0 +1,257 @@
+/*
+ *  FreeBSD ttycom definitions for ioctl(2) emulation
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _IOCTL_TTYCOM_H_
+#define _IOCTL_TTYCOM_H_
+
+#include "os-ioctl-ioccom.h"
+
+/* From sys/ttycom.h and sys/_termios.h */
+
+#define TARGET_VEOF     0   /* ICANON */
+#define TARGET_VEOL     1   /* ICANON */
+#define TARGET_VEOL2    2   /* ICANON together with IEXTEN */
+#define TARGET_VERASE   3   /* ICANON */
+#define TARGET_VWERASE  4   /* ICANON together with IEXTEN */
+#define TARGET_VKILL    5   /* ICANON */
+#define TARGET_VREPRINT 6   /* ICANON together with IEXTEN */
+#define TARGET_VERASE2  7   /* ICANON */
+#define TARGET_VINTR    8   /* ISIG */
+#define TARGET_VQUIT    9   /* ISIG */
+#define TARGET_VSUSP    10  /* ISIG */
+#define TARGET_VDSUSP   11  /* ISIG together with IEXTEN */
+#define TARGET_VSTART   12  /* IXON, IXOFF */
+#define TARGET_VSTOP    13  /* IXON, IXOFF */
+#define TARGET_VLNEXT   14  /* IEXTEN */
+#define TARGET_VDISCARD 15  /* IEXTEN */
+#define TARGET_VMIN     16  /* !ICANON */
+#define TARGET_VTIME    17  /* !ICANON */
+#define TARGET_VSTATUS  18  /* ICANON together with IEXTEN */
+/*                      19         spare 2 */
+#define TARGET_NCCS     20
+
+/*
+ * Input flags - software input processing
+ */
+#define TARGET_IGNBRK   0x00000001  /* ignore BREAK condition */
+#define TARGET_BRKINT   0x00000002  /* map BREAK to SIGINTR */
+#define TARGET_IGNPAR   0x00000004  /* ignore (discard) parity errors */
+#define TARGET_PARMRK   0x00000008  /* mark parity and framing errors */
+#define TARGET_INPCK    0x00000010  /* enable checking of parity errors */
+#define TARGET_ISTRIP   0x00000020  /* strip 8th bit off chars */
+#define TARGET_INLCR    0x00000040  /* map NL into CR */
+#define TARGET_IGNCR    0x00000080  /* ignore CR */
+#define TARGET_ICRNL    0x00000100  /* map CR to NL (ala CRMOD) */
+#define TARGET_IXON     0x00000200  /* enable output flow control */
+#define TARGET_IXOFF    0x00000400  /* enable input flow control */
+#define TARGET_IXANY    0x00000800  /* any char will restart after stop */
+#define TARGET_IMAXBEL  0x00002000  /* ring bell on input queue full */
+
+/*
+ * Output flags - software output processing
+ */
+#define TARGET_OPOST    0x00000001  /* enable following output processing */
+#define TARGET_ONLCR    0x00000002  /* map NL to CR-NL (ala CRMOD) */
+#define TARGET_TABDLY   0x00000004  /* tab delay mask */
+#define TARGET_TAB0     0x00000000  /* no tab delay and expansion */
+#define TARGET_TAB3     0x00000004  /* expand tabs to spaces */
+#define TARGET_ONOEOT   0x00000008  /* discard EOT's (^D) on output) */
+#define TARGET_OCRNL    0x00000010  /* map CR to NL on output */
+#define TARGET_ONOCR    0x00000020  /* no CR output at column 0 */
+#define TARGET_ONLRET   0x00000040  /* NL performs CR function */
+
+/*
+ * Control flags - hardware control of terminal
+ */
+#define TARGET_CIGNORE      0x00000001  /* ignore control flags */
+#define TARGET_CSIZE        0x00000300  /* character size mask */
+#define     TARGET_CS5      0x00000000  /* 5 bits (pseudo) */
+#define     TARGET_CS6      0x00000100  /* 6 bits */
+#define     TARGET_CS7      0x00000200  /* 7 bits */
+#define     TARGET_CS8      0x00000300  /* 8 bits */
+#define TARGET_CSTOPB       0x00000400  /* send 2 stop bits */
+#define TARGET_CREAD        0x00000800  /* enable receiver */
+#define TARGET_PARENB       0x00001000  /* parity enable */
+#define TARGET_PARODD       0x00002000  /* odd parity, else even */
+#define TARGET_HUPCL        0x00004000  /* hang up on last close */
+#define TARGET_CLOCAL       0x00008000  /* ignore modem status lines */
+#define TARGET_CCTS_OFLOW   0x00010000  /* CTS flow control of output */
+#define TARGET_CRTSCTS      (TARGET_CCTS_OFLOW | TARGET_CRTS_IFLOW)
+#define TARGET_CRTS_IFLOW   0x00020000  /* RTS flow control of input */
+#define TARGET_CDTR_IFLOW   0x00040000  /* DTR flow control of input */
+#define TARGET_CDSR_OFLOW   0x00080000  /* DSR flow control of output */
+#define TARGET_CCAR_OFLOW   0x00100000  /* DCD flow control of output */
+
+/*
+ * "Local" flags - dumping ground for other state
+ */
+#define TARGET_ECHOKE   0x00000001  /* visual erase for line kill */
+#define TARGET_ECHOE    0x00000002  /* visually erase chars */
+#define TARGET_ECHOK    0x00000004  /* echo NL after line kill */
+#define TARGET_ECHO 0x00000008  /* enable echoing */
+#define TARGET_ECHONL   0x00000010  /* echo NL even if ECHO is off */
+#define TARGET_ECHOPRT  0x00000020  /* visual erase mode for hardcopy */
+#define TARGET_ECHOCTL  0x00000040  /* echo control chars as ^(Char) */
+#define TARGET_ISIG 0x00000080  /* enable signals INTR, QUIT, [D]SUSP */
+#define TARGET_ICANON   0x00000100  /* canonicalize input lines */
+#define TARGET_ALTWERASE 0x00000200 /* use alternate WERASE algorithm */
+#define TARGET_IEXTEN   0x00000400  /* enable DISCARD and LNEXT */
+#define TARGET_EXTPROC  0x00000800  /* external processing */
+#define TARGET_TOSTOP   0x00400000  /* stop background jobs from output */
+#define TARGET_FLUSHO   0x00800000  /* output being flushed (state) */
+#define TARGET_NOKERNINFO 0x02000000    /* no kernel output from VSTATUS */
+#define TARGET_PENDIN   0x20000000  /* XXX retype pending input (state) */
+#define TARGET_NOFLSH   0x80000000  /* don't flush after interrupt */
+
+struct target_termios {
+    uint32_t c_iflag;   /* input flags */
+    uint32_t c_oflag;   /* output flags */
+    uint32_t c_cflag;   /* control flags */
+    uint32_t c_lflag;   /* local flags */
+    uint8_t  c_cc[TARGET_NCCS]; /* control chars */
+    uint32_t c_ispeed;  /* input speed */
+    uint32_t c_ospeed;  /* output speed */
+};
+
+
+struct target_winsize {
+    uint16_t ws_row;    /* rows, in characters */
+    uint16_t ws_col;    /* columns, in characters */
+    uint16_t ws_xpixel; /* horizontal size, pixels */
+    uint16_t ws_ypixel; /* vertical size, pixels */
+};
+
+                        /* 0-2 compat */
+                        /* 3-7 unused */
+                        /* 8-10 compat */
+                        /* 11-12 unused */
+#define TARGET_TIOCEXCL  TARGET_IO('t', 13) /* set exclusive use of tty */
+#define TARGET_TIOCNXCL  TARGET_IO('t', 14) /* reset exclusive use of tty */
+#define TARGET_TIOCGPTN  TARGET_IOR('t', 15, int) /* Get pts number. */
+#define TARGET_TIOCFLUSH TARGET_IOW('t', 16, int) /* flush buffers */
+                    /* 17-18 compat */
+/* get termios struct */
+#define TARGET_TIOCGETA TARGET_IOR('t', 19, struct target_termios)
+/* set termios struct */
+#define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios)
+/* drain output, set */
+#define TARGET_TIOCSETAW    TARGET_IOW('t', 21, struct target_termios)
+/* drn out, fls in, set */
+#define TARGET_TIOCSETAF    TARGET_IOW('t', 22, struct target_termios)
+                        /* 23-25 unused */
+#define TARGET_TIOCGETD TARGET_IOR('t', 26, int) /* get line discipline */
+#define TARGET_TIOCSETD TARGET_IOW('t', 27, int) /* set line discipline */
+#define TARGET_TIOCPTMASTER  TARGET_IO('t', 28) /* pts master validation */
+                    /* 29-85 unused */
+/* get ttywait timeout */
+#define TARGET_TIOCGDRAINWAIT   TARGET_IOR('t', 86, int)
+/* set ttywait timeout */
+#define TARGET_TIOCSDRAINWAIT   TARGET_IOW('t', 87, int)
+                    /* 88 unused */
+                    /* 89-91 conflicts: tun and tap */
+/* enable/get timestamp of last input event */
+#define TARGET_TIOCTIMESTAMP    TARGET_IOR('t', 89, struct target_timeval)
+/* modem: get wait on close */
+#define TARGET_TIOCMGDTRWAIT    TARGET_IOR('t', 90, int)
+/* modem: set wait on close */
+#define TARGET_TIOCMSDTRWAIT    TARGET_IOW('t', 91, int)
+                    /* 92-93 tun and tap */
+                    /* 94-97 conflicts: tun and tap */
+/* wait till output drained */
+#define TARGET_TIOCDRAIN     TARGET_IO('t', 94)
+ /* pty: generate signal */
+#define TARGET_TIOCSIG      TARGET_IOWINT('t', 95)
+/* pty: external processing */
+#define TARGET_TIOCEXT      TARGET_IOW('t', 96, int)
+/* become controlling tty */
+#define TARGET_TIOCSCTTY     TARGET_IO('t', 97)
+/* become virtual console */
+#define TARGET_TIOCCONS TARGET_IOW('t', 98, int)
+/* get session id */
+#define TARGET_TIOCGSID TARGET_IOR('t', 99, int)
+                        /* 100 unused */
+/* simulate ^T status message */
+#define TARGET_TIOCSTAT  TARGET_IO('t', 101)
+ /* pty: set/clr usr cntl mode */
+#define TARGET_TIOCUCNTL    TARGET_IOW('t', 102, int)
+/* usr cntl op "n" */
+#define TARGET_TIOCCMD(n)   TARGET_IO('u', n)
+/* set window size */
+#define TARGET_TIOCSWINSZ   TARGET_IOW('t', 103, struct target_winsize)
+/* get window size */
+#define TARGET_TIOCGWINSZ   TARGET_IOR('t', 104, struct target_winsize)
+                        /* 105 unused */
+/* get all modem bits */
+#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
+#define     TARGET_TIOCM_LE 0001        /* line enable */
+#define     TARGET_TIOCM_DTR    0002    /* data terminal ready */
+#define     TARGET_TIOCM_RTS    0004    /* request to send */
+#define     TARGET_TIOCM_ST 0010        /* secondary transmit */
+#define     TARGET_TIOCM_SR 0020        /* secondary receive */
+#define     TARGET_TIOCM_CTS    0040    /* clear to send */
+#define     TARGET_TIOCM_DCD    0100    /* data carrier detect */
+#define     TARGET_TIOCM_RI     0200    /* ring indicate */
+#define     TARGET_TIOCM_DSR    0400    /* data set ready */
+#define     TARGET_TIOCM_CD TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_CAR    TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_RNG    TARGET_TIOCM_RI
+#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) /* bic modem bits */
+#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) /* bis modem bits */
+#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) /* set all modem bits */
+/* start output, like ^Q */
+#define TARGET_TIOCSTART     TARGET_IO('t', 110)
+/* stop output, like ^S */
+#define TARGET_TIOCSTOP  TARGET_IO('t', 111)
+/* pty: set/clear packet mode */
+#define TARGET_TIOCPKT      TARGET_IOW('t', 112, int)
+#define     TARGET_TIOCPKT_DATA     0x00    /* data packet */
+#define     TARGET_TIOCPKT_FLUSHREAD    0x01    /* flush packet */
+#define     TARGET_TIOCPKT_FLUSHWRITE   0x02    /* flush packet */
+#define     TARGET_TIOCPKT_STOP     0x04    /* stop output */
+#define     TARGET_TIOCPKT_START        0x08    /* start output */
+#define     TARGET_TIOCPKT_NOSTOP       0x10    /* no more ^S, ^Q */
+#define     TARGET_TIOCPKT_DOSTOP       0x20    /* now do ^S ^Q */
+#define     TARGET_TIOCPKT_IOCTL        0x40    /* state change of pty
+                               driver */
+#define TARGET_TIOCNOTTY     TARGET_IO('t', 113)    /* void tty
+                               association */
+#define TARGET_TIOCSTI      TARGET_IOW('t', 114, char)  /* simulate
+                            terminal input */
+#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)   /* output queue size */
+                        /* 116-117 compat */
+#define TARGET_TIOCSPGRP    TARGET_IOW('t', 118, int) /* set pgrp of tty */
+#define TARGET_TIOCGPGRP    TARGET_IOR('t', 119, int) /* get pgrp of tty */
+#define TARGET_TIOCCDTR  TARGET_IO('t', 120)        /* clear data terminal
+                               ready */
+#define TARGET_TIOCSDTR  TARGET_IO('t', 121)        /* set data terminal
+                               ready */
+#define TARGET_TIOCCBRK  TARGET_IO('t', 122)        /* clear break bit */
+#define TARGET_TIOCSBRK  TARGET_IO('t', 123)        /* set break bit */
+                        /* 124-127 compat */
+
+#define TARGET_TTYDISC      0       /* termios tty line
+                           discipline */
+#define TARGET_SLIPDISC     4       /* serial IP discipline */
+#define TARGET_PPPDISC      5       /* PPP discipline */
+#define TARGET_NETGRAPHDISC 6       /* Netgraph tty node
+                           discipline */
+#define TARGET_H4DISC       7       /* Netgraph Bluetooth H4
+                           discipline */
+
+#endif /*! _IOCTL_TTYCOM_H_ */
diff --git a/bsd-user/freebsd/os-ioctl-types.h b/bsd-user/freebsd/os-ioctl-types.h
new file mode 100644
index 0000000..60b9288
--- /dev/null
+++ b/bsd-user/freebsd/os-ioctl-types.h
@@ -0,0 +1,7 @@
+
+STRUCT_SPECIAL(termios)
+
+STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
+
+STRUCT(fiodgname_arg, TYPE_INT, TYPE_PTRVOID)
+
diff --git a/bsd-user/netbsd/os-ioctl-cmds.h b/bsd-user/netbsd/os-ioctl-cmds.h
new file mode 100644
index 0000000..12af33c
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-cmds.h
@@ -0,0 +1,48 @@
+/* XXX should be fixed for NetBSD ioctl cmds */
+
+/* sys/ttycom.h tty(4) */
+IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCCBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCSDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCCDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR))
+IOCTL(TIOCNOTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCSTOP, IOC_, TYPE_NULL)
+IOCTL(TIOCSTART, IOC_, TYPE_NULL)
+IOCTL(TIOCSCTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCDRAIN, IOC_, TYPE_NULL)
+IOCTL(TIOCEXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCNXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
+
+/* sys/filio.h */
+IOCTL(FIOCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODTYPE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOGETLBA, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODGNAME, IOC_R, MK_PTR(STRUCT_fiodgname_arg))
+IOCTL(FIONWRITE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONSPACE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOSEEKDATA, IOC_RW, MK_PTR(TYPE_ULONG))
+IOCTL(FIOSEEKHOLE, IOC_RW, MK_PTR(TYPE_ULONG))
diff --git a/bsd-user/netbsd/os-ioctl-filio.h b/bsd-user/netbsd/os-ioctl-filio.h
new file mode 100644
index 0000000..24b63ae
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-filio.h
@@ -0,0 +1,29 @@
+#ifndef _IOCTL_FILIO_H_
+#define _IOCTL_FILIO_H_
+
+/* XXX needs to be fixed for NetBSD dependencies */
+
+/* see sys/filio.h */
+#define TARGET_FIOCLEX      TARGET_IO('f', 1)
+#define TARGET_FIONCLEX     TARGET_IO('f', 2)
+#define TARGET_FIONREAD     TARGET_IOR('f', 127, int)
+#define TARGET_FIONBIO      TARGET_IOW('f', 126, int)
+#define TARGET_FIOASYNC     TARGET_IOW('f', 125, int)
+#define TARGET_FIOSETOWN    TARGET_IOW('f', 124, int)
+#define TARGET_FIOGETOWN    TARGET_IOR('f', 123, int)
+#define TARGET_FIODTYPE     TARGET_IOR('f', 122, int)
+#define TARGET_FIOGETLBA    TARGET_IOR('f', 121, int)
+
+struct target_fiodgname_arg {
+    int32_t     len;
+    abi_ulong   buf;
+};
+
+#define TARGET_FIODGNAME    TARGET_IOW('f', 120,    \
+                struct target_fiodgname_arg)
+#define TARGET_FIONWRITE    TARGET_IOR('f', 119, int)
+#define TARGET_FIONSPACE    TARGET_IOR('f', 118, int)
+#define TARGET_FIOSEEKDATA  TARGET_IOWR('f', 97, off_t)
+#define TARGET_FIOSEEKHOLE  TARGET_IOWR('f', 98, off_t)
+
+#endif /* !_IOCTL_FILIO_H_ */
diff --git a/bsd-user/netbsd/os-ioctl-ioccom.h b/bsd-user/netbsd/os-ioctl-ioccom.h
new file mode 100644
index 0000000..e193a16
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-ioccom.h
@@ -0,0 +1,38 @@
+#ifndef _IOCTL_IOCCOM_H_
+#define _IOCTL_IOCCOM_H_
+
+/* XXX needs to be fixed for NetBSD dependencies */
+
+/*
+ * Ioctl's have the command encoded in the lower word, and the size of
+ * any in or out parameters in the upper word.  The high 3 bits of the
+ * upper word are used to encode the in/out status of the parameter.
+ */
+/* number of bits for ioctl size */
+#define TARGET_IOCPARM_SHIFT    13
+
+/* parameter length mask */
+#define TARGET_IOCPARM_MASK ((1 << TARGET_IOCPARM_SHIFT) - 1)
+
+#define TARGET_IOCPARM_LEN(x)   (((x) >> 16) & TARGET_IOCPARM_MASK)
+#define TARGET_IOCBASECMD(x)    ((x) & ~(TARGET_IOCPARM_MASK << 16))
+#define TARGET_IOCGROUP(x)  (((x) >> 8) & 0xff)
+
+#define TARGET_IOCPARM_MAX  (1 << TARGET_IOCPARM_SHIFT) /* max size of ioctl */
+#define TARGET_IOC_VOID     0x20000000  /* no parameters */
+#define TARGET_IOC_OUT      0x40000000  /* copy out parameters */
+#define TARGET_IOC_IN       0x80000000  /* copy in parameters */
+#define TARGET_IOC_INOUT    (TARGET_IOC_IN|TARGET_IOC_OUT)
+#define TARGET_IOC_DIRMASK  (TARGET_IOC_VOID|TARGET_IOC_OUT|TARGET_IOC_IN)
+
+#define TARGET_IOC(inout, group, num, len) ((abi_ulong) \
+    ((inout) | (((len) & TARGET_IOCPARM_MASK) << 16) | ((group) << 8) \
+     | (num)))
+#define TARGET_IO(g, n)      TARGET_IOC(IOC_VOID,    (g), (n), 0)
+#define TARGET_IOWINT(g, n)  TARGET_IOC(IOC_VOID,    (g), (n), sizeof(int))
+#define TARGET_IOR(g, n, t)   TARGET_IOC(IOC_OUT, (g), (n), sizeof(t))
+#define TARGET_IOW(g, n, t)   TARGET_IOC(IOC_IN,  (g), (n), sizeof(t))
+/* this should be _IORW, but stdio got there first */
+#define TARGET_IOWR(g, n, t)  TARGET_IOC(IOC_INOUT,   (g), (n), sizeof(t))
+
+#endif /* !_IOCTL_IOCCOM_H_ */
diff --git a/bsd-user/netbsd/os-ioctl-ttycom.h b/bsd-user/netbsd/os-ioctl-ttycom.h
new file mode 100644
index 0000000..9086635
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-ttycom.h
@@ -0,0 +1,240 @@
+#ifndef _IOCTL_TTYCOM_H_
+#define _IOCTL_TTYCOM_H_
+
+/* XXX Needs to be fixed for NetBSD dependencies */
+
+#include "os-ioctl-ioccom.h"
+
+/* From sys/ttycom.h and sys/_termios.h */
+
+#define TARGET_VEOF     0   /* ICANON */
+#define TARGET_VEOL     1   /* ICANON */
+#define TARGET_VEOL2    2   /* ICANON together with IEXTEN */
+#define TARGET_VERASE   3   /* ICANON */
+#define TARGET_VWERASE  4   /* ICANON together with IEXTEN */
+#define TARGET_VKILL    5   /* ICANON */
+#define TARGET_VREPRINT 6   /* ICANON together with IEXTEN */
+#define TARGET_VERASE2  7   /* ICANON */
+#define TARGET_VINTR    8   /* ISIG */
+#define TARGET_VQUIT    9   /* ISIG */
+#define TARGET_VSUSP    10  /* ISIG */
+#define TARGET_VDSUSP   11  /* ISIG together with IEXTEN */
+#define TARGET_VSTART   12  /* IXON, IXOFF */
+#define TARGET_VSTOP    13  /* IXON, IXOFF */
+#define TARGET_VLNEXT   14  /* IEXTEN */
+#define TARGET_VDISCARD 15  /* IEXTEN */
+#define TARGET_VMIN     16  /* !ICANON */
+#define TARGET_VTIME    17  /* !ICANON */
+#define TARGET_VSTATUS  18  /* ICANON together with IEXTEN */
+/*                      19         spare 2 */
+#define TARGET_NCCS     20
+
+/*
+ * Input flags - software input processing
+ */
+#define TARGET_IGNBRK   0x00000001  /* ignore BREAK condition */
+#define TARGET_BRKINT   0x00000002  /* map BREAK to SIGINTR */
+#define TARGET_IGNPAR   0x00000004  /* ignore (discard) parity errors */
+#define TARGET_PARMRK   0x00000008  /* mark parity and framing errors */
+#define TARGET_INPCK    0x00000010  /* enable checking of parity errors */
+#define TARGET_ISTRIP   0x00000020  /* strip 8th bit off chars */
+#define TARGET_INLCR    0x00000040  /* map NL into CR */
+#define TARGET_IGNCR    0x00000080  /* ignore CR */
+#define TARGET_ICRNL    0x00000100  /* map CR to NL (ala CRMOD) */
+#define TARGET_IXON     0x00000200  /* enable output flow control */
+#define TARGET_IXOFF    0x00000400  /* enable input flow control */
+#define TARGET_IXANY    0x00000800  /* any char will restart after stop */
+#define TARGET_IMAXBEL  0x00002000  /* ring bell on input queue full */
+
+/*
+ * Output flags - software output processing
+ */
+#define TARGET_OPOST    0x00000001  /* enable following output processing */
+#define TARGET_ONLCR    0x00000002  /* map NL to CR-NL (ala CRMOD) */
+#define TARGET_TABDLY   0x00000004  /* tab delay mask */
+#define TARGET_TAB0     0x00000000  /* no tab delay and expansion */
+#define TARGET_TAB3     0x00000004  /* expand tabs to spaces */
+#define TARGET_ONOEOT   0x00000008  /* discard EOT's (^D) on output) */
+#define TARGET_OCRNL    0x00000010  /* map CR to NL on output */
+#define TARGET_ONOCR    0x00000020  /* no CR output at column 0 */
+#define TARGET_ONLRET   0x00000040  /* NL performs CR function */
+
+/*
+ * Control flags - hardware control of terminal
+ */
+#define TARGET_CIGNORE      0x00000001  /* ignore control flags */
+#define TARGET_CSIZE        0x00000300  /* character size mask */
+#define     TARGET_CS5      0x00000000  /* 5 bits (pseudo) */
+#define     TARGET_CS6      0x00000100  /* 6 bits */
+#define     TARGET_CS7      0x00000200  /* 7 bits */
+#define     TARGET_CS8      0x00000300  /* 8 bits */
+#define TARGET_CSTOPB       0x00000400  /* send 2 stop bits */
+#define TARGET_CREAD        0x00000800  /* enable receiver */
+#define TARGET_PARENB       0x00001000  /* parity enable */
+#define TARGET_PARODD       0x00002000  /* odd parity, else even */
+#define TARGET_HUPCL        0x00004000  /* hang up on last close */
+#define TARGET_CLOCAL       0x00008000  /* ignore modem status lines */
+#define TARGET_CCTS_OFLOW   0x00010000  /* CTS flow control of output */
+#define TARGET_CRTSCTS      (TARGET_CCTS_OFLOW | TARGET_CRTS_IFLOW)
+#define TARGET_CRTS_IFLOW   0x00020000  /* RTS flow control of input */
+#define TARGET_CDTR_IFLOW   0x00040000  /* DTR flow control of input */
+#define TARGET_CDSR_OFLOW   0x00080000  /* DSR flow control of output */
+#define TARGET_CCAR_OFLOW   0x00100000  /* DCD flow control of output */
+
+/*
+ * "Local" flags - dumping ground for other state
+ */
+#define TARGET_ECHOKE   0x00000001  /* visual erase for line kill */
+#define TARGET_ECHOE    0x00000002  /* visually erase chars */
+#define TARGET_ECHOK    0x00000004  /* echo NL after line kill */
+#define TARGET_ECHO 0x00000008  /* enable echoing */
+#define TARGET_ECHONL   0x00000010  /* echo NL even if ECHO is off */
+#define TARGET_ECHOPRT  0x00000020  /* visual erase mode for hardcopy */
+#define TARGET_ECHOCTL  0x00000040  /* echo control chars as ^(Char) */
+#define TARGET_ISIG 0x00000080  /* enable signals INTR, QUIT, [D]SUSP */
+#define TARGET_ICANON   0x00000100  /* canonicalize input lines */
+#define TARGET_ALTWERASE 0x00000200 /* use alternate WERASE algorithm */
+#define TARGET_IEXTEN   0x00000400  /* enable DISCARD and LNEXT */
+#define TARGET_EXTPROC  0x00000800  /* external processing */
+#define TARGET_TOSTOP   0x00400000  /* stop background jobs from output */
+#define TARGET_FLUSHO   0x00800000  /* output being flushed (state) */
+#define TARGET_NOKERNINFO 0x02000000    /* no kernel output from VSTATUS */
+#define TARGET_PENDIN   0x20000000  /* XXX retype pending input (state) */
+#define TARGET_NOFLSH   0x80000000  /* don't flush after interrupt */
+
+struct target_termios {
+    uint32_t c_iflag;   /* input flags */
+    uint32_t c_oflag;   /* output flags */
+    uint32_t c_cflag;   /* control flags */
+    uint32_t c_lflag;   /* local flags */
+    uint8_t  c_cc[TARGET_NCCS]; /* control chars */
+    uint32_t c_ispeed;  /* input speed */
+    uint32_t c_ospeed;  /* output speed */
+};
+
+
+struct target_winsize {
+    uint16_t ws_row;    /* rows, in characters */
+    uint16_t ws_col;    /* columns, in characters */
+    uint16_t ws_xpixel; /* horizontal size, pixels */
+    uint16_t ws_ypixel; /* vertical size, pixels */
+};
+
+                        /* 0-2 compat */
+                        /* 3-7 unused */
+                        /* 8-10 compat */
+                        /* 11-12 unused */
+#define TARGET_TIOCEXCL  TARGET_IO('t', 13) /* set exclusive use of tty */
+#define TARGET_TIOCNXCL  TARGET_IO('t', 14) /* reset exclusive use of tty */
+#define TARGET_TIOCGPTN  TARGET_IOR('t', 15, int) /* Get pts number. */
+#define TARGET_TIOCFLUSH TARGET_IOW('t', 16, int) /* flush buffers */
+                    /* 17-18 compat */
+/* get termios struct */
+#define TARGET_TIOCGETA TARGET_IOR('t', 19, struct target_termios)
+/* set termios struct */
+#define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios)
+/* drain output, set */
+#define TARGET_TIOCSETAW    TARGET_IOW('t', 21, struct target_termios)
+/* drn out, fls in, set */
+#define TARGET_TIOCSETAF    TARGET_IOW('t', 22, struct target_termios)
+                        /* 23-25 unused */
+#define TARGET_TIOCGETD TARGET_IOR('t', 26, int) /* get line discipline */
+#define TARGET_TIOCSETD TARGET_IOW('t', 27, int) /* set line discipline */
+#define TARGET_TIOCPTMASTER  TARGET_IO('t', 28) /* pts master validation */
+                    /* 29-85 unused */
+/* get ttywait timeout */
+#define TARGET_TIOCGDRAINWAIT   TARGET_IOR('t', 86, int)
+/* set ttywait timeout */
+#define TARGET_TIOCSDRAINWAIT   TARGET_IOW('t', 87, int)
+                    /* 88 unused */
+                    /* 89-91 conflicts: tun and tap */
+/* enable/get timestamp of last input event */
+#define TARGET_TIOCTIMESTAMP    TARGET_IOR('t', 89, struct target_timeval)
+/* modem: get wait on close */
+#define TARGET_TIOCMGDTRWAIT    TARGET_IOR('t', 90, int)
+/* modem: set wait on close */
+#define TARGET_TIOCMSDTRWAIT    TARGET_IOW('t', 91, int)
+                    /* 92-93 tun and tap */
+                    /* 94-97 conflicts: tun and tap */
+/* wait till output drained */
+#define TARGET_TIOCDRAIN     TARGET_IO('t', 94)
+ /* pty: generate signal */
+#define TARGET_TIOCSIG      TARGET_IOWINT('t', 95)
+/* pty: external processing */
+#define TARGET_TIOCEXT      TARGET_IOW('t', 96, int)
+/* become controlling tty */
+#define TARGET_TIOCSCTTY     TARGET_IO('t', 97)
+/* become virtual console */
+#define TARGET_TIOCCONS TARGET_IOW('t', 98, int)
+/* get session id */
+#define TARGET_TIOCGSID TARGET_IOR('t', 99, int)
+                        /* 100 unused */
+/* simulate ^T status message */
+#define TARGET_TIOCSTAT  TARGET_IO('t', 101)
+ /* pty: set/clr usr cntl mode */
+#define TARGET_TIOCUCNTL    TARGET_IOW('t', 102, int)
+/* usr cntl op "n" */
+#define TARGET_TIOCCMD(n)   TARGET_IO('u', n)
+/* set window size */
+#define TARGET_TIOCSWINSZ   TARGET_IOW('t', 103, struct target_winsize)
+/* get window size */
+#define TARGET_TIOCGWINSZ   TARGET_IOR('t', 104, struct target_winsize)
+                        /* 105 unused */
+/* get all modem bits */
+#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
+#define     TARGET_TIOCM_LE 0001        /* line enable */
+#define     TARGET_TIOCM_DTR    0002    /* data terminal ready */
+#define     TARGET_TIOCM_RTS    0004    /* request to send */
+#define     TARGET_TIOCM_ST 0010        /* secondary transmit */
+#define     TARGET_TIOCM_SR 0020        /* secondary receive */
+#define     TARGET_TIOCM_CTS    0040    /* clear to send */
+#define     TARGET_TIOCM_DCD    0100    /* data carrier detect */
+#define     TARGET_TIOCM_RI     0200    /* ring indicate */
+#define     TARGET_TIOCM_DSR    0400    /* data set ready */
+#define     TARGET_TIOCM_CD TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_CAR    TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_RNG    TARGET_TIOCM_RI
+#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) /* bic modem bits */
+#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) /* bis modem bits */
+#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) /* set all modem bits */
+/* start output, like ^Q */
+#define TARGET_TIOCSTART     TARGET_IO('t', 110)
+/* stop output, like ^S */
+#define TARGET_TIOCSTOP  TARGET_IO('t', 111)
+/* pty: set/clear packet mode */
+#define TARGET_TIOCPKT      TARGET_IOW('t', 112, int)
+#define     TARGET_TIOCPKT_DATA     0x00    /* data packet */
+#define     TARGET_TIOCPKT_FLUSHREAD    0x01    /* flush packet */
+#define     TARGET_TIOCPKT_FLUSHWRITE   0x02    /* flush packet */
+#define     TARGET_TIOCPKT_STOP     0x04    /* stop output */
+#define     TARGET_TIOCPKT_START        0x08    /* start output */
+#define     TARGET_TIOCPKT_NOSTOP       0x10    /* no more ^S, ^Q */
+#define     TARGET_TIOCPKT_DOSTOP       0x20    /* now do ^S ^Q */
+#define     TARGET_TIOCPKT_IOCTL        0x40    /* state change of pty
+                               driver */
+#define TARGET_TIOCNOTTY     TARGET_IO('t', 113)    /* void tty
+                               association */
+#define TARGET_TIOCSTI      TARGET_IOW('t', 114, char)  /* simulate
+                            terminal input */
+#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)   /* output queue size */
+                        /* 116-117 compat */
+#define TARGET_TIOCSPGRP    TARGET_IOW('t', 118, int) /* set pgrp of tty */
+#define TARGET_TIOCGPGRP    TARGET_IOR('t', 119, int) /* get pgrp of tty */
+#define TARGET_TIOCCDTR  TARGET_IO('t', 120)        /* clear data terminal
+                               ready */
+#define TARGET_TIOCSDTR  TARGET_IO('t', 121)        /* set data terminal
+                               ready */
+#define TARGET_TIOCCBRK  TARGET_IO('t', 122)        /* clear break bit */
+#define TARGET_TIOCSBRK  TARGET_IO('t', 123)        /* set break bit */
+                        /* 124-127 compat */
+
+#define TARGET_TTYDISC      0       /* termios tty line
+                           discipline */
+#define TARGET_SLIPDISC     4       /* serial IP discipline */
+#define TARGET_PPPDISC      5       /* PPP discipline */
+#define TARGET_NETGRAPHDISC 6       /* Netgraph tty node
+                           discipline */
+#define TARGET_H4DISC       7       /* Netgraph Bluetooth H4
+                           discipline */
+
+#endif /*! _IOCTL_TTYCOM_H_ */
diff --git a/bsd-user/netbsd/os-ioctl-types.h b/bsd-user/netbsd/os-ioctl-types.h
new file mode 100644
index 0000000..e761c20
--- /dev/null
+++ b/bsd-user/netbsd/os-ioctl-types.h
@@ -0,0 +1,7 @@
+/* XXX should be fixed for NetBSD types and structs */
+STRUCT_SPECIAL(termios)
+
+STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
+
+STRUCT(fiodgname_arg, TYPE_INT, TYPE_PTRVOID)
+
diff --git a/bsd-user/openbsd/os-ioctl-cmds.h b/bsd-user/openbsd/os-ioctl-cmds.h
new file mode 100644
index 0000000..a15f056
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-cmds.h
@@ -0,0 +1,48 @@
+/* XXX should be fixed for OpenBSD ioctl cmds */
+
+/* sys/ttycom.h tty(4) */
+IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCCBRK, IOC_, TYPE_NULL)
+IOCTL(TIOCSDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCCDTR, IOC_, TYPE_NULL)
+IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR))
+IOCTL(TIOCNOTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCSTOP, IOC_, TYPE_NULL)
+IOCTL(TIOCSTART, IOC_, TYPE_NULL)
+IOCTL(TIOCSCTTY, IOC_, TYPE_NULL)
+IOCTL(TIOCDRAIN, IOC_, TYPE_NULL)
+IOCTL(TIOCEXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCNXCL, IOC_, TYPE_NULL)
+IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
+
+/* sys/filio.h */
+IOCTL(FIOCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONCLEX, IOC_, TYPE_NULL)
+IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT))
+IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODTYPE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOGETLBA, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIODGNAME, IOC_R, MK_PTR(STRUCT_fiodgname_arg))
+IOCTL(FIONWRITE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIONSPACE, IOC_R, MK_PTR(TYPE_INT))
+IOCTL(FIOSEEKDATA, IOC_RW, MK_PTR(TYPE_ULONG))
+IOCTL(FIOSEEKHOLE, IOC_RW, MK_PTR(TYPE_ULONG))
diff --git a/bsd-user/openbsd/os-ioctl-filio.h b/bsd-user/openbsd/os-ioctl-filio.h
new file mode 100644
index 0000000..e3f7474
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-filio.h
@@ -0,0 +1,29 @@
+#ifndef _IOCTL_FILIO_H_
+#define _IOCTL_FILIO_H_
+
+/* XXX needs to be fixed for OpenBSD dependencies */
+
+/* see sys/filio.h */
+#define TARGET_FIOCLEX      TARGET_IO('f', 1)
+#define TARGET_FIONCLEX     TARGET_IO('f', 2)
+#define TARGET_FIONREAD     TARGET_IOR('f', 127, int)
+#define TARGET_FIONBIO      TARGET_IOW('f', 126, int)
+#define TARGET_FIOASYNC     TARGET_IOW('f', 125, int)
+#define TARGET_FIOSETOWN    TARGET_IOW('f', 124, int)
+#define TARGET_FIOGETOWN    TARGET_IOR('f', 123, int)
+#define TARGET_FIODTYPE     TARGET_IOR('f', 122, int)
+#define TARGET_FIOGETLBA    TARGET_IOR('f', 121, int)
+
+struct target_fiodgname_arg {
+    int32_t     len;
+    abi_ulong   buf;
+};
+
+#define TARGET_FIODGNAME    TARGET_IOW('f', 120,    \
+                struct target_fiodgname_arg)
+#define TARGET_FIONWRITE    TARGET_IOR('f', 119, int)
+#define TARGET_FIONSPACE    TARGET_IOR('f', 118, int)
+#define TARGET_FIOSEEKDATA  TARGET_IOWR('f', 97, off_t)
+#define TARGET_FIOSEEKHOLE  TARGET_IOWR('f', 98, off_t)
+
+#endif /* !_IOCTL_FILIO_H_ */
diff --git a/bsd-user/openbsd/os-ioctl-ioccom.h b/bsd-user/openbsd/os-ioctl-ioccom.h
new file mode 100644
index 0000000..fa1c6b4
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-ioccom.h
@@ -0,0 +1,38 @@
+#ifndef _IOCTL_IOCCOM_H_
+#define _IOCTL_IOCCOM_H_
+
+/* XXX needs to be fixed for OpenBSD dependencies */
+
+/*
+ * Ioctl's have the command encoded in the lower word, and the size of
+ * any in or out parameters in the upper word.  The high 3 bits of the
+ * upper word are used to encode the in/out status of the parameter.
+ */
+/* number of bits for ioctl size */
+#define TARGET_IOCPARM_SHIFT    13
+
+/* parameter length mask */
+#define TARGET_IOCPARM_MASK ((1 << TARGET_IOCPARM_SHIFT) - 1)
+
+#define TARGET_IOCPARM_LEN(x)   (((x) >> 16) & TARGET_IOCPARM_MASK)
+#define TARGET_IOCBASECMD(x)    ((x) & ~(TARGET_IOCPARM_MASK << 16))
+#define TARGET_IOCGROUP(x)  (((x) >> 8) & 0xff)
+
+#define TARGET_IOCPARM_MAX  (1 << TARGET_IOCPARM_SHIFT) /* max size of ioctl */
+#define TARGET_IOC_VOID     0x20000000  /* no parameters */
+#define TARGET_IOC_OUT      0x40000000  /* copy out parameters */
+#define TARGET_IOC_IN       0x80000000  /* copy in parameters */
+#define TARGET_IOC_INOUT    (TARGET_IOC_IN|TARGET_IOC_OUT)
+#define TARGET_IOC_DIRMASK  (TARGET_IOC_VOID|TARGET_IOC_OUT|TARGET_IOC_IN)
+
+#define TARGET_IOC(inout, group, num, len) ((abi_ulong) \
+    ((inout) | (((len) & TARGET_IOCPARM_MASK) << 16) | ((group) << 8) \
+     | (num)))
+#define TARGET_IO(g, n)       TARGET_IOC(IOC_VOID,    (g), (n), 0)
+#define TARGET_IOWINT(g, n)   TARGET_IOC(IOC_VOID,    (g), (n), sizeof(int))
+#define TARGET_IOR(g, n, t)   TARGET_IOC(IOC_OUT, (g), (n), sizeof(t))
+#define TARGET_IOW(g, n, t)   TARGET_IOC(IOC_IN,  (g), (n), sizeof(t))
+/* this should be _IORW, but stdio got there first */
+#define TARGET_IOWR(g, n, t)  TARGET_IOC(IOC_INOUT,   (g), (n), sizeof(t))
+
+#endif /* !_IOCTL_IOCCOM_H_ */
diff --git a/bsd-user/openbsd/os-ioctl-ttycom.h b/bsd-user/openbsd/os-ioctl-ttycom.h
new file mode 100644
index 0000000..745d702
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-ttycom.h
@@ -0,0 +1,240 @@
+#ifndef _IOCTL_TTYCOM_H_
+#define _IOCTL_TTYCOM_H_
+
+/* XXX Needs to be fixed for OpenBSD dependencies */
+
+#include "os-ioctl-ioccom.h"
+
+/* From sys/ttycom.h and sys/_termios.h */
+
+#define TARGET_VEOF     0   /* ICANON */
+#define TARGET_VEOL     1   /* ICANON */
+#define TARGET_VEOL2    2   /* ICANON together with IEXTEN */
+#define TARGET_VERASE   3   /* ICANON */
+#define TARGET_VWERASE  4   /* ICANON together with IEXTEN */
+#define TARGET_VKILL    5   /* ICANON */
+#define TARGET_VREPRINT 6   /* ICANON together with IEXTEN */
+#define TARGET_VERASE2  7   /* ICANON */
+#define TARGET_VINTR    8   /* ISIG */
+#define TARGET_VQUIT    9   /* ISIG */
+#define TARGET_VSUSP    10  /* ISIG */
+#define TARGET_VDSUSP   11  /* ISIG together with IEXTEN */
+#define TARGET_VSTART   12  /* IXON, IXOFF */
+#define TARGET_VSTOP    13  /* IXON, IXOFF */
+#define TARGET_VLNEXT   14  /* IEXTEN */
+#define TARGET_VDISCARD 15  /* IEXTEN */
+#define TARGET_VMIN     16  /* !ICANON */
+#define TARGET_VTIME    17  /* !ICANON */
+#define TARGET_VSTATUS  18  /* ICANON together with IEXTEN */
+/*                      19         spare 2 */
+#define TARGET_NCCS     20
+
+/*
+ * Input flags - software input processing
+ */
+#define TARGET_IGNBRK   0x00000001  /* ignore BREAK condition */
+#define TARGET_BRKINT   0x00000002  /* map BREAK to SIGINTR */
+#define TARGET_IGNPAR   0x00000004  /* ignore (discard) parity errors */
+#define TARGET_PARMRK   0x00000008  /* mark parity and framing errors */
+#define TARGET_INPCK    0x00000010  /* enable checking of parity errors */
+#define TARGET_ISTRIP   0x00000020  /* strip 8th bit off chars */
+#define TARGET_INLCR    0x00000040  /* map NL into CR */
+#define TARGET_IGNCR    0x00000080  /* ignore CR */
+#define TARGET_ICRNL    0x00000100  /* map CR to NL (ala CRMOD) */
+#define TARGET_IXON     0x00000200  /* enable output flow control */
+#define TARGET_IXOFF    0x00000400  /* enable input flow control */
+#define TARGET_IXANY    0x00000800  /* any char will restart after stop */
+#define TARGET_IMAXBEL  0x00002000  /* ring bell on input queue full */
+
+/*
+ * Output flags - software output processing
+ */
+#define TARGET_OPOST    0x00000001  /* enable following output processing */
+#define TARGET_ONLCR    0x00000002  /* map NL to CR-NL (ala CRMOD) */
+#define TARGET_TABDLY   0x00000004  /* tab delay mask */
+#define TARGET_TAB0     0x00000000  /* no tab delay and expansion */
+#define TARGET_TAB3     0x00000004  /* expand tabs to spaces */
+#define TARGET_ONOEOT   0x00000008  /* discard EOT's (^D) on output) */
+#define TARGET_OCRNL    0x00000010  /* map CR to NL on output */
+#define TARGET_ONOCR    0x00000020  /* no CR output at column 0 */
+#define TARGET_ONLRET   0x00000040  /* NL performs CR function */
+
+/*
+ * Control flags - hardware control of terminal
+ */
+#define TARGET_CIGNORE      0x00000001  /* ignore control flags */
+#define TARGET_CSIZE        0x00000300  /* character size mask */
+#define     TARGET_CS5      0x00000000  /* 5 bits (pseudo) */
+#define     TARGET_CS6      0x00000100  /* 6 bits */
+#define     TARGET_CS7      0x00000200  /* 7 bits */
+#define     TARGET_CS8      0x00000300  /* 8 bits */
+#define TARGET_CSTOPB       0x00000400  /* send 2 stop bits */
+#define TARGET_CREAD        0x00000800  /* enable receiver */
+#define TARGET_PARENB       0x00001000  /* parity enable */
+#define TARGET_PARODD       0x00002000  /* odd parity, else even */
+#define TARGET_HUPCL        0x00004000  /* hang up on last close */
+#define TARGET_CLOCAL       0x00008000  /* ignore modem status lines */
+#define TARGET_CCTS_OFLOW   0x00010000  /* CTS flow control of output */
+#define TARGET_CRTSCTS      (TARGET_CCTS_OFLOW | TARGET_CRTS_IFLOW)
+#define TARGET_CRTS_IFLOW   0x00020000  /* RTS flow control of input */
+#define TARGET_CDTR_IFLOW   0x00040000  /* DTR flow control of input */
+#define TARGET_CDSR_OFLOW   0x00080000  /* DSR flow control of output */
+#define TARGET_CCAR_OFLOW   0x00100000  /* DCD flow control of output */
+
+/*
+ * "Local" flags - dumping ground for other state
+ */
+#define TARGET_ECHOKE   0x00000001  /* visual erase for line kill */
+#define TARGET_ECHOE    0x00000002  /* visually erase chars */
+#define TARGET_ECHOK    0x00000004  /* echo NL after line kill */
+#define TARGET_ECHO 0x00000008  /* enable echoing */
+#define TARGET_ECHONL   0x00000010  /* echo NL even if ECHO is off */
+#define TARGET_ECHOPRT  0x00000020  /* visual erase mode for hardcopy */
+#define TARGET_ECHOCTL  0x00000040  /* echo control chars as ^(Char) */
+#define TARGET_ISIG 0x00000080  /* enable signals INTR, QUIT, [D]SUSP */
+#define TARGET_ICANON   0x00000100  /* canonicalize input lines */
+#define TARGET_ALTWERASE 0x00000200 /* use alternate WERASE algorithm */
+#define TARGET_IEXTEN   0x00000400  /* enable DISCARD and LNEXT */
+#define TARGET_EXTPROC  0x00000800  /* external processing */
+#define TARGET_TOSTOP   0x00400000  /* stop background jobs from output */
+#define TARGET_FLUSHO   0x00800000  /* output being flushed (state) */
+#define TARGET_NOKERNINFO 0x02000000    /* no kernel output from VSTATUS */
+#define TARGET_PENDIN   0x20000000  /* XXX retype pending input (state) */
+#define TARGET_NOFLSH   0x80000000  /* don't flush after interrupt */
+
+struct target_termios {
+    uint32_t c_iflag;   /* input flags */
+    uint32_t c_oflag;   /* output flags */
+    uint32_t c_cflag;   /* control flags */
+    uint32_t c_lflag;   /* local flags */
+    uint8_t  c_cc[TARGET_NCCS]; /* control chars */
+    uint32_t c_ispeed;  /* input speed */
+    uint32_t c_ospeed;  /* output speed */
+};
+
+
+struct target_winsize {
+    uint16_t ws_row;    /* rows, in characters */
+    uint16_t ws_col;    /* columns, in characters */
+    uint16_t ws_xpixel; /* horizontal size, pixels */
+    uint16_t ws_ypixel; /* vertical size, pixels */
+};
+
+                        /* 0-2 compat */
+                        /* 3-7 unused */
+                        /* 8-10 compat */
+                        /* 11-12 unused */
+#define TARGET_TIOCEXCL  TARGET_IO('t', 13) /* set exclusive use of tty */
+#define TARGET_TIOCNXCL  TARGET_IO('t', 14) /* reset exclusive use of tty */
+#define TARGET_TIOCGPTN  TARGET_IOR('t', 15, int) /* Get pts number. */
+#define TARGET_TIOCFLUSH TARGET_IOW('t', 16, int) /* flush buffers */
+                    /* 17-18 compat */
+/* get termios struct */
+#define TARGET_TIOCGETA TARGET_IOR('t', 19, struct target_termios)
+/* set termios struct */
+#define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios)
+/* drain output, set */
+#define TARGET_TIOCSETAW    TARGET_IOW('t', 21, struct target_termios)
+/* drn out, fls in, set */
+#define TARGET_TIOCSETAF    TARGET_IOW('t', 22, struct target_termios)
+                        /* 23-25 unused */
+#define TARGET_TIOCGETD TARGET_IOR('t', 26, int) /* get line discipline */
+#define TARGET_TIOCSETD TARGET_IOW('t', 27, int) /* set line discipline */
+#define TARGET_TIOCPTMASTER  TARGET_IO('t', 28) /* pts master validation */
+                    /* 29-85 unused */
+/* get ttywait timeout */
+#define TARGET_TIOCGDRAINWAIT   TARGET_IOR('t', 86, int)
+/* set ttywait timeout */
+#define TARGET_TIOCSDRAINWAIT   TARGET_IOW('t', 87, int)
+                    /* 88 unused */
+                    /* 89-91 conflicts: tun and tap */
+/* enable/get timestamp of last input event */
+#define TARGET_TIOCTIMESTAMP    TARGET_IOR('t', 89, struct target_timeval)
+/* modem: get wait on close */
+#define TARGET_TIOCMGDTRWAIT    TARGET_IOR('t', 90, int)
+/* modem: set wait on close */
+#define TARGET_TIOCMSDTRWAIT    TARGET_IOW('t', 91, int)
+                    /* 92-93 tun and tap */
+                    /* 94-97 conflicts: tun and tap */
+/* wait till output drained */
+#define TARGET_TIOCDRAIN     TARGET_IO('t', 94)
+ /* pty: generate signal */
+#define TARGET_TIOCSIG      TARGET_IOWINT('t', 95)
+/* pty: external processing */
+#define TARGET_TIOCEXT      TARGET_IOW('t', 96, int)
+/* become controlling tty */
+#define TARGET_TIOCSCTTY     TARGET_IO('t', 97)
+/* become virtual console */
+#define TARGET_TIOCCONS TARGET_IOW('t', 98, int)
+/* get session id */
+#define TARGET_TIOCGSID TARGET_IOR('t', 99, int)
+                        /* 100 unused */
+/* simulate ^T status message */
+#define TARGET_TIOCSTAT  TARGET_IO('t', 101)
+ /* pty: set/clr usr cntl mode */
+#define TARGET_TIOCUCNTL    TARGET_IOW('t', 102, int)
+/* usr cntl op "n" */
+#define TARGET_TIOCCMD(n)   TARGET_IO('u', n)
+/* set window size */
+#define TARGET_TIOCSWINSZ   TARGET_IOW('t', 103, struct target_winsize)
+/* get window size */
+#define TARGET_TIOCGWINSZ   TARGET_IOR('t', 104, struct target_winsize)
+                        /* 105 unused */
+/* get all modem bits */
+#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
+#define     TARGET_TIOCM_LE 0001        /* line enable */
+#define     TARGET_TIOCM_DTR    0002    /* data terminal ready */
+#define     TARGET_TIOCM_RTS    0004    /* request to send */
+#define     TARGET_TIOCM_ST 0010        /* secondary transmit */
+#define     TARGET_TIOCM_SR 0020        /* secondary receive */
+#define     TARGET_TIOCM_CTS    0040    /* clear to send */
+#define     TARGET_TIOCM_DCD    0100    /* data carrier detect */
+#define     TARGET_TIOCM_RI     0200    /* ring indicate */
+#define     TARGET_TIOCM_DSR    0400    /* data set ready */
+#define     TARGET_TIOCM_CD TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_CAR    TARGET_TIOCM_DCD
+#define     TARGET_TIOCM_RNG    TARGET_TIOCM_RI
+#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) /* bic modem bits */
+#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) /* bis modem bits */
+#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) /* set all modem bits */
+/* start output, like ^Q */
+#define TARGET_TIOCSTART     TARGET_IO('t', 110)
+/* stop output, like ^S */
+#define TARGET_TIOCSTOP  TARGET_IO('t', 111)
+/* pty: set/clear packet mode */
+#define TARGET_TIOCPKT      TARGET_IOW('t', 112, int)
+#define     TARGET_TIOCPKT_DATA     0x00    /* data packet */
+#define     TARGET_TIOCPKT_FLUSHREAD    0x01    /* flush packet */
+#define     TARGET_TIOCPKT_FLUSHWRITE   0x02    /* flush packet */
+#define     TARGET_TIOCPKT_STOP     0x04    /* stop output */
+#define     TARGET_TIOCPKT_START        0x08    /* start output */
+#define     TARGET_TIOCPKT_NOSTOP       0x10    /* no more ^S, ^Q */
+#define     TARGET_TIOCPKT_DOSTOP       0x20    /* now do ^S ^Q */
+#define     TARGET_TIOCPKT_IOCTL        0x40    /* state change of pty
+                               driver */
+#define TARGET_TIOCNOTTY     TARGET_IO('t', 113)    /* void tty
+                               association */
+#define TARGET_TIOCSTI      TARGET_IOW('t', 114, char)  /* simulate
+                            terminal input */
+#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)   /* output queue size */
+                        /* 116-117 compat */
+#define TARGET_TIOCSPGRP    TARGET_IOW('t', 118, int) /* set pgrp of tty */
+#define TARGET_TIOCGPGRP    TARGET_IOR('t', 119, int) /* get pgrp of tty */
+#define TARGET_TIOCCDTR  TARGET_IO('t', 120)        /* clear data terminal
+                               ready */
+#define TARGET_TIOCSDTR  TARGET_IO('t', 121)        /* set data terminal
+                               ready */
+#define TARGET_TIOCCBRK  TARGET_IO('t', 122)        /* clear break bit */
+#define TARGET_TIOCSBRK  TARGET_IO('t', 123)        /* set break bit */
+                        /* 124-127 compat */
+
+#define TARGET_TTYDISC      0       /* termios tty line
+                           discipline */
+#define TARGET_SLIPDISC     4       /* serial IP discipline */
+#define TARGET_PPPDISC      5       /* PPP discipline */
+#define TARGET_NETGRAPHDISC 6       /* Netgraph tty node
+                           discipline */
+#define TARGET_H4DISC       7       /* Netgraph Bluetooth H4
+                           discipline */
+
+#endif /*! _IOCTL_TTYCOM_H_ */
diff --git a/bsd-user/openbsd/os-ioctl-types.h b/bsd-user/openbsd/os-ioctl-types.h
new file mode 100644
index 0000000..6f8b97b
--- /dev/null
+++ b/bsd-user/openbsd/os-ioctl-types.h
@@ -0,0 +1,7 @@
+/* XXX should be fixed for OpenBSD types and structs */
+STRUCT_SPECIAL(termios)
+
+STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
+
+STRUCT(fiodgname_arg, TYPE_INT, TYPE_PTRVOID)
+
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 4b2add2..10d0fc4 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -36,6 +36,7 @@ enum BSDType {
 };
 extern enum BSDType bsd_type;
 
+#include "exec/user/thunk.h"
 #include "syscall_defs.h"
 #include "syscall.h"
 #include "target_os_vmparam.h"
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 0a851fe..6cd7dbd 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -35,6 +35,7 @@
 
 /* BSD independent syscall shims */
 #include "bsd-file.h"
+#include "bsd-ioctl.h"
 #include "bsd-mem.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
@@ -81,16 +82,18 @@ int is_error(abi_long ret)
  * 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)
+        int count, int copy)
 {
     struct target_iovec *target_vec;
     abi_ulong base;
     int i;
 
-    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
-    if (!target_vec)
+    target_vec = lock_user(VERIFY_READ, target_addr,
+            count * sizeof(struct target_iovec), 1);
+    if (!target_vec) {
         return -TARGET_EFAULT;
-    for(i = 0;i < count; i++) {
+    }
+    for (i = 0; i < count; i++) {
         base = tswapl(target_vec[i].iov_base);
         vec[i].iov_len = tswapl(target_vec[i].iov_len);
         if (vec[i].iov_len != 0) {
@@ -107,16 +110,17 @@ static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
 }
 
 static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
-                             int count, int copy)
+        int count, int copy)
 {
     struct target_iovec *target_vec;
     abi_ulong base;
     int i;
 
-    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
+    target_vec = lock_user(VERIFY_READ, target_addr,
+            count * sizeof(struct target_iovec), 1);
     if (!target_vec)
         return -TARGET_EFAULT;
-    for(i = 0;i < count; i++) {
+    for (i = 0; i < count; i++) {
         if (target_vec[i].iov_base) {
             base = tswapl(target_vec[i].iov_base);
             unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
@@ -1177,6 +1181,13 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
         /*
+         * ioctl(2)
+         */
+    case TARGET_FREEBSD_NR_ioctl: /* ioctl(2) */
+        ret = do_bsd_ioctl(arg1, arg2, arg3);
+        break;
+
+        /*
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
@@ -1309,4 +1320,6 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
 
 void syscall_init(void)
 {
+
+    init_bsd_ioctl();
 }
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 16/19] bsd-user: add support for extattr and ACL related syscalls
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (16 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 15/19] bsd-user: add support for the ioctl system call Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 17/19] bsd-user: add support for miscellaneous system calls Stacey Son
                     ` (2 subsequent siblings)
  20 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change add support for extended attribute and Access
Control List (ACL) related system calls including extattrctl(),
extattr_set_file(2), extattr_delete_file(2), extattr_set_fd(2),
extattr_get_fd(2), extattr_delete_fd(2), extattr_get_link(2),
extattr_set_link(2), extattr_delete_link(2), extattr_list_fd(2),
extattr_list_file(2), extattr_list_link(2), __acl_aclcheck_fd(),
__acl_aclcheck_file(), __acl_aclcheck_link(), __acl_delete_fd(),
__acl_delete_file(), __acl_delete_link(), __acl_get_fd(),
__acl_get_file(), __acl_get_link(), __acl_get_fd(),
__acl_set_file(), and __acl_set_link().
---
 bsd-user/Makefile.objs        |    2 +-
 bsd-user/freebsd/os-extattr.c |  118 ++++++++
 bsd-user/freebsd/os-extattr.h |  654 +++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h    |    6 +
 bsd-user/netbsd/os-extattr.h  |  247 ++++++++++++++++
 bsd-user/openbsd/os-extattr.h |  247 ++++++++++++++++
 bsd-user/syscall.c            |  104 +++++++
 7 files changed, 1377 insertions(+), 1 deletions(-)
 create mode 100644 bsd-user/freebsd/os-extattr.c
 create mode 100644 bsd-user/freebsd/os-extattr.h
 create mode 100644 bsd-user/netbsd/os-extattr.h
 create mode 100644 bsd-user/openbsd/os-extattr.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index a6dba89..d2e005b 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,6 +1,6 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
 	        uaccess.o bsd-ioctl.o bsd-mem.o bsd-proc.o bsd-socket.o \
-			$(HOST_VARIANT_DIR)/os-proc.o \
+			$(HOST_VARIANT_DIR)/os-extattr.o $(HOST_VARIANT_DIR)/os-proc.o \
 			$(HOST_VARIANT_DIR)/os-socket.o $(HOST_VARIANT_DIR)/os-stat.o \
 			$(HOST_VARIANT_DIR)/os-sys.o $(HOST_VARIANT_DIR)/os-thread.o \
 			$(HOST_VARIANT_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/freebsd/os-extattr.c b/bsd-user/freebsd/os-extattr.c
new file mode 100644
index 0000000..95e7b24
--- /dev/null
+++ b/bsd-user/freebsd/os-extattr.c
@@ -0,0 +1,118 @@
+/*
+ *  FreeBSD extend attributes and ACL conversions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#ifndef _ACL_PRIVATE
+#define _ACL_PRIVATE
+#endif
+#include <sys/acl.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+/*
+ * FreeBSD ACL conversion.
+ */
+abi_long t2h_freebsd_acl(struct acl *host_acl, abi_ulong target_addr)
+{
+    uint32_t i;
+    struct target_freebsd_acl *target_acl;
+
+    if (!lock_user_struct(VERIFY_READ, target_acl, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt);
+    __get_user(host_acl->acl_cnt, &target_acl->acl_cnt);
+
+    for (i = 0; i < host_acl->acl_maxcnt; i++) {
+        __get_user(host_acl->acl_entry[i].ae_tag,
+            &target_acl->acl_entry[i].ae_tag);
+        __get_user(host_acl->acl_entry[i].ae_id,
+            &target_acl->acl_entry[i].ae_id);
+        __get_user(host_acl->acl_entry[i].ae_perm,
+            &target_acl->acl_entry[i].ae_perm);
+        __get_user(host_acl->acl_entry[i].ae_entry_type,
+            &target_acl->acl_entry[i].ae_entry_type);
+        __get_user(host_acl->acl_entry[i].ae_flags,
+            &target_acl->acl_entry[i].ae_flags);
+    }
+
+    unlock_user_struct(target_acl, target_addr, 0);
+    return 0;
+}
+
+abi_long h2t_freebsd_acl(abi_ulong target_addr, struct acl *host_acl)
+{
+    uint32_t i;
+    struct target_freebsd_acl *target_acl;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_acl, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    __put_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt);
+    __put_user(host_acl->acl_cnt, &target_acl->acl_cnt);
+
+    for (i = 0; i < host_acl->acl_maxcnt; i++) {
+        __put_user(host_acl->acl_entry[i].ae_tag,
+            &target_acl->acl_entry[i].ae_tag);
+        __put_user(host_acl->acl_entry[i].ae_id,
+            &target_acl->acl_entry[i].ae_id);
+        __put_user(host_acl->acl_entry[i].ae_perm,
+            &target_acl->acl_entry[i].ae_perm);
+        __put_user(host_acl->acl_entry[i].ae_entry_type,
+            &target_acl->acl_entry[i].ae_entry_type);
+        __put_user(host_acl->acl_entry[i].ae_flags,
+            &target_acl->acl_entry[i].ae_flags);
+    }
+
+    unlock_user_struct(target_acl, target_addr, 1);
+    return 0;
+}
+
+abi_long t2h_freebsd_acl_type(acl_type_t *host_type, abi_long target_type)
+{
+
+    switch (target_type) {
+    case TARGET_FREEBSD_ACL_TYPE_ACCESS_OLD:
+        *host_type = ACL_TYPE_ACCESS_OLD;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_DEFAULT_OLD:
+        *host_type = ACL_TYPE_DEFAULT_OLD;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_ACCESS:
+        *host_type = ACL_TYPE_ACCESS;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_DEFAULT:
+        *host_type = ACL_TYPE_ACCESS;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_NFS4:
+        *host_type = ACL_TYPE_NFS4;
+        break;
+
+    default:
+        return -TARGET_EINVAL;
+    }
+    return 0;
+}
+
diff --git a/bsd-user/freebsd/os-extattr.h b/bsd-user/freebsd/os-extattr.h
new file mode 100644
index 0000000..2e45f42
--- /dev/null
+++ b/bsd-user/freebsd/os-extattr.h
@@ -0,0 +1,654 @@
+/*
+ *  FreeBSD extended attributes and ACL system call support
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/extattr.h>
+#ifndef _ACL_PRIVATE
+#define _ACL_PRIVATE
+#endif
+#include <sys/acl.h>
+
+#include "qemu-os.h"
+
+/* extattrctl() */
+static inline abi_long do_freebsd_extattrctl(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *p, *a, *f;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    f = lock_user_string(arg3);
+    if (f == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg5);
+    if (a == NULL) {
+        unlock_user(f, arg3, 0);
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattrctl(path(p), arg2, f, arg4, a));
+    unlock_user(a, arg5, 0);
+    unlock_user(f, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_set_file(2) */
+static inline abi_long do_freebsd_extattr_set_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    d = lock_user(VERIFY_READ, arg4, arg5, 1);
+    if (d == NULL) {
+        unlock_user(a, arg3, 0);
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_set_file(path(p), arg2, a, d, arg5));
+    unlock_user(d, arg4, arg5);
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_get_file(2) */
+static inline abi_long do_freebsd_extattr_get_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    if (arg4 && arg5 > 0) {
+        d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
+        if (d == NULL) {
+            unlock_user(a, arg3, 0);
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_get_file(path(p), arg2, a, d, arg5));
+        unlock_user(d, arg4, arg5);
+    } else {
+        ret = get_errno(extattr_get_file(path(p), arg2, a, NULL, arg5));
+    }
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_delete_file(2) */
+static inline abi_long do_freebsd_extattr_delete_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *p, *a;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_delete_file(path(p), arg2, a));
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_set_fd(2) */
+static inline abi_long do_freebsd_extattr_set_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *a, *d;
+
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+    d = lock_user(VERIFY_READ, arg4, arg5, 1);
+    if (d == NULL) {
+        unlock_user(a, arg3, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_set_fd(arg1, arg2, a, d, arg5));
+    unlock_user(d, arg4, arg5);
+    unlock_user(a, arg3, 0);
+
+    return ret;
+}
+
+/* extattr_get_fd(2) */
+static inline abi_long do_freebsd_extattr_get_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void *a, *d;
+
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+
+    if (arg4 && arg5 > 0) {
+        d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
+        if (d == NULL) {
+            unlock_user(a, arg3, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_get_fd(arg1, arg2, a, d, arg5));
+        unlock_user(d, arg4, arg5);
+    } else {
+        ret = get_errno(extattr_get_fd(arg1, arg2, a, NULL, arg5));
+    }
+    unlock_user(a, arg3, 0);
+
+    return ret;
+}
+
+/* extattr_delete_fd(2) */
+static inline abi_long do_freebsd_extattr_delete_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *a;
+
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_delete_fd(arg1, arg2, a));
+    unlock_user(a, arg3, 0);
+
+    return ret;
+}
+
+/* extattr_get_link(2) */
+static inline abi_long do_freebsd_extattr_get_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void  *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    if (arg4 && arg5 > 0) {
+        d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
+        if (d == NULL) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_get_link(path(p), arg2, a, d, arg5));
+        unlock_user(d, arg4, arg5);
+    } else {
+        ret = get_errno(extattr_get_link(path(p), arg2, a, NULL, arg5));
+    }
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_set_link(2) */
+static inline abi_long do_freebsd_extattr_set_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    void  *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    d = lock_user(VERIFY_READ, arg4, arg5, 1);
+    if (d == NULL) {
+        unlock_user(a, arg3, 0);
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_set_link(path(p), arg2, a, d, arg5));
+    unlock_user(d, arg4, arg5);
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_delete_link(2) */
+static inline abi_long do_freebsd_extattr_delete_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *p, *a;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_delete_link(path(p), arg2, a));
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_list_fd(2) */
+static inline abi_long do_freebsd_extattr_list_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3, abi_ulong arg4)
+{
+    abi_long ret;
+    void *d;
+
+    if (arg3 && arg4 > 0) {
+        d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+        if (d == NULL) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_list_fd(arg1, arg2, d, arg4));
+        unlock_user(d, arg3, arg4);
+    } else {
+        ret = get_errno(extattr_list_fd(arg1, arg2, NULL, arg4));
+    }
+    return ret;
+}
+
+/* extattr_list_file(2) */
+static inline abi_long do_freebsd_extattr_list_file(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+    abi_long ret;
+    void *p, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (arg3 && arg4 > 0) {
+        d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+        if (d == NULL) {
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_list_file(path(p), arg2, d, arg4));
+        unlock_user(d, arg3, arg4);
+    } else {
+        ret = get_errno(extattr_list_file(path(p), arg2, NULL, arg4));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_list_link(2) */
+static inline abi_long do_freebsd_extattr_list_link(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+    abi_long ret;
+    void *p, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (arg3 && arg4 > 0) {
+        d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+        if (d == NULL) {
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_list_link(path(p), arg2, d, arg4));
+        unlock_user(d, arg3, arg4);
+    } else {
+        ret = get_errno(extattr_list_link(path(p), arg2, NULL, arg4));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/*
+ *  Access Control Lists
+ */
+
+/* __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_fd(abi_long arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    struct acl host_acl;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_aclcheck_fd(arg1, type, &host_acl));
+    }
+
+    return ret;
+}
+
+/* __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    struct acl host_acl;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_aclcheck_file(path(p) , arg2, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    struct acl host_acl;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_aclcheck_link(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_delete_fd(int filedes, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_fd(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    return get_errno(__acl_delete_fd(arg1, type));
+}
+
+/* int __acl_delete_file(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_file(abi_ulong arg1,
+        abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_delete_file(path(p), type));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_delete_link(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_link(abi_ulong arg1,
+        abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_delete_link(path(p), type));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    acl_type_t type;
+    struct acl host_acl;
+
+    bzero(&host_acl, sizeof(struct acl));
+    host_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = get_errno(__acl_get_fd(arg1, type, &host_acl));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_acl(arg3, &host_acl);
+    }
+
+    return ret;
+}
+
+/* __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    bzero(&host_acl, sizeof(struct acl));
+    host_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+	return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_get_file(path(p), type, &host_acl));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_acl(arg3, &host_acl);
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    bzero(&host_acl, sizeof(struct acl));
+    host_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_get_link(path(p), type, &host_acl));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_acl(arg3, &host_acl);
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_set_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_set_fd(arg1, type, &host_acl));
+    }
+
+    return ret;
+}
+
+/* int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_set_file(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_set_link(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index b5510dc..7d79e52 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -70,4 +70,10 @@ abi_long h2t_freebsd_rtprio(abi_ulong target_addr, struct rtprio *host_rtp);
 abi_long do_freebsd_thr_new(CPUArchState *env, abi_ulong target_param_addr,
         int32_t param_size);
 
+/* os-extattr.c */
+struct acl;
+abi_long t2h_freebsd_acl(struct acl *host_acl, abi_ulong target_addr);
+abi_long h2t_freebsd_acl(abi_ulong target_addr, struct acl *host_acl);
+abi_long t2h_freebsd_acl_type(acl_type_t *host_type, abi_long target_type);
+
 #endif /* !_QEMU_OS_H_ */
diff --git a/bsd-user/netbsd/os-extattr.h b/bsd-user/netbsd/os-extattr.h
new file mode 100644
index 0000000..c2f42ac
--- /dev/null
+++ b/bsd-user/netbsd/os-extattr.h
@@ -0,0 +1,247 @@
+/*
+ *  NetBSD extended attributes and ACL system call support
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* XXX To support FreeBSD targets the following will need to be added. */
+
+/* extattrctl() */
+static inline abi_long do_freebsd_extattrctl(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattrctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_file(2) */
+static inline abi_long do_freebsd_extattr_set_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_file(2) */
+static inline abi_long do_freebsd_extattr_get_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_file(2) */
+static inline abi_long do_freebsd_extattr_delete_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_fd(2) */
+static inline abi_long do_freebsd_extattr_set_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_fd(2) */
+static inline abi_long do_freebsd_extattr_get_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_fd(2) */
+static inline abi_long do_freebsd_extattr_delete_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_link(2) */
+static inline abi_long do_freebsd_extattr_get_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_link(2) */
+static inline abi_long do_freebsd_extattr_set_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_link(2) */
+static inline abi_long do_freebsd_extattr_delete_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_fd(2) */
+static inline abi_long do_freebsd_extattr_list_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall exattr_list_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_file(2) */
+static inline abi_long do_freebsd_extattr_list_file(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_list_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_link(2) */
+static inline abi_long do_freebsd_extattr_list_link(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_list_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ *  Access Control Lists
+ */
+
+/* __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_fd(abi_long arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_fd(int filedes, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_fd(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_file(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_file(abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_fil()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_link(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_link(abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall _acl_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
diff --git a/bsd-user/openbsd/os-extattr.h b/bsd-user/openbsd/os-extattr.h
new file mode 100644
index 0000000..5c23af3
--- /dev/null
+++ b/bsd-user/openbsd/os-extattr.h
@@ -0,0 +1,247 @@
+/*
+ *  OpenBSD extended attributes and ACL system call support
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* XXX To support FreeBSD targets the following will need to be added. */
+
+/* extattrctl() */
+static inline abi_long do_freebsd_extattrctl(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattrctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_file(2) */
+static inline abi_long do_freebsd_extattr_set_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_file(2) */
+static inline abi_long do_freebsd_extattr_get_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_file(2) */
+static inline abi_long do_freebsd_extattr_delete_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_fd(2) */
+static inline abi_long do_freebsd_extattr_set_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_fd(2) */
+static inline abi_long do_freebsd_extattr_get_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_fd(2) */
+static inline abi_long do_freebsd_extattr_delete_fd(abi_long arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_get_link(2) */
+static inline abi_long do_freebsd_extattr_get_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_set_link(2) */
+static inline abi_long do_freebsd_extattr_set_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_delete_link(2) */
+static inline abi_long do_freebsd_extattr_delete_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_delete_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_fd(2) */
+static inline abi_long do_freebsd_extattr_list_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall exattr_list_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_file(2) */
+static inline abi_long do_freebsd_extattr_list_file(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_list_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* extattr_list_link(2) */
+static inline abi_long do_freebsd_extattr_list_link(abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall extattr_list_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ *  Access Control Lists
+ */
+
+/* __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_fd(abi_long arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_file(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_link(abi_ulong arg1,
+        abi_long arg2, abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_aclcheck_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_fd(int filedes, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_fd(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_file(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_file(abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_fil()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_delete_link(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_link(abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_delete_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall _acl_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_fd(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_file(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_link(abi_ulong arg1, abi_long arg2,
+       abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall __acl_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 6cd7dbd..ab17f3f 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -42,6 +42,7 @@
 #include "bsd-socket.h"
 
 /* *BSD dependent syscall shims */
+#include "os-extattr.h"
 #include "os-time.h"
 #include "os-proc.h"
 #include "os-signal.h"
@@ -1204,6 +1205,109 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                 arg5, arg6, arg7, arg8, 0);
         break;
 
+        /*
+         * extended attributes system calls
+         */
+    case TARGET_FREEBSD_NR_extattrctl: /* extattrctl() */
+        ret = do_freebsd_extattrctl(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_set_file: /* extattr_set_file(2) */
+        ret = do_freebsd_extattr_set_file(arg1, arg2, arg3, arg4, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_get_file: /* extattr_get_file(2) */
+        ret = do_freebsd_extattr_get_file(arg1, arg2, arg3, arg4, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_delete_file: /* extattr_delete_file(2) */
+        ret = do_freebsd_extattr_delete_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_set_fd: /* extattr_set_fd(2) */
+        ret = do_freebsd_extattr_set_fd(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_get_fd: /* extattr_get_fd(2) */
+        ret = do_freebsd_extattr_get_fd(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_delete_fd: /* extattr_delete_fd(2) */
+        ret = do_freebsd_extattr_delete_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_get_link: /* extattr_get_link(2) */
+        ret = do_freebsd_extattr_get_link(arg1, arg2, arg3, arg4, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_set_link: /* extattr_set_link(2) */
+        ret = do_freebsd_extattr_set_link(arg1, arg2, arg3, arg4, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_delete_link: /* extattr_delete_link(2) */
+        ret = do_freebsd_extattr_delete_link(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_list_fd: /* extattr_list_fd(2) */
+        ret = do_freebsd_extattr_list_fd(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_list_file: /* extattr_list_file(2) */
+        ret = do_freebsd_extattr_list_file(arg1, arg2, arg3,  arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_list_link: /* extattr_list_link(2) */
+        ret = do_freebsd_extattr_list_link(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_aclcheck_fd: /* __acl_aclcheck_fd() */
+        ret = do_freebsd__acl_aclcheck_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_aclcheck_file: /* __acl_aclcheck_file() */
+        ret = do_freebsd__acl_aclcheck_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_aclcheck_link: /* __acl_aclcheck_link() */
+        ret = do_freebsd__acl_aclcheck_link(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_delete_fd: /* __acl_delete_fd() */
+        ret = do_freebsd__acl_delete_fd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_delete_file: /* __acl_delete_file() */
+        ret = do_freebsd__acl_delete_file(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_delete_link: /* __acl_delete_link() */
+        ret = do_freebsd__acl_delete_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_get_fd: /* __acl_get_fd() */
+        ret =  do_freebsd__acl_get_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_get_file: /* __acl_get_file() */
+        ret = do_freebsd__acl_get_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_get_link: /* __acl_get_link() */
+        ret = do_freebsd__acl_get_link(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_set_fd: /* __acl_get_fd() */
+        ret = do_freebsd__acl_set_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_set_file: /* __acl_set_file() */
+        ret = do_freebsd__acl_set_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_set_link: /* __acl_set_link() */
+        ret = do_freebsd__acl_set_link(arg1, arg2, arg3);
+        break;
+
     default:
         ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
                     arg8));
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 17/19] bsd-user: add support for miscellaneous system calls
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (17 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 16/19] bsd-user: add support for extattr and ACL related syscalls Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 18/19] bsd-user: add arm, mips and mips64 options to configure target-list Stacey Son
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto Stacey Son
  20 siblings, 0 replies; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds support or stubs for miscellaneous system calls
including extattr*() (extended attributes), __acl*() (access
control lists), sem*() (system V semaphores), msg*() (system V
messages), sched_*() (scheduler control), cpuset*() (CPU affinity
set management), mod*() and kld*() (kernel module), rctl_*()
(resource controls), __mac_*() (Mandatory Access Control),
posix_*() (additional posix support), and other miscellaneous
system calls.
---
 bsd-user/Makefile.objs     |    2 +-
 bsd-user/bsd-misc.c        |  209 +++++++++++++++++++++
 bsd-user/bsd-misc.h        |  339 +++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-misc.h |  442 ++++++++++++++++++++++++++++++++++++++++++++
 bsd-user/netbsd/os-misc.h  |  375 +++++++++++++++++++++++++++++++++++++
 bsd-user/openbsd/os-misc.h |  375 +++++++++++++++++++++++++++++++++++++
 bsd-user/qemu-bsd.h        |   18 ++
 bsd-user/syscall.c         |  229 +++++++++++++++++++++++
 8 files changed, 1988 insertions(+), 1 deletions(-)
 create mode 100644 bsd-user/bsd-misc.c
 create mode 100644 bsd-user/bsd-misc.h
 create mode 100644 bsd-user/freebsd/os-misc.h
 create mode 100644 bsd-user/netbsd/os-misc.h
 create mode 100644 bsd-user/openbsd/os-misc.h

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index d2e005b..ab025a4 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,5 +1,5 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-ioctl.o bsd-mem.o bsd-proc.o bsd-socket.o \
+	        uaccess.o bsd-ioctl.o bsd-mem.o bsd-misc.o bsd-proc.o bsd-socket.o \
 			$(HOST_VARIANT_DIR)/os-extattr.o $(HOST_VARIANT_DIR)/os-proc.o \
 			$(HOST_VARIANT_DIR)/os-socket.o $(HOST_VARIANT_DIR)/os-stat.o \
 			$(HOST_VARIANT_DIR)/os-sys.o $(HOST_VARIANT_DIR)/os-thread.o \
diff --git a/bsd-user/bsd-misc.c b/bsd-user/bsd-misc.c
new file mode 100644
index 0000000..bc85473
--- /dev/null
+++ b/bsd-user/bsd-misc.c
@@ -0,0 +1,209 @@
+/*
+ *  BSD misc system call conversions routines
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/uuid.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+/*
+ * BSD uuidgen(2) struct uuid conversion
+ */
+abi_long host_to_target_uuid(abi_ulong target_addr, struct uuid *host_uuid)
+{
+    struct target_uuid *target_uuid;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_uuid, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_uuid->time_low, &target_uuid->time_low);
+    __put_user(host_uuid->time_mid, &target_uuid->time_mid);
+    __put_user(host_uuid->time_hi_and_version,
+        &target_uuid->time_hi_and_version);
+    host_uuid->clock_seq_hi_and_reserved =
+        target_uuid->clock_seq_hi_and_reserved;
+    host_uuid->clock_seq_low = target_uuid->clock_seq_low;
+    memcpy(host_uuid->node, target_uuid->node, TARGET_UUID_NODE_LEN);
+    unlock_user_struct(target_uuid, target_addr, 1);
+    return 0;
+}
+
+abi_long target_to_host_semarray(int semid, unsigned short **host_array,
+        abi_ulong target_addr)
+{
+    abi_long ret;
+    int nsems, i;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+
+    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 = (unsigned short *)malloc(nsems * sizeof(unsigned short));
+    array = lock_user(VERIFY_READ, target_addr,
+        nsems*sizeof(unsigned short), 1);
+    if (array == NULL) {
+        free(*host_array);
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsems; i++) {
+        (*host_array)[i] = array[i];
+    }
+    unlock_user(array, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+        unsigned short **host_array)
+{
+    abi_long ret;
+    int nsems, i;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1) {
+        free(*host_array);
+        return get_errno(ret);
+    }
+
+    nsems = semid_ds.sem_nsems;
+    array = (unsigned short *)lock_user(VERIFY_WRITE, target_addr,
+        nsems*sizeof(unsigned short), 0);
+    if (array == NULL) {
+        free(*host_array);
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsems; i++) {
+        array[i] = (*host_array)[i];
+    }
+    free(*host_array);
+    unlock_user(array, target_addr, 1);
+    return 0;
+}
+
+abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
+        abi_ulong target_addr)
+{
+    struct target_semid_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->sem_perm), (target_addr +
+                    offsetof(struct target_semid_ds, sem_perm)))) {
+        return -TARGET_EFAULT;
+    }
+    /* sem_base is not used by kernel for IPC_STAT/IPC_SET */
+    /* host_sd->sem_base  = g2h(target_sd->sem_base); */
+    host_sd->sem_nsems = tswap16(target_sd->sem_nsems);
+    host_sd->sem_otime = tswapal(target_sd->sem_otime);
+    host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+abi_long host_to_target_semid_ds(abi_ulong target_addr,
+        struct semid_ds *host_sd)
+{
+    struct target_semid_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 +
+                    offsetof(struct target_semid_ds, sem_perm)),
+                &(host_sd->sem_perm))) {
+        return -TARGET_EFAULT;
+    }
+    /* sem_base is not used by kernel for IPC_STAT/IPC_SET */
+    /* target_sd->sem_base = h2g((void *)host_sd->sem_base); */
+    target_sd->sem_nsems = tswap16(host_sd->sem_nsems);
+    target_sd->sem_otime = tswapal(host_sd->sem_otime);
+    target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 1);
+
+    return 0;
+}
+
+abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
+        abi_ulong target_addr)
+{
+    struct target_msqid_ds *target_md;
+
+    if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    if (target_to_host_ipc_perm(&(host_md->msg_perm), target_addr)) {
+        return -TARGET_EFAULT;
+    }
+
+    /* msg_first and msg_last are not used by IPC_SET/IPC_STAT in kernel. */
+    host_md->msg_first = host_md->msg_last = NULL;
+    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);
+    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);
+    unlock_user_struct(target_md, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_msqid_ds(abi_ulong target_addr,
+        struct msqid_ds *host_md)
+{
+    struct target_msqid_ds *target_md;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    if (host_to_target_ipc_perm(target_addr, &(host_md->msg_perm))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* msg_first and msg_last are not used by IPC_SET/IPC_STAT in kernel. */
+    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);
+    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);
+    unlock_user_struct(target_md, target_addr, 1);
+
+    return 0;
+}
+
diff --git a/bsd-user/bsd-misc.h b/bsd-user/bsd-misc.h
new file mode 100644
index 0000000..0c34089
--- /dev/null
+++ b/bsd-user/bsd-misc.h
@@ -0,0 +1,339 @@
+/*
+ *  miscellaneous BSD system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_MISC_H_
+#define __BSD_MISC_H_
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/uuid.h>
+
+#include "qemu-bsd.h"
+
+/* quotactl(2) */
+static inline abi_long do_bsd_quotactl(abi_ulong path, abi_long cmd,
+        abi_ulong target_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall quotactl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* reboot(2) */
+static inline abi_long do_bsd_reboot(abi_long how)
+{
+
+    qemu_log("qemu: Unsupported syscall reboot()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* uuidgen(2) */
+static inline abi_long do_bsd_uuidgen(abi_ulong target_addr, int count)
+{
+    int i;
+    abi_long ret;
+    struct uuid *host_uuid;
+
+    if (count < 1 || count > 2048) {
+        return -TARGET_EINVAL;
+    }
+
+    host_uuid = (struct uuid *)g_malloc(count * sizeof(struct uuid));
+
+    if (host_uuid == NULL) {
+        return -TARGET_ENOMEM;
+    }
+
+    ret = get_errno(uuidgen(host_uuid, count));
+    if (is_error(ret)) {
+        goto out;
+    }
+    for (i = 0; i < count; i++) {
+        ret = host_to_target_uuid(target_addr +
+            (abi_ulong)(sizeof(struct target_uuid) * i), &host_uuid[i]);
+        if (is_error(ret)) {
+            goto out;
+        }
+    }
+
+out:
+    g_free(host_uuid);
+    return ret;
+}
+
+
+/*
+ * System V Semaphores
+ */
+
+/* semget(2) */
+static inline abi_long do_bsd_semget(abi_long key, int nsems,
+        int target_flags)
+{
+
+    return get_errno(semget(key, nsems,
+                target_to_host_bitmask(target_flags, ipc_flags_tbl)));
+}
+
+/* semop(2) */
+static inline abi_long do_bsd_semop(int semid, abi_long ptr, unsigned nsops)
+{
+    struct sembuf sops[nsops];
+    struct target_sembuf *target_sembuf;
+    int i;
+
+    target_sembuf = lock_user(VERIFY_READ, ptr,
+            nsops * sizeof(struct target_sembuf), 1);
+    if (target_sembuf == NULL) {
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsops; i++) {
+        __get_user(sops[i].sem_num, &target_sembuf[i].sem_num);
+        __get_user(sops[i].sem_op, &target_sembuf[i].sem_op);
+        __get_user(sops[i].sem_flg, &target_sembuf[i].sem_flg);
+    }
+    unlock_user(target_sembuf, ptr, 0);
+
+    return semop(semid, sops, nsops);
+}
+
+/* __semctl(2) */
+static inline abi_long do_bsd___semctl(int semid, int semnum, int target_cmd,
+        union target_semun target_su)
+{
+    union semun arg;
+    struct semid_ds dsarg;
+    unsigned short *array = NULL;
+    int host_cmd;
+    abi_long ret = 0;
+    abi_long err;
+    abi_ulong target_addr;
+
+    switch (target_cmd) {
+    case TARGET_GETVAL:
+        host_cmd = GETVAL;
+        break;
+
+    case TARGET_SETVAL:
+        host_cmd = SETVAL;
+        break;
+
+    case TARGET_GETALL:
+        host_cmd = GETALL;
+        break;
+
+    case TARGET_SETALL:
+        host_cmd = SETALL;
+        break;
+
+    case TARGET_IPC_STAT:
+        host_cmd = IPC_STAT;
+        break;
+
+    case TARGET_IPC_SET:
+        host_cmd = IPC_SET;
+        break;
+
+    case TARGET_IPC_RMID:
+        host_cmd = IPC_RMID;
+        break;
+
+    case TARGET_GETPID:
+        host_cmd = GETPID;
+        break;
+
+    case TARGET_GETNCNT:
+        host_cmd = GETNCNT;
+        break;
+
+    case TARGET_GETZCNT:
+        host_cmd = GETZCNT;
+        break;
+
+    default:
+        return -TARGET_EINVAL;
+    }
+
+    switch (host_cmd) {
+    case GETVAL:
+    case SETVAL:
+        arg.val = tswap32(target_su.val);
+        ret = get_errno(semctl(semid, semnum, host_cmd, arg));
+        target_su.val = tswap32(arg.val);
+        break;
+
+    case GETALL:
+    case SETALL:
+        if (get_user_ual(target_addr, (abi_ulong)target_su.array)) {
+            return -TARGET_EFAULT;
+        }
+        err = target_to_host_semarray(semid, &array, target_addr);
+        if (is_error(err)) {
+            return err;
+        }
+        arg.array = array;
+        ret = get_errno(semctl(semid, semnum, host_cmd, arg));
+        err = host_to_target_semarray(semid, target_addr, &array);
+        if (is_error(err)) {
+            return err;
+        }
+        break;
+
+    case IPC_STAT:
+    case IPC_SET:
+        if (get_user_ual(target_addr, (abi_ulong)target_su.buf)) {
+            return -TARGET_EFAULT;
+        }
+        err = target_to_host_semid_ds(&dsarg, target_addr);
+        if (is_error(err)) {
+            return err;
+        }
+        arg.buf = &dsarg;
+        ret = get_errno(semctl(semid, semnum, host_cmd, arg));
+        err = host_to_target_semid_ds(target_addr, &dsarg);
+        if (is_error(err)) {
+            return err;
+        }
+        break;
+
+    case IPC_RMID:
+    case GETPID:
+    case GETNCNT:
+    case GETZCNT:
+        ret = get_errno(semctl(semid, semnum, host_cmd, NULL));
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+/* msgctl(2) */
+static inline abi_long do_bsd_msgctl(int msgid, int target_cmd, abi_long ptr)
+{
+    struct msqid_ds dsarg;
+    abi_long ret = -TARGET_EINVAL;
+    int host_cmd;
+
+    switch (target_cmd) {
+    case TARGET_IPC_STAT:
+        host_cmd = IPC_STAT;
+        break;
+
+    case TARGET_IPC_SET:
+        host_cmd = IPC_SET;
+        break;
+
+    case TARGET_IPC_RMID:
+        host_cmd = IPC_RMID;
+        break;
+
+    default:
+        return -TARGET_EINVAL;
+    }
+
+    switch (host_cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+        if (target_to_host_msqid_ds(&dsarg, ptr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(msgctl(msgid, host_cmd, &dsarg));
+        if (host_to_target_msqid_ds(ptr, &dsarg)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    case IPC_RMID:
+        ret = get_errno(msgctl(msgid, host_cmd, NULL));
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+/* msgsnd(2) */
+static inline abi_long do_bsd_msgsnd(int msqid, abi_long msgp,
+        unsigned int msgsz, int msgflg)
+{
+    struct target_msgbuf *target_mb;
+    struct mymsg *host_mb;
+    abi_long ret;
+
+    if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) {
+        return -TARGET_EFAULT;
+    }
+    host_mb = g_malloc(msgsz+sizeof(long));
+    host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
+    memcpy(host_mb->mtext, target_mb->mtext, msgsz);
+    ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
+    g_free(host_mb);
+    unlock_user_struct(target_mb, msgp, 0);
+
+    return ret;
+}
+
+/* msgrcv(2) */
+static inline abi_long do_bsd_msgrcv(int msqid, abi_long msgp,
+        unsigned int msgsz, abi_long msgtyp, int msgflg)
+{
+    struct target_msgbuf *target_mb = NULL;
+    char *target_mtext;
+    struct mymsg *host_mb;
+    abi_long ret = 0;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) {
+        return -TARGET_EFAULT;
+    }
+    host_mb = g_malloc(msgsz+sizeof(long));
+    ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
+    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 == NULL) {
+            ret = -TARGET_EFAULT;
+            goto end;
+        }
+        memcpy(target_mb->mtext, host_mb->mtext, ret);
+        unlock_user(target_mtext, target_mtext_addr, ret);
+    }
+    target_mb->mtype = tswapal(host_mb->mtype);
+end:
+    if (target_mb != NULL) {
+        unlock_user_struct(target_mb, msgp, 1);
+    }
+    g_free(host_mb);
+    return ret;
+}
+
+/* getdtablesize(2) */
+static inline abi_long do_bsd_getdtablesize(void)
+{
+
+    return get_errno(getdtablesize());
+}
+
+#endif /* ! __BSD_MISC_H_ */
diff --git a/bsd-user/freebsd/os-misc.h b/bsd-user/freebsd/os-misc.h
new file mode 100644
index 0000000..07e60fe
--- /dev/null
+++ b/bsd-user/freebsd/os-misc.h
@@ -0,0 +1,442 @@
+/*
+ *  miscellaneous FreeBSD system call shims
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __OS_MISC_H_
+#define __OS_MISC_H_
+
+#include <sys/cpuset.h>
+#include <sched.h>
+
+/* sched_setparam(2) */
+static inline abi_long do_freebsd_sched_setparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+    abi_long ret;
+    struct sched_param host_sp;
+
+    ret = get_user_s32(host_sp.sched_priority, target_sp_addr);
+    if (!is_error(ret)) {
+        ret = get_errno(sched_setparam(pid, &host_sp));
+    }
+    return ret;
+}
+
+/* sched_get_param(2) */
+static inline abi_long do_freebsd_sched_getparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+    abi_long ret;
+    struct sched_param host_sp;
+
+    ret = get_errno(sched_getparam(pid, &host_sp));
+    if (!is_error(ret)) {
+        ret = put_user_s32(host_sp.sched_priority, target_sp_addr);
+    }
+    return ret;
+}
+
+/* sched_setscheduler(2) */
+static inline abi_long do_freebsd_sched_setscheduler(pid_t pid, int policy,
+        abi_ulong target_sp_addr)
+{
+    abi_long ret;
+    struct sched_param host_sp;
+
+    ret = get_user_s32(host_sp.sched_priority, target_sp_addr);
+    if (!is_error(ret)) {
+        ret = get_errno(sched_setscheduler(pid, policy, &host_sp));
+    }
+    return ret;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_getscheduler(pid_t pid)
+{
+
+    return get_errno(sched_getscheduler(pid));
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_rr_get_interval(pid_t pid,
+        abi_ulong target_ts_addr)
+{
+    abi_long ret;
+    struct timespec host_ts;
+
+    ret = get_errno(sched_rr_get_interval(pid, &host_ts));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_timespec(target_ts_addr, &host_ts);
+    }
+    return ret;
+}
+
+/* cpuset(2) */
+static inline abi_long do_freebsd_cpuset(abi_ulong target_cpuid)
+{
+    abi_long ret;
+    cpusetid_t setid;
+
+    ret = get_errno(cpuset(&setid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return put_user_s32(setid, target_cpuid);
+}
+
+#define target_to_host_cpuset_which(hp, t) { \
+    (*hp) = t;                               \
+} while (0)
+
+#define target_to_host_cpuset_level(hp, t) { \
+    (*hp) = t;                               \
+} while (0)
+
+/* cpuset_setid(2) */
+static inline abi_long do_freebsd_cpuset_setid(void *cpu_env, abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    id_t id;    /* 64-bit value */
+    cpusetid_t setid;
+    cpuwhich_t which;
+
+    target_to_host_cpuset_which(&which, arg1);
+#if TARGET_ABI_BITS == 32
+    /* See if we need to align the register pairs */
+    if (regpairs_aligned(cpu_env)) {
+        id = target_offset64(arg3, arg4);
+        setid = arg5;
+    } else {
+        id = target_offset64(arg2, arg3);
+        setid = arg4;
+    }
+#else
+    id = arg2;
+    setid = arg3;
+#endif
+    return get_errno(cpuset_setid(which, id, setid));
+}
+
+/* cpuset_getid(2) */
+static inline abi_long do_freebsd_cpuset_getid(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    id_t id;    /* 64-bit value */
+    cpusetid_t setid;
+    cpuwhich_t which;
+    cpulevel_t level;
+    abi_ulong target_setid;
+
+    target_to_host_cpuset_which(&which, arg1);
+    target_to_host_cpuset_level(&level, arg2);
+#if TARGET_ABI_BITS == 32
+    id = target_offset64(arg3, arg4);
+    target_setid = arg5;
+#else
+    id = arg3;
+    target_setid = arg4;
+#endif
+    ret = get_errno(cpuset_getid(level, which, id, &setid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return put_user_s32(setid, target_setid);
+}
+
+/* cpuset_getaffinity(2) */
+static inline abi_long do_freebsd_cpuset_getaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setaffinity(2) */
+static inline abi_long do_freebsd_cpuset_setaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* modfnext(2) */
+static inline abi_long do_freebsd_modfnext(abi_long modid)
+{
+
+    qemu_log("qemu: Unsupported syscall modfnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* modfind(2) */
+static inline abi_long do_freebsd_modfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall modfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldload(2) */
+static inline abi_long do_freebsd_kldload(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunload(2) */
+static inline abi_long do_freebsd_kldunload(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunloadf(2) */
+static inline abi_long do_freebsd_kldunloadf(abi_long fileid, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunloadf()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfind(2) */
+static inline abi_long do_freebsd_kldfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldnext(2) */
+static inline abi_long do_freebsd_kldnext(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* kldstat(2) */
+static inline abi_long do_freebsd_kldstat(abi_long fileid,
+        abi_ulong target_stat)
+{
+
+    qemu_log("qemu: Unsupported syscall kldstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfirstmod(2) */
+static inline abi_long do_freebsd_kldfirstmod(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfirstmod()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldsym(2) */
+static inline abi_long do_freebsd_kldsym(abi_long fileid, abi_long cmd,
+        abi_ulong target_data)
+{
+
+    qemu_log("qemu: Unsupported syscall kldsym()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Resource limits (undocumented except for rctl(8) and rctl.conf(5) )
+ */
+/* rctl_get_racct() */
+static inline abi_long do_freebsd_rctl_get_racct(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_racct()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_rules() */
+static inline abi_long do_freebsd_rctl_get_rules(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_rules()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_add_rule() */
+static inline abi_long do_freebsd_rctl_add_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_add_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_remove_rule() */
+static inline abi_long do_freebsd_rctl_remove_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_remove_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_limits() */
+static inline abi_long do_freebsd_rctl_get_limits(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_limits()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Kernel environment
+ */
+
+/* kenv(2) */
+static inline abi_long do_freebsd_kenv(abi_long what, abi_ulong target_name,
+        abi_ulong target_value, abi_long len)
+{
+
+    qemu_log("qemu: Unsupported syscall kenv()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ *  Mandatory Access Control
+ */
+
+/* __mac_get_proc */
+static inline abi_long do_freebsd___mac_get_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_proc */
+static inline abi_long do_freebsd___mac_set_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* __mac_get_fd */
+static inline abi_long do_freebsd___mac_get_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_fd */
+static inline abi_long do_freebsd___mac_set_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_file */
+static inline abi_long do_freebsd___mac_get_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_file */
+static inline abi_long do_freebsd___mac_set_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_link */
+static inline abi_long do_freebsd___mac_get_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_link */
+static inline abi_long do_freebsd___mac_set_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* mac_syscall */
+static inline abi_long do_freebsd_mac_syscall(abi_ulong target_policy,
+        abi_long call, abi_ulong target_arg)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_syscall()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ * New posix calls
+ */
+/* posix_fallocate(2) */
+static inline abi_long do_freebsd_posix_fallocate(abi_long fd, abi_ulong offset,
+        abi_ulong len)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fallocate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_openpt(2) */
+static inline abi_long do_freebsd_posix_openpt(abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_openpt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_fadvise(2) */
+static inline abi_long do_freebsd_posix_fadvise(abi_long fd, abi_ulong offset,
+        abi_ulong len, abi_long advise)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fadvise()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+#endif /* ! __OS_MISC_H_ */
diff --git a/bsd-user/netbsd/os-misc.h b/bsd-user/netbsd/os-misc.h
new file mode 100644
index 0000000..8be3662
--- /dev/null
+++ b/bsd-user/netbsd/os-misc.h
@@ -0,0 +1,375 @@
+/*
+ *  miscellaneous NetBSD system call shims
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __OS_MISC_H_
+#define __OS_MISC_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* sched_setparam(2) */
+static inline abi_long do_freebsd_sched_setparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_setparam()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_get_param(2) */
+static inline abi_long do_freebsd_sched_getparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_getparam()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_setscheduler(2) */
+static inline abi_long do_freebsd_sched_setscheduler(pid_t pid, int policy,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_setscheduler()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_getscheduler(pid_t pid)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_getscheduler()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_rr_get_interval(pid_t pid,
+        abi_ulong target_ts_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_rr_get_interval()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset(2) */
+static inline abi_long do_freebsd_cpuset(abi_ulong target_cpuid)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setid(2) */
+static inline abi_long do_freebsd_cpuset_setid(void *cpu_env, abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_getid(2) */
+static inline abi_long do_freebsd_cpuset_getid(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_getaffinity(2) */
+static inline abi_long do_freebsd_cpuset_getaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setaffinity(2) */
+static inline abi_long do_freebsd_cpuset_setaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* modfnext(2) */
+static inline abi_long do_freebsd_modfnext(abi_long modid)
+{
+
+    qemu_log("qemu: Unsupported syscall modfnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* modfind(2) */
+static inline abi_long do_freebsd_modfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall modfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldload(2) */
+static inline abi_long do_freebsd_kldload(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunload(2) */
+static inline abi_long do_freebsd_kldunload(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunloadf(2) */
+static inline abi_long do_freebsd_kldunloadf(abi_long fileid, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunloadf()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfind(2) */
+static inline abi_long do_freebsd_kldfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldnext(2) */
+static inline abi_long do_freebsd_kldnext(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* kldstat(2) */
+static inline abi_long do_freebsd_kldstat(abi_long fileid,
+        abi_ulong target_stat)
+{
+
+    qemu_log("qemu: Unsupported syscall kldstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfirstmod(2) */
+static inline abi_long do_freebsd_kldfirstmod(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfirstmod()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldsym(2) */
+static inline abi_long do_freebsd_kldsym(abi_long fileid, abi_long cmd,
+        abi_ulong target_data)
+{
+
+    qemu_log("qemu: Unsupported syscall kldsym()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Resource limits (undocumented except for rctl(8) and rctl.conf(5) )
+ */
+/* rctl_get_racct() */
+static inline abi_long do_freebsd_rctl_get_racct(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_racct()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_rules() */
+static inline abi_long do_freebsd_rctl_get_rules(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_rules()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_add_rule() */
+static inline abi_long do_freebsd_rctl_add_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_add_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_remove_rule() */
+static inline abi_long do_freebsd_rctl_remove_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_remove_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_limits() */
+static inline abi_long do_freebsd_rctl_get_limits(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_limits()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Kernel environment
+ */
+
+/* kenv(2) */
+static inline abi_long do_freebsd_kenv(abi_long what, abi_ulong target_name,
+        abi_ulong target_value, abi_long len)
+{
+
+    qemu_log("qemu: Unsupported syscall kenv()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ *  Mandatory Access Control
+ */
+
+/* __mac_get_proc */
+static inline abi_long do_freebsd___mac_get_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_proc */
+static inline abi_long do_freebsd___mac_set_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* __mac_get_fd */
+static inline abi_long do_freebsd___mac_get_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_fd */
+static inline abi_long do_freebsd___mac_set_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_file */
+static inline abi_long do_freebsd___mac_get_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_file */
+static inline abi_long do_freebsd___mac_set_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_link */
+static inline abi_long do_freebsd___mac_get_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_link */
+static inline abi_long do_freebsd___mac_set_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* mac_syscall */
+static inline abi_long do_freebsd_mac_syscall(abi_ulong target_policy,
+        abi_long call, abi_ulong target_arg)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_syscall()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ * New posix calls
+ */
+/* posix_fallocate(2) */
+static inline abi_long do_freebsd_posix_fallocate(abi_long fd, abi_ulong offset,
+        abi_ulong len)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fallocate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_openpt(2) */
+static inline abi_long do_freebsd_posix_openpt(abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_openpt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_fadvise(2) */
+static inline abi_long do_freebsd_posix_fadvise(abi_long fd, abi_ulong offset,
+        abi_ulong len, abi_long advise)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fadvise()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OS_MISC_H_ */
diff --git a/bsd-user/openbsd/os-misc.h b/bsd-user/openbsd/os-misc.h
new file mode 100644
index 0000000..5a17ac9
--- /dev/null
+++ b/bsd-user/openbsd/os-misc.h
@@ -0,0 +1,375 @@
+/*
+ *  miscellaneous OpenBSD system call shims
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __OS_MISC_H_
+#define __OS_MISC_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* sched_setparam(2) */
+static inline abi_long do_freebsd_sched_setparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_setparam()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_get_param(2) */
+static inline abi_long do_freebsd_sched_getparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_getparam()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_setscheduler(2) */
+static inline abi_long do_freebsd_sched_setscheduler(pid_t pid, int policy,
+        abi_ulong target_sp_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_setscheduler()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_getscheduler(pid_t pid)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_getscheduler()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_rr_get_interval(pid_t pid,
+        abi_ulong target_ts_addr)
+{
+
+    qemu_log("qemu: Unsupported syscall sched_rr_get_interval()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset(2) */
+static inline abi_long do_freebsd_cpuset(abi_ulong target_cpuid)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setid(2) */
+static inline abi_long do_freebsd_cpuset_setid(void *cpu_env, abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_getid(2) */
+static inline abi_long do_freebsd_cpuset_getid(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_getaffinity(2) */
+static inline abi_long do_freebsd_cpuset_getaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_getaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cpuset_setaffinity(2) */
+static inline abi_long do_freebsd_cpuset_setaffinity(abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+
+    qemu_log("qemu: Unsupported syscall cpuset_setaffinity()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* modfnext(2) */
+static inline abi_long do_freebsd_modfnext(abi_long modid)
+{
+
+    qemu_log("qemu: Unsupported syscall modfnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* modfind(2) */
+static inline abi_long do_freebsd_modfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall modfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldload(2) */
+static inline abi_long do_freebsd_kldload(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunload(2) */
+static inline abi_long do_freebsd_kldunload(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunload()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldunloadf(2) */
+static inline abi_long do_freebsd_kldunloadf(abi_long fileid, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall kldunloadf()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfind(2) */
+static inline abi_long do_freebsd_kldfind(abi_ulong target_name)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfind()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldnext(2) */
+static inline abi_long do_freebsd_kldnext(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldnext()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* kldstat(2) */
+static inline abi_long do_freebsd_kldstat(abi_long fileid,
+        abi_ulong target_stat)
+{
+
+    qemu_log("qemu: Unsupported syscall kldstat()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldfirstmod(2) */
+static inline abi_long do_freebsd_kldfirstmod(abi_long fileid)
+{
+
+    qemu_log("qemu: Unsupported syscall kldfirstmod()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* kldsym(2) */
+static inline abi_long do_freebsd_kldsym(abi_long fileid, abi_long cmd,
+        abi_ulong target_data)
+{
+
+    qemu_log("qemu: Unsupported syscall kldsym()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Resource limits (undocumented except for rctl(8) and rctl.conf(5) )
+ */
+/* rctl_get_racct() */
+static inline abi_long do_freebsd_rctl_get_racct(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_racct()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_rules() */
+static inline abi_long do_freebsd_rctl_get_rules(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_rules()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_add_rule() */
+static inline abi_long do_freebsd_rctl_add_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_add_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_remove_rule() */
+static inline abi_long do_freebsd_rctl_remove_rule(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_remove_rule()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rctl_get_limits() */
+static inline abi_long do_freebsd_rctl_get_limits(abi_ulong target_inbufp,
+        abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
+{
+
+    qemu_log("qemu: Unsupported syscall rctl_get_limits()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * Kernel environment
+ */
+
+/* kenv(2) */
+static inline abi_long do_freebsd_kenv(abi_long what, abi_ulong target_name,
+        abi_ulong target_value, abi_long len)
+{
+
+    qemu_log("qemu: Unsupported syscall kenv()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ *  Mandatory Access Control
+ */
+
+/* __mac_get_proc */
+static inline abi_long do_freebsd___mac_get_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_proc */
+static inline abi_long do_freebsd___mac_set_proc(abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_proc()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* __mac_get_fd */
+static inline abi_long do_freebsd___mac_get_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_fd */
+static inline abi_long do_freebsd___mac_set_fd(abi_long fd,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_fd()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_file */
+static inline abi_long do_freebsd___mac_get_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_file */
+static inline abi_long do_freebsd___mac_set_file(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_file()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_get_link */
+static inline abi_long do_freebsd___mac_get_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_get_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* __mac_set_link */
+static inline abi_long do_freebsd___mac_set_link(abi_ulong target_path,
+        abi_ulong target_mac)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_set_link()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* mac_syscall */
+static inline abi_long do_freebsd_mac_syscall(abi_ulong target_policy,
+        abi_long call, abi_ulong target_arg)
+{
+
+    qemu_log("qemu: Unsupported syscall mac_syscall()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/*
+ * New posix calls
+ */
+/* posix_fallocate(2) */
+static inline abi_long do_freebsd_posix_fallocate(abi_long fd, abi_ulong offset,
+        abi_ulong len)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fallocate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_openpt(2) */
+static inline abi_long do_freebsd_posix_openpt(abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_openpt()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* posix_fadvise(2) */
+static inline abi_long do_freebsd_posix_fadvise(abi_long fd, abi_ulong offset,
+        abi_ulong len, abi_long advise)
+{
+
+    qemu_log("qemu: Unsupported syscall posix_fadvise()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OS_MISC_H_ */
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
index 09b99ef..771245d 100644
--- a/bsd-user/qemu-bsd.h
+++ b/bsd-user/qemu-bsd.h
@@ -58,4 +58,22 @@ abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
 abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr,
         socklen_t len);
 
+/* bsd-misc.c */
+abi_long host_to_target_uuid(abi_ulong target_addr, struct uuid *host_uuid);
+
+abi_long target_to_host_semarray(int semid, unsigned short **host_array,
+        abi_ulong target_addr);
+abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+        unsigned short **host_array);
+
+abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
+        abi_ulong target_addr);
+abi_long host_to_target_semid_ds(abi_ulong target_addr,
+        struct semid_ds *host_sd);
+
+abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
+        abi_ulong target_addr);
+abi_long host_to_target_msqid_ds(abi_ulong target_addr,
+        struct msqid_ds *host_md);
+
 #endif /* !_QEMU_BSD_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index ab17f3f..35bf394 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -37,6 +37,7 @@
 #include "bsd-file.h"
 #include "bsd-ioctl.h"
 #include "bsd-mem.h"
+#include "bsd-misc.h"
 #include "bsd-proc.h"
 #include "bsd-signal.h"
 #include "bsd-socket.h"
@@ -44,6 +45,7 @@
 /* *BSD dependent syscall shims */
 #include "os-extattr.h"
 #include "os-time.h"
+#include "os-misc.h"
 #include "os-proc.h"
 #include "os-signal.h"
 #include "os-socket.h"
@@ -1308,6 +1310,233 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = do_freebsd__acl_set_link(arg1, arg2, arg3);
         break;
 
+        /*
+         * SysV Semaphores
+         */
+    case TARGET_FREEBSD_NR_semget: /* semget(2) */
+        ret = do_bsd_semget(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_semop: /* semop(2) */
+        ret = do_bsd_semop(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___semctl: /* __semctl() undocumented */
+        ret = do_bsd___semctl(arg1, arg2, arg3,
+                (union target_semun)(abi_ulong)arg4);
+        break;
+
+        /*
+         * SysV Messages
+         */
+    case TARGET_FREEBSD_NR_msgctl: /* msgctl(2) */
+        ret = do_bsd_msgctl(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_msgsnd: /* msgsnd(2) */
+        ret = do_bsd_msgsnd(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_msgrcv: /* msgrcv(2) */
+        ret = do_bsd_msgrcv(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+        /*
+         * FreeBSD scheduler control
+         */
+    case TARGET_FREEBSD_NR_sched_setparam: /* sched_setparam(2) */
+        ret = do_freebsd_sched_setparam(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_getparam: /* sched_getparam(2) */
+        ret = do_freebsd_sched_getparam(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_setscheduler: /* sched_setscheduler(2) */
+        ret = do_freebsd_sched_setscheduler(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_getscheduler: /* sched_getscheduler(2) */
+        ret = do_freebsd_sched_getscheduler(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_rr_get_interval: /* sched_rr_get_interval(2) */
+        ret = do_freebsd_sched_rr_get_interval(arg1, arg2);
+        break;
+
+        /*
+         * FreeBSD CPU affinity sets management
+         */
+    case TARGET_FREEBSD_NR_cpuset: /* cpuset(2) */
+        ret = do_freebsd_cpuset(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_setid: /* cpuset_setid(2) */
+        ret = do_freebsd_cpuset_setid(cpu_env, arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_getid: /* cpuset_getid(2) */
+        ret = do_freebsd_cpuset_getid(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_getaffinity: /* cpuset_getaffinity(2) */
+        ret = do_freebsd_cpuset_getaffinity(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_setaffinity: /* cpuset_setaffinity(2) */
+        ret = do_freebsd_cpuset_setaffinity(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+
+        /*
+         * FreeBSD kernel module
+         */
+    case TARGET_FREEBSD_NR_modfnext: /* modfnext(2) */
+        ret = do_freebsd_modfnext(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_modfind: /* modfind(2) */
+        ret = do_freebsd_modfind(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldload: /* kldload(2) */
+        ret = do_freebsd_kldload(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldunload: /* kldunload(2) */
+        ret = do_freebsd_kldunload(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldunloadf: /* kldunloadf(2) */
+        ret = do_freebsd_kldunloadf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kldfind: /* kldfind(2) */
+        ret = do_freebsd_kldfind(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldnext: /* kldnext(2) */
+        ret = do_freebsd_kldnext(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldstat: /* kldstat(2) */
+        ret = do_freebsd_kldstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kldfirstmod: /* kldfirstmod(2) */
+        ret = do_freebsd_kldfirstmod(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldsym: /* kldsym(2) */
+        ret = do_freebsd_kldsym(arg1, arg2, arg3);
+        break;
+
+        /*
+         * FreeBSD resource controls (undocumented except for rctl(8)
+         * and rctl.conf(5) )
+         */
+    case TARGET_FREEBSD_NR_rctl_get_racct: /* rctl_get_racct() */
+        ret = do_freebsd_rctl_get_racct(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_rctl_get_rules: /* rctl_get_rules() */
+        ret = do_freebsd_rctl_get_rules(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_rctl_add_rule: /* rctl_add_rule() */
+        ret = do_freebsd_rctl_add_rule(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_rctl_remove_rule: /* rctl_remove_rule() */
+        ret = do_freebsd_rctl_remove_rule(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_rctl_get_limits: /* rctl_get_limits() */
+        ret = do_freebsd_rctl_get_limits(arg1, arg2, arg3, arg4);
+        break;
+
+        /*
+         * FreeBSD Mandatory Access Control
+         */
+    case TARGET_FREEBSD_NR___mac_get_proc: /* __mac_get_proc() */
+        ret = do_freebsd___mac_get_proc(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_set_proc: /* __mac_set_proc() */
+        ret = do_freebsd___mac_set_proc(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_get_fd: /* __mac_get_fd() */
+        ret = do_freebsd___mac_get_fd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_set_fd: /* __mac_set_fd() */
+        ret = do_freebsd___mac_set_fd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_get_file: /* __mac_get_file() */
+        ret = do_freebsd___mac_get_proc(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_set_file: /* __mac_set_file() */
+        ret = do_freebsd___mac_set_file(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_get_link: /* __mac_get_link() */
+        ret = do_freebsd___mac_get_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___mac_set_link: /* __mac_set_link() */
+        ret = do_freebsd___mac_set_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mac_syscall: /* mac_syscall() */
+        ret = do_freebsd_mac_syscall(arg1, arg2, arg3);
+        break;
+
+        /*
+         * FreeBSD additional posix support
+         */
+    case TARGET_FREEBSD_NR_posix_fallocate: /* posix_fallocate(2) */
+        ret = do_freebsd_posix_fallocate(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_posix_openpt: /* posix_fallocate(2) */
+        ret = do_freebsd_posix_openpt(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_posix_fadvise: /* posix_fadvise(2) */
+        ret = do_freebsd_posix_fadvise(arg1, arg2, arg3, arg4);
+        break;
+
+        /*
+         * Misc
+         */
+    case TARGET_FREEBSD_NR_quotactl: /* quotactl(2) */
+        ret = do_bsd_quotactl(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_reboot: /* reboot(2) */
+        ret = do_bsd_reboot(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_uuidgen: /* uuidgen(2) */
+        ret = do_bsd_uuidgen(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getdtablesize: /* getdtablesize(2) */
+        ret = do_bsd_getdtablesize();
+        break;
+
+    case TARGET_FREEBSD_NR_kenv: /* kenv(2) */
+        ret = do_freebsd_kenv(arg1, arg2, arg2, arg4);
+        break;
+
+
+    case TARGET_FREEBSD_NR_break:
+        ret = do_obreak(arg1);
+        break;
+
     default:
         ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
                     arg8));
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 18/19] bsd-user: add arm, mips and mips64 options to configure target-list
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (18 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 17/19] bsd-user: add support for miscellaneous system calls Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2014-01-27 20:03     ` Peter Maydell
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto Stacey Son
  20 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

This change adds arm-bsd-user, mips-bsd-user, mips64-bsd-user,
mips64el-bsd-user, and mipsel-bsd-user as --target-list options to configure.
---
 default-configs/arm-bsd-user.mak      |    3 +++
 default-configs/mips-bsd-user.mak     |    1 +
 default-configs/mips64-bsd-user.mak   |    1 +
 default-configs/mips64el-bsd-user.mak |    1 +
 default-configs/mipsel-bsd-user.mak   |    1 +
 5 files changed, 7 insertions(+), 0 deletions(-)
 create mode 100644 default-configs/arm-bsd-user.mak
 create mode 100644 default-configs/mips-bsd-user.mak
 create mode 100644 default-configs/mips64-bsd-user.mak
 create mode 100644 default-configs/mips64el-bsd-user.mak
 create mode 100644 default-configs/mipsel-bsd-user.mak

diff --git a/default-configs/arm-bsd-user.mak b/default-configs/arm-bsd-user.mak
new file mode 100644
index 0000000..869e6fb
--- /dev/null
+++ b/default-configs/arm-bsd-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for arm-bsd-user
+
+CONFIG_GDBSTUB_XML=y
diff --git a/default-configs/mips-bsd-user.mak b/default-configs/mips-bsd-user.mak
new file mode 100644
index 0000000..3fb129a
--- /dev/null
+++ b/default-configs/mips-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips-bsd-user
diff --git a/default-configs/mips64-bsd-user.mak b/default-configs/mips64-bsd-user.mak
new file mode 100644
index 0000000..d4e72a6
--- /dev/null
+++ b/default-configs/mips64-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips64-bsd-user
diff --git a/default-configs/mips64el-bsd-user.mak b/default-configs/mips64el-bsd-user.mak
new file mode 100644
index 0000000..b879228
--- /dev/null
+++ b/default-configs/mips64el-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips64el-bsd-user
diff --git a/default-configs/mipsel-bsd-user.mak b/default-configs/mipsel-bsd-user.mak
new file mode 100644
index 0000000..312b9d5
--- /dev/null
+++ b/default-configs/mipsel-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for mipsel-bsd-user
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [Qemu-devel] [PATCH v3 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto
  2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
                     ` (19 preceding siblings ...)
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 18/19] bsd-user: add arm, mips and mips64 options to configure target-list Stacey Son
@ 2013-12-17 11:52   ` Stacey Son
  2014-01-27 20:07     ` Peter Maydell
  20 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2013-12-17 11:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stacey Son

FreeBSD has it's own AES_set_decrypt_key, etc. in libcrypto.  This
change fixes these conflicts and allows statically linking BSD
user mode qemu.
---
 include/qemu/aes.h |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/include/qemu/aes.h b/include/qemu/aes.h
index e79c707..6d253a3 100644
--- a/include/qemu/aes.h
+++ b/include/qemu/aes.h
@@ -10,6 +10,15 @@ struct aes_key_st {
 };
 typedef struct aes_key_st AES_KEY;
 
+/* FreeBSD has it's own AES_set_decrypt_key in -lcrypto, avoid conflicts. */
+#ifdef __FreeBSD__
+#define AES_set_encrypt_key QEMU_AES_set_encrypt_key
+#define AES_set_decrypt_key QEMU_AES_set_decrypt_key
+#define AES_encrypt QEMU_AES_encrypt
+#define AES_decrypt QEMU_AES_decrypt
+#define AES_cbc_encrypt QEMU_AES_cbc_encrypt
+#endif
+
 int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
 	AES_KEY *key);
 int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
-- 
1.7.8

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/19] bsd-user: Add system call and mips/arm support.
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 " Stacey Son
@ 2014-01-27 19:15     ` Peter Maydell
  2014-01-27 19:27       ` Stacey Son
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Maydell @ 2014-01-27 19:15 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers

On 17 December 2013 11:52, Stacey Son <sson@freebsd.org> wrote:
> [v3]
>
> - Rebases to commit f46e720a82ccdf1a521cf459448f3f96ed895d43 (HEAD).
> - Changes 'HOST_API_DIR' to 'HOST_VARIANT_DIR' for the BSD variant.
> - Fixes boundry condition bug in mmap() system call handler.
> - Fixes floating point support for MIPS64.
> - Fixes execve() syscall handler so shell scripts are properly exec'ed.
> - Fixes uninitialized data bug for extended attribute syscall handlers.
> - Fixes minor typos in ACL syscall structures.

> This patch series adds a significant number of system calls and mips/arm
> support for bsd-user.  In its current state it can emulate most
> FreeBSD mips/mips64 and arm target binaries on a x86 host in a simple
> chroot environment. (see https://wiki.freebsd.org/QemuUserModeHowTo for
> the details.)

I've been hoping somebody who uses FreeBSD would review
these, but since nobody has I'm going to take a look at
them. However, I've noticed that none of the patches in
this series have Signed-off-by: lines (oddly, since v2
and v1 certainly did). We can't apply them at all without
those, so you'll need to fix that in your next respin.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/19] bsd-user: Add system call and mips/arm support.
  2014-01-27 19:15     ` Peter Maydell
@ 2014-01-27 19:27       ` Stacey Son
  2014-01-27 20:18         ` Peter Maydell
  0 siblings, 1 reply; 95+ messages in thread
From: Stacey Son @ 2014-01-27 19:27 UTC (permalink / raw)
  To: Peter Maydell; +Cc: QEMU Developers, Anthony Liguori


On Jan 27, 2014, at 1:15 PM, Peter Maydell <peter.maydell@linaro.org> wrote:

> On 17 December 2013 11:52, Stacey Son <sson@freebsd.org> wrote:
>> [v3]
>> 
>> - Rebases to commit f46e720a82ccdf1a521cf459448f3f96ed895d43 (HEAD).
>> - Changes 'HOST_API_DIR' to 'HOST_VARIANT_DIR' for the BSD variant.
>> - Fixes boundry condition bug in mmap() system call handler.
>> - Fixes floating point support for MIPS64.
>> - Fixes execve() syscall handler so shell scripts are properly exec'ed.
>> - Fixes uninitialized data bug for extended attribute syscall handlers.
>> - Fixes minor typos in ACL syscall structures.
> 
>> This patch series adds a significant number of system calls and mips/arm
>> support for bsd-user.  In its current state it can emulate most
>> FreeBSD mips/mips64 and arm target binaries on a x86 host in a simple
>> chroot environment. (see https://wiki.freebsd.org/QemuUserModeHowTo for
>> the details.)
> 
> I've been hoping somebody who uses FreeBSD would review
> these, but since nobody has I'm going to take a look at
> them. However, I've noticed that none of the patches in
> this series have Signed-off-by: lines (oddly, since v2
> and v1 certainly did). We can't apply them at all without
> those, so you'll need to fix that in your next respin.


I must have neglected to include the signed off option that last time I generated a patch set.

I'll generate a new patch set (v4) here in the next day or so.  FYI, Anthony Liguori mentioned that he might be able to help with these patches as well.

Thanks,

-stacey.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 01/19] bsd-user: refresh freebsd system call numbers
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 01/19] bsd-user: refresh freebsd system call numbers Stacey Son
@ 2014-01-27 19:30     ` Peter Maydell
  2014-02-01 12:11       ` Ed Maste
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Maydell @ 2014-01-27 19:30 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers

On 17 December 2013 11:52, Stacey Son <sson@freebsd.org> wrote:
> Update FreeBSD system call numbers in freebsd/syscall_nr.h.
>
> Reviewed-by: Ed Maste <emaste@freebsd.org>


Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

though this patch would look much nicer if you hadn't
changed every single line in the file including the
ones for syscalls we already had the #defines for.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 02/19] bsd-user: add HOST_VARIANT_DIR for various *BSD dependent code
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 02/19] bsd-user: add HOST_VARIANT_DIR for various *BSD dependent code Stacey Son
@ 2014-01-27 19:31     ` Peter Maydell
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Maydell @ 2014-01-27 19:31 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers

On 17 December 2013 11:52, Stacey Son <sson@freebsd.org> wrote:
> This change adds HOST_VARIANT_DIR so the various BSD OS dependent
> code can be seperated into its own directories rather than
> using #ifdef's.   This may also allow an BSD variant OS to host
> another BSD variant's executible as a target.


Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/19] bsd-user: move strace OS/arch dependent code to host/arch dirs
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 03/19] bsd-user: move strace OS/arch dependent code to host/arch dirs Stacey Son
@ 2014-01-27 19:46     ` Peter Maydell
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Maydell @ 2014-01-27 19:46 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers

On 17 December 2013 11:52, Stacey Son <sson@freebsd.org> wrote:
> This change moves host OS and arch dependent code for the sysarch
> system call related to the -strace functionality into the
> appropriate host OS and target arch directories.

This patch seems to be trying to do too much at once.

Before this patch is applied, bsd-user supports
just i386, x86_64, sparc, sparc64. You should have
a patch which refactors the code for those targets
to move them into the per-target/per-host-os
directories. Then once you've done that (and all
the other refactoring patches), have patches at
the very end of the series which simply add new arm
and mips support in the correct places.


> --- a/bsd-user/freebsd/strace.list
> +++ b/bsd-user/freebsd/strace.list
> @@ -1,7 +1,38 @@
> +/*
> + *  FreeBSD strace list
> + *
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +{ TARGET_FREEBSD_NR___acl_aclcheck_fd, "__acl_get_fd", "%s(%d, %d, %#x)", NULL, NULL },
> +{ TARGET_FREEBSD_NR___acl_aclcheck_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL },
> +{ TARGET_FREEBSD_NR___acl_aclcheck_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL },
> +{ TARGET_FREEBSD_NR___acl_delete_fd, "__acl_delete_fd", "%s(%d, %d)", NULL, NULL },
> +{ TARGET_FREEBSD_NR___acl_delete_file, "__acl_delete_file", "%s(\"%s\", %d)", NULL, NULL },
> +{ TARGET_FREEBSD_NR___acl_delete_link, "__acl_delete_link", "%s(\"%s\", %d)", NULL, NULL },
> +{ TARGET_FREEBSD_NR___acl_get_fd, "__acl_get_fd", "%s(\"%s\", %d, %#x)", NULL, NULL },
> +{ TARGET_FREEBSD_NR___acl_get_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL },
> +{ TARGET_FREEBSD_NR___acl_get_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL },
> +{ TARGET_FREEBSD_NR___acl_set_fd, "__acl_get_fd", "%s(\"%s\", %d, %#x)", NULL, NULL },
> +{ TARGET_FREEBSD_NR___acl_set_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL },
> +{ TARGET_FREEBSD_NR___acl_set_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL },
>  { TARGET_FREEBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL },
>  { TARGET_FREEBSD_NR___semctl, "__semctl", NULL, NULL, NULL },
>  { TARGET_FREEBSD_NR___syscall, "__syscall", NULL, NULL, NULL },
> -{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL },
> +{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, print_sysctl, NULL },
> +{ TARGET_FREEBSD_NR__umtx_op, "_umtx_op", "%s(%#x, %d, %d, %#x, %#x)", NULL, NULL },

This hunk seems to just be adding strace support for a
lot of new syscalls. It ought to be in its own patch,
not in this one.
> --- /dev/null
> +++ b/bsd-user/i386/target_arch_sysarch.h
> @@ -0,0 +1,78 @@
> +/*
> + *  i386 sysarch system call emulation
> + *
> + *  Copyright (c) 2013 Stacey D. Son
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef __ARCH_SYSARCH_H_
> +#define __ARCH_SYSARCH_H_
> +
> +#include "syscall.h"
> +
> +static inline abi_long do_freebsd_arch_sysarch(CPUX86State *env, int op,
> +        abi_ulong parms)
> +{
> +    abi_long ret = 0;
> +    abi_ulong val;
> +    int idx;
> +
> +    switch (op) {
> +    case TARGET_FREEBSD_I386_SET_GSBASE:
> +    case TARGET_FREEBSD_I386_SET_FSBASE:
> +        if (op == TARGET_FREEBSD_I386_SET_GSBASE) {
> +            idx = R_GS;
> +        } else {
> +            idx = R_FS;
> +        }
> +        if (get_user(val, parms, abi_ulong)) {
> +            return -TARGET_EFAULT;
> +        }
> +        cpu_x86_load_seg(env, idx, 0);
> +        env->segs[idx].base = val;
> +        break;
> +
> +    case TARGET_FREEBSD_I386_GET_GSBASE:
> +    case TARGET_FREEBSD_I386_GET_FSBASE:
> +        if (op == TARGET_FREEBSD_I386_GET_GSBASE) {
> +            idx = R_GS;
> +        } else {
> +            idx = R_FS;
> +        }
> +        val = env->segs[idx].base;
> +        if (put_user(val, parms, abi_ulong)) {
> +            return -TARGET_EFAULT;
> +        }
> +        break;
> +
> +    /* XXX handle the others... */
> +    default:
> +        ret = -TARGET_EINVAL;
> +        break;
> +    }
> +    return ret;
> +}

This patch adds this function, but the old version is
still in syscalls.c (it doesn't get deleted until patch 5).
This patch should be doing the refactoring, which means it
should add the code in the new correct location and also
delete it from the old.

(The patchstack should also compile and work at every
point along it, so git bisect works. If you haven't
tested that, you should do so.)

>  /*
>   * The public interface to this module.
>   */
> -void
> -print_freebsd_syscall(int num,
> -                      abi_long arg1, abi_long arg2, abi_long arg3,
> -                      abi_long arg4, abi_long arg5, abi_long arg6)
> +void print_freebsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
> +        abi_long arg4, abi_long arg5, abi_long arg6)
>  {
> -    print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames),
> -                  arg1, arg2, arg3, arg4, arg5, arg6);
> +
> +    print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames), arg1, arg2,
> +            arg3, arg4, arg5, arg6);

So this hunk (and some others) are doing nothing
but whitespace changes. QEMU general policy on this
sort of style fixup is:

(1) for lines of code your patch is touching because it's
making a functional change, it's recommended to fix those
lines to follow the coding style (where the metric of this is
"is scripts/checkpatch.pl happy with your patch?". checkpatch
is sometimes wrong, especially where preprocessor macros are
involved, so you need to exercise some judgement, but it will
spot all the nits like hardcoded tabs, missing braces, etc.
I noticed a lot of your patches are failing checkpatch.

(2) don't include in patches sections like this which
are *only* making whitespace or style changes: it makes
it harder to see what the patch is actually doing when
the functional changes are mixed up with whitespace changes

(3) mostly we prefer not to do "update whole file to
the coding style" patches, because they break git blame
and similar tools. However if you really want to do them
keep them in completely separate patches so those can
be reviewed as "should make no code changes".

thanks
-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 04/19] bsd-user: move arch/OS dependent code out of main.c
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 04/19] bsd-user: move arch/OS dependent code out of main.c Stacey Son
@ 2014-01-27 19:50     ` Peter Maydell
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Maydell @ 2014-01-27 19:50 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers

On 17 December 2013 11:52, Stacey Son <sson@freebsd.org> wrote:
> This change moves the cpu initialization and main loop code from
> main.c to the OS and arch dependent directories. This eliminates
> many of the #ifdef's in main.c. The cpu initialization and loop
> code is now located in the arch directory along with target arch
> support code.

Again, this is mixing refactoring and adding the
new architecture support.

>  40 files changed, 3001 insertions(+), 765 deletions(-)

3000 lines of code is way too much to review in
a single patch unless it is pure copy-and-paste
code movement (and even then it's borderline).

thanks
-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 05/19] bsd-user: move arch/OS dependent code out of syscall.c
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 05/19] bsd-user: move arch/OS dependent code out of syscall.c Stacey Son
@ 2014-01-27 19:52     ` Peter Maydell
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Maydell @ 2014-01-27 19:52 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers

On 17 December 2013 11:52, Stacey Son <sson@freebsd.org> wrote:
> This change moves the system call handler for sysctl(2) and
> sysarch(2) from syscall.c to the OS and arch dependent directories.
> This eliminates many of the #ifdef's in syscall.c.  These system
> call handlers are now located in the host os and target arch
> directories.
> ---
>  bsd-user/Makefile.objs                  |    2 +-
>  bsd-user/arm/target_arch_sigtramp.h     |   33 ++++
>  bsd-user/bsdload.c                      |  170 +++++++++++++-----
>  bsd-user/elfload.c                      |    9 +-

It also appears to be making a pile of changes to
the executable loading code. Those need to be their
own self-contained patch.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 06/19] bsd-user: add support for freebsd time related system calls
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 06/19] bsd-user: add support for freebsd time related system calls Stacey Son
@ 2014-01-27 19:58     ` Peter Maydell
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Maydell @ 2014-01-27 19:58 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers

On 17 December 2013 11:52, Stacey Son <sson@freebsd.org> wrote:
> This change adds support or stubs for time related system calls
> including nanosleep(2), clock_gettime(2), clock_settime(2),
> clock_getres(2), gettimeofday(2), settimeofday(2), adjtime(2),
> ntp_adjtime(2), ntp_gettime(2), utimes(2), lutimes(2), futimes(2),
> futimesat(2), select(2), pselect(2), kqueue(2), kevent(2),
> setitimer(2), getitimer(2), and the undocumented ktimer_*() calls.
> ---
>  bsd-user/Makefile.objs     |    3 +-
>  bsd-user/freebsd/os-time.c |  205 ++++++++++++
>  bsd-user/freebsd/os-time.h |  643 +++++++++++++++++++++++++++++++++++
>  bsd-user/freebsd/qemu-os.h |   53 +++
>  bsd-user/netbsd/os-time.c  |    1 +
>  bsd-user/netbsd/os-time.h  |  179 ++++++++++
>  bsd-user/netbsd/qemu-os.h  |    1 +
>  bsd-user/openbsd/os-time.c |    1 +
>  bsd-user/openbsd/os-time.h |  179 ++++++++++
>  bsd-user/openbsd/qemu-os.h |    1 +
>  bsd-user/syscall.c         |  102 ++++++
>  bsd-user/syscall_defs.h    |  796 ++++++++++++++++++++++++++++++++++++++------
>  12 files changed, 2061 insertions(+), 103 deletions(-)

This looks OK on a quick skim though once again
it's more than 2000 lines, whcih suggests it could
profitably be split into more manageable pieces.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 18/19] bsd-user: add arm, mips and mips64 options to configure target-list
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 18/19] bsd-user: add arm, mips and mips64 options to configure target-list Stacey Son
@ 2014-01-27 20:03     ` Peter Maydell
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Maydell @ 2014-01-27 20:03 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers

On 17 December 2013 11:52, Stacey Son <sson@freebsd.org> wrote:
> This change adds arm-bsd-user, mips-bsd-user, mips64-bsd-user,
> mips64el-bsd-user, and mipsel-bsd-user as --target-list options to configure.
> ---
>  default-configs/arm-bsd-user.mak      |    3 +++
>  default-configs/mips-bsd-user.mak     |    1 +
>  default-configs/mips64-bsd-user.mak   |    1 +
>  default-configs/mips64el-bsd-user.mak |    1 +
>  default-configs/mipsel-bsd-user.mak   |    1 +
>  5 files changed, 7 insertions(+), 0 deletions(-)
>  create mode 100644 default-configs/arm-bsd-user.mak
>  create mode 100644 default-configs/mips-bsd-user.mak
>  create mode 100644 default-configs/mips64-bsd-user.mak
>  create mode 100644 default-configs/mips64el-bsd-user.mak
>  create mode 100644 default-configs/mipsel-bsd-user.mak
>
> diff --git a/default-configs/arm-bsd-user.mak b/default-configs/arm-bsd-user.mak
> new file mode 100644
> index 0000000..869e6fb
> --- /dev/null
> +++ b/default-configs/arm-bsd-user.mak
> @@ -0,0 +1,3 @@
> +# Default configuration for arm-bsd-user
> +
> +CONFIG_GDBSTUB_XML=y

You don't need to specify this any more, configure will
automatically work it out.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto
  2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto Stacey Son
@ 2014-01-27 20:07     ` Peter Maydell
  2014-01-27 20:15       ` Stacey Son
  2014-01-28 10:17       ` Paolo Bonzini
  0 siblings, 2 replies; 95+ messages in thread
From: Peter Maydell @ 2014-01-27 20:07 UTC (permalink / raw)
  To: Stacey Son; +Cc: Paolo Bonzini, QEMU Developers

On 17 December 2013 11:52, Stacey Son <sson@freebsd.org> wrote:
> FreeBSD has it's own AES_set_decrypt_key, etc. in libcrypto.  This
> change fixes these conflicts and allows statically linking BSD
> user mode qemu.
> ---
>  include/qemu/aes.h |    9 +++++++++
>  1 files changed, 9 insertions(+), 0 deletions(-)
>
> diff --git a/include/qemu/aes.h b/include/qemu/aes.h
> index e79c707..6d253a3 100644
> --- a/include/qemu/aes.h
> +++ b/include/qemu/aes.h
> @@ -10,6 +10,15 @@ struct aes_key_st {
>  };
>  typedef struct aes_key_st AES_KEY;
>
> +/* FreeBSD has it's own AES_set_decrypt_key in -lcrypto, avoid conflicts. */
> +#ifdef __FreeBSD__
> +#define AES_set_encrypt_key QEMU_AES_set_encrypt_key
> +#define AES_set_decrypt_key QEMU_AES_set_decrypt_key
> +#define AES_encrypt QEMU_AES_encrypt
> +#define AES_decrypt QEMU_AES_decrypt
> +#define AES_cbc_encrypt QEMU_AES_cbc_encrypt
> +#endif

You never answered Paolo's question about this patch, I think:
"What is the error?  Do the functions have different signatures
or semantics between QEMU and FreeBSD?"

If we need to resolve a clash, maybe we should just rename
the QEMU versions. Paolo?

thanks
-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH 16/18] bsd-user: add support for extended attribute and ACL related syscalls
  2013-10-16 14:37 ` [Qemu-devel] [PATCH 16/18] bsd-user: add support for extended attribute and ACL related syscalls Stacey Son
@ 2014-01-27 20:11   ` Peter Maydell
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Maydell @ 2014-01-27 20:11 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers

On 16 October 2013 15:37, Stacey Son <sson@freebsd.org> wrote:
> This change add support for extended attribute and Access Control List
> (ACL) related system calls including extattrctl(), extattr_set_file(2),
> extattr_delete_file(2), extattr_set_fd(2), extattr_get_fd(2),
> extattr_delete_fd(2), extattr_get_link(2), extattr_set_link(2),
> extattr_delete_link(2), extattr_list_fd(2), extattr_list_file(2),
> extattr_list_link(2), __acl_aclcheck_fd(), __acl_aclcheck_file(),
> __acl_aclcheck_link(), __acl_delete_fd(), __acl_delete_file(),
> __acl_delete_link(), __acl_get_fd(), __acl_get_file(), __acl_get_link(),
> __acl_get_fd(), __acl_set_file(), and __acl_set_link().
>
> Signed-off-by: Stacey Son <sson@FreeBSD.org>
> ---
>  bsd-user/Makefile.objs        |    2 +-
>  bsd-user/freebsd/os-extattr.c |  119 ++++++++
>  bsd-user/freebsd/os-extattr.h |  644 +++++++++++++++++++++++++++++++++++++++++
>  bsd-user/freebsd/qemu-os.h    |    6 +
>  bsd-user/netbsd/os-extattr.h  |  247 ++++++++++++++++
>  bsd-user/openbsd/os-extattr.h |  247 ++++++++++++++++

This is 500 lines of boilerplate just to say "these
system calls aren't implemented for these host OSes".
That's way too many; isn't there a better way to do this?
(Applies similarly to all these syscall-implementing
patches.)

thanks
-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto
  2014-01-27 20:07     ` Peter Maydell
@ 2014-01-27 20:15       ` Stacey Son
  2014-01-28 10:17       ` Paolo Bonzini
  1 sibling, 0 replies; 95+ messages in thread
From: Stacey Son @ 2014-01-27 20:15 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Paolo Bonzini, QEMU Developers


On Jan 27, 2014, at 2:07 PM, Peter Maydell <peter.maydell@linaro.org> wrote:

> On 17 December 2013 11:52, Stacey Son <sson@freebsd.org> wrote:
>> FreeBSD has it's own AES_set_decrypt_key, etc. in libcrypto.  This
>> change fixes these conflicts and allows statically linking BSD
>> user mode qemu.
>> ---
>> include/qemu/aes.h |    9 +++++++++
>> 1 files changed, 9 insertions(+), 0 deletions(-)
>> 
>> diff --git a/include/qemu/aes.h b/include/qemu/aes.h
>> index e79c707..6d253a3 100644
>> --- a/include/qemu/aes.h
>> +++ b/include/qemu/aes.h
>> @@ -10,6 +10,15 @@ struct aes_key_st {
>> };
>> typedef struct aes_key_st AES_KEY;
>> 
>> +/* FreeBSD has it's own AES_set_decrypt_key in -lcrypto, avoid conflicts. */
>> +#ifdef __FreeBSD__
>> +#define AES_set_encrypt_key QEMU_AES_set_encrypt_key
>> +#define AES_set_decrypt_key QEMU_AES_set_decrypt_key
>> +#define AES_encrypt QEMU_AES_encrypt
>> +#define AES_decrypt QEMU_AES_decrypt
>> +#define AES_cbc_encrypt QEMU_AES_cbc_encrypt
>> +#endif
> 
> You never answered Paolo's question about this patch, I think:
> "What is the error?  Do the functions have different signatures
> or semantics between QEMU and FreeBSD?"
> 
> If we need to resolve a clash, maybe we should just rename
> the QEMU versions. Paolo?

I must have missed Paolo's question.

The linker error (during a static build of qemu bsd-user)...

/usr/lib/libcrypto.a(aes-x86_64.o): In function `asm_AES_cbc_encrypt':
(.text+0xfa0): multiple definition of `AES_cbc_encrypt'
libqemuutil.a(aes.o):/home/sson/src/qemu/util/aes.c:1263: first defined here
/usr/lib/libcrypto.a(aes-x86_64.o): In function `asm_AES_decrypt':
(.text+0x9f0): multiple definition of `AES_decrypt'
libqemuutil.a(aes.o):/home/sson/src/qemu/util/aes.c:1072: first defined here
/usr/lib/libcrypto.a(aes-x86_64.o): In function `asm_AES_encrypt':
(.text+0x460): multiple definition of `AES_encrypt'

-stacey.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/19] bsd-user: Add system call and mips/arm support.
  2014-01-27 19:27       ` Stacey Son
@ 2014-01-27 20:18         ` Peter Maydell
  2014-05-08 14:59           ` Peter Maydell
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Maydell @ 2014-01-27 20:18 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers, Anthony Liguori

On 27 January 2014 19:27, Stacey Son <sson@freebsd.org> wrote:
> On Jan 27, 2014, at 1:15 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> I've been hoping somebody who uses FreeBSD would review
>> these, but since nobody has I'm going to take a look at
>> them. However, I've noticed that none of the patches in
>> this series have Signed-off-by: lines (oddly, since v2
>> and v1 certainly did). We can't apply them at all without
>> those, so you'll need to fix that in your next respin.
>
> I'll generate a new patch set (v4) here in the next day or so.

I've finished my first-pass review of these patches now.
You should probably address my comments before you post a v4.

In general I'd like to see these patches go in (much better
if you're helping to maintain bsd-user in-tree rather than
as a set of separate patches out of tree); however it's
going to be really difficult to get 25000 lines of code
reviewed and committed, especially since we don't have any
active bsd-user developers currently. You need to make the
process as easy as possible for us by making sure all your
patches are easy to review: not too big, and doing just
one thing at once, rather than mixing several changes together.

Looking at this patch series, I think it actually could
use being split into four different series:
 (1) Refactor existing bsd-user code to separate out
     the per-target-arch and per-OS parts
 (2) Add new system calls
 (3) Add ARM target support
 (4) Add MIPS target support

I think you will have much higher chances of success
if you try to get this work reviewed as four separate patch
series than if you submit it all as one enormous series.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto
  2014-01-27 20:07     ` Peter Maydell
  2014-01-27 20:15       ` Stacey Son
@ 2014-01-28 10:17       ` Paolo Bonzini
  1 sibling, 0 replies; 95+ messages in thread
From: Paolo Bonzini @ 2014-01-28 10:17 UTC (permalink / raw)
  To: Peter Maydell, Stacey Son; +Cc: QEMU Developers

Il 27/01/2014 21:07, Peter Maydell ha scritto:
> You never answered Paolo's question about this patch, I think:
> "What is the error?  Do the functions have different signatures
> or semantics between QEMU and FreeBSD?"
>
> If we need to resolve a clash, maybe we should just rename
> the QEMU versions. Paolo?

Yeah, but it looks like there's no clash.  Perhaps we can use libcrypto 
if present, and only include aes.c if libcrypto is not there.

Paolo

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 01/19] bsd-user: refresh freebsd system call numbers
  2014-01-27 19:30     ` Peter Maydell
@ 2014-02-01 12:11       ` Ed Maste
  0 siblings, 0 replies; 95+ messages in thread
From: Ed Maste @ 2014-02-01 12:11 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Stacey Son, QEMU Developers

On 27 January 2014 14:30, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> though this patch would look much nicer if you hadn't
> changed every single line in the file including the
> ones for syscalls we already had the #defines for.

The new version of this file was generated from the canonical FreeBSD
syscall numbering, using the same script that's in the FreeBSD tree
(makesyscalls.sh).  Future updates shouldn't encounter this again.

-Ed

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/19] bsd-user: Add system call and mips/arm support.
  2014-01-27 20:18         ` Peter Maydell
@ 2014-05-08 14:59           ` Peter Maydell
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Maydell @ 2014-05-08 14:59 UTC (permalink / raw)
  To: Stacey Son; +Cc: QEMU Developers, Anthony Liguori

On 27 January 2014 20:18, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 27 January 2014 19:27, Stacey Son <sson@freebsd.org> wrote:
>> On Jan 27, 2014, at 1:15 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
>>> I've been hoping somebody who uses FreeBSD would review
>>> these, but since nobody has I'm going to take a look at
>>> them. However, I've noticed that none of the patches in
>>> this series have Signed-off-by: lines (oddly, since v2
>>> and v1 certainly did). We can't apply them at all without
>>> those, so you'll need to fix that in your next respin.
>>
>> I'll generate a new patch set (v4) here in the next day or so.
>
> I've finished my first-pass review of these patches now.
> You should probably address my comments before you post a v4.

Hi Stacey -- I was just wondering if you were still planning
to do a revised version of these bsd-user patches?

thanks
-- PMM

^ permalink raw reply	[flat|nested] 95+ messages in thread

end of thread, other threads:[~2014-05-08 15:00 UTC | newest]

Thread overview: 95+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-16 14:36 [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Stacey Son
2013-10-16 14:36 ` [Qemu-devel] [PATCH 01/18] bsd-user: refresh freebsd system call numbers Stacey Son
2013-10-24  1:22   ` Ed Maste
2013-10-16 14:36 ` [Qemu-devel] [PATCH 02/18] bsd-user: add HOST_ABI_DIR for the various *BSD dependent code Stacey Son
2013-10-16 14:36 ` [Qemu-devel] [PATCH 03/18] bsd-user: move OS/arch dependent code for strace into separate directories Stacey Son
2013-10-16 14:36 ` [Qemu-devel] [PATCH 04/18] bsd-user: move target arch and host OS dependent code out of main.c Stacey Son
2013-10-16 15:38   ` [Qemu-devel] [PATCH 04/18] bsd-user: move target arch and host OSdependent code out of main.cc Alex Bennée
2013-10-16 15:46     ` Stacey Son
2013-10-16 16:32       ` Peter Maydell
2013-10-17 19:07         ` Stacey Son
2013-10-16 14:36 ` [Qemu-devel] [PATCH 05/18] bsd-user: move target arch and host OS dependent code out of syscall.c Stacey Son
2013-10-16 14:37 ` [Qemu-devel] [PATCH 06/18] bsd-user: add support for freebsd time related system calls Stacey Son
2013-10-16 14:37 ` [Qemu-devel] [PATCH 07/18] bsd-user: add support for freebsd signal " Stacey Son
2013-10-16 14:37 ` [Qemu-devel] [PATCH 08/18] bsd-user: move target arch and host OS dependent code out of elfload.c Stacey Son
2013-10-16 14:37 ` [Qemu-devel] [PATCH 09/18] bsd-user: add support for freebsd process related system calls Stacey Son
2013-10-16 14:37 ` [Qemu-devel] [PATCH 10/18] bsd-user: add support for file system " Stacey Son
2013-10-16 14:37 ` [Qemu-devel] [PATCH 11/18] bsd-user: add support for stat, directory, and file control " Stacey Son
2013-10-16 14:37 ` [Qemu-devel] [PATCH 12/18] bsd-user: add support for memory management " Stacey Son
2013-10-16 14:37 ` [Qemu-devel] [PATCH 13/18] bsd-user: add support for socket " Stacey Son
2013-10-16 14:37 ` [Qemu-devel] [PATCH 14/18] bsd-user: add support for thread " Stacey Son
2013-10-16 14:37 ` [Qemu-devel] [PATCH 15/18] bsd-user: add support for the ioctl system call Stacey Son
2013-10-16 14:37 ` [Qemu-devel] [PATCH 16/18] bsd-user: add support for extended attribute and ACL related syscalls Stacey Son
2014-01-27 20:11   ` Peter Maydell
2013-10-16 14:37 ` [Qemu-devel] [PATCH 17/18] bsd-user: add support for miscellaneous system calls Stacey Son
2013-10-16 14:37 ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-list Stacey Son
2013-10-16 15:22   ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-listt Alex Bennée
2013-10-16 16:12     ` Stacey Son
2013-10-16 16:31     ` Peter Maydell
2013-10-16 16:26   ` [Qemu-devel] [PATCH 18/18] bsd-user: add arm, mips and mips64 options to configure target-list Peter Maydell
2013-10-16 15:27 ` [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/armsupport Alex Bennée
2013-10-16 15:40   ` Stacey Son
2013-10-16 16:29 ` [Qemu-devel] [PATCH 00/18] bsd-user: Add system call and mips/arm support Peter Maydell
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 00/19] " Stacey Son
2013-11-26 21:01   ` Ed Maste
2013-11-27 11:29     ` Paolo Bonzini
2013-12-12 19:57       ` Ed Maste
2013-12-12 20:15         ` Stacey Son
2013-12-13 12:44         ` Paolo Bonzini
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 " Stacey Son
2014-01-27 19:15     ` Peter Maydell
2014-01-27 19:27       ` Stacey Son
2014-01-27 20:18         ` Peter Maydell
2014-05-08 14:59           ` Peter Maydell
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 01/19] bsd-user: refresh freebsd system call numbers Stacey Son
2014-01-27 19:30     ` Peter Maydell
2014-02-01 12:11       ` Ed Maste
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 02/19] bsd-user: add HOST_VARIANT_DIR for various *BSD dependent code Stacey Son
2014-01-27 19:31     ` Peter Maydell
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 03/19] bsd-user: move strace OS/arch dependent code to host/arch dirs Stacey Son
2014-01-27 19:46     ` Peter Maydell
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 04/19] bsd-user: move arch/OS dependent code out of main.c Stacey Son
2014-01-27 19:50     ` Peter Maydell
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 05/19] bsd-user: move arch/OS dependent code out of syscall.c Stacey Son
2014-01-27 19:52     ` Peter Maydell
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 06/19] bsd-user: add support for freebsd time related system calls Stacey Son
2014-01-27 19:58     ` Peter Maydell
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 07/19] bsd-user: add support for freebsd signal " Stacey Son
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 08/19] bsd-user: move arch/OS dependent code out of elfload.c Stacey Son
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 09/19] bsd-user: add support for freebsd process related system calls Stacey Son
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 10/19] bsd-user: add support for file system " Stacey Son
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 11/19] bsd-user: add support for stat, dir, and fcntl related syscalls Stacey Son
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 12/19] bsd-user: add support for memory management " Stacey Son
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 13/19] bsd-user: add support for socket related system calls Stacey Son
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 14/19] bsd-user: add support for thread " Stacey Son
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 15/19] bsd-user: add support for the ioctl system call Stacey Son
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 16/19] bsd-user: add support for extattr and ACL related syscalls Stacey Son
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 17/19] bsd-user: add support for miscellaneous system calls Stacey Son
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 18/19] bsd-user: add arm, mips and mips64 options to configure target-list Stacey Son
2014-01-27 20:03     ` Peter Maydell
2013-12-17 11:52   ` [Qemu-devel] [PATCH v3 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto Stacey Son
2014-01-27 20:07     ` Peter Maydell
2014-01-27 20:15       ` Stacey Son
2014-01-28 10:17       ` Paolo Bonzini
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 01/19] bsd-user: refresh freebsd system call numbers Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 02/19] bsd-user: add HOST_ABI_DIR for the various *BSD dependent code Stacey Son
2013-11-27 11:27   ` Paolo Bonzini
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 03/19] bsd-user: move OS/arch dependent code for strace into separate directories Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 04/19] bsd-user: move target arch and host OS dependent code out of main.c Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 05/19] bsd-user: move target arch and host OS dependent code out of syscall.c Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 06/19] bsd-user: add support for freebsd time related system calls Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 07/19] bsd-user: add support for freebsd signal " Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 08/19] bsd-user: move target arch and host OS dependent code out of elfload.c Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 09/19] bsd-user: add support for freebsd process related system calls Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 10/19] bsd-user: add support for file system " Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 11/19] bsd-user: add support for stat, directory, and file control " Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 12/19] bsd-user: add support for memory management " Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 13/19] bsd-user: add support for socket " Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 14/19] bsd-user: add support for thread " Stacey Son
2013-11-27 11:28   ` Paolo Bonzini
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 15/19] bsd-user: add support for the ioctl system call Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 16/19] bsd-user: add support for extended attribute and ACL related syscalls Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 17/19] bsd-user: add support for miscellaneous system calls Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 18/19] bsd-user: add arm, mips and mips64 options to configure target-list Stacey Son
2013-11-08 16:33 ` [Qemu-devel] [PATCH v2 19/19] bsd-user: fix linking conflicts with FreeBSD libcrypto Stacey Son
2013-11-27 11:23   ` Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.