X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=cpu-exec.c;h=cf7c1fba7ea8bc0a249ab6931705b8b714d7eeb4;hb=d5e701af471d8a917043a75e92534f66f82d4394;hp=2c77b923fd67eeec738db84c7a4f2f44974ee38e;hpb=becfc3904194e76436ad0a60c2dde148e1927e4c;p=qemu diff --git a/cpu-exec.c b/cpu-exec.c index 2c77b92..cf7c1fb 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -15,10 +15,9 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA */ #include "config.h" -#define CPU_NO_GLOBAL_REGS #include "exec.h" #include "disas.h" #include "tcg.h" @@ -86,6 +85,7 @@ void cpu_resume_from_signal(CPUState *env1, void *puc) #endif } #endif + env->exception_index = -1; longjmp(env->jmp_env, 1); } @@ -110,7 +110,7 @@ static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb) 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); + cpu_pc_from_tb(env, tb); } tb_phys_invalidate(tb, -1); tb_free(tb); @@ -169,71 +169,12 @@ static inline TranslationBlock *tb_find_fast(void) { TranslationBlock *tb; target_ulong cs_base, pc; - uint64_t flags; + int flags; /* we record a subset of the CPU state. It will always be the same before a given translated block is executed. */ -#if defined(TARGET_I386) - flags = env->hflags; - flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); - cs_base = env->segs[R_CS].base; - pc = cs_base + env->eip; -#elif defined(TARGET_ARM) - flags = env->thumb | (env->vfp.vec_len << 1) - | (env->vfp.vec_stride << 4); - if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) - 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 - // 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 . Supervisor - flags = (env->psref << 4) | env->psrs; -#endif - cs_base = env->npc; - pc = env->pc; -#elif defined(TARGET_PPC) - 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->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->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] & (S_FLAG | P_FLAG | U_FLAG | X_FLAG); - flags |= env->dslot; - cs_base = 0; - pc = env->pc; -#else -#error unsupported CPU -#endif + cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]; if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base || tb->flags != flags)) { @@ -242,6 +183,28 @@ static inline TranslationBlock *tb_find_fast(void) return tb; } +static CPUDebugExcpHandler *debug_excp_handler; + +CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler) +{ + CPUDebugExcpHandler *old_handler = debug_excp_handler; + + debug_excp_handler = handler; + return old_handler; +} + +static void cpu_handle_debug_exception(CPUState *env) +{ + CPUWatchpoint *wp; + + if (!env->watchpoint_hit) + TAILQ_FOREACH(wp, &env->watchpoints, entry) + wp->flags &= ~BP_WATCHPOINT_HIT; + + if (debug_excp_handler) + debug_excp_handler(env); +} + /* main execution loop */ int cpu_exec(CPUState *env1) @@ -296,8 +259,11 @@ int cpu_exec(CPUState *env1) if (env->exception_index >= EXCP_INTERRUPT) { /* exit request from the cpu execution loop */ ret = env->exception_index; + if (ret == EXCP_DEBUG) + cpu_handle_debug_exception(env); break; - } else if (env->user_mode_only) { + } else { +#if defined(CONFIG_USER_ONLY) /* if user mode only, we simulate a fake exception which will be handled outside the cpu execution loop */ @@ -311,7 +277,7 @@ int cpu_exec(CPUState *env1) #endif ret = env->exception_index; break; - } else { +#else #if defined(TARGET_I386) /* simulate a real cpu exception. On i386, it can trigger new exceptions, but we do not handle @@ -339,13 +305,14 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_M68K) do_interrupt(0); #endif +#endif } env->exception_index = -1; } #ifdef USE_KQEMU - if (kqemu_is_ok(env) && env->interrupt_request == 0) { + if (kqemu_is_ok(env) && env->interrupt_request == 0 && env->exit_request == 0) { int ret; - env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); + env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); ret = kqemu_cpu_exec(env); /* put eflags in CPU temporary format */ CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); @@ -358,7 +325,7 @@ int cpu_exec(CPUState *env1) } else if (ret == 2) { /* softmmu execution needed */ } else { - if (env->interrupt_request != 0) { + if (env->interrupt_request != 0 || env->exit_request != 0) { /* hardware interrupt will be executed just after */ } else { /* otherwise, we restart */ @@ -422,9 +389,7 @@ int cpu_exec(CPUState *env1) 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); - } + qemu_log_mask(CPU_LOG_TB_IN_ASM, "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 */ @@ -436,11 +401,10 @@ int cpu_exec(CPUState *env1) 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); + qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno); do_interrupt(intno, 0, 0, 0, 1); + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; next_tb = 0; #endif } @@ -560,40 +524,40 @@ int cpu_exec(CPUState *env1) the program flow was changed */ next_tb = 0; } - if (interrupt_request & CPU_INTERRUPT_EXIT) { - env->interrupt_request &= ~CPU_INTERRUPT_EXIT; - env->exception_index = EXCP_INTERRUPT; - cpu_loop_exit(); - } + } + if (unlikely(env->exit_request)) { + env->exit_request = 0; + env->exception_index = EXCP_INTERRUPT; + cpu_loop_exit(); } #ifdef DEBUG_EXEC - if ((loglevel & CPU_LOG_TB_CPU)) { + if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) { /* restore flags in standard format */ 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 = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); + log_cpu_state(env, 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); + log_cpu_state(env, 0); #elif defined(TARGET_SPARC) - cpu_dump_state(env, logfile, fprintf, 0); + log_cpu_state(env, 0); #elif defined(TARGET_PPC) - cpu_dump_state(env, logfile, fprintf, 0); + log_cpu_state(env, 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); + log_cpu_state(env, 0); #elif defined(TARGET_MIPS) - cpu_dump_state(env, logfile, fprintf, 0); + log_cpu_state(env, 0); #elif defined(TARGET_SH4) - cpu_dump_state(env, logfile, fprintf, 0); + log_cpu_state(env, 0); #elif defined(TARGET_ALPHA) - cpu_dump_state(env, logfile, fprintf, 0); + log_cpu_state(env, 0); #elif defined(TARGET_CRIS) - cpu_dump_state(env, logfile, fprintf, 0); + log_cpu_state(env, 0); #else #error unsupported target CPU #endif @@ -611,11 +575,9 @@ int cpu_exec(CPUState *env1) tb_invalidated_flag = 0; } #ifdef DEBUG_EXEC - if ((loglevel & CPU_LOG_EXEC)) { - fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", - (long)tb->tc_ptr, tb->pc, - lookup_symbol(tb->pc)); - } + qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", + (long)tb->tc_ptr, tb->pc, + lookup_symbol(tb->pc)); #endif /* see if we can patch the calling TB. When the TB spans two pages, we cannot safely do a direct @@ -636,7 +598,7 @@ int cpu_exec(CPUState *env1) TB, but before it is linked into a potentially infinite loop and becomes env->current_tb. Avoid starting execution if there is a pending interrupt. */ - if (unlikely (env->interrupt_request & CPU_INTERRUPT_EXIT)) + if (unlikely (env->exit_request)) env->current_tb = NULL; while (env->current_tb) { @@ -654,7 +616,7 @@ int cpu_exec(CPUState *env1) int insns_left; tb = (TranslationBlock *)(long)(next_tb & ~3); /* Restore PC. */ - CPU_PC_FROM_TB(env, tb); + cpu_pc_from_tb(env, tb); insns_left = env->icount_decr.u32; if (env->icount_extra && insns_left >= 0) { /* Refill decrementer and continue execution. */ @@ -695,7 +657,7 @@ int cpu_exec(CPUState *env1) #if defined(TARGET_I386) /* restore flags in standard format */ - env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); + env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); #elif defined(TARGET_ARM) /* XXX: Save/restore host fpu exception state?. */ #elif defined(TARGET_SPARC) @@ -953,7 +915,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); - do_raise_exception_err(env->exception_index, env->error_code); + cpu_loop_exit(); } else { /* activate soft MMU for this block */ cpu_resume_from_signal(env, puc); @@ -1042,7 +1004,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); - do_raise_exception_err(env->exception_index, env->error_code); + cpu_loop_exit(); } else { /* activate soft MMU for this block */ cpu_resume_from_signal(env, puc); @@ -1223,21 +1185,36 @@ int cpu_signal_handler(int host_signum, void *pinfo, #elif defined(__x86_64__) +#ifdef __NetBSD__ +#define REG_ERR _REG_ERR +#define REG_TRAPNO _REG_TRAPNO + +#define QEMU_UC_MCONTEXT_GREGS(uc, reg) (uc)->uc_mcontext.__gregs[(reg)] +#define QEMU_UC_MACHINE_PC(uc) _UC_MACHINE_PC(uc) +#else +#define QEMU_UC_MCONTEXT_GREGS(uc, reg) (uc)->uc_mcontext.gregs[(reg)] +#define QEMU_UC_MACHINE_PC(uc) QEMU_UC_MCONTEXT_GREGS(uc, REG_RIP) +#endif + int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { siginfo_t *info = pinfo; - struct ucontext *uc = puc; unsigned long pc; +#ifdef __NetBSD__ + ucontext_t *uc = puc; +#else + struct ucontext *uc = puc; +#endif - pc = uc->uc_mcontext.gregs[REG_RIP]; + pc = QEMU_UC_MACHINE_PC(uc); return handle_cpu_signal(pc, (unsigned long)info->si_addr, - uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? - (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0, + QEMU_UC_MCONTEXT_GREGS(uc, REG_TRAPNO) == 0xe ? + (QEMU_UC_MCONTEXT_GREGS(uc, REG_ERR) >> 1) & 1 : 0, &uc->uc_sigmask, puc); } -#elif defined(__powerpc__) +#elif defined(_ARCH_PPC) /*********************************************************************** * signal context platform-specific definitions