@@ -173,6 +173,7 @@ typedef struct CPUWatchpoint {
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
uint32_t interrupt_request; \
volatile sig_atomic_t exit_request; \
+ volatile sig_atomic_t tcg_exit_req; \
CPU_COMMON_TLB \
struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \
/* buffer for temporaries in the code generator */ \
@@ -63,6 +63,12 @@ static inline tcg_target_ulong cpu_tb_exec(CPUArchState *env, 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.
+ */
+ env->tcg_exit_req = 0;
+ }
return next_tb;
}
@@ -578,7 +584,20 @@ int cpu_exec(CPUArchState *env)
tc_ptr = tb->tc_ptr;
/* execute the generated code */
next_tb = cpu_tb_exec(env, 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);
@@ -602,6 +621,10 @@ int cpu_exec(CPUArchState *env)
next_tb = 0;
cpu_loop_exit(env);
}
+ break;
+ }
+ default:
+ break;
}
}
env->current_tb = NULL;
@@ -1756,7 +1756,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(env);
+ env->tcg_exit_req = 1;
}
}
@@ -1767,7 +1767,7 @@ CPUInterruptHandler cpu_interrupt_handler = tcg_handle_interrupt;
void cpu_interrupt(CPUArchState *env, int mask)
{
env->interrupt_request |= mask;
- cpu_unlink_tb(env);
+ env->tcg_exit_req = 1;
}
#endif /* CONFIG_USER_ONLY */
@@ -1779,7 +1779,7 @@ void cpu_reset_interrupt(CPUArchState *env, int mask)
void cpu_exit(CPUArchState *env)
{
env->exit_request = 1;
- cpu_unlink_tb(env);
+ env->tcg_exit_req = 1;
}
const CPULogItem cpu_log_items[] = {
@@ -4,10 +4,18 @@
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(CPUArchState, tcg_exit_req));
+ tcg_gen_brcondi_i32(TCG_COND_NE, flag, 0, exitreq_label);
+ tcg_temp_free_i32(flag);
if (!use_icount)
return;
@@ -26,6 +34,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);
@@ -607,6 +607,10 @@ extern uint8_t code_gen_prologue[];
* 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
@@ -623,6 +627,7 @@ extern uint8_t code_gen_prologue[];
#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) \