diff options
-rw-r--r-- | Makefile.target | 10 | ||||
-rw-r--r-- | cpu-exec.c | 655 | ||||
-rw-r--r-- | user-exec.c | 673 |
3 files changed, 678 insertions, 660 deletions
diff --git a/Makefile.target b/Makefile.target index 2e281a4588..602d50dc64 100644 --- a/Makefile.target +++ b/Makefile.target @@ -94,10 +94,10 @@ tcg/tcg.o: cpu.h # HELPER_CFLAGS is used for all the code compiled with static register # variables -%_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +%_helper.o cpu-exec.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) # Note: this is a workaround. The real fix is to avoid compiling -# cpu_signal_handler() in cpu-exec.c. +# cpu_signal_handler() in user-exec.c. signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS) ######################################################### @@ -110,7 +110,7 @@ $(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \ elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o \ - qemu-malloc.o $(oslib-obj-y) + qemu-malloc.o user-exec.o $(oslib-obj-y) obj-$(TARGET_HAS_BFLT) += flatload.o @@ -148,7 +148,7 @@ LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000 LIBS+=-lmx obj-y = main.o commpage.o machload.o mmap.o signal.o syscall.o thunk.o \ - gdbstub.o + gdbstub.o user-exec.o obj-i386-y += ioport-user.o @@ -170,7 +170,7 @@ $(call set-vpath, $(SRC_PATH)/bsd-user) QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH) obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \ - gdbstub.o uaccess.o + gdbstub.o uaccess.o user-exec.o obj-i386-y += ioport-user.o diff --git a/cpu-exec.c b/cpu-exec.c index f197ff9875..6ddd8dd1ae 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -23,22 +23,6 @@ #include "kvm.h" #include "qemu-barrier.h" -#if !defined(CONFIG_SOFTMMU) -#undef EAX -#undef ECX -#undef EDX -#undef EBX -#undef ESP -#undef EBP -#undef ESI -#undef EDI -#undef EIP -#include <signal.h> -#ifdef __linux__ -#include <sys/ucontext.h> -#endif -#endif - #if defined(__sparc__) && !defined(CONFIG_SOLARIS) // Work around ugly bugs in glibc that mangle global register contents #undef env @@ -48,7 +32,6 @@ int tb_invalidated_flag; //#define CONFIG_DEBUG_EXEC -//#define DEBUG_SIGNAL int qemu_cpu_has_work(CPUState *env) { @@ -74,36 +57,6 @@ void cpu_resume_from_signal(CPUState *env1, void *puc) env->exception_index = -1; longjmp(env->jmp_env, 1); } - -#else - -void cpu_resume_from_signal(CPUState *env1, void *puc) -{ -#ifdef __linux__ - struct ucontext *uc = puc; -#elif defined(__OpenBSD__) - struct sigcontext *uc = puc; -#endif - - env = env1; - - /* XXX: restore cpu registers saved in host registers */ - - if (puc) { - /* XXX: use siglongjmp ? */ -#ifdef __linux__ -#ifdef __ia64 - sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL); -#else - sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL); -#endif -#elif defined(__OpenBSD__) - sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL); -#endif - } - env->exception_index = -1; - longjmp(env->jmp_env, 1); -} #endif /* Execute the code without caching the generated code. An interpreter @@ -713,611 +666,3 @@ int cpu_exec(CPUState *env1) cpu_single_env = NULL; return ret; } - -#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY) - -void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) -{ - CPUX86State *saved_env; - - saved_env = env; - env = s; - if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { - selector &= 0xffff; - cpu_x86_load_seg_cache(env, seg_reg, selector, - (selector << 4), 0xffff, 0); - } else { - helper_load_seg(seg_reg, selector); - } - env = saved_env; -} - -void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32) -{ - CPUX86State *saved_env; - - saved_env = env; - env = s; - - helper_fsave(ptr, data32); - - env = saved_env; -} - -void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32) -{ - CPUX86State *saved_env; - - saved_env = env; - env = s; - - helper_frstor(ptr, data32); - - env = saved_env; -} - -#endif /* TARGET_I386 */ - -#if !defined(CONFIG_SOFTMMU) - -#if defined(TARGET_I386) -#define EXCEPTION_ACTION \ - raise_exception_err(env->exception_index, env->error_code) -#else -#define EXCEPTION_ACTION \ - cpu_loop_exit() -#endif - -/* 'pc' is the host PC at which the exception was raised. 'address' is - the effective address of the memory exception. 'is_write' is 1 if a - write caused the exception and otherwise 0'. 'old_set' is the - signal set which should be restored */ -static inline int handle_cpu_signal(unsigned long pc, unsigned long address, - int is_write, sigset_t *old_set, - void *puc) -{ - TranslationBlock *tb; - int ret; - - if (cpu_single_env) { - env = cpu_single_env; /* XXX: find a correct solution for multithread */ - } -#if defined(DEBUG_SIGNAL) - qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", - pc, address, is_write, *(unsigned long *)old_set); -#endif - /* XXX: locking issue */ - if (is_write && page_unprotect(h2g(address), pc, puc)) { - return 1; - } - - /* see if it is an MMU fault */ - ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); - if (ret < 0) { - return 0; /* not an MMU fault */ - } - if (ret == 0) { - return 1; /* the MMU fault was handled without causing real CPU fault */ - } - /* now we have a real cpu fault */ - tb = tb_find_pc(pc); - if (tb) { - /* the PC is inside the translated code. It means that we have - a virtual CPU fault */ - cpu_restore_state(tb, env, pc); - } - - /* we restore the process signal mask as the sigreturn should - do it (XXX: use sigsetjmp) */ - sigprocmask(SIG_SETMASK, old_set, NULL); - EXCEPTION_ACTION; - - /* never comes here */ - return 1; -} - -#if defined(__i386__) - -#if defined(__APPLE__) -#include <sys/ucontext.h> - -#define EIP_sig(context) (*((unsigned long *)&(context)->uc_mcontext->ss.eip)) -#define TRAP_sig(context) ((context)->uc_mcontext->es.trapno) -#define ERROR_sig(context) ((context)->uc_mcontext->es.err) -#define MASK_sig(context) ((context)->uc_sigmask) -#elif defined(__NetBSD__) -#include <ucontext.h> - -#define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP]) -#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) -#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) -#define MASK_sig(context) ((context)->uc_sigmask) -#elif defined(__FreeBSD__) || defined(__DragonFly__) -#include <ucontext.h> - -#define EIP_sig(context) (*((unsigned long *)&(context)->uc_mcontext.mc_eip)) -#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) -#define ERROR_sig(context) ((context)->uc_mcontext.mc_err) -#define MASK_sig(context) ((context)->uc_sigmask) -#elif defined(__OpenBSD__) -#define EIP_sig(context) ((context)->sc_eip) -#define TRAP_sig(context) ((context)->sc_trapno) -#define ERROR_sig(context) ((context)->sc_err) -#define MASK_sig(context) ((context)->sc_mask) -#else -#define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP]) -#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) -#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) -#define MASK_sig(context) ((context)->uc_sigmask) -#endif - -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) -{ - siginfo_t *info = pinfo; -#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) - ucontext_t *uc = puc; -#elif defined(__OpenBSD__) - struct sigcontext *uc = puc; -#else - struct ucontext *uc = puc; -#endif - unsigned long pc; - int trapno; - -#ifndef REG_EIP -/* for glibc 2.1 */ -#define REG_EIP EIP -#define REG_ERR ERR -#define REG_TRAPNO TRAPNO -#endif - pc = EIP_sig(uc); - trapno = TRAP_sig(uc); - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - trapno == 0xe ? - (ERROR_sig(uc) >> 1) & 1 : 0, - &MASK_sig(uc), puc); -} - -#elif defined(__x86_64__) - -#ifdef __NetBSD__ -#define PC_sig(context) _UC_MACHINE_PC(context) -#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) -#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) -#define MASK_sig(context) ((context)->uc_sigmask) -#elif defined(__OpenBSD__) -#define PC_sig(context) ((context)->sc_rip) -#define TRAP_sig(context) ((context)->sc_trapno) -#define ERROR_sig(context) ((context)->sc_err) -#define MASK_sig(context) ((context)->sc_mask) -#elif defined(__FreeBSD__) || defined(__DragonFly__) -#include <ucontext.h> - -#define PC_sig(context) (*((unsigned long *)&(context)->uc_mcontext.mc_rip)) -#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) -#define ERROR_sig(context) ((context)->uc_mcontext.mc_err) -#define MASK_sig(context) ((context)->uc_sigmask) -#else -#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP]) -#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) -#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) -#define MASK_sig(context) ((context)->uc_sigmask) -#endif - -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) -{ - siginfo_t *info = pinfo; - unsigned long pc; -#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) - ucontext_t *uc = puc; -#elif defined(__OpenBSD__) - struct sigcontext *uc = puc; -#else - struct ucontext *uc = puc; -#endif - - pc = PC_sig(uc); - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - TRAP_sig(uc) == 0xe ? - (ERROR_sig(uc) >> 1) & 1 : 0, - &MASK_sig(uc), puc); -} - -#elif defined(_ARCH_PPC) - -/*********************************************************************** - * signal context platform-specific definitions - * From Wine - */ -#ifdef linux -/* All Registers access - only for local access */ -#define REG_sig(reg_name, context) \ - ((context)->uc_mcontext.regs->reg_name) -/* Gpr Registers access */ -#define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context) -/* Program counter */ -#define IAR_sig(context) REG_sig(nip, context) -/* Machine State Register (Supervisor) */ -#define MSR_sig(context) REG_sig(msr, context) -/* Count register */ -#define CTR_sig(context) REG_sig(ctr, context) -/* User's integer exception register */ -#define XER_sig(context) REG_sig(xer, context) -/* Link register */ -#define LR_sig(context) REG_sig(link, context) -/* Condition register */ -#define CR_sig(context) REG_sig(ccr, context) - -/* Float Registers access */ -#define FLOAT_sig(reg_num, context) \ - (((double *)((char *)((context)->uc_mcontext.regs + 48 * 4)))[reg_num]) -#define FPSCR_sig(context) \ - (*(int *)((char *)((context)->uc_mcontext.regs + (48 + 32 * 2) * 4))) -/* Exception Registers access */ -#define DAR_sig(context) REG_sig(dar, context) -#define DSISR_sig(context) REG_sig(dsisr, context) -#define TRAP_sig(context) REG_sig(trap, context) -#endif /* linux */ - -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -#include <ucontext.h> -#define IAR_sig(context) ((context)->uc_mcontext.mc_srr0) -#define MSR_sig(context) ((context)->uc_mcontext.mc_srr1) -#define CTR_sig(context) ((context)->uc_mcontext.mc_ctr) -#define XER_sig(context) ((context)->uc_mcontext.mc_xer) -#define LR_sig(context) ((context)->uc_mcontext.mc_lr) -#define CR_sig(context) ((context)->uc_mcontext.mc_cr) -/* Exception Registers access */ -#define DAR_sig(context) ((context)->uc_mcontext.mc_dar) -#define DSISR_sig(context) ((context)->uc_mcontext.mc_dsisr) -#define TRAP_sig(context) ((context)->uc_mcontext.mc_exc) -#endif /* __FreeBSD__|| __FreeBSD_kernel__ */ - -#ifdef __APPLE__ -#include <sys/ucontext.h> -typedef struct ucontext SIGCONTEXT; -/* All Registers access - only for local access */ -#define REG_sig(reg_name, context) \ - ((context)->uc_mcontext->ss.reg_name) -#define FLOATREG_sig(reg_name, context) \ - ((context)->uc_mcontext->fs.reg_name) -#define EXCEPREG_sig(reg_name, context) \ - ((context)->uc_mcontext->es.reg_name) -#define VECREG_sig(reg_name, context) \ - ((context)->uc_mcontext->vs.reg_name) -/* Gpr Registers access */ -#define GPR_sig(reg_num, context) REG_sig(r##reg_num, context) -/* Program counter */ -#define IAR_sig(context) REG_sig(srr0, context) -/* Machine State Register (Supervisor) */ -#define MSR_sig(context) REG_sig(srr1, context) -#define CTR_sig(context) REG_sig(ctr, context) -/* Link register */ -#define XER_sig(context) REG_sig(xer, context) -/* User's integer exception register */ -#define LR_sig(context) REG_sig(lr, context) -/* Condition register */ -#define CR_sig(context) REG_sig(cr, context) -/* Float Registers access */ -#define FLOAT_sig(reg_num, context) \ - FLOATREG_sig(fpregs[reg_num], context) -#define FPSCR_sig(context) \ - ((double)FLOATREG_sig(fpscr, context)) -/* Exception Registers access */ -/* Fault registers for coredump */ -#define DAR_sig(context) EXCEPREG_sig(dar, context) -#define DSISR_sig(context) EXCEPREG_sig(dsisr, context) -/* number of powerpc exception taken */ -#define TRAP_sig(context) EXCEPREG_sig(exception, context) -#endif /* __APPLE__ */ - -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) -{ - siginfo_t *info = pinfo; -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - ucontext_t *uc = puc; -#else - struct ucontext *uc = puc; -#endif - unsigned long pc; - int is_write; - - pc = IAR_sig(uc); - is_write = 0; -#if 0 - /* ppc 4xx case */ - if (DSISR_sig(uc) & 0x00800000) { - is_write = 1; - } -#else - if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000)) { - is_write = 1; - } -#endif - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask, puc); -} - -#elif defined(__alpha__) - -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) -{ - siginfo_t *info = pinfo; - struct ucontext *uc = puc; - uint32_t *pc = uc->uc_mcontext.sc_pc; - uint32_t insn = *pc; - int is_write = 0; - - /* XXX: need kernel patch to get write flag faster */ - switch (insn >> 26) { - case 0x0d: /* stw */ - case 0x0e: /* stb */ - case 0x0f: /* stq_u */ - case 0x24: /* stf */ - case 0x25: /* stg */ - case 0x26: /* sts */ - case 0x27: /* stt */ - case 0x2c: /* stl */ - case 0x2d: /* stq */ - case 0x2e: /* stl_c */ - case 0x2f: /* stq_c */ - is_write = 1; - } - - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask, puc); -} -#elif defined(__sparc__) - -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) -{ - siginfo_t *info = pinfo; - int is_write; - uint32_t insn; -#if !defined(__arch64__) || defined(CONFIG_SOLARIS) - uint32_t *regs = (uint32_t *)(info + 1); - void *sigmask = (regs + 20); - /* XXX: is there a standard glibc define ? */ - unsigned long pc = regs[1]; -#else -#ifdef __linux__ - struct sigcontext *sc = puc; - unsigned long pc = sc->sigc_regs.tpc; - void *sigmask = (void *)sc->sigc_mask; -#elif defined(__OpenBSD__) - struct sigcontext *uc = puc; - unsigned long pc = uc->sc_pc; - void *sigmask = (void *)(long)uc->sc_mask; -#endif -#endif - - /* XXX: need kernel patch to get write flag faster */ - is_write = 0; - insn = *(uint32_t *)pc; - if ((insn >> 30) == 3) { - switch ((insn >> 19) & 0x3f) { - case 0x05: /* stb */ - case 0x15: /* stba */ - case 0x06: /* sth */ - case 0x16: /* stha */ - case 0x04: /* st */ - case 0x14: /* sta */ - case 0x07: /* std */ - case 0x17: /* stda */ - case 0x0e: /* stx */ - case 0x1e: /* stxa */ - case 0x24: /* stf */ - case 0x34: /* stfa */ - case 0x27: /* stdf */ - case 0x37: /* stdfa */ - case 0x26: /* stqf */ - case 0x36: /* stqfa */ - case 0x25: /* stfsr */ - case 0x3c: /* casa */ - case 0x3e: /* casxa */ - is_write = 1; - break; - } - } - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, sigmask, NULL); -} - -#elif defined(__arm__) - -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) -{ - siginfo_t *info = pinfo; - struct ucontext *uc = puc; - unsigned long pc; - int is_write; - -#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) - pc = uc->uc_mcontext.gregs[R15]; -#else - pc = uc->uc_mcontext.arm_pc; -#endif - /* XXX: compute is_write */ - is_write = 0; - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, - &uc->uc_sigmask, puc); -} - -#elif defined(__mc68000) - -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) -{ - siginfo_t *info = pinfo; - struct ucontext *uc = puc; - unsigned long pc; - int is_write; - - pc = uc->uc_mcontext.gregs[16]; - /* XXX: compute is_write */ - is_write = 0; - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, - &uc->uc_sigmask, puc); -} - -#elif defined(__ia64) - -#ifndef __ISR_VALID - /* This ought to be in <bits/siginfo.h>... */ -# define __ISR_VALID 1 -#endif - -int cpu_signal_handler(int host_signum, void *pinfo, void *puc) -{ - siginfo_t *info = pinfo; - struct ucontext *uc = puc; - unsigned long ip; - int is_write = 0; - - ip = uc->uc_mcontext.sc_ip; - switch (host_signum) { - case SIGILL: - case SIGFPE: - case SIGSEGV: - case SIGBUS: - case SIGTRAP: - if (info->si_code && (info->si_segvflags & __ISR_VALID)) { - /* ISR.W (write-access) is bit 33: */ - is_write = (info->si_isr >> 33) & 1; - } - break; - - default: - break; - } - return handle_cpu_signal(ip, (unsigned long)info->si_addr, - is_write, - (sigset_t *)&uc->uc_sigmask, puc); -} - -#elif defined(__s390__) - -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) -{ - siginfo_t *info = pinfo; - struct ucontext *uc = puc; - unsigned long pc; - uint16_t *pinsn; - int is_write = 0; - - pc = uc->uc_mcontext.psw.addr; - - /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead - of the normal 2 arguments. The 3rd argument contains the "int_code" - from the hardware which does in fact contain the is_write value. - The rt signal handler, as far as I can tell, does not give this value - at all. Not that we could get to it from here even if it were. */ - /* ??? This is not even close to complete, since it ignores all - of the read-modify-write instructions. */ - pinsn = (uint16_t *)pc; - switch (pinsn[0] >> 8) { - case 0x50: /* ST */ - case 0x42: /* STC */ - case 0x40: /* STH */ - is_write = 1; - break; - case 0xc4: /* RIL format insns */ - switch (pinsn[0] & 0xf) { - case 0xf: /* STRL */ - case 0xb: /* STGRL */ - case 0x7: /* STHRL */ - is_write = 1; - } - break; - case 0xe3: /* RXY format insns */ - switch (pinsn[2] & 0xff) { - case 0x50: /* STY */ - case 0x24: /* STG */ - case 0x72: /* STCY */ - case 0x70: /* STHY */ - case 0x8e: /* STPQ */ - case 0x3f: /* STRVH */ - case 0x3e: /* STRV */ - case 0x2f: /* STRVG */ - is_write = 1; - } - break; - } - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask, puc); -} - -#elif defined(__mips__) - -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) -{ - siginfo_t *info = pinfo; - struct ucontext *uc = puc; - greg_t pc = uc->uc_mcontext.pc; - int is_write; - - /* XXX: compute is_write */ - is_write = 0; - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask, puc); -} - -#elif defined(__hppa__) - -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) -{ - struct siginfo *info = pinfo; - struct ucontext *uc = puc; - unsigned long pc = uc->uc_mcontext.sc_iaoq[0]; - uint32_t insn = *(uint32_t *)pc; - int is_write = 0; - - /* XXX: need kernel patch to get write flag faster. */ - switch (insn >> 26) { - case 0x1a: /* STW */ - case 0x19: /* STH */ - case 0x18: /* STB */ - case 0x1b: /* STWM */ - is_write = 1; - break; - - case 0x09: /* CSTWX, FSTWX, FSTWS */ - case 0x0b: /* CSTDX, FSTDX, FSTDS */ - /* Distinguish from coprocessor load ... */ - is_write = (insn >> 9) & 1; - break; - - case 0x03: - switch ((insn >> 6) & 15) { - case 0xa: /* STWS */ - case 0x9: /* STHS */ - case 0x8: /* STBS */ - case 0xe: /* STWAS */ - case 0xc: /* STBYS */ - is_write = 1; - } - break; - } - - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask, puc); -} - -#else - -#error host CPU specific signal handler needed - -#endif - -#endif /* !defined(CONFIG_SOFTMMU) */ diff --git a/user-exec.c b/user-exec.c new file mode 100644 index 0000000000..d4a6abb8f5 --- /dev/null +++ b/user-exec.c @@ -0,0 +1,673 @@ +/* + * User emulator execution + * + * Copyright (c) 2003-2005 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "config.h" +#include "exec.h" +#include "disas.h" +#include "tcg.h" + +#undef EAX +#undef ECX +#undef EDX +#undef EBX +#undef ESP +#undef EBP +#undef ESI +#undef EDI +#undef EIP +#include <signal.h> +#ifdef __linux__ +#include <sys/ucontext.h> +#endif + +//#define DEBUG_SIGNAL + +#if defined(TARGET_I386) +#define EXCEPTION_ACTION \ + raise_exception_err(env->exception_index, env->error_code) +#else +#define EXCEPTION_ACTION \ + cpu_loop_exit() +#endif + +/* exit the current TB from a signal handler. The host registers are + restored in a state compatible with the CPU emulator + */ +void cpu_resume_from_signal(CPUState *env1, void *puc) +{ +#ifdef __linux__ + struct ucontext *uc = puc; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; +#endif + + env = env1; + + /* XXX: restore cpu registers saved in host registers */ + + if (puc) { + /* XXX: use siglongjmp ? */ +#ifdef __linux__ +#ifdef __ia64 + sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL); +#else + sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL); +#endif +#elif defined(__OpenBSD__) + sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL); +#endif + } + env->exception_index = -1; + longjmp(env->jmp_env, 1); +} + +/* 'pc' is the host PC at which the exception was raised. 'address' is + the effective address of the memory exception. 'is_write' is 1 if a + write caused the exception and otherwise 0'. 'old_set' is the + signal set which should be restored */ +static inline int handle_cpu_signal(unsigned long pc, unsigned long address, + int is_write, sigset_t *old_set, + void *puc) +{ + TranslationBlock *tb; + int ret; + + if (cpu_single_env) { + env = cpu_single_env; /* XXX: find a correct solution for multithread */ + } +#if defined(DEBUG_SIGNAL) + qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", + pc, address, is_write, *(unsigned long *)old_set); +#endif + /* XXX: locking issue */ + if (is_write && page_unprotect(h2g(address), pc, puc)) { + return 1; + } + + /* see if it is an MMU fault */ + ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); + if (ret < 0) { + return 0; /* not an MMU fault */ + } + if (ret == 0) { + return 1; /* the MMU fault was handled without causing real CPU fault */ + } + /* now we have a real cpu fault */ + tb = tb_find_pc(pc); + if (tb) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + cpu_restore_state(tb, env, pc); + } + + /* we restore the process signal mask as the sigreturn should + do it (XXX: use sigsetjmp) */ + sigprocmask(SIG_SETMASK, old_set, NULL); + EXCEPTION_ACTION; + + /* never comes here */ + return 1; +} + +#if defined(__i386__) + +#if defined(__APPLE__) +#include <sys/ucontext.h> + +#define EIP_sig(context) (*((unsigned long *)&(context)->uc_mcontext->ss.eip)) +#define TRAP_sig(context) ((context)->uc_mcontext->es.trapno) +#define ERROR_sig(context) ((context)->uc_mcontext->es.err) +#define MASK_sig(context) ((context)->uc_sigmask) +#elif defined(__NetBSD__) +#include <ucontext.h> + +#define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP]) +#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) +#define MASK_sig(context) ((context)->uc_sigmask) +#elif defined(__FreeBSD__) || defined(__DragonFly__) +#include <ucontext.h> + +#define EIP_sig(context) (*((unsigned long *)&(context)->uc_mcontext.mc_eip)) +#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) +#define ERROR_sig(context) ((context)->uc_mcontext.mc_err) +#define MASK_sig(context) ((context)->uc_sigmask) +#elif defined(__OpenBSD__) +#define EIP_sig(context) ((context)->sc_eip) +#define TRAP_sig(context) ((context)->sc_trapno) +#define ERROR_sig(context) ((context)->sc_err) +#define MASK_sig(context) ((context)->sc_mask) +#else +#define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP]) +#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) +#define MASK_sig(context) ((context)->uc_sigmask) +#endif + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) + ucontext_t *uc = puc; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; +#else + struct ucontext *uc = puc; +#endif + unsigned long pc; + int trapno; + +#ifndef REG_EIP +/* for glibc 2.1 */ +#define REG_EIP EIP +#define REG_ERR ERR +#define REG_TRAPNO TRAPNO +#endif + pc = EIP_sig(uc); + trapno = TRAP_sig(uc); + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + trapno == 0xe ? + (ERROR_sig(uc) >> 1) & 1 : 0, + &MASK_sig(uc), puc); +} + +#elif defined(__x86_64__) + +#ifdef __NetBSD__ +#define PC_sig(context) _UC_MACHINE_PC(context) +#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) +#define MASK_sig(context) ((context)->uc_sigmask) +#elif defined(__OpenBSD__) +#define PC_sig(context) ((context)->sc_rip) +#define TRAP_sig(context) ((context)->sc_trapno) +#define ERROR_sig(context) ((context)->sc_err) +#define MASK_sig(context) ((context)->sc_mask) +#elif defined(__FreeBSD__) || defined(__DragonFly__) +#include <ucontext.h> + +#define PC_sig(context) (*((unsigned long *)&(context)->uc_mcontext.mc_rip)) +#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) +#define ERROR_sig(context) ((context)->uc_mcontext.mc_err) +#define MASK_sig(context) ((context)->uc_sigmask) +#else +#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP]) +#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) +#define MASK_sig(context) ((context)->uc_sigmask) +#endif + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + unsigned long pc; +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) + ucontext_t *uc = puc; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; +#else + struct ucontext *uc = puc; +#endif + + pc = PC_sig(uc); + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + TRAP_sig(uc) == 0xe ? + (ERROR_sig(uc) >> 1) & 1 : 0, + &MASK_sig(uc), puc); +} + +#elif defined(_ARCH_PPC) + +/*********************************************************************** + * signal context platform-specific definitions + * From Wine + */ +#ifdef linux +/* All Registers access - only for local access */ +#define REG_sig(reg_name, context) \ + ((context)->uc_mcontext.regs->reg_name) +/* Gpr Registers access */ +#define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context) +/* Program counter */ +#define IAR_sig(context) REG_sig(nip, context) +/* Machine State Register (Supervisor) */ +#define MSR_sig(context) REG_sig(msr, context) +/* Count register */ +#define CTR_sig(context) REG_sig(ctr, context) +/* User's integer exception register */ +#define XER_sig(context) REG_sig(xer, context) +/* Link register */ +#define LR_sig(context) REG_sig(link, context) +/* Condition register */ +#define CR_sig(context) REG_sig(ccr, context) + +/* Float Registers access */ +#define FLOAT_sig(reg_num, context) \ + (((double *)((char *)((context)->uc_mcontext.regs + 48 * 4)))[reg_num]) +#define FPSCR_sig(context) \ + (*(int *)((char *)((context)->uc_mcontext.regs + (48 + 32 * 2) * 4))) +/* Exception Registers access */ +#define DAR_sig(context) REG_sig(dar, context) +#define DSISR_sig(context) REG_sig(dsisr, context) +#define TRAP_sig(context) REG_sig(trap, context) +#endif /* linux */ + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include <ucontext.h> +#define IAR_sig(context) ((context)->uc_mcontext.mc_srr0) +#define MSR_sig(context) ((context)->uc_mcontext.mc_srr1) +#define CTR_sig(context) ((context)->uc_mcontext.mc_ctr) +#define XER_sig(context) ((context)->uc_mcontext.mc_xer) +#define LR_sig(context) ((context)->uc_mcontext.mc_lr) +#define CR_sig(context) ((context)->uc_mcontext.mc_cr) +/* Exception Registers access */ +#define DAR_sig(context) ((context)->uc_mcontext.mc_dar) +#define DSISR_sig(context) ((context)->uc_mcontext.mc_dsisr) +#define TRAP_sig(context) ((context)->uc_mcontext.mc_exc) +#endif /* __FreeBSD__|| __FreeBSD_kernel__ */ + +#ifdef __APPLE__ +#include <sys/ucontext.h> +typedef struct ucontext SIGCONTEXT; +/* All Registers access - only for local access */ +#define REG_sig(reg_name, context) \ + ((context)->uc_mcontext->ss.reg_name) +#define FLOATREG_sig(reg_name, context) \ + ((context)->uc_mcontext->fs.reg_name) +#define EXCEPREG_sig(reg_name, context) \ + ((context)->uc_mcontext->es.reg_name) +#define VECREG_sig(reg_name, context) \ + ((context)->uc_mcontext->vs.reg_name) +/* Gpr Registers access */ +#define GPR_sig(reg_num, context) REG_sig(r##reg_num, context) +/* Program counter */ +#define IAR_sig(context) REG_sig(srr0, context) +/* Machine State Register (Supervisor) */ +#define MSR_sig(context) REG_sig(srr1, context) +#define CTR_sig(context) REG_sig(ctr, context) +/* Link register */ +#define XER_sig(context) REG_sig(xer, context) +/* User's integer exception register */ +#define LR_sig(context) REG_sig(lr, context) +/* Condition register */ +#define CR_sig(context) REG_sig(cr, context) +/* Float Registers access */ +#define FLOAT_sig(reg_num, context) \ + FLOATREG_sig(fpregs[reg_num], context) +#define FPSCR_sig(context) \ + ((double)FLOATREG_sig(fpscr, context)) +/* Exception Registers access */ +/* Fault registers for coredump */ +#define DAR_sig(context) EXCEPREG_sig(dar, context) +#define DSISR_sig(context) EXCEPREG_sig(dsisr, context) +/* number of powerpc exception taken */ +#define TRAP_sig(context) EXCEPREG_sig(exception, context) +#endif /* __APPLE__ */ + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + ucontext_t *uc = puc; +#else + struct ucontext *uc = puc; +#endif + unsigned long pc; + int is_write; + + pc = IAR_sig(uc); + is_write = 0; +#if 0 + /* ppc 4xx case */ + if (DSISR_sig(uc) & 0x00800000) { + is_write = 1; + } +#else + if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000)) { + is_write = 1; + } +#endif + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} + +#elif defined(__alpha__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + uint32_t *pc = uc->uc_mcontext.sc_pc; + uint32_t insn = *pc; + int is_write = 0; + + /* XXX: need kernel patch to get write flag faster */ + switch (insn >> 26) { + case 0x0d: /* stw */ + case 0x0e: /* stb */ + case 0x0f: /* stq_u */ + case 0x24: /* stf */ + case 0x25: /* stg */ + case 0x26: /* sts */ + case 0x27: /* stt */ + case 0x2c: /* stl */ + case 0x2d: /* stq */ + case 0x2e: /* stl_c */ + case 0x2f: /* stq_c */ + is_write = 1; + } + + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} +#elif defined(__sparc__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + int is_write; + uint32_t insn; +#if !defined(__arch64__) || defined(CONFIG_SOLARIS) + uint32_t *regs = (uint32_t *)(info + 1); + void *sigmask = (regs + 20); + /* XXX: is there a standard glibc define ? */ + unsigned long pc = regs[1]; +#else +#ifdef __linux__ + struct sigcontext *sc = puc; + unsigned long pc = sc->sigc_regs.tpc; + void *sigmask = (void *)sc->sigc_mask; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; + unsigned long pc = uc->sc_pc; + void *sigmask = (void *)(long)uc->sc_mask; +#endif +#endif + + /* XXX: need kernel patch to get write flag faster */ + is_write = 0; + insn = *(uint32_t *)pc; + if ((insn >> 30) == 3) { + switch ((insn >> 19) & 0x3f) { + case 0x05: /* stb */ + case 0x15: /* stba */ + case 0x06: /* sth */ + case 0x16: /* stha */ + case 0x04: /* st */ + case 0x14: /* sta */ + case 0x07: /* std */ + case 0x17: /* stda */ + case 0x0e: /* stx */ + case 0x1e: /* stxa */ + case 0x24: /* stf */ + case 0x34: /* stfa */ + case 0x27: /* stdf */ + case 0x37: /* stdfa */ + case 0x26: /* stqf */ + case 0x36: /* stqfa */ + case 0x25: /* stfsr */ + case 0x3c: /* casa */ + case 0x3e: /* casxa */ + is_write = 1; + break; + } + } + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, sigmask, NULL); +} + +#elif defined(__arm__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + +#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) + pc = uc->uc_mcontext.gregs[R15]; +#else + pc = uc->uc_mcontext.arm_pc; +#endif + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + +#elif defined(__mc68000) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = uc->uc_mcontext.gregs[16]; + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + +#elif defined(__ia64) + +#ifndef __ISR_VALID + /* This ought to be in <bits/siginfo.h>... */ +# define __ISR_VALID 1 +#endif + +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long ip; + int is_write = 0; + + ip = uc->uc_mcontext.sc_ip; + switch (host_signum) { + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGTRAP: + if (info->si_code && (info->si_segvflags & __ISR_VALID)) { + /* ISR.W (write-access) is bit 33: */ + is_write = (info->si_isr >> 33) & 1; + } + break; + + default: + break; + } + return handle_cpu_signal(ip, (unsigned long)info->si_addr, + is_write, + (sigset_t *)&uc->uc_sigmask, puc); +} + +#elif defined(__s390__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + uint16_t *pinsn; + int is_write = 0; + + pc = uc->uc_mcontext.psw.addr; + + /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead + of the normal 2 arguments. The 3rd argument contains the "int_code" + from the hardware which does in fact contain the is_write value. + The rt signal handler, as far as I can tell, does not give this value + at all. Not that we could get to it from here even if it were. */ + /* ??? This is not even close to complete, since it ignores all + of the read-modify-write instructions. */ + pinsn = (uint16_t *)pc; + switch (pinsn[0] >> 8) { + case 0x50: /* ST */ + case 0x42: /* STC */ + case 0x40: /* STH */ + is_write = 1; + break; + case 0xc4: /* RIL format insns */ + switch (pinsn[0] & 0xf) { + case 0xf: /* STRL */ + case 0xb: /* STGRL */ + case 0x7: /* STHRL */ + is_write = 1; + } + break; + case 0xe3: /* RXY format insns */ + switch (pinsn[2] & 0xff) { + case 0x50: /* STY */ + case 0x24: /* STG */ + case 0x72: /* STCY */ + case 0x70: /* STHY */ + case 0x8e: /* STPQ */ + case 0x3f: /* STRVH */ + case 0x3e: /* STRV */ + case 0x2f: /* STRVG */ + is_write = 1; + } + break; + } + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} + +#elif defined(__mips__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + greg_t pc = uc->uc_mcontext.pc; + int is_write; + + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} + +#elif defined(__hppa__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + struct siginfo *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc = uc->uc_mcontext.sc_iaoq[0]; + uint32_t insn = *(uint32_t *)pc; + int is_write = 0; + + /* XXX: need kernel patch to get write flag faster. */ + switch (insn >> 26) { + case 0x1a: /* STW */ + case 0x19: /* STH */ + case 0x18: /* STB */ + case 0x1b: /* STWM */ + is_write = 1; + break; + + case 0x09: /* CSTWX, FSTWX, FSTWS */ + case 0x0b: /* CSTDX, FSTDX, FSTDS */ + /* Distinguish from coprocessor load ... */ + is_write = (insn >> 9) & 1; + break; + + case 0x03: + switch ((insn >> 6) & 15) { + case 0xa: /* STWS */ + case 0x9: /* STHS */ + case 0x8: /* STBS */ + case 0xe: /* STWAS */ + case 0xc: /* STBYS */ + is_write = 1; + } + break; + } + + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} + +#else + +#error host CPU specific signal handler needed + +#endif + +#if defined(TARGET_I386) + +void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { + selector &= 0xffff; + cpu_x86_load_seg_cache(env, seg_reg, selector, + (selector << 4), 0xffff, 0); + } else { + helper_load_seg(seg_reg, selector); + } + env = saved_env; +} + +void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + + helper_fsave(ptr, data32); + + env = saved_env; +} + +void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + + helper_frstor(ptr, data32); + + env = saved_env; +} + +#endif /* TARGET_I386 */ |