From 9cd792a1dcf78c0d80129b1292095f87091cb87d Mon Sep 17 00:00:00 2001 In-Reply-To: <1383928417-38009-1-git-send-email-sson@FreeBSD.org> References: <1383928417-38009-1-git-send-email-sson@FreeBSD.org> From: Stacey Son Date: Sun, 6 Oct 2013 15:55:28 -0500 Subject: [PATCH v3 04/19] bsd-user: move arch/OS dependent code out of main.c This change moves the cpu initialization and main loop code from main.c to the OS and arch dependent directories. This eliminates many of the #ifdef's in main.c. The cpu initialization and loop code is now located in the arch directory along with target arch support code. --- bsd-user/Makefile.objs | 2 +- bsd-user/arm/target_arch.h | 10 + bsd-user/arm/target_arch_cpu.c | 27 + bsd-user/arm/target_arch_cpu.h | 375 +++++++++++++ bsd-user/arm/target_arch_vmparam.h | 48 ++ bsd-user/elfload.c | 2 +- bsd-user/freebsd/host_os.h | 46 ++ bsd-user/freebsd/target_os_vmparam.h | 23 + bsd-user/i386/target_arch.h | 13 + bsd-user/i386/target_arch_cpu.c | 79 +++ bsd-user/i386/target_arch_cpu.h | 302 +++++++++++ bsd-user/i386/target_arch_vmparam.h | 28 + bsd-user/i386/target_signal.h | 6 - bsd-user/main.c | 927 +++++++------------------------- bsd-user/mips/target_arch.h | 10 + bsd-user/mips/target_arch_cpu.c | 27 + bsd-user/mips/target_arch_cpu.h | 257 +++++++++ bsd-user/mips/target_arch_vmparam.h | 50 ++ bsd-user/mips64/target_arch.h | 10 + bsd-user/mips64/target_arch_cpu.c | 27 + bsd-user/mips64/target_arch_cpu.h | 243 +++++++++ bsd-user/mips64/target_arch_vmparam.h | 47 ++ bsd-user/netbsd/host_os.h | 31 ++ bsd-user/openbsd/host_os.h | 31 ++ bsd-user/qemu.h | 10 +- bsd-user/sparc/target_arch.h | 11 + bsd-user/sparc/target_arch_cpu.c | 113 ++++ bsd-user/sparc/target_arch_cpu.h | 158 ++++++ bsd-user/sparc/target_arch_vmparam.h | 37 ++ bsd-user/sparc/target_signal.h | 5 - bsd-user/sparc64/target_arch.h | 11 + bsd-user/sparc64/target_arch_cpu.c | 118 ++++ bsd-user/sparc64/target_arch_cpu.h | 191 +++++++ bsd-user/sparc64/target_arch_vmparam.h | 37 ++ bsd-user/sparc64/target_signal.h | 5 - bsd-user/x86_64/target_arch.h | 13 + bsd-user/x86_64/target_arch_cpu.c | 79 +++ bsd-user/x86_64/target_arch_cpu.h | 324 +++++++++++ bsd-user/x86_64/target_arch_vmparam.h | 28 + bsd-user/x86_64/target_signal.h | 5 - 40 files changed, 3001 insertions(+), 765 deletions(-) create mode 100644 bsd-user/arm/target_arch.h create mode 100644 bsd-user/arm/target_arch_cpu.c create mode 100644 bsd-user/arm/target_arch_cpu.h create mode 100644 bsd-user/arm/target_arch_vmparam.h create mode 100644 bsd-user/freebsd/host_os.h create mode 100644 bsd-user/freebsd/target_os_vmparam.h create mode 100644 bsd-user/i386/target_arch.h create mode 100644 bsd-user/i386/target_arch_cpu.c create mode 100644 bsd-user/i386/target_arch_cpu.h create mode 100644 bsd-user/i386/target_arch_vmparam.h create mode 100644 bsd-user/mips/target_arch.h create mode 100644 bsd-user/mips/target_arch_cpu.c create mode 100644 bsd-user/mips/target_arch_cpu.h create mode 100644 bsd-user/mips/target_arch_vmparam.h create mode 100644 bsd-user/mips64/target_arch.h create mode 100644 bsd-user/mips64/target_arch_cpu.c create mode 100644 bsd-user/mips64/target_arch_cpu.h create mode 100644 bsd-user/mips64/target_arch_vmparam.h create mode 100644 bsd-user/netbsd/host_os.h create mode 100644 bsd-user/openbsd/host_os.h create mode 100644 bsd-user/sparc/target_arch.h create mode 100644 bsd-user/sparc/target_arch_cpu.c create mode 100644 bsd-user/sparc/target_arch_cpu.h create mode 100644 bsd-user/sparc/target_arch_vmparam.h create mode 100644 bsd-user/sparc64/target_arch.h create mode 100644 bsd-user/sparc64/target_arch_cpu.c create mode 100644 bsd-user/sparc64/target_arch_cpu.h create mode 100644 bsd-user/sparc64/target_arch_vmparam.h create mode 100644 bsd-user/x86_64/target_arch.h create mode 100644 bsd-user/x86_64/target_arch_cpu.c create mode 100644 bsd-user/x86_64/target_arch_cpu.h create mode 100644 bsd-user/x86_64/target_arch_vmparam.h diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs index 5e77f57..41e8dce 100644 --- a/bsd-user/Makefile.objs +++ b/bsd-user/Makefile.objs @@ -1,2 +1,2 @@ obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \ - uaccess.o + uaccess.o $(TARGET_ABI_DIR)/target_arch_cpu.o diff --git a/bsd-user/arm/target_arch.h b/bsd-user/arm/target_arch.h new file mode 100644 index 0000000..b5c5ddb --- /dev/null +++ b/bsd-user/arm/target_arch.h @@ -0,0 +1,10 @@ + +#ifndef _TARGET_ARCH_H_ +#define _TARGET_ARCH_H_ + +#include "qemu.h" + +void target_cpu_set_tls(CPUARMState *env, target_ulong newtls); +target_ulong target_cpu_get_tls(CPUARMState *env); + +#endif /* !_TARGET_ARCH_H_ */ diff --git a/bsd-user/arm/target_arch_cpu.c b/bsd-user/arm/target_arch_cpu.c new file mode 100644 index 0000000..d94a32a --- /dev/null +++ b/bsd-user/arm/target_arch_cpu.c @@ -0,0 +1,27 @@ +/* + * arm cpu related code + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#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_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/elfload.c b/bsd-user/elfload.c index 93fd9e4..ccf72d1 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -674,7 +674,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, /* Create enough stack to hold everything. If we don't use * it for args, we'll use it for something else... */ - size = x86_stack_size; + size = target_dflssiz; if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; error = target_mmap(0, diff --git a/bsd-user/freebsd/host_os.h b/bsd-user/freebsd/host_os.h new file mode 100644 index 0000000..efe2351 --- /dev/null +++ b/bsd-user/freebsd/host_os.h @@ -0,0 +1,46 @@ +/* + * FreeBSD host dependent code and definitions + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#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/target_os_vmparam.h b/bsd-user/freebsd/target_os_vmparam.h new file mode 100644 index 0000000..80ac6c8 --- /dev/null +++ b/bsd-user/freebsd/target_os_vmparam.h @@ -0,0 +1,23 @@ +#ifndef _TARGET_OS_VMPARAM_H_ +#define _TARGET_OS_VMPARAM_H_ + +#include "target_arch_vmparam.h" + +#define TARGET_SPACE_USRSPACE 4096 +#define TARGET_ARG_MAX 262144 + +/* Compare to sys/exec.h */ +struct target_ps_strings { + abi_ulong ps_argvstr; + uint32_t ps_nargvstr; + abi_ulong ps_envstr; + uint32_t ps_nenvstr; +}; + +extern abi_ulong target_stkbas; +extern abi_ulong target_stksiz; + +#define TARGET_PS_STRINGS ((target_stkbas + target_stksiz) - \ + sizeof(struct target_ps_strings)) + +#endif /* !TARGET_OS_VMPARAM_H_ */ diff --git a/bsd-user/i386/target_arch.h b/bsd-user/i386/target_arch.h new file mode 100644 index 0000000..4cb398c --- /dev/null +++ b/bsd-user/i386/target_arch.h @@ -0,0 +1,13 @@ + +#ifndef _TARGET_ARCH_H_ +#define _TARGET_ARCH_H_ + +/* target_arch_cpu.c */ +void bsd_i386_write_dt(void *ptr, unsigned long addr, unsigned long limit, + int flags); +void bsd_i386_set_idt(int n, unsigned int dpl); +void bsd_i386_set_idt_base(uint64_t base); + +#define target_cpu_set_tls(env, newtls) + +#endif /* ! _TARGET_ARCH_H_ */ diff --git a/bsd-user/i386/target_arch_cpu.c b/bsd-user/i386/target_arch_cpu.c new file mode 100644 index 0000000..2e0eec0 --- /dev/null +++ b/bsd-user/i386/target_arch_cpu.c @@ -0,0 +1,79 @@ +/* + * i386 cpu related code + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#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_vmparam.h b/bsd-user/i386/target_arch_vmparam.h new file mode 100644 index 0000000..f15af91 --- /dev/null +++ b/bsd-user/i386/target_arch_vmparam.h @@ -0,0 +1,28 @@ +#ifndef _TARGET_ARCH_VMPARAM_H_ +#define _TARGET_ARCH_VMPARAM_H_ + +#include "cpu.h" + +/* compare to i386/include/vmparam.h */ +#define TARGET_MAXTSIZ (128UL*1024*1024) /* max text size */ +#define TARGET_DFLDSIZ (128UL*1024*1024) /* initial data size limit */ +#define TARGET_MAXDSIZ (512UL*1024*1024) /* max data size */ +#define TARGET_DFLSSIZ (8UL*1024*1024) /* initial stack size limit */ +#define TARGET_MAXSSIZ (64UL*1024*1024) /* max stack size */ +#define TARGET_SGROWSIZ (128UL*1024) /* amount to grow stack */ + +#define TARGET_RESERVED_VA 0xf7000000 + +#define TARGET_USRSTACK (0xbfc00000) + +static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) +{ + return state->regs[R_ESP]; +} + +static inline void set_second_rval(CPUX86State *state, abi_ulong retval2) +{ + state->regs[R_EDX] = retval2; +} + +#endif /* !_TARGET_ARCH_VMPARAM_H_ */ diff --git a/bsd-user/i386/target_signal.h b/bsd-user/i386/target_signal.h index 2ef36d1..5491687 100644 --- a/bsd-user/i386/target_signal.h +++ b/bsd-user/i386/target_signal.h @@ -11,10 +11,4 @@ typedef struct target_sigaltstack { abi_ulong ss_size; } target_stack_t; - -static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) -{ - return state->regs[R_ESP]; -} - #endif /* TARGET_SIGNAL_H */ diff --git a/bsd-user/main.c b/bsd-user/main.c index f9246aa..44d8f98 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -1,7 +1,8 @@ /* - * qemu user main + * qemu bsd user main * * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2013 Stacey Son * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,652 +24,183 @@ #include #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; env->opaque = ts; -#if defined(TARGET_I386) - cpu_x86_set_cpl(env, 3); - - env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; - env->hflags |= HF_PE_MASK; - if (env->features[FEAT_1_EDX] & CPUID_SSE) { - env->cr[4] |= CR4_OSFXSR_MASK; - env->hflags |= HF_OSFXSR_MASK; - } -#ifndef TARGET_ABI32 - /* enable 64 bit mode if possible */ - if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) { - fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n"); - exit(1); - } - env->cr[4] |= CR4_PAE_MASK; - env->efer |= MSR_EFER_LMA | MSR_EFER_LME; - env->hflags |= HF_LMA_MASK; -#endif - - /* flags setup : we activate the IRQs by default as in user mode */ - env->eflags |= IF_MASK; - - /* linux register setup */ -#ifndef TARGET_ABI32 - env->regs[R_EAX] = regs->rax; - env->regs[R_EBX] = regs->rbx; - env->regs[R_ECX] = regs->rcx; - env->regs[R_EDX] = regs->rdx; - env->regs[R_ESI] = regs->rsi; - env->regs[R_EDI] = regs->rdi; - env->regs[R_EBP] = regs->rbp; - env->regs[R_ESP] = regs->rsp; - env->eip = regs->rip; -#else - env->regs[R_EAX] = regs->eax; - env->regs[R_EBX] = regs->ebx; - env->regs[R_ECX] = regs->ecx; - env->regs[R_EDX] = regs->edx; - env->regs[R_ESI] = regs->esi; - env->regs[R_EDI] = regs->edi; - env->regs[R_EBP] = regs->ebp; - env->regs[R_ESP] = regs->esp; - env->eip = regs->eip; -#endif - - /* linux interrupt setup */ -#ifndef TARGET_ABI32 - env->idt.limit = 511; -#else - env->idt.limit = 255; -#endif - env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1), - PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); - idt_table = g2h(env->idt.base); - set_idt(0, 0); - set_idt(1, 0); - set_idt(2, 0); - set_idt(3, 3); - set_idt(4, 3); - set_idt(5, 0); - set_idt(6, 0); - set_idt(7, 0); - set_idt(8, 0); - set_idt(9, 0); - set_idt(10, 0); - set_idt(11, 0); - set_idt(12, 0); - set_idt(13, 0); - set_idt(14, 0); - set_idt(15, 0); - set_idt(16, 0); - set_idt(17, 0); - set_idt(18, 0); - set_idt(19, 0); - set_idt(0x80, 3); - - /* linux segment setup */ - { - uint64_t *gdt_table; - env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES, - PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); - env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1; - gdt_table = g2h(env->gdt.base); -#ifdef TARGET_ABI32 - write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | - (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); -#else - /* 64 bit code segment */ - write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | - DESC_L_MASK | - (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); -#endif - write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | - (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); - } - - cpu_x86_load_seg(env, R_CS, __USER_CS); - cpu_x86_load_seg(env, R_SS, __USER_DS); -#ifdef TARGET_ABI32 - cpu_x86_load_seg(env, R_DS, __USER_DS); - cpu_x86_load_seg(env, R_ES, __USER_DS); - cpu_x86_load_seg(env, R_FS, __USER_DS); - cpu_x86_load_seg(env, R_GS, __USER_DS); - /* This hack makes Wine work... */ - env->segs[R_FS].selector = 0; -#else - cpu_x86_load_seg(env, R_DS, 0); - cpu_x86_load_seg(env, R_ES, 0); - cpu_x86_load_seg(env, R_FS, 0); - cpu_x86_load_seg(env, R_GS, 0); -#endif -#elif defined(TARGET_SPARC) - { - int i; - env->pc = regs->pc; - env->npc = regs->npc; - env->y = regs->y; - for(i = 0; i < 8; i++) - env->gregs[i] = regs->u_regs[i]; - for(i = 0; i < 8; i++) - env->regwptr[i] = regs->u_regs[i + 8]; - } -#else -#error unsupported target CPU -#endif + target_cpu_init(env, regs); if (gdbstub_port) { gdbserver_start (gdbstub_port); diff --git a/bsd-user/mips/target_arch.h b/bsd-user/mips/target_arch.h new file mode 100644 index 0000000..b3d32ba --- /dev/null +++ b/bsd-user/mips/target_arch.h @@ -0,0 +1,10 @@ + +#ifndef _TARGET_ARCH_H_ +#define _TARGET_ARCH_H_ + +#include "qemu.h" + +void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls); +target_ulong target_cpu_get_tls(CPUMIPSState *env); + +#endif /* !_TARGET_ARCH_H_ */ diff --git a/bsd-user/mips/target_arch_cpu.c b/bsd-user/mips/target_arch_cpu.c new file mode 100644 index 0000000..dd59435 --- /dev/null +++ b/bsd-user/mips/target_arch_cpu.c @@ -0,0 +1,27 @@ +/* + * mips cpu related code + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#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_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/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_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/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/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/qemu.h b/bsd-user/qemu.h index b8a34c7..cb77069 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -38,6 +38,7 @@ extern enum BSDType bsd_type; #include "syscall_defs.h" #include "syscall.h" +#include "target_os_vmparam.h" #include "target_signal.h" #include "exec/gdbstub.h" @@ -99,6 +100,7 @@ typedef struct TaskState { } __attribute__((aligned(16))) TaskState; void init_task_state(TaskState *ts); +void stop_all_tasks(void); extern const char *qemu_uname_release; #if defined(CONFIG_USE_GUEST_BASE) extern unsigned long mmap_min_addr; @@ -222,7 +224,13 @@ void mmap_fork_end(int child); #endif /* main.c */ -extern unsigned long x86_stack_size; +extern unsigned long target_maxtsiz; +extern unsigned long target_dfldsiz; +extern unsigned long target_maxdsiz; +extern unsigned long target_dflssiz; +extern unsigned long target_maxssiz; +extern unsigned long target_sgrowsiz; +extern char qemu_proc_pathname[]; /* user access */ diff --git a/bsd-user/sparc/target_arch.h b/bsd-user/sparc/target_arch.h new file mode 100644 index 0000000..5ee479b --- /dev/null +++ b/bsd-user/sparc/target_arch.h @@ -0,0 +1,11 @@ + +#ifndef _TARGET_ARCH_H_ +#define _TARGET_ARCH_H_ + +void bsd_sparc_save_window(CPUSPARCState *env); +void bsd_sparc_restore_window(CPUSPARCState *env); +void bsd_sparc_flush_windows(CPUSPARCState *env); + +#define target_cpu_set_tls(env, newtls) + +#endif /* ! _TARGET_ARCH_H_ */ diff --git a/bsd-user/sparc/target_arch_cpu.c b/bsd-user/sparc/target_arch_cpu.c new file mode 100644 index 0000000..0af5c7e --- /dev/null +++ b/bsd-user/sparc/target_arch_cpu.c @@ -0,0 +1,113 @@ +/* + * sparc cpu related code + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#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_vmparam.h b/bsd-user/sparc/target_arch_vmparam.h new file mode 100644 index 0000000..5f28fcf --- /dev/null +++ b/bsd-user/sparc/target_arch_vmparam.h @@ -0,0 +1,37 @@ +#ifndef _TARGET_ARCH_VMPARAM_H_ +#define _TARGET_ARCH_VMPARAM_H_ + +#include "cpu.h" + +#define TARGET_MAXTSIZ (1*1024*1024*1024) /* max text size */ +#define TARGET_DFLDSIZ (128*1024*1024) /* initial data size limit */ +#define TARGET_MAXDSIZ (1*1024*1024*1024) /* max data size */ +#define TARGET_DFLSSIZ (128*1024*1024) /* initial stack size limit */ +#define TARGET_MAXSSIZ (1*1024*1024*1024) /* max stack size */ +#define TARGET_SGROWSIZ (128*1024) /* amount to grow stack */ + +#define TARGET_RESERVED_VA 0xf7000000 + +/* XXX this may not be right */ +#define TARGET_VM_MAXUSER_ADDRESS (0xc0000000 - (512 * 1024 * 1024)) +#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE) + +#ifndef UREG_I6 +#define UREG_I6 6 +#endif +#ifndef UREG_FP +#define UREG_FP UREG_I6 +#endif + +static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) +{ + return state->regwptr[UREG_FP]; +} + +static inline void set_second_rval(CPUSPARCState *state, abi_ulong retval2) +{ + state->regwptr[1] = retval2; +} + +#endif /* !_TARGET_ARCH_VMPARAM_H_ */ + diff --git a/bsd-user/sparc/target_signal.h b/bsd-user/sparc/target_signal.h index 5b2abba..181867a 100644 --- a/bsd-user/sparc/target_signal.h +++ b/bsd-user/sparc/target_signal.h @@ -19,9 +19,4 @@ typedef struct target_sigaltstack { #define UREG_FP UREG_I6 #endif -static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) -{ - return state->regwptr[UREG_FP]; -} - #endif /* TARGET_SIGNAL_H */ diff --git a/bsd-user/sparc64/target_arch.h b/bsd-user/sparc64/target_arch.h new file mode 100644 index 0000000..46bbcf8 --- /dev/null +++ b/bsd-user/sparc64/target_arch.h @@ -0,0 +1,11 @@ + +#ifndef _TARGET_ARCH_H_ +#define _TARGET_ARCH_H_ + +void bsd_sparc64_save_window(CPUSPARCState *env); +void bsd_sparc64_restore_window(CPUSPARCState *env); +void bsd_sparc64_flush_windows(CPUSPARCState *env); + +#define target_cpu_set_tls(env, newtls) + +#endif /* ! _TARGET_ARCH_H_ */ diff --git a/bsd-user/sparc64/target_arch_cpu.c b/bsd-user/sparc64/target_arch_cpu.c new file mode 100644 index 0000000..e7bede8 --- /dev/null +++ b/bsd-user/sparc64/target_arch_cpu.c @@ -0,0 +1,118 @@ +/* + * sparc64 cpu related code + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#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_vmparam.h b/bsd-user/sparc64/target_arch_vmparam.h new file mode 100644 index 0000000..2c2323b --- /dev/null +++ b/bsd-user/sparc64/target_arch_vmparam.h @@ -0,0 +1,37 @@ +#ifndef _TARGET_ARCH_VMPARAM_H_ +#define _TARGET_ARCH_VMPARAM_H_ + +#include "cpu.h" + +/* compare to amd64/include/vmparam.h */ +#define TARGET_MAXTSIZ (1*1024*1024*1024) /* max text size */ +#define TARGET_DFLDSIZ (128*1024*1024) /* initial data size limit */ +#define TARGET_MAXDSIZ (1*1024*1024*1024) /* max data size */ +#define TARGET_DFLSSIZ (128*1024*1024) /* initial stack size limit */ +#define TARGET_MAXSSIZ (1*1024*1024*1024) /* max stack size */ +#define TARGET_SGROWSIZ (128*1024) /* amount to grow stack */ + +/* XXX */ +#define TARGET_VM_MINUSER_ADDRESS (0x0000000000000000UL) +#define TARGET_VM_MAXUSER_ADDRESS (0x000007fe00000000UL) +#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE) + +#ifndef UREG_I6 +#define UREG_I6 6 +#endif +#ifndef UREG_FP +#define UREG_FP UREG_I6 +#endif + +static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) +{ + return state->regwptr[UREG_FP]; +} + +static inline void set_second_rval(CPUSPARCState *state, abi_ulong retval2) +{ + state->regwptr[1] = retval2; +} + +#endif /* !_TARGET_ARCH_VMPARAM_H_ */ + diff --git a/bsd-user/sparc64/target_signal.h b/bsd-user/sparc64/target_signal.h index 5b2abba..181867a 100644 --- a/bsd-user/sparc64/target_signal.h +++ b/bsd-user/sparc64/target_signal.h @@ -19,9 +19,4 @@ typedef struct target_sigaltstack { #define UREG_FP UREG_I6 #endif -static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) -{ - return state->regwptr[UREG_FP]; -} - #endif /* TARGET_SIGNAL_H */ diff --git a/bsd-user/x86_64/target_arch.h b/bsd-user/x86_64/target_arch.h new file mode 100644 index 0000000..7fe81dc --- /dev/null +++ b/bsd-user/x86_64/target_arch.h @@ -0,0 +1,13 @@ + +#ifndef _TARGET_ARCH_H_ +#define _TARGET_ARCH_H_ + +/* target_arch_cpu.c */ +void bsd_x86_64_write_dt(void *ptr, unsigned long addr, unsigned long limit, + int flags); +void bsd_x86_64_set_idt(int n, unsigned int dpl); +void bsd_x86_64_set_idt_base(uint64_t base); + +#define target_cpu_set_tls(env, newtls) + +#endif /* !_TARGET_ARCH_H_ */ diff --git a/bsd-user/x86_64/target_arch_cpu.c b/bsd-user/x86_64/target_arch_cpu.c new file mode 100644 index 0000000..5cfdfca --- /dev/null +++ b/bsd-user/x86_64/target_arch_cpu.c @@ -0,0 +1,79 @@ +/* + * x86_64 cpu related code + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#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_vmparam.h b/bsd-user/x86_64/target_arch_vmparam.h new file mode 100644 index 0000000..5e13076 --- /dev/null +++ b/bsd-user/x86_64/target_arch_vmparam.h @@ -0,0 +1,28 @@ +#ifndef _TARGET_ARCH_VMPARAM_H_ +#define _TARGET_ARCH_VMPARAM_H_ + +#include "cpu.h" + +/* compare to amd64/include/vmparam.h */ +#define TARGET_MAXTSIZ (128UL*1024*1024) /* max text size */ +#define TARGET_DFLDSIZ (32768UL*1024*1024) /* initial data size limit */ +#define TARGET_MAXDSIZ (32768UL*1024*1024) /* max data size */ +#define TARGET_DFLSSIZ (8UL*1024*1024) /* initial stack size limit */ +#define TARGET_MAXSSIZ (512UL*1024*1024) /* max stack size */ +#define TARGET_SGROWSIZ (128UL*1024) /* amount to grow stack */ + +#define TARGET_VM_MAXUSER_ADDRESS (0x0000800000000000UL) + +#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE) + +static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) +{ + return state->regs[R_ESP]; +} + +static inline void set_second_rval(CPUX86State *state, abi_ulong retval2) +{ + state->regs[R_EDX] = retval2; +} + +#endif /* !_TARGET_ARCH_VMPARAM_H_ */ diff --git a/bsd-user/x86_64/target_signal.h b/bsd-user/x86_64/target_signal.h index 659cd40..5491687 100644 --- a/bsd-user/x86_64/target_signal.h +++ b/bsd-user/x86_64/target_signal.h @@ -11,9 +11,4 @@ typedef struct target_sigaltstack { abi_ulong ss_size; } target_stack_t; -static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) -{ - return state->regs[R_ESP]; -} - #endif /* TARGET_SIGNAL_H */ -- 1.7.8