diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:43:59 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:43:59 -0800 |
commit | c27f813900a3c114562efbb8df1065e94766fc48 (patch) | |
tree | d95919283707dcab61009e27007374a745c9541e /cpu-exec.c | |
parent | 0852ad57fa372f9b2854e4df685eaba8d8ef6790 (diff) | |
download | external_qemu-c27f813900a3c114562efbb8df1065e94766fc48.zip external_qemu-c27f813900a3c114562efbb8df1065e94766fc48.tar.gz external_qemu-c27f813900a3c114562efbb8df1065e94766fc48.tar.bz2 |
auto import from //branches/cupcake/...@130745
Diffstat (limited to 'cpu-exec.c')
-rw-r--r-- | cpu-exec.c | 1079 |
1 files changed, 515 insertions, 564 deletions
@@ -18,24 +18,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" +#define CPU_NO_GLOBAL_REGS #include "exec.h" #include "disas.h" - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#endif - -#ifndef _WIN32 -#include <unistd.h> -#endif - -extern int qemu_milli_needed; -extern int qemu_milli_check(void); -extern void qemu_check_interrupts(void); - -extern int qemu_cpu_delay; -extern int qemu_cpu_delay_count; +#include "tcg.h" #if !defined(CONFIG_SOFTMMU) #undef EAX @@ -51,19 +37,26 @@ extern int qemu_cpu_delay_count; #include <sys/ucontext.h> #endif +#if defined(__sparc__) && !defined(HOST_SOLARIS) +// Work around ugly bugs in glibc that mangle global register contents +#undef env +#define env cpu_single_env +#endif + int tb_invalidated_flag; //#define DEBUG_EXEC //#define DEBUG_SIGNAL -#if defined(TARGET_ARM) || defined(TARGET_SPARC) -/* XXX: unify with i386 target */ void cpu_loop_exit(void) { + /* NOTE: the register at this point must be saved by hand because + longjmp restore them */ + regs_to_env(); longjmp(env->jmp_env, 1); } -#endif -#if !(defined(TARGET_SPARC) || defined(TARGET_SH4)) + +#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K)) #define reg_T2 #endif @@ -89,18 +82,40 @@ void cpu_resume_from_signal(CPUState *env1, void *puc) longjmp(env->jmp_env, 1); } +/* Execute the code without caching the generated code. An interpreter + could be used if available. */ +static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb) +{ + unsigned long next_tb; + TranslationBlock *tb; + + /* Should never happen. + We only end up here when an existing TB is too long. */ + if (max_cycles > CF_COUNT_MASK) + max_cycles = CF_COUNT_MASK; + + tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags, + max_cycles); + env->current_tb = tb; + /* execute the generated code */ + next_tb = tcg_qemu_tb_exec(tb->tc_ptr); + + if ((next_tb & 3) == 2) { + /* Restore PC. This may happen if async event occurs before + the TB starts executing. */ + CPU_PC_FROM_TB(env, tb); + } + tb_phys_invalidate(tb, -1); + tb_free(tb); +} static TranslationBlock *tb_find_slow(target_ulong pc, target_ulong cs_base, - unsigned int flags) + uint64_t flags) { TranslationBlock *tb, **ptb1; - int code_gen_size; unsigned int h; target_ulong phys_pc, phys_page1, phys_page2, virt_page2; - uint8_t *tc_ptr; - - spin_lock(&tb_lock); tb_invalidated_flag = 0; @@ -134,39 +149,12 @@ static TranslationBlock *tb_find_slow(target_ulong pc, ptb1 = &tb->phys_hash_next; } not_found: - /* if no translated code available, then translate it now */ - tb = tb_alloc(pc); - if (!tb) { - /* flush must be done */ - tb_flush(env); - /* cannot fail at this point */ - tb = tb_alloc(pc); - /* don't forget to invalidate previous TB info */ - tb_invalidated_flag = 1; - } - tc_ptr = code_gen_ptr; - tb->tc_ptr = tc_ptr; - tb->cs_base = cs_base; - tb->flags = flags; -#ifdef CONFIG_TRACE - tb->bb_rec = NULL; - tb->prev_time = 0; -#endif - cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); - code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); - - /* check next page if needed */ - virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; - phys_page2 = -1; - if ((pc & TARGET_PAGE_MASK) != virt_page2) { - phys_page2 = get_phys_addr_code(env, virt_page2); - } - tb_link_phys(tb, phys_pc, phys_page2); + /* if no translated code available, then translate it now */ + tb = tb_gen_code(env, pc, cs_base, flags, 0); found: /* we add the TB in the virtual pc hash table */ env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb; - spin_unlock(&tb_lock); return tb; } @@ -174,7 +162,7 @@ static inline TranslationBlock *tb_find_fast(void) { TranslationBlock *tb; target_ulong cs_base, pc; - unsigned int flags; + uint64_t flags; /* we record a subset of the CPU state. It will always be the same before a given translated block @@ -191,207 +179,101 @@ static inline TranslationBlock *tb_find_fast(void) flags |= (1 << 6); if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) flags |= (1 << 7); + flags |= (env->condexec_bits << 8); cs_base = 0; pc = env->regs[15]; #elif defined(TARGET_SPARC) #ifdef TARGET_SPARC64 - // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled - flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2)) + // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled + flags = ((env->pstate & PS_AM) << 2) + | (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2)) | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); #else - // FPU enable . MMU enabled . MMU no-fault . Supervisor - flags = (env->psref << 3) | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1) - | env->psrs; + // FPU enable . Supervisor + flags = (env->psref << 4) | env->psrs; #endif cs_base = env->npc; pc = env->pc; #elif defined(TARGET_PPC) - flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | - (msr_se << MSR_SE) | (msr_le << MSR_LE); + flags = env->hflags; cs_base = 0; pc = env->nip; #elif defined(TARGET_MIPS) flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK); cs_base = 0; - pc = env->PC; + pc = env->active_tc.PC; +#elif defined(TARGET_M68K) + flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */ + | (env->sr & SR_S) /* Bit 13 */ + | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */ + cs_base = 0; + pc = env->pc; #elif defined(TARGET_SH4) - flags = env->sr & (SR_MD | SR_RB); - cs_base = 0; /* XXXXX */ + flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL + | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME)) /* Bits 0- 3 */ + | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */ + | (env->sr & (SR_MD | SR_RB)); /* Bits 29-30 */ + cs_base = 0; + pc = env->pc; +#elif defined(TARGET_ALPHA) + flags = env->ps; + cs_base = 0; + pc = env->pc; +#elif defined(TARGET_CRIS) + flags = env->pregs[PR_CCS] & (P_FLAG | U_FLAG | X_FLAG); + flags |= env->dslot; + cs_base = 0; pc = env->pc; #else #error unsupported CPU #endif tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]; - if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base || - tb->flags != flags, 0)) { + if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base || + tb->flags != flags)) { tb = tb_find_slow(pc, cs_base, flags); - /* Note: we do it here to avoid a gcc bug on Mac OS X when - doing it in tb_find_slow */ - if (tb_invalidated_flag) { - /* as some TB could have been invalidated because - of memory exceptions while generating the code, we - must recompute the hash index here */ - T0 = 0; - } } return tb; } - /* main execution loop */ int cpu_exec(CPUState *env1) { - int saved_T0, saved_T1; -#if defined(reg_T2) - int saved_T2; -#endif - CPUState *saved_env; -#if defined(TARGET_I386) -#ifdef reg_EAX - int saved_EAX; -#endif -#ifdef reg_ECX - int saved_ECX; -#endif -#ifdef reg_EDX - int saved_EDX; -#endif -#ifdef reg_EBX - int saved_EBX; -#endif -#ifdef reg_ESP - int saved_ESP; -#endif -#ifdef reg_EBP - int saved_EBP; -#endif -#ifdef reg_ESI - int saved_ESI; -#endif -#ifdef reg_EDI - int saved_EDI; -#endif -#elif defined(TARGET_SPARC) -#if defined(reg_REGWPTR) - uint32_t *saved_regwptr; -#endif -#endif -#if defined(__sparc__) && !defined(HOST_SOLARIS) - int saved_i7, tmp_T0; -#endif +#define DECLARE_HOST_REGS 1 +#include "hostregs_helper.h" int ret, interrupt_request; - void (*gen_func)(void); TranslationBlock *tb; uint8_t *tc_ptr; + unsigned long next_tb; -#if defined(TARGET_I386) - /* handle exit of HALTED state */ - if (env1->hflags & HF_HALTED_MASK) { - /* disable halt condition */ - if ((env1->interrupt_request & CPU_INTERRUPT_HARD) && - (env1->eflags & IF_MASK)) { - env1->hflags &= ~HF_HALTED_MASK; - } else { - return EXCP_HALTED; - } - } -#elif defined(TARGET_PPC) - if (env1->halted) { - if (env1->msr[MSR_EE] && - (env1->interrupt_request & - (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) { - env1->halted = 0; - } else { - return EXCP_HALTED; - } - } -#elif defined(TARGET_SPARC) - if (env1->halted) { - if ((env1->interrupt_request & CPU_INTERRUPT_HARD) && - (env1->psret != 0)) { - env1->halted = 0; - } else { - return EXCP_HALTED; - } - } -#elif defined(TARGET_ARM) - if (env1->halted) { - /* An interrupt wakes the CPU even if the I and F CPSR bits are - set. */ - if (env1->interrupt_request - & (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD)) { - env1->halted = 0; - } else { - return EXCP_HALTED; - } - } -#elif defined(TARGET_MIPS) - if (env1->halted) { - if (env1->interrupt_request & - (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)) { - env1->halted = 0; - } else { - return EXCP_HALTED; - } - } -#endif + if (cpu_halted(env1) == EXCP_HALTED) + return EXCP_HALTED; cpu_single_env = env1; /* first we save global registers */ - saved_env = env; +#define SAVE_HOST_REGS 1 +#include "hostregs_helper.h" env = env1; - saved_T0 = T0; - saved_T1 = T1; -#if defined(reg_T2) - saved_T2 = T2; -#endif -#if defined(__sparc__) && !defined(HOST_SOLARIS) - /* we also save i7 because longjmp may not restore it */ - asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); -#endif - -#if defined(TARGET_I386) -#ifdef reg_EAX - saved_EAX = EAX; -#endif -#ifdef reg_ECX - saved_ECX = ECX; -#endif -#ifdef reg_EDX - saved_EDX = EDX; -#endif -#ifdef reg_EBX - saved_EBX = EBX; -#endif -#ifdef reg_ESP - saved_ESP = ESP; -#endif -#ifdef reg_EBP - saved_EBP = EBP; -#endif -#ifdef reg_ESI - saved_ESI = ESI; -#endif -#ifdef reg_EDI - saved_EDI = EDI; -#endif env_to_regs(); +#if defined(TARGET_I386) /* put eflags in CPU temporary format */ CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); DF = 1 - (2 * ((env->eflags >> 10) & 1)); CC_OP = CC_OP_EFLAGS; env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); -#elif defined(TARGET_ARM) #elif defined(TARGET_SPARC) -#if defined(reg_REGWPTR) - saved_regwptr = REGWPTR; -#endif +#elif defined(TARGET_M68K) + env->cc_op = CC_OP_FLAGS; + env->cc_dest = env->sr & 0xf; + env->cc_x = (env->sr >> 4) & 1; +#elif defined(TARGET_ALPHA) +#elif defined(TARGET_ARM) #elif defined(TARGET_PPC) #elif defined(TARGET_MIPS) #elif defined(TARGET_SH4) +#elif defined(TARGET_CRIS) /* XXXXX */ #else #error unsupported target CPU @@ -410,13 +292,15 @@ int cpu_exec(CPUState *env1) break; } else if (env->user_mode_only) { /* if user mode only, we simulate a fake exception - which will be hanlded outside the cpu execution + which will be handled outside the cpu execution loop */ #if defined(TARGET_I386) do_interrupt_user(env->exception_index, env->exception_is_int, env->error_code, env->exception_next_eip); + /* successfully delivered */ + env->old_exception = -1; #endif ret = env->exception_index; break; @@ -429,16 +313,24 @@ int cpu_exec(CPUState *env1) env->exception_is_int, env->error_code, env->exception_next_eip, 0); + /* successfully delivered */ + env->old_exception = -1; #elif defined(TARGET_PPC) do_interrupt(env); #elif defined(TARGET_MIPS) do_interrupt(env); #elif defined(TARGET_SPARC) - do_interrupt(env->exception_index); + do_interrupt(env); #elif defined(TARGET_ARM) do_interrupt(env); #elif defined(TARGET_SH4) do_interrupt(env); +#elif defined(TARGET_ALPHA) + do_interrupt(env); +#elif defined(TARGET_CRIS) + do_interrupt(env); +#elif defined(TARGET_M68K) + do_interrupt(0); #endif } env->exception_index = -1; @@ -469,33 +361,71 @@ int cpu_exec(CPUState *env1) } #endif - T0 = 0; /* force lookup of first TB */ + next_tb = 0; /* force lookup of first TB */ for(;;) { -#if defined(__sparc__) && !defined(HOST_SOLARIS) - /* g1 can be modified by some libc? functions */ - tmp_T0 = T0; -#endif interrupt_request = env->interrupt_request; - if (__builtin_expect(interrupt_request, 0)) { + if (unlikely(interrupt_request) && + likely(!(env->singlestep_enabled & SSTEP_NOIRQ))) { + if (interrupt_request & CPU_INTERRUPT_DEBUG) { + env->interrupt_request &= ~CPU_INTERRUPT_DEBUG; + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); + } +#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \ + defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) + if (interrupt_request & CPU_INTERRUPT_HALT) { + env->interrupt_request &= ~CPU_INTERRUPT_HALT; + env->halted = 1; + env->exception_index = EXCP_HLT; + cpu_loop_exit(); + } +#endif #if defined(TARGET_I386) - /* if hardware interrupt pending, we execute it */ - if ((interrupt_request & CPU_INTERRUPT_HARD) && - (env->eflags & IF_MASK) && - !(env->hflags & HF_INHIBIT_IRQ_MASK)) { - int intno; - env->interrupt_request &= ~CPU_INTERRUPT_HARD; - intno = cpu_get_pic_interrupt(env); - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); - } - do_interrupt(intno, 0, 0, 0, 1); - /* ensure that no TB jump will be modified as - the program flow was changed */ -#if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; -#else - T0 = 0; + if (env->hflags2 & HF2_GIF_MASK) { + if ((interrupt_request & CPU_INTERRUPT_SMI) && + !(env->hflags & HF_SMM_MASK)) { + svm_check_intercept(SVM_EXIT_SMI); + env->interrupt_request &= ~CPU_INTERRUPT_SMI; + do_smm_enter(); + next_tb = 0; + } else if ((interrupt_request & CPU_INTERRUPT_NMI) && + !(env->hflags2 & HF2_NMI_MASK)) { + env->interrupt_request &= ~CPU_INTERRUPT_NMI; + env->hflags2 |= HF2_NMI_MASK; + do_interrupt(EXCP02_NMI, 0, 0, 0, 1); + next_tb = 0; + } else if ((interrupt_request & CPU_INTERRUPT_HARD) && + (((env->hflags2 & HF2_VINTR_MASK) && + (env->hflags2 & HF2_HIF_MASK)) || + (!(env->hflags2 & HF2_VINTR_MASK) && + (env->eflags & IF_MASK && + !(env->hflags & HF_INHIBIT_IRQ_MASK))))) { + int intno; + svm_check_intercept(SVM_EXIT_INTR); + env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ); + intno = cpu_get_pic_interrupt(env); + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); + } + do_interrupt(intno, 0, 0, 0, 1); + /* ensure that no TB jump will be modified as + the program flow was changed */ + next_tb = 0; +#if !defined(CONFIG_USER_ONLY) + } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) && + (env->eflags & IF_MASK) && + !(env->hflags & HF_INHIBIT_IRQ_MASK)) { + int intno; + /* FIXME: this should respect TPR */ + svm_check_intercept(SVM_EXIT_VINTR); + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno); + do_interrupt(intno, 0, 0, 0, 1); + next_tb = 0; #endif + } } #elif defined(TARGET_PPC) #if 0 @@ -503,48 +433,24 @@ int cpu_exec(CPUState *env1) cpu_ppc_reset(env); } #endif - if (msr_ee != 0) { - if ((interrupt_request & CPU_INTERRUPT_HARD)) { - /* Raise it */ - env->exception_index = EXCP_EXTERNAL; - env->error_code = 0; - do_interrupt(env); + if (interrupt_request & CPU_INTERRUPT_HARD) { + ppc_hw_interrupt(env); + if (env->pending_interrupts == 0) env->interrupt_request &= ~CPU_INTERRUPT_HARD; -#if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; -#else - T0 = 0; -#endif - } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) { - /* Raise it */ - env->exception_index = EXCP_DECR; - env->error_code = 0; - do_interrupt(env); - env->interrupt_request &= ~CPU_INTERRUPT_TIMER; -#if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; -#else - T0 = 0; -#endif - } + next_tb = 0; } #elif defined(TARGET_MIPS) if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && (env->CP0_Status & (1 << CP0St_IE)) && - (env->CP0_Status & env->CP0_Cause & 0x0000FF00) && - !(env->hflags & MIPS_HFLAG_EXL) && - !(env->hflags & MIPS_HFLAG_ERL) && + !(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { /* Raise it */ env->exception_index = EXCP_EXT_INTERRUPT; env->error_code = 0; do_interrupt(env); - env->interrupt_request &= ~CPU_INTERRUPT_HARD; -#if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; -#else - T0 = 0; -#endif + next_tb = 0; } #elif defined(TARGET_SPARC) if ((interrupt_request & CPU_INTERRUPT_HARD) && @@ -556,34 +462,77 @@ int cpu_exec(CPUState *env1) (pil == 15 || pil > env->psrpil)) || type != TT_EXTINT) { env->interrupt_request &= ~CPU_INTERRUPT_HARD; - do_interrupt(env->interrupt_index); + env->exception_index = env->interrupt_index; + do_interrupt(env); env->interrupt_index = 0; -#if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; -#else - T0 = 0; +#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) + cpu_check_irqs(env); #endif + next_tb = 0; } } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); env->interrupt_request &= ~CPU_INTERRUPT_TIMER; - } else if (interrupt_request & CPU_INTERRUPT_HALT) { - env1->halted = 1; - return EXCP_HALTED; - } + } #elif defined(TARGET_ARM) if (interrupt_request & CPU_INTERRUPT_FIQ && !(env->uncached_cpsr & CPSR_F)) { env->exception_index = EXCP_FIQ; do_interrupt(env); + next_tb = 0; } + /* ARMv7-M interrupt return works by loading a magic value + into the PC. On real hardware the load causes the + return to occur. The qemu implementation performs the + jump normally, then does the exception return when the + CPU tries to execute code at the magic address. + This will cause the magic PC value to be pushed to + the stack if an interrupt occured at the wrong time. + We avoid this by disabling interrupts when + pc contains a magic address. */ if (interrupt_request & CPU_INTERRUPT_HARD - && !(env->uncached_cpsr & CPSR_I)) { + && ((IS_M(env) && env->regs[15] < 0xfffffff0) + || !(env->uncached_cpsr & CPSR_I))) { env->exception_index = EXCP_IRQ; do_interrupt(env); + next_tb = 0; } #elif defined(TARGET_SH4) - /* XXXXX */ + if (interrupt_request & CPU_INTERRUPT_HARD) { + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_ALPHA) + if (interrupt_request & CPU_INTERRUPT_HARD) { + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_CRIS) + if (interrupt_request & CPU_INTERRUPT_HARD + && (env->pregs[PR_CCS] & I_FLAG)) { + env->exception_index = EXCP_IRQ; + do_interrupt(env); + next_tb = 0; + } + if (interrupt_request & CPU_INTERRUPT_NMI + && (env->pregs[PR_CCS] & M_FLAG)) { + env->exception_index = EXCP_NMI; + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_M68K) + if (interrupt_request & CPU_INTERRUPT_HARD + && ((env->sr & SR_I) >> SR_I_SHIFT) + < env->pending_level) { + /* Real hardware gets the interrupt vector via an + IACK cycle at this point. Current emulated + hardware doesn't rely on this, so we + provide/save the vector when the interrupt is + first signalled. */ + env->exception_index = env->pending_vector; + do_interrupt(1); + next_tb = 0; + } #endif /* Don't use the cached interupt_request value, do_interrupt may have updated the EXITTB flag. */ @@ -591,11 +540,7 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; /* ensure that no TB jump will be modified as the program flow was changed */ -#if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; -#else - T0 = 0; -#endif + next_tb = 0; } if (interrupt_request & CPU_INTERRUPT_EXIT) { env->interrupt_request &= ~CPU_INTERRUPT_EXIT; @@ -605,53 +550,48 @@ int cpu_exec(CPUState *env1) } #ifdef DEBUG_EXEC if ((loglevel & CPU_LOG_TB_CPU)) { -#if defined(TARGET_I386) /* restore flags in standard format */ -#ifdef reg_EAX - env->regs[R_EAX] = EAX; -#endif -#ifdef reg_EBX - env->regs[R_EBX] = EBX; -#endif -#ifdef reg_ECX - env->regs[R_ECX] = ECX; -#endif -#ifdef reg_EDX - env->regs[R_EDX] = EDX; -#endif -#ifdef reg_ESI - env->regs[R_ESI] = ESI; -#endif -#ifdef reg_EDI - env->regs[R_EDI] = EDI; -#endif -#ifdef reg_EBP - env->regs[R_EBP] = EBP; -#endif -#ifdef reg_ESP - env->regs[R_ESP] = ESP; -#endif + regs_to_env(); +#if defined(TARGET_I386) env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); #elif defined(TARGET_ARM) cpu_dump_state(env, logfile, fprintf, 0); #elif defined(TARGET_SPARC) - REGWPTR = env->regbase + (env->cwp * 16); - env->regwptr = REGWPTR; cpu_dump_state(env, logfile, fprintf, 0); #elif defined(TARGET_PPC) cpu_dump_state(env, logfile, fprintf, 0); +#elif defined(TARGET_M68K) + cpu_m68k_flush_flags(env, env->cc_op); + env->cc_op = CC_OP_FLAGS; + env->sr = (env->sr & 0xffe0) + | env->cc_dest | (env->cc_x << 4); + cpu_dump_state(env, logfile, fprintf, 0); #elif defined(TARGET_MIPS) cpu_dump_state(env, logfile, fprintf, 0); #elif defined(TARGET_SH4) cpu_dump_state(env, logfile, fprintf, 0); +#elif defined(TARGET_ALPHA) + cpu_dump_state(env, logfile, fprintf, 0); +#elif defined(TARGET_CRIS) + cpu_dump_state(env, logfile, fprintf, 0); #else #error unsupported target CPU #endif } #endif + spin_lock(&tb_lock); tb = tb_find_fast(); + /* Note: we do it here to avoid a gcc bug on Mac OS X when + doing it in tb_find_slow */ + if (tb_invalidated_flag) { + /* as some TB could have been invalidated because + of memory exceptions while generating the code, we + must recompute the hash index here */ + next_tb = 0; + tb_invalidated_flag = 0; + } #ifdef DEBUG_EXEC if ((loglevel & CPU_LOG_EXEC)) { fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", @@ -659,157 +599,60 @@ int cpu_exec(CPUState *env1) lookup_symbol(tb->pc)); } #endif -#if defined(__sparc__) && !defined(HOST_SOLARIS) - T0 = tmp_T0; -#endif /* see if we can patch the calling TB. When the TB spans two pages, we cannot safely do a direct jump. */ { - if (T0 != 0 && -#if USE_KQEMU + if (next_tb != 0 && +#ifdef USE_KQEMU (env->kqemu_enabled != 2) && #endif - tb->page_addr[1] == -1 -#if defined(TARGET_I386) && defined(USE_CODE_COPY) - && (tb->cflags & CF_CODE_COPY) == - (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY) -#endif - ) { - spin_lock(&tb_lock); - tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb); -#if defined(USE_CODE_COPY) - /* propagates the FP use info */ - ((TranslationBlock *)(T0 & ~3))->cflags |= - (tb->cflags & CF_FP_USED); -#endif - spin_unlock(&tb_lock); + tb->page_addr[1] == -1) { + tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb); } } - tc_ptr = tb->tc_ptr; + spin_unlock(&tb_lock); env->current_tb = tb; + while (env->current_tb) { + tc_ptr = tb->tc_ptr; /* execute the generated code */ - gen_func = (void *)tc_ptr; -#if defined(__sparc__) - __asm__ __volatile__("call %0\n\t" - "mov %%o7,%%i0" - : /* no outputs */ - : "r" (gen_func) - : "i0", "i1", "i2", "i3", "i4", "i5", - "l0", "l1", "l2", "l3", "l4", "l5", - "l6", "l7"); -#elif defined(__arm__) - asm volatile ("mov pc, %0\n\t" - ".global exec_loop\n\t" - "exec_loop:\n\t" - : /* no outputs */ - : "r" (gen_func) - : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); -#elif defined(TARGET_X86_64) && defined(__i386__) - asm volatile ("push %%ebx\n" - "push %%esi\n" - "push %%edi\n" - "call *%0\n" - "pop %%edi\n" - "pop %%esi\n" - "pop %%ebx\n" - : : "r" (gen_func) : "ebx", "esi", "edi"); -#elif defined(TARGET_I386) && defined(USE_CODE_COPY) -{ - if (!(tb->cflags & CF_CODE_COPY)) { - if ((tb->cflags & CF_FP_USED) && env->native_fp_regs) { - save_native_fp_state(env); - } - gen_func(); - } else { - if ((tb->cflags & CF_FP_USED) && !env->native_fp_regs) { - restore_native_fp_state(env); - } - /* we work with native eflags */ - CC_SRC = cc_table[CC_OP].compute_all(); - CC_OP = CC_OP_EFLAGS; - asm(".globl exec_loop\n" - "\n" - "debug1:\n" - " pushl %%ebp\n" - " fs movl %10, %9\n" - " fs movl %11, %%eax\n" - " andl $0x400, %%eax\n" - " fs orl %8, %%eax\n" - " pushl %%eax\n" - " popf\n" - " fs movl %%esp, %12\n" - " fs movl %0, %%eax\n" - " fs movl %1, %%ecx\n" - " fs movl %2, %%edx\n" - " fs movl %3, %%ebx\n" - " fs movl %4, %%esp\n" - " fs movl %5, %%ebp\n" - " fs movl %6, %%esi\n" - " fs movl %7, %%edi\n" - " fs jmp *%9\n" - "exec_loop:\n" - " fs movl %%esp, %4\n" - " fs movl %12, %%esp\n" - " fs movl %%eax, %0\n" - " fs movl %%ecx, %1\n" - " fs movl %%edx, %2\n" - " fs movl %%ebx, %3\n" - " fs movl %%ebp, %5\n" - " fs movl %%esi, %6\n" - " fs movl %%edi, %7\n" - " pushf\n" - " popl %%eax\n" - " movl %%eax, %%ecx\n" - " andl $0x400, %%ecx\n" - " shrl $9, %%ecx\n" - " andl $0x8d5, %%eax\n" - " fs movl %%eax, %8\n" - " movl $1, %%eax\n" - " subl %%ecx, %%eax\n" - " fs movl %%eax, %11\n" - " fs movl %9, %%ebx\n" /* get T0 value */ - " popl %%ebp\n" - : - : "m" (*(uint8_t *)offsetof(CPUState, regs[0])), - "m" (*(uint8_t *)offsetof(CPUState, regs[1])), - "m" (*(uint8_t *)offsetof(CPUState, regs[2])), - "m" (*(uint8_t *)offsetof(CPUState, regs[3])), - "m" (*(uint8_t *)offsetof(CPUState, regs[4])), - "m" (*(uint8_t *)offsetof(CPUState, regs[5])), - "m" (*(uint8_t *)offsetof(CPUState, regs[6])), - "m" (*(uint8_t *)offsetof(CPUState, regs[7])), - "m" (*(uint8_t *)offsetof(CPUState, cc_src)), - "m" (*(uint8_t *)offsetof(CPUState, tmp0)), - "a" (gen_func), - "m" (*(uint8_t *)offsetof(CPUState, df)), - "m" (*(uint8_t *)offsetof(CPUState, saved_esp)) - : "%ecx", "%edx" - ); - } -} -#elif defined(__ia64) - struct fptr { - void *ip; - void *gp; - } fp; - - fp.ip = tc_ptr; - fp.gp = code_gen_buffer + 2 * (1 << 20); - (*(void (*)(void)) &fp)(); -#else - gen_func(); -#endif - env->current_tb = NULL; +#if defined(__sparc__) && !defined(HOST_SOLARIS) +#undef env + env = cpu_single_env; +#define env cpu_single_env +#endif + next_tb = tcg_qemu_tb_exec(tc_ptr); + env->current_tb = NULL; + if ((next_tb & 3) == 2) { + /* Instruction counter expired. */ + int insns_left; + tb = (TranslationBlock *)(long)(next_tb & ~3); + /* Restore PC. */ + CPU_PC_FROM_TB(env, tb); + insns_left = env->icount_decr.u32; + if (env->icount_extra && insns_left >= 0) { + /* Refill decrementer and continue execution. */ + env->icount_extra += insns_left; + if (env->icount_extra > 0xffff) { + insns_left = 0xffff; + } else { + insns_left = env->icount_extra; + } + env->icount_extra -= insns_left; + env->icount_decr.u16.low = insns_left; + } else { + if (insns_left > 0) { + /* Execute remaining instructions. */ + cpu_exec_nocache(insns_left, tb); + } + env->exception_index = EXCP_INTERRUPT; + next_tb = 0; + cpu_loop_exit(); + } + } + } /* reset soft MMU for next block (it can currently only be set by a memory fault) */ -#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU) - if (env->hflags & HF_SOFTMMU_MASK) { - env->hflags &= ~HF_SOFTMMU_MASK; - /* do not allow linking to another block */ - T0 = 0; - } -#endif #if defined(USE_KQEMU) #define MIN_CYCLE_BEFORE_SWITCH (100 * 1000) if (kqemu_is_ok(env) && @@ -817,31 +660,7 @@ int cpu_exec(CPUState *env1) cpu_loop_exit(); } #endif - -#if 0 /* digit: implement high-resolution polling */ - if (qemu_milli_needed) { - static int counter; - - if (++counter == 50) { - counter = 0; - if (qemu_milli_check()) - qemu_check_interrupts(); - } - } -#endif -/* ANDROID-BEGIN */ - if (qemu_cpu_delay) { - if (++qemu_cpu_delay_count >= qemu_cpu_delay) { - qemu_cpu_delay_count = 0; -#ifdef _WIN32 - Sleep(1); -#else - usleep(1000); -#endif - } - } -/* ANDROID-END */ - } + } /* for(;;) */ } else { env_to_regs(); } @@ -849,61 +668,29 @@ int cpu_exec(CPUState *env1) #if defined(TARGET_I386) -#if defined(USE_CODE_COPY) - if (env->native_fp_regs) { - save_native_fp_state(env); - } -#endif /* restore flags in standard format */ env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); - - /* restore global registers */ -#ifdef reg_EAX - EAX = saved_EAX; -#endif -#ifdef reg_ECX - ECX = saved_ECX; -#endif -#ifdef reg_EDX - EDX = saved_EDX; -#endif -#ifdef reg_EBX - EBX = saved_EBX; -#endif -#ifdef reg_ESP - ESP = saved_ESP; -#endif -#ifdef reg_EBP - EBP = saved_EBP; -#endif -#ifdef reg_ESI - ESI = saved_ESI; -#endif -#ifdef reg_EDI - EDI = saved_EDI; -#endif #elif defined(TARGET_ARM) /* XXX: Save/restore host fpu exception state?. */ #elif defined(TARGET_SPARC) -#if defined(reg_REGWPTR) - REGWPTR = saved_regwptr; -#endif #elif defined(TARGET_PPC) +#elif defined(TARGET_M68K) + cpu_m68k_flush_flags(env, env->cc_op); + env->cc_op = CC_OP_FLAGS; + env->sr = (env->sr & 0xffe0) + | env->cc_dest | (env->cc_x << 4); #elif defined(TARGET_MIPS) #elif defined(TARGET_SH4) +#elif defined(TARGET_ALPHA) +#elif defined(TARGET_CRIS) /* XXXXX */ #else #error unsupported target CPU #endif -#if defined(__sparc__) && !defined(HOST_SOLARIS) - asm volatile ("mov %0, %%i7" : : "r" (saved_i7)); -#endif - T0 = saved_T0; - T1 = saved_T1; -#if defined(reg_T2) - T2 = saved_T2; -#endif - env = saved_env; + + /* restore global registers */ +#include "hostregs_helper.h" + /* fail safe : never use cpu_single_env outside cpu_exec() */ cpu_single_env = NULL; return ret; @@ -935,31 +722,31 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) cpu_x86_load_seg_cache(env, seg_reg, selector, (selector << 4), 0xffff, 0); } else { - load_seg(seg_reg, selector); + helper_load_seg(seg_reg, selector); } env = saved_env; } -void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32) +void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32) { CPUX86State *saved_env; saved_env = env; env = s; - helper_fsave((target_ulong)ptr, data32); + helper_fsave(ptr, data32); env = saved_env; } -void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) +void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32) { CPUX86State *saved_env; saved_env = env; env = s; - helper_frstor((target_ulong)ptr, data32); + helper_frstor(ptr, data32); env = saved_env; } @@ -993,8 +780,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_x86_handle_mmu_fault(env, address, is_write, - ((env->hflags & HF_CPL_MASK) == 3), 0); + ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -1043,7 +829,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, return 1; } /* see if it is an MMU fault */ - ret = cpu_arm_handle_mmu_fault(env, address, is_write, 1, 0); + ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -1059,6 +845,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); cpu_loop_exit(); + /* never comes here */ + return 1; } #elif defined(TARGET_SPARC) static inline int handle_cpu_signal(unsigned long pc, unsigned long address, @@ -1079,7 +867,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, return 1; } /* see if it is an MMU fault */ - ret = cpu_sparc_handle_mmu_fault(env, address, is_write, 1, 0); + ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -1095,6 +883,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); cpu_loop_exit(); + /* never comes here */ + return 1; } #elif defined (TARGET_PPC) static inline int handle_cpu_signal(unsigned long pc, unsigned long address, @@ -1116,7 +906,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0); + ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -1146,6 +936,45 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, return 1; } +#elif defined(TARGET_M68K) +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) + 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(address, pc, puc)) { + return 1; + } + /* see if it is an MMU fault */ + ret = cpu_m68k_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, puc); + } + /* we restore the process signal mask as the sigreturn should + do it (XXX: use sigsetjmp) */ + sigprocmask(SIG_SETMASK, old_set, NULL); + cpu_loop_exit(); + /* never comes here */ + return 1; +} + #elif defined (TARGET_MIPS) static inline int handle_cpu_signal(unsigned long pc, unsigned long address, int is_write, sigset_t *old_set, @@ -1166,7 +995,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_mips_handle_mmu_fault(env, address, is_write, 1, 0); + ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -1181,8 +1010,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } if (ret == 1) { #if 0 - printf("PF exception: NIP=0x%08x error=0x%x %p\n", - env->nip, env->error_code, tb); + printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n", + env->PC, env->error_code, tb); #endif /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ @@ -1216,7 +1045,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_sh4_handle_mmu_fault(env, address, is_write, 1, 0); + ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -1240,35 +1069,114 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* never comes here */ return 1; } -#else -#error unsupported target CPU + +#elif defined (TARGET_ALPHA) +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) + 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; + } -#if defined(__i386__) + /* see if it is an MMU fault */ + ret = cpu_alpha_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 */ -#if defined(USE_CODE_COPY) -static void cpu_send_trap(unsigned long pc, int trap, - struct ucontext *uc) + /* 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, puc); + } +#if 0 + printf("PF exception: NIP=0x%08x error=0x%x %p\n", + env->nip, env->error_code, tb); +#endif + /* we restore the process signal mask as the sigreturn should + do it (XXX: use sigsetjmp) */ + sigprocmask(SIG_SETMASK, old_set, NULL); + cpu_loop_exit(); + /* never comes here */ + return 1; +} +#elif defined (TARGET_CRIS) +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) + 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_cris_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, uc); + cpu_restore_state(tb, env, pc, puc); } - sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL); - raise_exception_err(trap, env->error_code); + /* we restore the process signal mask as the sigreturn should + do it (XXX: use sigsetjmp) */ + sigprocmask(SIG_SETMASK, old_set, NULL); + cpu_loop_exit(); + /* never comes here */ + return 1; } + +#else +#error unsupported target CPU +#endif + +#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) +#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]) #endif -int cpu_signal_handler(int host_signum, struct siginfo *info, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { + siginfo_t *info = pinfo; struct ucontext *uc = puc; unsigned long pc; int trapno; @@ -1279,26 +1187,20 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, #define REG_ERR ERR #define REG_TRAPNO TRAPNO #endif - pc = uc->uc_mcontext.gregs[REG_EIP]; - trapno = uc->uc_mcontext.gregs[REG_TRAPNO]; -#if defined(TARGET_I386) && defined(USE_CODE_COPY) - if (trapno == 0x00 || trapno == 0x05) { - /* send division by zero or bound exception */ - cpu_send_trap(pc, trapno, uc); - return 1; - } else -#endif - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - trapno == 0xe ? - (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0, - &uc->uc_sigmask, puc); + 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, + &uc->uc_sigmask, puc); } #elif defined(__x86_64__) -int cpu_signal_handler(int host_signum, struct siginfo *info, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { + siginfo_t *info = pinfo; struct ucontext *uc = puc; unsigned long pc; @@ -1360,9 +1262,10 @@ typedef struct ucontext SIGCONTEXT; # define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */ #endif /* __APPLE__ */ -int cpu_signal_handler(int host_signum, struct siginfo *info, +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; @@ -1383,9 +1286,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, #elif defined(__alpha__) -int cpu_signal_handler(int host_signum, struct siginfo *info, +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; @@ -1412,17 +1316,23 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, } #elif defined(__sparc__) -int cpu_signal_handler(int host_signum, struct siginfo *info, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { - uint32_t *regs = (uint32_t *)(info + 1); - void *sigmask = (regs + 20); - unsigned long pc; + siginfo_t *info = pinfo; int is_write; uint32_t insn; - +#if !defined(__arch64__) || defined(HOST_SOLARIS) + uint32_t *regs = (uint32_t *)(info + 1); + void *sigmask = (regs + 20); /* XXX: is there a standard glibc define ? */ - pc = regs[1]; + unsigned long pc = regs[1]; +#else + struct sigcontext *sc = puc; + unsigned long pc = sc->sigc_regs.tpc; + void *sigmask = (void *)sc->sigc_mask; +#endif + /* XXX: need kernel patch to get write flag faster */ is_write = 0; insn = *(uint32_t *)pc; @@ -1445,26 +1355,32 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, #elif defined(__arm__) -int cpu_signal_handler(int host_signum, struct siginfo *info, +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); + &uc->uc_sigmask, puc); } #elif defined(__mc68000) -int cpu_signal_handler(int host_signum, struct siginfo *info, +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; @@ -1484,8 +1400,9 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, # define __ISR_VALID 1 #endif -int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc) +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; @@ -1512,9 +1429,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc) #elif defined(__s390__) -int cpu_signal_handler(int host_signum, struct siginfo *info, +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; @@ -1523,6 +1441,39 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, /* 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(__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; + int is_write; + + pc = uc->uc_mcontext.sc_iaoq[0]; + /* FIXME: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, is_write, &uc->uc_sigmask, puc); } |