We were generating code during tb_invalidate_phys_page_range and check_watchpoint, and (seemingly) discarding the TB, assuming that it would magically be picked up during the next iteration through the cpu_exec loop.
Instead, set a flag in CPUState so that we set cflags to properly request a TB with a single guest insn so that there is no more magic. Signed-off-by: Richard Henderson <richard.hender...@linaro.org> --- include/qom/cpu.h | 1 + accel/tcg/cpu-exec.c | 19 +++++++++++++++---- accel/tcg/translate-all.c | 18 ++++-------------- exec.c | 6 +----- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/include/qom/cpu.h b/include/qom/cpu.h index df0ba86202..1fb165a43c 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -344,6 +344,7 @@ struct CPUState { bool unplug; bool crash_occurred; bool exit_request; + bool step_next_tb; /* updates protected by BQL */ uint32_t interrupt_request; int singlestep_enabled; diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 99f1d519c5..df410a8d6e 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -367,13 +367,12 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, static inline TranslationBlock *tb_find(CPUState *cpu, TranslationBlock *last_tb, - int tb_exit) + int tb_exit, uint32_t cf_mask) { TranslationBlock *tb; target_ulong cs_base, pc; uint32_t flags; bool acquired_tb_lock = false; - uint32_t cf_mask = curr_cflags(); tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags, cf_mask); if (tb == NULL) { @@ -501,7 +500,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) } else if (replay_has_exception() && cpu->icount_decr.u16.low + cpu->icount_extra == 0) { /* try to cause an exception pending in the log */ - cpu_exec_nocache(cpu, 1, tb_find(cpu, NULL, 0), true); + cpu_exec_nocache(cpu, 1, tb_find(cpu, NULL, 0, curr_cflags()), true); *ret = -1; return true; #endif @@ -697,7 +696,19 @@ int cpu_exec(CPUState *cpu) int tb_exit = 0; while (!cpu_handle_interrupt(cpu, &last_tb)) { - TranslationBlock *tb = tb_find(cpu, last_tb, tb_exit); + uint32_t cf_mask = curr_cflags(); + TranslationBlock *tb; + + /* For precise smc, we generate a block containing just the + instruction modifying the memory, ensuring that it cannot + modify itself. We also need to single-step past a + stop-after-access watchpoint. */ + if (cpu->step_next_tb) { + cf_mask |= 1; + cpu->step_next_tb = false; + } + + tb = tb_find(cpu, last_tb, tb_exit, cf_mask); cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit); /* Try to align the host and virtual clocks if the guest is in advance */ diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 1271944ae8..a7415c8661 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -1463,14 +1463,12 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, int is_cpu_write_access) { TranslationBlock *tb, *tb_next; -#if defined(TARGET_HAS_PRECISE_SMC) - CPUState *cpu = current_cpu; - CPUArchState *env = NULL; -#endif tb_page_addr_t tb_start, tb_end; PageDesc *p; int n; #ifdef TARGET_HAS_PRECISE_SMC + CPUState *cpu = current_cpu; + CPUArchState *env = NULL; int current_tb_not_found = is_cpu_write_access; TranslationBlock *current_tb = NULL; int current_tb_modified = 0; @@ -1547,11 +1545,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, #endif #ifdef TARGET_HAS_PRECISE_SMC if (current_tb_modified) { - /* we generate a block containing just the instruction - modifying the memory. It will ensure that it cannot modify - itself */ - tb_gen_code(cpu, current_pc, current_cs_base, current_flags, - 1 | curr_cflags()); + cpu->step_next_tb = true; cpu_loop_exit_noexc(cpu); } #endif @@ -1666,11 +1660,7 @@ static bool tb_invalidate_phys_page(tb_page_addr_t addr, uintptr_t pc) p->first_tb = NULL; #ifdef TARGET_HAS_PRECISE_SMC if (current_tb_modified) { - /* we generate a block containing just the instruction - modifying the memory. It will ensure that it cannot modify - itself */ - tb_gen_code(cpu, current_pc, current_cs_base, current_flags, - 1 | curr_cflags()); + cpu->step_next_tb = true; /* tb_lock will be reset after cpu_loop_exit_noexc longjmps * back into the cpu_exec loop. */ return true; diff --git a/exec.c b/exec.c index 5d43d9541f..a9737ba5e9 100644 --- a/exec.c +++ b/exec.c @@ -2390,11 +2390,8 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags) { CPUState *cpu = current_cpu; CPUClass *cc = CPU_GET_CLASS(cpu); - CPUArchState *env = cpu->env_ptr; - target_ulong pc, cs_base; target_ulong vaddr; CPUWatchpoint *wp; - uint32_t cpu_flags; assert(tcg_enabled()); if (cpu->watchpoint_hit) { @@ -2434,8 +2431,7 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags) cpu->exception_index = EXCP_DEBUG; cpu_loop_exit(cpu); } else { - cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags); - tb_gen_code(cpu, pc, cs_base, cpu_flags, 1 | curr_cflags()); + cpu->step_next_tb = true; cpu_loop_exit_noexc(cpu); } } -- 2.13.6