diff --git a/qemu/cpu-exec.c b/qemu/cpu-exec.c index 250b0ffc..08d82152 100644 --- a/qemu/cpu-exec.c +++ b/qemu/cpu-exec.c @@ -258,6 +258,63 @@ static inline bool cpu_handle_exception(struct uc_struct *uc, CPUState *cpu, int return false; } +static inline void cpu_handle_interrupt(CPUState *cpu, + TranslationBlock **last_tb) +{ + CPUClass *cc = CPU_GET_CLASS(cpu->uc, cpu); + int interrupt_request = cpu->interrupt_request; + + if (unlikely(interrupt_request)) { + if (unlikely(cpu->singlestep_enabled & SSTEP_NOIRQ)) { + /* Mask out external interrupts for this step. */ + interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK; + } + if (interrupt_request & CPU_INTERRUPT_DEBUG) { + cpu->interrupt_request &= ~CPU_INTERRUPT_DEBUG; + cpu->exception_index = EXCP_DEBUG; + cpu_loop_exit(cpu); + } + if (interrupt_request & CPU_INTERRUPT_HALT) { + cpu->interrupt_request &= ~CPU_INTERRUPT_HALT; + cpu->halted = 1; + cpu->exception_index = EXCP_HLT; + cpu_loop_exit(cpu); + } +#if defined(TARGET_I386) + if (interrupt_request & CPU_INTERRUPT_INIT) { + cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0); + do_cpu_init(x86_cpu); + cpu->exception_index = EXCP_HALTED; + cpu_loop_exit(cpu); + } +#else + if (interrupt_request & CPU_INTERRUPT_RESET) { + cpu_reset(cpu); + } +#endif + /* The target hook has 3 exit conditions: + False when the interrupt isn't processed, + True when it is, and we should restart on a new TB, + and via longjmp via cpu_loop_exit. */ + if (cc->cpu_exec_interrupt(cpu, interrupt_request)) { + *last_tb = NULL; + } + /* Don't use the cached interrupt_request value, + do_interrupt may have updated the EXITTB flag. */ + if (cpu->interrupt_request & CPU_INTERRUPT_EXITTB) { + cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB; + /* ensure that no TB jump will be modified as + the program flow was changed */ + *last_tb = NULL; + } + } + if (unlikely(cpu->exit_request)) { + cpu->exit_request = 0; + cpu->exception_index = EXCP_INTERRUPT; + cpu_loop_exit(cpu); + } +} + /* main execution loop */ int cpu_exec(struct uc_struct *uc, CPUState *cpu) @@ -267,7 +324,7 @@ int cpu_exec(struct uc_struct *uc, CPUState *cpu) #ifdef TARGET_I386 X86CPU *x86_cpu = X86_CPU(uc, cpu); #endif - int ret, interrupt_request; + int ret; TranslationBlock *tb, *last_tb; int tb_exit = 0; @@ -301,57 +358,7 @@ int cpu_exec(struct uc_struct *uc, CPUState *cpu) last_tb = NULL; /* forget the last executed TB after exception */ cpu->tb_flushed = false; /* reset before first TB lookup */ for(;;) { - interrupt_request = cpu->interrupt_request; - - if (unlikely(interrupt_request)) { - if (unlikely(cpu->singlestep_enabled & SSTEP_NOIRQ)) { - /* Mask out external interrupts for this step. */ - interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK; - } - if (interrupt_request & CPU_INTERRUPT_DEBUG) { - cpu->interrupt_request &= ~CPU_INTERRUPT_DEBUG; - cpu->exception_index = EXCP_DEBUG; - cpu_loop_exit(cpu); - } - if (interrupt_request & CPU_INTERRUPT_HALT) { - cpu->interrupt_request &= ~CPU_INTERRUPT_HALT; - cpu->halted = 1; - cpu->exception_index = EXCP_HLT; - cpu_loop_exit(cpu); - } -#if defined(TARGET_I386) - if (interrupt_request & CPU_INTERRUPT_INIT) { - cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0); - do_cpu_init(x86_cpu); - cpu->exception_index = EXCP_HALTED; - cpu_loop_exit(cpu); - } -#else - if (interrupt_request & CPU_INTERRUPT_RESET) { - cpu_reset(cpu); - } -#endif - /* The target hook has 3 exit conditions: - False when the interrupt isn't processed, - True when it is, and we should restart on a new TB, - and via longjmp via cpu_loop_exit. */ - if (cc->cpu_exec_interrupt(cpu, interrupt_request)) { - last_tb = NULL; - } - /* Don't use the cached interrupt_request value, - do_interrupt may have updated the EXITTB flag. */ - if (cpu->interrupt_request & CPU_INTERRUPT_EXITTB) { - cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB; - /* ensure that no TB jump will be modified as - the program flow was changed */ - last_tb = NULL; - } - } - if (unlikely(cpu->exit_request)) { - cpu->exit_request = 0; - cpu->exception_index = EXCP_INTERRUPT; - cpu_loop_exit(cpu); - } + cpu_handle_interrupt(cpu, &last_tb); tb = tb_find_fast(cpu, &last_tb, tb_exit); if (!tb) { // invalid TB due to invalid code? uc->invalid_error = UC_ERR_FETCH_UNMAPPED;