diff options
author | Juergen Lock <nox@FreeBSD.org> | 2014-04-18 10:53:51 +0000 |
---|---|---|
committer | Juergen Lock <nox@FreeBSD.org> | 2014-04-18 10:53:51 +0000 |
commit | cf14e8bdd746039cc679bf4d0fc205ba4b95a2fb (patch) | |
tree | 3bcb58d0ad89f99a424a2a52c1c438790976da7d /emulators | |
parent | f107703159f52960021a3a7a4255308eb359ed1d (diff) | |
download | ports-cf14e8bdd746039cc679bf4d0fc205ba4b95a2fb.tar.gz ports-cf14e8bdd746039cc679bf4d0fc205ba4b95a2fb.zip |
Notes
Diffstat (limited to 'emulators')
20 files changed, 30564 insertions, 132 deletions
diff --git a/emulators/qemu-devel/Makefile b/emulators/qemu-devel/Makefile index a4e221894c70..9b4bb19509c0 100644 --- a/emulators/qemu-devel/Makefile +++ b/emulators/qemu-devel/Makefile @@ -2,8 +2,7 @@ # $FreeBSD$ PORTNAME= qemu -PORTVERSION= 1.7.1 -PORTREVISION= 5 +PORTVERSION= 2.0.0 CATEGORIES= emulators MASTER_SITES= http://wiki.qemu.org/download/:release \ LOCAL/nox:snapshot @@ -45,27 +44,14 @@ OPTIONS_DEFAULT=X11 GTK2 OPENGL GNUTLS SASL JPEG PNG CDROM_DMA CURL PCAP .include <bsd.port.options.mk> .if ${PORT_OPTIONS:MBSD_USER} -PATCH_SITES= http://people.freebsd.org/~sson/qemu/qemu-bsd-user/ -PATCHFILES= \ - 0001-bsd-user-refresh-freebsd-system-call-numbers.patch \ - 0002-bsd-user-add-HOST_VARIANT_DIR-for-various-BSD-depend.patch \ - 0003-bsd-user-move-strace-OS-arch-dependent-code-to-host-.patch \ - 0004-bsd-user-move-arch-OS-dependent-code-out-of-main.c.patch \ - 0005-bsd-user-move-arch-OS-dependent-code-out-of-syscall..patch \ - 0006-bsd-user-add-support-for-freebsd-time-related-system.patch \ - 0007-bsd-user-add-support-for-freebsd-signal-related-syst.patch \ - 0008-bsd-user-move-arch-OS-dependent-code-out-of-elfload..patch \ - 0009-bsd-user-add-support-for-freebsd-process-related-sys.patch \ - 0010-bsd-user-add-support-for-file-system-related-system-.patch \ - 0011-bsd-user-add-support-for-stat-dir-and-fcntl-related-.patch \ - 0012-bsd-user-add-support-for-memory-management-related-s.patch \ - 0013-bsd-user-add-support-for-socket-related-system-calls.patch \ - 0014-bsd-user-add-support-for-thread-related-system-calls.patch \ - 0015-bsd-user-add-support-for-the-ioctl-system-call.patch \ - 0016-bsd-user-add-support-for-extattr-and-ACL-related-sys.patch \ - 0017-bsd-user-add-support-for-miscellaneous-system-calls.patch \ - 0018-bsd-user-add-arm-mips-and-mips64-options-to-configur.patch -PATCH_DIST_STRIP= -p1 +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-790d0ef625d22ff3f1a895d266a48e2bacd63776 +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-3d175d6ed5b809976662135369c639f53780ca5c +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-a3129eea10f188bfd39ce83b18b25dcefbc5bffc +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-fd7ec8e06cd1876ef478975f052ff64134d19c6c +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-9ac2c49c734a49025fe1647ce84728d3988ea5d2 +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-38f8d5aaebdb4b1624bae86b374b5265c9f01b54 +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-c13_tls2 +# EXTRA_PATCHES+= ${FILESDIR}/extra-patch-bsd-user-freebsd-os-proc.c EXTRA_PATCHES+= ${FILESDIR}/extra-patch-05ee8495804599b52a88eb36b13ea9c06b3207cd EXTRA_PATCHES+= ${FILESDIR}/extra-patch-bsd-user-mips-target_arch_vmparam.h @@ -97,7 +83,7 @@ CONFIGURE_ARGS+= --target-list=i386-softmmu,x86_64-softmmu CONFIGURE_ARGS+= --disable-bsd-user .else .if ${ARCH} != "amd64" -CONFIGURE_ARGS+= --target-list=i386-softmmu,x86_64-softmmu,alpha-softmmu,arm-softmmu,cris-softmmu,lm32-softmmu,m68k-softmmu,microblaze-softmmu,microblazeel-softmmu,mips-softmmu,mipsel-softmmu,mips64-softmmu,mips64el-softmmu,or32-softmmu,ppc-softmmu,ppcemb-softmmu,ppc64-softmmu,sh4-softmmu,sh4eb-softmmu,sparc-softmmu,sparc64-softmmu,s390x-softmmu,xtensa-softmmu,xtensaeb-softmmu,unicore32-softmmu,moxie-softmmu,i386-bsd-user,sparc-bsd-user,arm-bsd-user,mips-bsd-user,mipsel-bsd-user +CONFIGURE_ARGS+= --target-list=i386-softmmu,x86_64-softmmu,aarch64-softmmu,alpha-softmmu,arm-softmmu,cris-softmmu,lm32-softmmu,m68k-softmmu,microblaze-softmmu,microblazeel-softmmu,mips-softmmu,mipsel-softmmu,mips64-softmmu,mips64el-softmmu,or32-softmmu,ppc-softmmu,ppcemb-softmmu,ppc64-softmmu,sh4-softmmu,sh4eb-softmmu,sparc-softmmu,sparc64-softmmu,s390x-softmmu,xtensa-softmmu,xtensaeb-softmmu,unicore32-softmmu,moxie-softmmu,i386-bsd-user,sparc-bsd-user,arm-bsd-user,mips-bsd-user,mipsel-bsd-user .endif .endif .endif @@ -144,7 +130,7 @@ USE_SDL= sdl .endif .if empty(PORT_OPTIONS:MGTK2) -CONFIGURE_ARGS+= --disable-gtk +CONFIGURE_ARGS+= --disable-gtk --disable-vte PLIST_SUB+= GTK2="@comment " .else USE_GNOME+= gtk20 vte @@ -241,11 +227,6 @@ MAKE_ENV+= COMPILER_PATH=${LOCALBASE}/bin CONFIGURE_ARGS+= --python=${PYTHON_CMD} -.if ${PORT_OPTIONS:MBSD_USER} -pre-patch: - @cd ${WRKSRC} && ${PATCH} --quiet < ${FILESDIR}/prepatch-configure -.endif - # -lprocstat actually only _needs_ -lelf after r249666 or r250870 (MFC) # but it shouldn't matter much post-patch: diff --git a/emulators/qemu-devel/distinfo b/emulators/qemu-devel/distinfo index 81eeabf70792..71faa8a40180 100644 --- a/emulators/qemu-devel/distinfo +++ b/emulators/qemu-devel/distinfo @@ -1,38 +1,2 @@ -SHA256 (qemu/1.7.1/qemu-1.7.1.tar.bz2) = d68942a004222eebae5d156ceefb308fabd98edb282d1dde49ec810bbf01bef4 -SIZE (qemu/1.7.1/qemu-1.7.1.tar.bz2) = 12246206 -SHA256 (qemu/1.7.1/0001-bsd-user-refresh-freebsd-system-call-numbers.patch) = 15fa3f286ae03636c9340de0b44ec4fc47e428025f103382a578029db45ec252 -SIZE (qemu/1.7.1/0001-bsd-user-refresh-freebsd-system-call-numbers.patch) = 36542 -SHA256 (qemu/1.7.1/0002-bsd-user-add-HOST_VARIANT_DIR-for-various-BSD-depend.patch) = 021f8c1fdba448c8eeb7a9f8035b8a47b1f463a59ee7da60d733bd63c2924b13 -SIZE (qemu/1.7.1/0002-bsd-user-add-HOST_VARIANT_DIR-for-various-BSD-depend.patch) = 2730 -SHA256 (qemu/1.7.1/0003-bsd-user-move-strace-OS-arch-dependent-code-to-host-.patch) = b0b08af1a4d6e7e660290c9f0293d7ad486c51df8fce29abed9db76143317d8a -SIZE (qemu/1.7.1/0003-bsd-user-move-strace-OS-arch-dependent-code-to-host-.patch) = 50756 -SHA256 (qemu/1.7.1/0004-bsd-user-move-arch-OS-dependent-code-out-of-main.c.patch) = 184336d1e8a6fabfa4fc6043603ab4f373d1ae80aefd7c57ba23cc36038b81da -SIZE (qemu/1.7.1/0004-bsd-user-move-arch-OS-dependent-code-out-of-main.c.patch) = 143116 -SHA256 (qemu/1.7.1/0005-bsd-user-move-arch-OS-dependent-code-out-of-syscall..patch) = 352b624cb09223a2c2df6281211719e20964829b5d776a18a8a0b5fe405ac9e3 -SIZE (qemu/1.7.1/0005-bsd-user-move-arch-OS-dependent-code-out-of-syscall..patch) = 44814 -SHA256 (qemu/1.7.1/0006-bsd-user-add-support-for-freebsd-time-related-system.patch) = fa6a24c90f451ba087964c3089b887cc97ef4aec66a251dd0b67279f66134737 -SIZE (qemu/1.7.1/0006-bsd-user-add-support-for-freebsd-time-related-system.patch) = 75063 -SHA256 (qemu/1.7.1/0007-bsd-user-add-support-for-freebsd-signal-related-syst.patch) = e4d78570ab787be5131a9336d06c51309a684a02b612099929f0bea728c99225 -SIZE (qemu/1.7.1/0007-bsd-user-add-support-for-freebsd-signal-related-syst.patch) = 100195 -SHA256 (qemu/1.7.1/0008-bsd-user-move-arch-OS-dependent-code-out-of-elfload..patch) = 6a5083c5257aea2da050cdf47a261b4e883a7b4e8a1410dd7dae4b1499f600c8 -SIZE (qemu/1.7.1/0008-bsd-user-move-arch-OS-dependent-code-out-of-elfload..patch) = 93309 -SHA256 (qemu/1.7.1/0009-bsd-user-add-support-for-freebsd-process-related-sys.patch) = 7e5e99ef2279c3023d21b9540eb9ad9355cd0010dd402cd60ab3abe6c40cb36f -SIZE (qemu/1.7.1/0009-bsd-user-add-support-for-freebsd-process-related-sys.patch) = 60141 -SHA256 (qemu/1.7.1/0010-bsd-user-add-support-for-file-system-related-system-.patch) = 52f97f394b5c75778e4f003de1033896fdc07c235289a9e91a8771e75bb9fd18 -SIZE (qemu/1.7.1/0010-bsd-user-add-support-for-file-system-related-system-.patch) = 43516 -SHA256 (qemu/1.7.1/0011-bsd-user-add-support-for-stat-dir-and-fcntl-related-.patch) = 5d25f3363080806a939cc985c9866c409006b35840a81f8d3c74f2cb9451ed31 -SIZE (qemu/1.7.1/0011-bsd-user-add-support-for-stat-dir-and-fcntl-related-.patch) = 31292 -SHA256 (qemu/1.7.1/0012-bsd-user-add-support-for-memory-management-related-s.patch) = f9e39e7138ad8c995255a4300b6887fce468296f61467445d3d2438cb6e1a761 -SIZE (qemu/1.7.1/0012-bsd-user-add-support-for-memory-management-related-s.patch) = 37395 -SHA256 (qemu/1.7.1/0013-bsd-user-add-support-for-socket-related-system-calls.patch) = 3e9f586a7327424d449c5a7c9cd7a589d8b14091bbe860cfe00a518bd1f6800c -SIZE (qemu/1.7.1/0013-bsd-user-add-support-for-socket-related-system-calls.patch) = 46894 -SHA256 (qemu/1.7.1/0014-bsd-user-add-support-for-thread-related-system-calls.patch) = f33d86896466ba39484715253ba9284d6c335b4e0e635150507bad63ef19e113 -SIZE (qemu/1.7.1/0014-bsd-user-add-support-for-thread-related-system-calls.patch) = 67546 -SHA256 (qemu/1.7.1/0015-bsd-user-add-support-for-the-ioctl-system-call.patch) = 90407a8e312ac5f4b3524cd5f65274baea49c4addf04a4614ce356e069983ab3 -SIZE (qemu/1.7.1/0015-bsd-user-add-support-for-the-ioctl-system-call.patch) = 77683 -SHA256 (qemu/1.7.1/0016-bsd-user-add-support-for-extattr-and-ACL-related-sys.patch) = b74903bfa42718edf4db21a2d746ab2c9548694c6dd6a270ea7c6885405505ec -SIZE (qemu/1.7.1/0016-bsd-user-add-support-for-extattr-and-ACL-related-sys.patch) = 43940 -SHA256 (qemu/1.7.1/0017-bsd-user-add-support-for-miscellaneous-system-calls.patch) = 6238ab7325c95b64544e7e72e7c45e44d4625a2e64851248dbb621b86ac7ed0d -SIZE (qemu/1.7.1/0017-bsd-user-add-support-for-miscellaneous-system-calls.patch) = 58081 -SHA256 (qemu/1.7.1/0018-bsd-user-add-arm-mips-and-mips64-options-to-configur.patch) = 694159e25187159709d449741446cc3218d31ea7eee47dde4946e8505d48a798 -SIZE (qemu/1.7.1/0018-bsd-user-add-arm-mips-and-mips64-options-to-configur.patch) = 2341 +SHA256 (qemu/2.0.0/qemu-2.0.0.tar.bz2) = 60cc1aa0cad39cec891f970bed60ca8a484f071adad4943123599ac223543a3b +SIZE (qemu/2.0.0/qemu-2.0.0.tar.bz2) = 12839647 diff --git a/emulators/qemu-devel/files/extra-patch-38f8d5aaebdb4b1624bae86b374b5265c9f01b54 b/emulators/qemu-devel/files/extra-patch-38f8d5aaebdb4b1624bae86b374b5265c9f01b54 new file mode 100644 index 000000000000..3de6319ed4f6 --- /dev/null +++ b/emulators/qemu-devel/files/extra-patch-38f8d5aaebdb4b1624bae86b374b5265c9f01b54 @@ -0,0 +1,29 @@ +diff --git a/bsd-user/freebsd/os-thread.c b/bsd-user/freebsd/os-thread.c +index 6bf2a9f..bcd2445 100644 +--- a/bsd-user/freebsd/os-thread.c ++++ b/bsd-user/freebsd/os-thread.c +@@ -899,11 +899,13 @@ abi_long do_freebsd_thr_new(CPUArchState *env, + pthread_attr_t attr; + TaskState *ts; + CPUArchState *new_env; ++ CPUState *new_cpu; + 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; ++ CPUState *parent_cpu = ENV_GET_CPU(env); ++ TaskState *parent_ts = parent_cpu->opaque; + sigset_t sigmask; + struct sched_param sched_param; + int sched_policy; +@@ -948,7 +950,8 @@ abi_long do_freebsd_thr_new(CPUArchState *env, + + /* init regs that differ from the parent thread. */ + target_cpu_clone_regs(new_env, info.param.stack_base); +- new_env->opaque = ts; ++ new_cpu = ENV_GET_CPU(new_env); ++ new_cpu->opaque = ts; + ts->bprm = parent_ts->bprm; + ts->info = parent_ts->info; + diff --git a/emulators/qemu-devel/files/extra-patch-3d175d6ed5b809976662135369c639f53780ca5c b/emulators/qemu-devel/files/extra-patch-3d175d6ed5b809976662135369c639f53780ca5c new file mode 100644 index 000000000000..9272f46aa42f --- /dev/null +++ b/emulators/qemu-devel/files/extra-patch-3d175d6ed5b809976662135369c639f53780ca5c @@ -0,0 +1,38 @@ +diff --git a/bsd-user/main.c b/bsd-user/main.c +index f27fcbc..16a0590 100644 +--- a/bsd-user/main.c ++++ b/bsd-user/main.c +@@ -272,6 +272,7 @@ void init_task_state(TaskState *ts) + CPUArchState *cpu_copy(CPUArchState *env) + { + CPUArchState *new_env = cpu_init(cpu_model); ++ CPUState *cpu; + #if defined(TARGET_HAS_ICE) + CPUBreakpoint *bp; + CPUWatchpoint *wp; +@@ -281,18 +282,19 @@ CPUArchState *cpu_copy(CPUArchState *env) + cpu_reset(ENV_GET_CPU(new_env)); + + memcpy(new_env, env, sizeof(CPUArchState)); ++ cpu = ENV_GET_CPU(env); + + /* 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); ++ QTAILQ_INIT(&cpu->breakpoints); ++ QTAILQ_INIT(&cpu->watchpoints); + #if defined(TARGET_HAS_ICE) +- QTAILQ_FOREACH(bp, &env->breakpoints, entry) { +- cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL); ++ QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { ++ cpu_breakpoint_insert(cpu, bp->pc, bp->flags, NULL); + } +- QTAILQ_FOREACH(wp, &env->watchpoints, entry) { +- cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1, ++ QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) { ++ cpu_watchpoint_insert(cpu, wp->vaddr, (~wp->len_mask) + 1, + wp->flags, NULL); + } + #endif diff --git a/emulators/qemu-devel/files/extra-patch-790d0ef625d22ff3f1a895d266a48e2bacd63776 b/emulators/qemu-devel/files/extra-patch-790d0ef625d22ff3f1a895d266a48e2bacd63776 new file mode 100644 index 000000000000..15043fae944d --- /dev/null +++ b/emulators/qemu-devel/files/extra-patch-790d0ef625d22ff3f1a895d266a48e2bacd63776 @@ -0,0 +1,30291 @@ +diff --git a/Makefile.target b/Makefile.target +index ba12340..9e9a913 100644 +--- a/Makefile.target ++++ b/Makefile.target +@@ -99,10 +99,11 @@ 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 ++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 5e77f57..ab025a4 100644 +--- a/bsd-user/Makefile.objs ++++ b/bsd-user/Makefile.objs +@@ -1,2 +1,6 @@ + obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \ +- uaccess.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 \ ++ $(HOST_VARIANT_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o +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.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_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_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/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/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/arm/target_arch_thread.h b/bsd-user/arm/target_arch_thread.h +new file mode 100644 +index 0000000..e69f612d +--- /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/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/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/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/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/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/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/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/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/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 93fd9e4..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,544 +27,12 @@ + + #include "qemu.h" + #include "disas/disas.h" ++#include "target_os_elf.h" ++#include "target_os_stack.h" ++#include "target_os_thread.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 +- +-#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 ++abi_ulong target_stksiz; ++abi_ulong target_stkbas; + + static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) + { +@@ -560,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 */ +@@ -568,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) +@@ -608,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 +@@ -665,42 +165,34 @@ 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; +- 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 = x86_stack_size; +- 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) { ++ size = target_dflssiz; ++ 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; + } + +@@ -758,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) +@@ -855,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) || +@@ -898,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 +@@ -920,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); +@@ -979,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) { +@@ -1048,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 +@@ -1058,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; + } + } +@@ -1093,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 || +@@ -1147,8 +550,32 @@ 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) ++/* 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) + { + struct elfhdr elf_ex; + struct elfhdr interp_elf_ex; +@@ -1166,20 +593,18 @@ int load_elf_binary(struct linux_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) || +@@ -1187,12 +612,14 @@ int load_elf_binary(struct linux_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); +@@ -1213,19 +640,16 @@ int load_elf_binary(struct linux_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; +@@ -1233,7 +657,7 @@ int load_elf_binary(struct linux_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 ) + { +@@ -1271,9 +695,9 @@ int load_elf_binary(struct linux_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 +@@ -1403,7 +827,7 @@ int load_elf_binary(struct linux_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; +@@ -1420,7 +844,7 @@ int load_elf_binary(struct linux_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, +@@ -1517,7 +941,7 @@ int load_elf_binary(struct linux_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, +@@ -1533,19 +957,22 @@ int load_elf_binary(struct linux_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 ) +@@ -1554,12 +981,21 @@ int load_elf_binary(struct linux_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; + } + +@@ -1571,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/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/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/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/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/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/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/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/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/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/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/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/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/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..7d79e52 +--- /dev/null ++++ b/bsd-user/freebsd/qemu-os.h +@@ -0,0 +1,79 @@ ++/* ++ * 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); ++ ++/* 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); ++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); ++ ++/* 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); ++ ++/* 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/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/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$ +- * 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 +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_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<OSTOP)*/ ++#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/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/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/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/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.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_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_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/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/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/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/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 f81ba55..f27fcbc 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 = ®s1; + 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; + cpu->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/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.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_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_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/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/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/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/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/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.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_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_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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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_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<OSTOP) */ ++#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/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/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/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/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/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/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/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/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/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/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/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/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/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/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_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<OSTOP) */ ++#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_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/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/qemu-bsd.h b/bsd-user/qemu-bsd.h +new file mode 100644 +index 0000000..771245d +--- /dev/null ++++ b/bsd-user/qemu-bsd.h +@@ -0,0 +1,79 @@ ++/* ++ * 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-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); ++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); ++ ++/* 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); ++ ++/* 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/qemu.h b/bsd-user/qemu.h +index ddc74ed..10d0fc4 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 + +@@ -20,16 +36,14 @@ enum BSDType { + }; + extern enum BSDType bsd_type; + ++#include "exec/user/thunk.h" + #include "syscall_defs.h" + #include "syscall.h" +-#include "target_signal.h" ++#include "target_os_vmparam.h" ++#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 +@@ -50,21 +64,23 @@ struct image_info { + abi_ulong entry; + abi_ulong code_offset; + abi_ulong data_offset; ++ abi_ulong arg_start; ++ abi_ulong arg_end; + int personality; + }; + + #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 +@@ -72,17 +88,28 @@ 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; + + 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]; + } __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; +@@ -100,7 +127,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; +@@ -109,19 +136,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); +@@ -149,6 +180,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, +@@ -169,17 +210,24 @@ 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); + 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, +@@ -188,15 +236,73 @@ 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) + void mmap_fork_start(void); + 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[]; ++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, ++ 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); ++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 */ + +@@ -387,8 +493,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 defined(CONFIG_USE_NPTL) +-#include <pthread.h> ++#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 ++ ++#include <pthread.h> + + #endif /* QEMU_H */ +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/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.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_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_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/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/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/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/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/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.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_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_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/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/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/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/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/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/syscall.c b/bsd-user/syscall.c +index a4d1583..35bf394 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 +@@ -16,403 +17,1538 @@ + * 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" + +-//#define DEBUG ++#define target_to_host_bitmask(x, tbl) (x) ++ ++/* BSD independent syscall shims */ ++#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" ++ ++/* *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" ++#include "os-stat.h" ++#include "os-thread.h" ++ ++/* #define DEBUG */ ++ ++/* ++ * errno conversion. ++ */ ++abi_long get_errno(abi_long ret) ++{ ++ ++ if (ret == -1) { ++ /* XXX need to translate host -> target errnos here */ ++ return -(errno); ++ } else { ++ return ret; ++ } ++} ++ ++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); ++} ++ ++/* FIXME ++ * lock_iovec()/unlock_iovec() have a return code of 0 for success where ++ * other lock functions have a return code of 0 for failure. ++ */ ++static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr, ++ int count, int copy) ++{ ++ 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) { ++ return -TARGET_EFAULT; ++ } ++ 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) { ++ vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy); ++ /* Don't check lock_user return value. We must call writev even ++ if a element has invalid base address. */ ++ } else { ++ /* zero length pointer is ignored */ ++ vec[i].iov_base = NULL; ++ } ++ } ++ unlock_user (target_vec, target_addr, 0); ++ return 0; ++} ++ ++static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, ++ 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) ++ return -TARGET_EFAULT; ++ 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); ++ } ++ } ++ unlock_user (target_vec, target_addr, 0); ++ ++ 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>. */ ++abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, ++ abi_long arg2, abi_long arg3, abi_long arg4, ++ abi_long arg5, abi_long arg6, abi_long arg7, ++ abi_long arg8) ++{ ++ abi_long ret; ++ ++#ifdef DEBUG ++ gemu_log("freebsd syscall %d\n", num); ++#endif ++ if(do_strace) ++ print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); ++ ++ switch(num) { ++ /* ++ * 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 ++ ++ 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; ++ ++ ++ ++ /* ++ * File system calls. ++ */ ++ case TARGET_FREEBSD_NR_read: /* read(2) */ ++ ret = do_bsd_read(arg1, arg2, arg3); ++ break; ++ ++ case TARGET_FREEBSD_NR_pread: /* pread(2) */ ++ ret = do_bsd_pread(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); ++ break; ++ ++ 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_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; ++ ++ /* ++ * 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; ++ ++ ++ /* ++ * 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_munlock: /* munlock(2) */ ++ ret = do_bsd_munlock(arg1, arg2); ++ break; ++ ++ case TARGET_FREEBSD_NR_mlockall: /* mlockall(2) */ ++ ret = do_bsd_mlockall(arg1); ++ break; ++ ++ 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. ++ */ ++ 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; ++ ++ /* ++ * 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; ++ ++ /* ++ * 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; ++ ++ /* ++ * 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; + +-static abi_ulong target_brk; +-static abi_ulong target_original_brk; ++ case TARGET_FREEBSD_NR_thr_exit: /* thr_exit(2) */ ++ ret = do_freebsd_thr_exit(cpu_env, arg1); ++ break; + +-static inline abi_long get_errno(abi_long ret) +-{ +- if (ret == -1) +- /* XXX need to translate host -> target errnos here */ +- return -(errno); +- else +- return ret; +-} ++ case TARGET_FREEBSD_NR_rtprio_thread: /* rtprio_thread(2) */ ++ ret = do_freebsd_rtprio_thread(arg1, arg2, arg3); ++ break; + +-#define target_to_host_bitmask(x, tbl) (x) ++ case TARGET_FREEBSD_NR_getcontext: /* getcontext(2) */ ++ ret = do_freebsd_getcontext(cpu_env, arg1); ++ break; + +-static inline int is_error(abi_long ret) +-{ +- return (abi_ulong)ret >= (abi_ulong)(-4096); +-} ++ case TARGET_FREEBSD_NR_setcontext: /* setcontext(2) */ ++ ret = do_freebsd_setcontext(cpu_env, arg1); ++ break; + +-void target_set_brk(abi_ulong new_brk) +-{ +- target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); +-} ++ case TARGET_FREEBSD_NR_swapcontext: /* swapcontext(2) */ ++ ret = do_freebsd_swapcontext(cpu_env, arg1, arg2); ++ break; + +-/* 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; ++ case TARGET_FREEBSD_NR__umtx_lock: /* undocumented */ ++ ret = do_freebsd__umtx_lock(arg1); ++ break; + +- if (!new_brk) +- return 0; +- if (new_brk < target_original_brk) +- return -TARGET_EINVAL; ++ case TARGET_FREEBSD_NR__umtx_unlock: /* undocumented */ ++ ret = do_freebsd__umtx_unlock(arg1); ++ break; + +- brk_page = HOST_PAGE_ALIGN(target_brk); ++ case TARGET_FREEBSD_NR__umtx_op: /* undocumented */ ++ ret = do_freebsd__umtx_op(arg1, arg2, arg3, arg4, arg5); ++ break; + +- /* 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; +- } ++ /* ++ * ioctl(2) ++ */ ++ case TARGET_FREEBSD_NR_ioctl: /* ioctl(2) */ ++ ret = do_bsd_ioctl(arg1, arg2, arg3); ++ break; + +- /* 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)); ++ /* ++ * sys{ctl, arch, call} ++ */ ++ case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */ ++ ret = do_freebsd_sysctl(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); ++ break; + +- if (!is_error(mapped_addr)) +- target_brk = new_brk; +- else +- return mapped_addr; ++ case TARGET_FREEBSD_NR_sysarch: /* sysarch(2) */ ++ ret = do_freebsd_sysarch(cpu_env, arg1, arg2); ++ break; + +- return 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; + +-#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; ++ /* ++ * extended attributes system calls ++ */ ++ case TARGET_FREEBSD_NR_extattrctl: /* extattrctl() */ ++ ret = do_freebsd_extattrctl(arg1, arg2, arg3, arg4, arg5); + 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 ++ case TARGET_FREEBSD_NR_extattr_set_file: /* extattr_set_file(2) */ ++ ret = do_freebsd_extattr_set_file(arg1, arg2, arg3, arg4, arg4); ++ break; + +-#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; ++ case TARGET_FREEBSD_NR_extattr_get_file: /* extattr_get_file(2) */ ++ ret = do_freebsd_extattr_get_file(arg1, arg2, arg3, arg4, arg4); ++ break; + +- qoid[0] = 0; +- qoid[1] = 4; +- memcpy(qoid + 2, oid, len * sizeof(int)); ++ case TARGET_FREEBSD_NR_extattr_delete_file: /* extattr_delete_file(2) */ ++ ret = do_freebsd_extattr_delete_file(arg1, arg2, arg3); ++ break; + +- j = sizeof(buf); +- i = sysctl(qoid, len + 2, buf, &j, 0, 0); +- if (i) +- return i; ++ case TARGET_FREEBSD_NR_extattr_set_fd: /* extattr_set_fd(2) */ ++ ret = do_freebsd_extattr_set_fd(arg1, arg2, arg3, arg4, arg5); ++ break; + +- if (kind) +- *kind = *(uint32_t *)buf; ++ case TARGET_FREEBSD_NR_extattr_get_fd: /* extattr_get_fd(2) */ ++ ret = do_freebsd_extattr_get_fd(arg1, arg2, arg3, arg4, arg5); ++ break; + +- if (fmt) +- strcpy(fmt, (char *)(buf + sizeof(uint32_t))); +- return (0); +-} ++ case TARGET_FREEBSD_NR_extattr_delete_fd: /* extattr_delete_fd(2) */ ++ ret = do_freebsd_extattr_delete_fd(arg1, arg2, arg3); ++ break; + +-/* +- * 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); ++ case TARGET_FREEBSD_NR_extattr_get_link: /* extattr_get_link(2) */ ++ ret = do_freebsd_extattr_get_link(arg1, arg2, arg3, arg4, arg4); + break; +-#endif +-#ifdef CTLTYPE_U64 +- case CTLTYPE_S64: +- case CTLTYPE_U64: +-#else +- case CTLTYPE_QUAD: +-#endif +- *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp); ++ ++ case TARGET_FREEBSD_NR_extattr_set_link: /* extattr_set_link(2) */ ++ ret = do_freebsd_extattr_set_link(arg1, arg2, arg3, arg4, arg4); + break; +- case CTLTYPE_STRING: ++ ++ case TARGET_FREEBSD_NR_extattr_delete_link: /* extattr_delete_link(2) */ ++ ret = do_freebsd_extattr_delete_link(arg1, arg2, arg3); + 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 ++ case TARGET_FREEBSD_NR_extattr_list_fd: /* extattr_list_fd(2) */ ++ ret = do_freebsd_extattr_list_fd(arg1, arg2, arg3, arg4); ++ break; + +-/* FIXME +- * lock_iovec()/unlock_iovec() have a return code of 0 for success where +- * other lock functions have a return code of 0 for failure. +- */ +-static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr, +- int count, int copy) +-{ +- struct target_iovec *target_vec; +- abi_ulong base; +- int i; ++ case TARGET_FREEBSD_NR_extattr_list_file: /* extattr_list_file(2) */ ++ ret = do_freebsd_extattr_list_file(arg1, arg2, arg3, arg4); ++ break; + +- 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++) { +- base = tswapl(target_vec[i].iov_base); +- vec[i].iov_len = tswapl(target_vec[i].iov_len); +- if (vec[i].iov_len != 0) { +- vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy); +- /* Don't check lock_user return value. We must call writev even +- if a element has invalid base address. */ +- } else { +- /* zero length pointer is ignored */ +- vec[i].iov_base = NULL; +- } +- } +- unlock_user (target_vec, target_addr, 0); +- return 0; +-} ++ case TARGET_FREEBSD_NR_extattr_list_link: /* extattr_list_link(2) */ ++ ret = do_freebsd_extattr_list_link(arg1, arg2, arg3, arg4); ++ break; + +-static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, +- int count, int copy) +-{ +- struct target_iovec *target_vec; +- abi_ulong base; +- int i; ++ case TARGET_FREEBSD_NR___acl_aclcheck_fd: /* __acl_aclcheck_fd() */ ++ ret = do_freebsd__acl_aclcheck_fd(arg1, arg2, arg3); ++ break; + +- 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++) { +- 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); +- } +- } +- unlock_user (target_vec, target_addr, 0); ++ case TARGET_FREEBSD_NR___acl_aclcheck_file: /* __acl_aclcheck_file() */ ++ ret = do_freebsd__acl_aclcheck_file(arg1, arg2, arg3); ++ break; + +- return 0; +-} ++ case TARGET_FREEBSD_NR___acl_aclcheck_link: /* __acl_aclcheck_link() */ ++ ret = do_freebsd__acl_aclcheck_link(arg1, arg2, arg3); ++ break; + +-/* 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>. */ +-abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, +- abi_long arg2, abi_long arg3, abi_long arg4, +- abi_long arg5, abi_long arg6, abi_long arg7, +- abi_long arg8) +-{ +- abi_long ret; +- void *p; ++ case TARGET_FREEBSD_NR___acl_delete_fd: /* __acl_delete_fd() */ ++ ret = do_freebsd__acl_delete_fd(arg1, arg2); ++ break; + +-#ifdef DEBUG +- gemu_log("freebsd syscall %d\n", num); +-#endif +- if(do_strace) +- print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); ++ case TARGET_FREEBSD_NR___acl_delete_file: /* __acl_delete_file() */ ++ ret = do_freebsd__acl_delete_file(arg1, arg2); ++ break; + +- switch(num) { +- case TARGET_FREEBSD_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 */ +- 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); +- 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); +- 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___acl_delete_link: /* __acl_delete_link() */ ++ ret = do_freebsd__acl_delete_link(arg1, arg2); + 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___acl_get_fd: /* __acl_get_fd() */ ++ ret = do_freebsd__acl_get_fd(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), +- arg5, +- arg6)); ++ ++ case TARGET_FREEBSD_NR___acl_get_file: /* __acl_get_file() */ ++ ret = do_freebsd__acl_get_file(arg1, arg2, arg3); + break; +- case TARGET_FREEBSD_NR_mprotect: +- ret = get_errno(target_mprotect(arg1, arg2, arg3)); ++ ++ case TARGET_FREEBSD_NR___acl_get_link: /* __acl_get_link() */ ++ ret = do_freebsd__acl_get_link(arg1, arg2, arg3); + break; +- case TARGET_FREEBSD_NR_break: +- ret = do_obreak(arg1); ++ ++ case TARGET_FREEBSD_NR___acl_set_fd: /* __acl_get_fd() */ ++ ret = do_freebsd__acl_set_fd(arg1, arg2, arg3); + break; +-#ifdef __FreeBSD__ +- case TARGET_FREEBSD_NR___sysctl: +- ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6); ++ ++ case TARGET_FREEBSD_NR___acl_set_file: /* __acl_set_file() */ ++ ret = do_freebsd__acl_set_file(arg1, arg2, arg3); + break; +-#endif +- case TARGET_FREEBSD_NR_sysarch: +- ret = do_freebsd_sysarch(cpu_env, arg1, arg2); ++ ++ case TARGET_FREEBSD_NR___acl_set_link: /* __acl_set_link() */ ++ 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_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_break: ++ ret = do_obreak(arg1); + 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: ++ + #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, +@@ -420,7 +1556,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); +@@ -430,43 +1565,26 @@ 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), +- 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: + case TARGET_NETBSD_NR___syscall: + ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); +@@ -475,16 +1593,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, +@@ -492,7 +1606,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); +@@ -502,43 +1615,26 @@ 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), +- 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: + case TARGET_OPENBSD_NR___syscall: + ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); +@@ -547,18 +1643,16 @@ 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) + { ++ ++ init_bsd_ioctl(); + } +diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h +index 207ddee..13678d4 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<OSTOP) */ +-#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,759 @@ 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]; ++}; ++ ++ ++/* ++ * 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/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.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_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_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_ */ +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_ */ +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_ */ +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_ */ +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 */ +diff --git a/configure b/configure +index aae617e..f0b4da7 100755 +--- a/configure ++++ b/configure +@@ -526,6 +526,9 @@ fi + + # OS specific + ++# host *BSD for user mode ++HOST_VARIANT_DIR="" ++ + case $targetos in + CYGWIN*) + mingw32="yes" +@@ -551,12 +554,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" +@@ -564,12 +569,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" +@@ -587,6 +594,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" +@@ -4894,6 +4902,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 +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 +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, +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 diff --git a/emulators/qemu-devel/files/extra-patch-9ac2c49c734a49025fe1647ce84728d3988ea5d2 b/emulators/qemu-devel/files/extra-patch-9ac2c49c734a49025fe1647ce84728d3988ea5d2 new file mode 100644 index 000000000000..048a3ede5414 --- /dev/null +++ b/emulators/qemu-devel/files/extra-patch-9ac2c49c734a49025fe1647ce84728d3988ea5d2 @@ -0,0 +1,14 @@ +diff --git a/bsd-user/freebsd/os-sys.c b/bsd-user/freebsd/os-sys.c +index c8f999f..2578645 100644 +--- a/bsd-user/freebsd/os-sys.c ++++ b/bsd-user/freebsd/os-sys.c +@@ -130,7 +130,8 @@ abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen, + 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; ++ CPUState *cpu = ENV_GET_CPU(env); ++ TaskState *ts = cpu->opaque; + + if (oldlenp) { + if (get_user_ual(oldlen, oldlenp)) { diff --git a/emulators/qemu-devel/files/extra-patch-a3129eea10f188bfd39ce83b18b25dcefbc5bffc b/emulators/qemu-devel/files/extra-patch-a3129eea10f188bfd39ce83b18b25dcefbc5bffc new file mode 100644 index 000000000000..11056d010961 --- /dev/null +++ b/emulators/qemu-devel/files/extra-patch-a3129eea10f188bfd39ce83b18b25dcefbc5bffc @@ -0,0 +1,53 @@ +diff --git a/bsd-user/signal.c b/bsd-user/signal.c +index 3619b00..01374a6 100644 +--- a/bsd-user/signal.c ++++ b/bsd-user/signal.c +@@ -283,7 +283,8 @@ static int core_dump_signal(int sig) + /* Signal queue handling. */ + static inline struct qemu_sigqueue *alloc_sigqueue(CPUArchState *env) + { +- TaskState *ts = env->opaque; ++ CPUState *cpu = thread_cpu; ++ TaskState *ts = (TaskState *)cpu->opaque; + struct qemu_sigqueue *q = ts->first_free; + + if (!q) { +@@ -296,7 +297,8 @@ static inline struct qemu_sigqueue *alloc_sigqueue(CPUArchState *env) + static inline void free_sigqueue(CPUArchState *env, struct qemu_sigqueue *q) + { + +- TaskState *ts = env->opaque; ++ CPUState *cpu = thread_cpu; ++ TaskState *ts = (TaskState *)cpu->opaque; + q->next = ts->first_free; + ts->first_free = q; + } +@@ -305,7 +307,8 @@ static inline void free_sigqueue(CPUArchState *env, struct qemu_sigqueue *q) + void QEMU_NORETURN force_sig(int target_sig) + { + CPUArchState *env = thread_cpu->env_ptr; +- TaskState *ts = (TaskState *)env->opaque; ++ CPUState *cpu = thread_cpu; ++ TaskState *ts = (TaskState *)cpu->opaque; + int core_dumped = 0; + int host_sig; + struct sigaction act; +@@ -365,7 +368,8 @@ void QEMU_NORETURN force_sig(int target_sig) + */ + int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info) + { +- TaskState *ts = env->opaque; ++ CPUState *cpu = thread_cpu; ++ TaskState *ts = (TaskState *)cpu->opaque; + struct emulated_sigtable *k; + struct qemu_sigqueue *q, **pq; + abi_ulong handler; +@@ -826,7 +830,7 @@ void process_pending_signals(CPUArchState *cpu_env) + struct emulated_sigtable *k; + struct target_sigaction *sa; + struct qemu_sigqueue *q; +- TaskState *ts = cpu_env->opaque; ++ TaskState *ts = cpu->opaque; + + if (!ts->signal_pending) { + return; diff --git a/emulators/qemu-devel/files/extra-patch-bsd-user-freebsd-os-proc.c b/emulators/qemu-devel/files/extra-patch-bsd-user-freebsd-os-proc.c index 78c80e43a3a1..b53b82e72d69 100644 --- a/emulators/qemu-devel/files/extra-patch-bsd-user-freebsd-os-proc.c +++ b/emulators/qemu-devel/files/extra-patch-bsd-user-freebsd-os-proc.c @@ -1,3 +1,14 @@ +From nox Mon Sep 17 00:00:00 2001 +From: Juergen Lock <nox@jelal.kn-bremen.de> +Date: 22 Mar 2014 00:21:00 +0100 +Subject: Fix bsd-user targets running scripts with shebang args + +This fixes running scripts starting like: + + #! /usr/bin/perl -w + +Signed-off-by: Juergen Lock <nox@jelal.kn-bremen.de> + --- a/bsd-user/freebsd/os-proc.c --- b/bsd-user/freebsd/os-proc.c @@ -83,7 +83,7 @@ out: diff --git a/emulators/qemu-devel/files/extra-patch-bsd-user-mips-target_arch_vmparam.h b/emulators/qemu-devel/files/extra-patch-bsd-user-mips-target_arch_vmparam.h index f022cbb696c2..ec347bbb8d6f 100644 --- a/emulators/qemu-devel/files/extra-patch-bsd-user-mips-target_arch_vmparam.h +++ b/emulators/qemu-devel/files/extra-patch-bsd-user-mips-target_arch_vmparam.h @@ -1,3 +1,13 @@ +From nox Mon Sep 17 00:00:00 2001 +From: Juergen Lock <nox@jelal.kn-bremen.de> +Date: 04 Apr 2014 02:09:00 +0200 +Subject: Lower 32bit mips TARGET_USRSTACK + +Lower 32bit mips TARGET_USRSTACK to fix an assert starting mips-bsd-user +processes on 64bit hosts. (like amd64) + +Signed-off-by: Juergen Lock <nox@jelal.kn-bremen.de> + --- a/bsd-user/mips/target_arch_vmparam.h +++ b/bsd-user/mips/target_arch_vmparam.h @@ -35,7 +35,8 @@ diff --git a/emulators/qemu-devel/files/extra-patch-bsd-user-mmap.c b/emulators/qemu-devel/files/extra-patch-bsd-user-mmap.c index 9370e5bd7fd3..f8b393397839 100644 --- a/emulators/qemu-devel/files/extra-patch-bsd-user-mmap.c +++ b/emulators/qemu-devel/files/extra-patch-bsd-user-mmap.c @@ -1,3 +1,13 @@ +From nox Mon Sep 17 00:00:00 2001 +From: Juergen Lock <nox@jelal.kn-bremen.de> +Date: 06 Apr 2014 02:20:00 +0200 +Subject: Wrap bsd-user mmap(2) allocation search to low memory + +Wrap bsd-user mmap(2) allocation search to low memory to avoid +another assert on 64bit hosts. + +Signed-off-by: Juergen Lock <nox@jelal.kn-bremen.de> + --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -238,8 +238,13 @@ abi_ulong mmap_find_vma(abi_ulong start, diff --git a/emulators/qemu-devel/files/extra-patch-bsd-user-syscall.c b/emulators/qemu-devel/files/extra-patch-bsd-user-syscall.c index 3570ca234e35..1dda197e9c3d 100644 --- a/emulators/qemu-devel/files/extra-patch-bsd-user-syscall.c +++ b/emulators/qemu-devel/files/extra-patch-bsd-user-syscall.c @@ -1,3 +1,12 @@ +From nox Mon Sep 17 00:00:00 2001 +From: Juergen Lock <nox@jelal.kn-bremen.de> +Date: 05 Apr 2014 02:04:00 +0200 +Subject: Fix bsd-user FreeBSD fchflags() syscall (typo) + +Fix bsd-user FreeBSD fchflags() syscall. (typo) + +Signed-off-by: Juergen Lock <nox@jelal.kn-bremen.de> + --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -627,7 +627,7 @@ abi_long do_freebsd_syscall(void *cpu_en diff --git a/emulators/qemu-devel/files/extra-patch-c13_tls2 b/emulators/qemu-devel/files/extra-patch-c13_tls2 new file mode 100644 index 000000000000..fca58f546c57 --- /dev/null +++ b/emulators/qemu-devel/files/extra-patch-c13_tls2 @@ -0,0 +1,15 @@ +--- a/bsd-user/arm/target_arch_cpu.c ++++ b/bsd-user/arm/target_arch_cpu.c +@@ -18,10 +18,10 @@ + + void target_cpu_set_tls(CPUARMState *env, target_ulong newtls) + { +- env->cp15.c13_tls2 = newtls; ++ env->cp15.tpidrro_el0 = newtls; + } + + target_ulong target_cpu_get_tls(CPUARMState *env) + { +- return (env->cp15.c13_tls2); ++ return (env->cp15.tpidrro_el0); + } diff --git a/emulators/qemu-devel/files/extra-patch-fd7ec8e06cd1876ef478975f052ff64134d19c6c b/emulators/qemu-devel/files/extra-patch-fd7ec8e06cd1876ef478975f052ff64134d19c6c new file mode 100644 index 000000000000..27bc834a9844 --- /dev/null +++ b/emulators/qemu-devel/files/extra-patch-fd7ec8e06cd1876ef478975f052ff64134d19c6c @@ -0,0 +1,13 @@ +diff --git a/bsd-user/freebsd/os-thread.h b/bsd-user/freebsd/os-thread.h +index 5e24852..28f737f 100644 +--- a/bsd-user/freebsd/os-thread.h ++++ b/bsd-user/freebsd/os-thread.h +@@ -68,7 +68,7 @@ static abi_long do_freebsd_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr) + } + thread_cpu = NULL; + object_unref(OBJECT(ENV_GET_CPU(cpu_env))); +- ts = ((CPUArchState *)cpu_env)->opaque; ++ ts = cpu->opaque; + g_free(ts); + pthread_exit(NULL); + /* Doesn't return */ diff --git a/emulators/qemu-devel/files/extra-patch-inherit-interp_prefix b/emulators/qemu-devel/files/extra-patch-inherit-interp_prefix index 6cfb157353a1..3d1c360b8e07 100644 --- a/emulators/qemu-devel/files/extra-patch-inherit-interp_prefix +++ b/emulators/qemu-devel/files/extra-patch-inherit-interp_prefix @@ -1,3 +1,13 @@ +From nox Mon Sep 17 00:00:00 2001 +From: Juergen Lock <nox@jelal.kn-bremen.de> +Date: 04 Apr 2014 16:36:00 +0200 +Subject: Pass down interp_prefix (-L arg) to bsd-user child processes + +Pass down interp_prefix (-L arg) to bsd-user target child processes +so running shared target binaries as subprocesses works. + +Signed-off-by: Juergen Lock <nox@jelal.kn-bremen.de> + --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -58,7 +58,7 @@ unsigned long reserved_va; diff --git a/emulators/qemu-devel/files/extra-patch-sysctl-0oldlen b/emulators/qemu-devel/files/extra-patch-sysctl-0oldlen index 72a8d52d92d7..0f2d96e5ee1d 100644 --- a/emulators/qemu-devel/files/extra-patch-sysctl-0oldlen +++ b/emulators/qemu-devel/files/extra-patch-sysctl-0oldlen @@ -1,3 +1,13 @@ +From nox Mon Sep 17 00:00:00 2001 +From: Juergen Lock <nox@jelal.kn-bremen.de> +Date: 05 Apr 2014 23:36:00 +0200 +Subject: Fix FreeBSD sysctls kern.usrstack and kern.ps_strings + +Fix FreeBSD sysctls kern.usrstack and kern.ps_strings invoked with +oidlen zero. (like from sysctl(8)) + +Signed-off-by: Juergen Lock <nox@jelal.kn-bremen.de> + --- a/bsd-user/freebsd/os-sys.c +++ b/bsd-user/freebsd/os-sys.c @@ -165,7 +165,9 @@ abi_long do_freebsd_sysctl(CPUArchState diff --git a/emulators/qemu-devel/files/extra-patch-sysctl-hw-availpages b/emulators/qemu-devel/files/extra-patch-sysctl-hw-availpages index 914f146961b4..5253802430bc 100644 --- a/emulators/qemu-devel/files/extra-patch-sysctl-hw-availpages +++ b/emulators/qemu-devel/files/extra-patch-sysctl-hw-availpages @@ -1,3 +1,13 @@ +From nox Mon Sep 17 00:00:00 2001 +From: Juergen Lock <nox@jelal.kn-bremen.de> +Date: 05 Apr 2014 21:06:00 +0200 +Subject: Fix bsd-user FreeBSD hw.availpages sysctl + +hw.availpages is defined as OID_AUTO so the mib can change; find out +it's value at the first hw.* sysctl syscall. + +Signed-off-by: Juergen Lock <nox@jelal.kn-bremen.de> + --- a/bsd-user/freebsd/os-sys.c +++ b/bsd-user/freebsd/os-sys.c @@ -219,24 +219,36 @@ abi_long do_freebsd_sysctl(CPUArchState diff --git a/emulators/qemu-devel/files/patch-configure b/emulators/qemu-devel/files/patch-configure index 49b7e000a62d..e87341476e6b 100644 --- a/emulators/qemu-devel/files/patch-configure +++ b/emulators/qemu-devel/files/patch-configure @@ -9,16 +9,16 @@ datadir="\${prefix}/share" qemu_docdir="\${prefix}/share/doc/qemu" bindir="\${prefix}/bin" -@@ -1749,7 +1749,7 @@ if test "$gtk" != "no"; then - gtk_libs=`$pkg_config --libs $gtkpackage` - vte_cflags=`$pkg_config --cflags $vtepackage` - vte_libs=`$pkg_config --libs $vtepackage` -- libs_softmmu="$gtk_libs $vte_libs $libs_softmmu" -+ libs_softmmu="$gtk_libs -lintl $vte_libs $libs_softmmu" - gtk="yes" - fi - fi -@@ -2956,15 +2956,18 @@ if compile_prog "" "" ; then +@@ -1980,7 +1980,7 @@ if test "$gtk" != "no"; then + if $pkg_config --exists "$gtkpackage >= $gtkversion"; then + gtk_cflags=`$pkg_config --cflags $gtkpackage` + gtk_libs=`$pkg_config --libs $gtkpackage` +- libs_softmmu="$gtk_libs $libs_softmmu" ++ libs_softmmu="$gtk_libs -lintl $libs_softmmu" + gtk="yes" + elif test "$gtk" = "yes"; then + feature_not_found "gtk" "Install gtk2 or gtk3 (requires --with-gtkabi=3.0 option to configure) devel" +@@ -3320,15 +3320,18 @@ if compile_prog "" "" ; then fi # Check if tools are available to build documentation. @@ -27,7 +27,7 @@ +# docs=yes +# else +# if test "$docs" = "yes" ; then -+# feature_not_found "docs" ++# feature_not_found "docs" "Install texinfo and Perl/perl-podlators" +# fi +# docs=no +# fi @@ -37,7 +37,7 @@ - docs=yes - else - if test "$docs" = "yes" ; then -- feature_not_found "docs" +- feature_not_found "docs" "Install texinfo and Perl/perl-podlators" - fi - docs=no - fi @@ -45,15 +45,10 @@ fi # Search for bswap_32 function -@@ -3121,17 +3124,30 @@ fi +@@ -3498,6 +3501,17 @@ fi # check for libusb if test "$libusb" != "no" ; then -- if $pkg_config --atleast-version=1.0.13 libusb-1.0; then -- libusb="yes" -- libusb_cflags=$($pkg_config --cflags libusb-1.0) -- libusb_libs=$($pkg_config --libs libusb-1.0) -- QEMU_CFLAGS="$QEMU_CFLAGS $libusb_cflags" + cat > $TMPC << EOF +#include <libusb.h> + @@ -63,24 +58,16 @@ + libusb="yes" + libusb_cflags="" + libusb_libs=-lusb - libs_softmmu="$libs_softmmu $libusb_libs" - else -- if test "$libusb" = "yes"; then -- feature_not_found "libusb" -+ if $pkg_config --atleast-version=1.0.13 libusb-1.0; then -+ libusb="yes" -+ usb="libusb" -+ libusb_cflags=$($pkg_config --cflags libusb-1.0) -+ libusb_libs=$($pkg_config --libs libusb-1.0) -+ QEMU_CFLAGS="$QEMU_CFLAGS $libusb_cflags" -+ libs_softmmu="$libs_softmmu $libusb_libs" -+ else -+ if test "$libusb" = "yes"; then -+ feature_not_found "libusb" -+ fi -+ libusb="no" ++ libs_softmmu="$libs_softmmu $libusb_libs" ++ else + if $pkg_config --atleast-version=1.0.13 libusb-1.0; then + libusb="yes" + libusb_cflags=$($pkg_config --cflags libusb-1.0) +@@ -3510,6 +3524,7 @@ if test "$libusb" != "no" ; then fi -- libusb="no" + libusb="no" fi ++ fi fi + # check for usbredirparser for usb network redirection support diff --git a/emulators/qemu-devel/files/patch-tcg-i386-tcg-target.c b/emulators/qemu-devel/files/patch-tcg-i386-tcg-target.c deleted file mode 100644 index 308f934b4965..000000000000 --- a/emulators/qemu-devel/files/patch-tcg-i386-tcg-target.c +++ /dev/null @@ -1,13 +0,0 @@ ---- a/tcg/i386/tcg-target.c -+++ b/tcg/i386/tcg-target.c -@@ -104,6 +104,10 @@ static const int tcg_target_call_oarg_re - # define have_cmov 1 - #elif defined(CONFIG_CPUID_H) - #include <cpuid.h> -+#ifndef bit_CMOV -+/* clang's <cpuid.h> doesn't define bit_* */ -+#define bit_CMOV (1 << 15) -+#endif - static bool have_cmov; - #else - # define have_cmov 0 diff --git a/emulators/qemu-devel/files/pcap-patch b/emulators/qemu-devel/files/pcap-patch index 1688360e8c6c..497827e6037c 100644 --- a/emulators/qemu-devel/files/pcap-patch +++ b/emulators/qemu-devel/files/pcap-patch @@ -1,16 +1,16 @@ --- configure.orig +++ configure -@@ -261,6 +261,9 @@ gtkabi="2.0" - tpm="no" +@@ -324,6 +324,9 @@ tpm="no" libssh2="" vhdx="" + quorum="no" +pcap="no" +pcap_create="no" +bpf="no" # parse CC options first for opt do -@@ -787,6 +790,10 @@ for opt do +@@ -865,6 +868,10 @@ for opt do ;; --enable-vnc-ws) vnc_ws="yes" ;; @@ -21,7 +21,7 @@ --disable-slirp) slirp="no" ;; --disable-uuid) uuid="no" -@@ -1884,6 +1891,51 @@ EOF +@@ -2130,6 +2137,51 @@ EOF fi ########################################## @@ -73,7 +73,7 @@ # VNC TLS/WS detection if test "$vnc" = "yes" -a \( "$vnc_tls" != "no" -o "$vnc_ws" != "no" \) ; then cat > $TMPC <<EOF -@@ -3747,6 +3799,7 @@ echo "Audio drivers $audio_drv_list" +@@ -4133,6 +4185,7 @@ echo "Audio drivers $audio_drv_list" echo "Block whitelist (rw) $block_drv_rw_whitelist" echo "Block whitelist (ro) $block_drv_ro_whitelist" echo "VirtFS support $virtfs" @@ -81,7 +81,7 @@ echo "VNC support $vnc" if test "$vnc" = "yes" ; then echo "VNC TLS support $vnc_tls" -@@ -3897,6 +3950,15 @@ fi +@@ -4297,6 +4350,15 @@ fi if test "$profiler" = "yes" ; then echo "CONFIG_PROFILER=y" >> $config_host_mak fi diff --git a/emulators/qemu-devel/files/prepatch-configure b/emulators/qemu-devel/files/prepatch-configure deleted file mode 100644 index 1b4708fc382f..000000000000 --- a/emulators/qemu-devel/files/prepatch-configure +++ /dev/null @@ -1,10 +0,0 @@ ---- a/configure -+++ b/configure -@@ -491,6 +491,7 @@ FreeBSD) - audio_possible_drivers="oss sdl esd pa" - # needed for kinfo_getvmmap(3) in libutil.h - LIBS="-lutil $LIBS" -+ netmap="" # enable netmap autodetect - ;; - DragonFly) - bsd="yes" |