diff options
-rw-r--r-- | accel/tcg/translate-all.c | 24 | ||||
-rw-r--r-- | include/exec/exec-all.h | 2 | ||||
-rw-r--r-- | include/hw/core/tcg-cpu-ops.h | 11 |
3 files changed, 34 insertions, 3 deletions
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 433fa247f4..4d8783efc7 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -256,7 +256,6 @@ int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, { target_ulong data[TARGET_INSN_START_WORDS]; uintptr_t host_pc = (uintptr_t)tb->tc.ptr; - CPUArchState *env = cpu->env_ptr; const uint8_t *p = tb->tc.ptr + tb->tc.size; int i, j, num_insns = tb->icount; #ifdef CONFIG_PROFILER @@ -295,7 +294,20 @@ int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, and shift if to the number of actually executed instructions */ cpu_neg(cpu)->icount_decr.u16.low += num_insns - i; } - restore_state_to_opc(env, tb, data); + + { + const struct TCGCPUOps *ops = cpu->cc->tcg_ops; + __typeof(ops->restore_state_to_opc) restore = ops->restore_state_to_opc; + if (restore) { + uint64_t d64[TARGET_INSN_START_WORDS]; + for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { + d64[i] = data[i]; + } + restore(cpu, tb, d64); + } else { + restore_state_to_opc(cpu->env_ptr, tb, data); + } + } #ifdef CONFIG_PROFILER qatomic_set(&prof->restore_time, @@ -308,6 +320,14 @@ int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit) { /* + * The pc update associated with restore without exit will + * break the relative pc adjustments performed by TARGET_TB_PCREL. + */ + if (TARGET_TB_PCREL) { + assert(will_exit); + } + + /* * The host_pc has to be in the rx region of the code buffer. * If it is not we will not be able to resolve it here. * The two cases where host_pc will not be correct are: diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 5ae484e34d..3b5e84240b 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -40,7 +40,7 @@ typedef ram_addr_t tb_page_addr_t; #endif void restore_state_to_opc(CPUArchState *env, TranslationBlock *tb, - target_ulong *data); + target_ulong *data) __attribute__((weak)); /** * cpu_restore_state: diff --git a/include/hw/core/tcg-cpu-ops.h b/include/hw/core/tcg-cpu-ops.h index 78c6c6635d..20e3c0ffbb 100644 --- a/include/hw/core/tcg-cpu-ops.h +++ b/include/hw/core/tcg-cpu-ops.h @@ -31,6 +31,17 @@ struct TCGCPUOps { * function to restore all the state, and register it here. */ void (*synchronize_from_tb)(CPUState *cpu, const TranslationBlock *tb); + /** + * @restore_state_to_opc: Synchronize state from INDEX_op_start_insn + * + * This is called when we unwind state in the middle of a TB, + * usually before raising an exception. Set all part of the CPU + * state which are tracked insn-by-insn in the target-specific + * arguments to start_insn, passed as @data. + */ + void (*restore_state_to_opc)(CPUState *cpu, const TranslationBlock *tb, + const uint64_t *data); + /** @cpu_exec_enter: Callback for cpu_exec preparation */ void (*cpu_exec_enter)(CPUState *cpu); /** @cpu_exec_exit: Callback for cpu_exec cleanup */ |