aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpu-exec.c32
-rw-r--r--exec.c2
-rw-r--r--include/exec/gen-icount.h12
-rw-r--r--include/qom/cpu.h3
-rw-r--r--tcg/tcg.h5
-rw-r--r--translate-all.c4
6 files changed, 51 insertions, 7 deletions
diff --git a/cpu-exec.c b/cpu-exec.c
index 4b35315c83..37ae2857b0 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -52,7 +52,8 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc)
#endif
/* Execute a TB, and fix up the CPU state afterwards if necessary */
-static inline tcg_target_ulong cpu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
+static inline tcg_target_ulong cpu_tb_exec(CPUArchState *env, CPUState *cpu,
+ uint8_t *tb_ptr)
{
tcg_target_ulong next_tb = tcg_qemu_tb_exec(env, tb_ptr);
if ((next_tb & TB_EXIT_MASK) > TB_EXIT_IDX1) {
@@ -63,6 +64,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.
+ */
+ cpu->tcg_exit_req = 0;
+ }
return next_tb;
}
@@ -83,7 +90,7 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
max_cycles);
cpu->current_tb = tb;
/* execute the generated code */
- cpu_tb_exec(env, tb->tc_ptr);
+ cpu_tb_exec(env, cpu, tb->tc_ptr);
cpu->current_tb = NULL;
tb_phys_invalidate(tb, -1);
tb_free(tb);
@@ -606,8 +613,21 @@ int cpu_exec(CPUArchState *env)
if (likely(!cpu->exit_request)) {
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) {
+ next_tb = cpu_tb_exec(env, cpu, tc_ptr);
+ 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);
@@ -631,6 +651,10 @@ int cpu_exec(CPUArchState *env)
next_tb = 0;
cpu_loop_exit(env);
}
+ break;
+ }
+ default:
+ break;
}
}
cpu->current_tb = NULL;
diff --git a/exec.c b/exec.c
index a41bcb8694..46a283071a 100644
--- a/exec.c
+++ b/exec.c
@@ -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 c858a738c0..384153b4c4 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 ee1a7c878a..ab2657c558 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;
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 2ebde07fb7..90375c0120 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -695,6 +695,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
@@ -711,6 +715,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 b50fb89528..9741d96395 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;
}
/*