diff options
-rw-r--r-- | cpu-exec.c | 25 | ||||
-rw-r--r-- | exec.c | 2 | ||||
-rw-r--r-- | include/exec/gen-icount.h | 12 | ||||
-rw-r--r-- | include/qom/cpu.h | 3 | ||||
-rw-r--r-- | tcg/tcg.h | 5 | ||||
-rw-r--r-- | translate-all.c | 4 |
6 files changed, 47 insertions, 4 deletions
@@ -64,6 +64,12 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr) TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); cpu_pc_from_tb(env, tb); } + if ((next_tb & TB_EXIT_MASK) == TB_EXIT_REQUESTED) { + /* We were asked to stop executing TBs (probably a pending + * interrupt. We've now stopped, so clear the flag. + */ + cpu->tcg_exit_req = 0; + } return next_tb; } @@ -608,7 +614,20 @@ int cpu_exec(CPUArchState *env) tc_ptr = tb->tc_ptr; /* execute the generated code */ next_tb = cpu_tb_exec(cpu, tc_ptr); - if ((next_tb & TB_EXIT_MASK) == TB_EXIT_ICOUNT_EXPIRED) { + switch (next_tb & TB_EXIT_MASK) { + case TB_EXIT_REQUESTED: + /* Something asked us to stop executing + * chained TBs; just continue round the main + * loop. Whatever requested the exit will also + * have set something else (eg exit_request or + * interrupt_request) which we will handle + * next time around the loop. + */ + tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); + next_tb = 0; + break; + case TB_EXIT_ICOUNT_EXPIRED: + { /* Instruction counter expired. */ int insns_left; tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); @@ -632,6 +651,10 @@ int cpu_exec(CPUArchState *env) next_tb = 0; cpu_loop_exit(env); } + break; + } + default: + break; } } cpu->current_tb = NULL; @@ -495,7 +495,7 @@ void cpu_exit(CPUArchState *env) CPUState *cpu = ENV_GET_CPU(env); cpu->exit_request = 1; - cpu_unlink_tb(cpu); + cpu->tcg_exit_req = 1; } void cpu_abort(CPUArchState *env, const char *fmt, ...) diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h index c858a73..384153b 100644 --- a/include/exec/gen-icount.h +++ b/include/exec/gen-icount.h @@ -7,10 +7,19 @@ static TCGArg *icount_arg; static int icount_label; +static int exitreq_label; static inline void gen_icount_start(void) { TCGv_i32 count; + TCGv_i32 flag; + + exitreq_label = gen_new_label(); + flag = tcg_temp_local_new_i32(); + tcg_gen_ld_i32(flag, cpu_env, + offsetof(CPUState, tcg_exit_req) - ENV_OFFSET); + tcg_gen_brcondi_i32(TCG_COND_NE, flag, 0, exitreq_label); + tcg_temp_free_i32(flag); if (!use_icount) return; @@ -29,6 +38,9 @@ static inline void gen_icount_start(void) static void gen_icount_end(TranslationBlock *tb, int num_insns) { + gen_set_label(exitreq_label); + tcg_gen_exit_tb((tcg_target_long)tb + TB_EXIT_REQUESTED); + if (use_icount) { *icount_arg = num_insns; gen_set_label(icount_label); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index ee1a7c8..ab2657c 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -71,6 +71,8 @@ struct kvm_run; * @created: Indicates whether the CPU thread has been successfully created. * @stop: Indicates a pending stop request. * @stopped: Indicates the CPU has been artificially stopped. + * @tcg_exit_req: Set to force TCG to stop executing linked TBs for this + * CPU and return to its top level loop. * @env_ptr: Pointer to subclass-specific CPUArchState field. * @current_tb: Currently executing TB. * @kvm_fd: vCPU file descriptor for KVM. @@ -100,6 +102,7 @@ struct CPUState { bool stop; bool stopped; volatile sig_atomic_t exit_request; + volatile sig_atomic_t tcg_exit_req; void *env_ptr; /* CPUArchState */ struct TranslationBlock *current_tb; @@ -703,6 +703,10 @@ TCGv_i64 tcg_const_local_i64(int64_t val); * would hit zero midway through it. In this case the next-TB pointer * returned is the TB we were about to execute, and the caller must * arrange to execute the remaining count of instructions. + * 3: we stopped because the CPU's exit_request flag was set + * (usually meaning that there is an interrupt that needs to be + * handled). The next-TB pointer returned is the TB we were + * about to execute when we noticed the pending exit request. * * If the bottom two bits indicate an exit-via-index then the CPU * state is correctly synchronised and ready for execution of the next @@ -719,6 +723,7 @@ TCGv_i64 tcg_const_local_i64(int64_t val); #define TB_EXIT_IDX0 0 #define TB_EXIT_IDX1 1 #define TB_EXIT_ICOUNT_EXPIRED 2 +#define TB_EXIT_REQUESTED 3 #if !defined(tcg_qemu_tb_exec) # define tcg_qemu_tb_exec(env, tb_ptr) \ diff --git a/translate-all.c b/translate-all.c index b50fb89..9741d96 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1475,7 +1475,7 @@ static void tcg_handle_interrupt(CPUArchState *env, int mask) cpu_abort(env, "Raised interrupt while not in I/O function"); } } else { - cpu_unlink_tb(cpu); + cpu->tcg_exit_req = 1; } } @@ -1626,7 +1626,7 @@ void cpu_interrupt(CPUArchState *env, int mask) CPUState *cpu = ENV_GET_CPU(env); env->interrupt_request |= mask; - cpu_unlink_tb(cpu); + cpu->tcg_exit_req = 1; } /* |