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