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 . + */ +#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 . + */ + +#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 . + */ +#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 . + */ +#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 . + */ + +#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 . + */ +#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 . + */ +#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 . + */ + +#ifndef __BSD_FILE_H_ +#define __BSD_FILE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 . + */ + +#include +#include +#include +#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 +#include +#else +#include +#endif +#include +#include + +#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 . + */ + +#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 . + */ + +#include +#include + +#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 . + */ + +/*-- + * 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 +#include +#include +#include +#include + +#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 . + */ + +#include +#include +#include +#include +#include + +#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 . + */ + +#ifndef __BSD_MISC_H_ +#define __BSD_MISC_H_ + +#include +#include +#include +#include +#include + +#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 . + */ + +#include +#include +#include + +#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 . + */ + +#ifndef __BSD_PROC_H_ +#define __BSD_PROC_H_ + +#include +#include +#include +#include +#include + +#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 . + */ + +#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 . + */ + +#include +#include +#include +#include + +#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 . + */ +#ifndef __BSD_SOCKET_H_ +#define __BSD_SOCKET_H_ + +#include +#include +#include +#include + +#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 . + */ #include #include @@ -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 ; ipage[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 ; ipage[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 . + */ #include #include @@ -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; ie_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; ie_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; ip_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 . + */ + +#ifndef __HOST_OS_H_ +#define __HOST_OS_H_ + +#include +#include + +#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 . + */ + +#include +#ifndef _ACL_PRIVATE +#define _ACL_PRIVATE +#endif +#include + +#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 . + */ + +#include +#ifndef _ACL_PRIVATE +#define _ACL_PRIVATE +#endif +#include + +#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 . + */ +#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 . + */ + +#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 . + */ + +#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 . + */ +#ifndef __OS_MISC_H_ +#define __OS_MISC_H_ + +#include +#include + +/* 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 . + */ + +#include +#include +#include +#include +#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 +#include +#endif +#include + +#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 . + */ + +#ifndef __FREEBSD_PROC_H_ +#define __FREEBSD_PROC_H_ + +#include +#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 +#include +#endif +#include +#include + +#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 . + */ + +#ifndef __FREEBSD_OS_SIGNAL_H_ +#define __FREEBSD_OS_SIGNAL_H_ + +#include + +#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 . + */ + +#include +#include +#include + +#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 . + */ +#ifndef __FREEBSD_SOCKET_H_ +#define __FREEBSD_SOCKET_H_ + +#include +#include +#include +#include + +#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 . + */ + +#include +#include +#include + +#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 . + */ + +#ifndef __FREEBSD_STAT_H_ +#define __FREEBSD_STAT_H_ + +#include +#include +#include +#include +#include + +#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 . + */ + +#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 . + */ + +#include +#include +#include +#include + +#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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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(" %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(" %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(" %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(" %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(" %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(" %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(" %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(" %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(" %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(" %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(" %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(" %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(" %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(" %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(" %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(" %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(" %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(" %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(" %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 . + */ +#ifndef __FREEBSD_OS_THREAD_H_ +#define __FREEBSD_OS_THREAD_H_ + +#include +#include +#include + +#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 . + */ + +#include +#include +#include + +#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 . + */ + +#ifndef __FREEBSD_OS_TIME_H_ +#define __FREEBSD_OS_TIME_H_ + +#include +#include +#include +#include +#include +#include + +#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 . + */ + +#ifndef _QEMU_OS_H_ +#define _QEMU_OS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* 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 . + */ + +{ 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 . + */ +#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 . + */ +#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 +#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 . + */ +#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 . + */ + +#include + +#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 . + */ + +#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 . + */ +#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 . + */ +#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 . + */ + +#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 . + */ +#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 #include #include +#include #include #include #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 . + */ +#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 . + */ +#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 . + */ + +#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 . + */ +#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 . + */ +#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 . + */ + +#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 . + */ +#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 . + */ +#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 . + */ +#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 . + */ +#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 . + */ + +#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 . + */ +#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 . + */ +#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 . + */ + +#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 . + */ +#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 . + */ +#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 . + */ + +#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 . + */ + +/* 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 . + */ +#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 . + */ +#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 . + */ + +#include +#include +#include +#include + +#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 . + */ +#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 . + */ + +#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 . + */ + +/* 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 . + */ +#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 . + */ +#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 . + */ + +#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 . + */ + +#include +#include +#include +#include + +#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 . + */ +#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 . + */ + +#ifndef _QEMU_BSD_H_ +#define _QEMU_BSD_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 . + */ #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 +#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 #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 #include #include +#include +#include +#include #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 + * -. 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 . + */ +#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 . + */ + +#include + +#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 . + */ + +#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 . + */ +#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 . + */ + +#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 . + */ +#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 . + */ +#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 . + */ + +#include + +#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 . + */ + +#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 . + */ +#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 . + */ +#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 . + */ + +#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 . + */ +#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 . + */ + #include #include #include #include #include #include +#include +#include + #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 . */ -#include #include #include #include #include #include -#include -#include #include -#include #include -#include #include #include #include -#include #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_. */ +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_. */ -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 . + */ +#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 . + */ + +#include + +#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 . + */ + +#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 . + */ +#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 . + */ +#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 . + */ + +#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 . + */ +#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