Decompose the halt-to-execution transition into distinct steps: - process_async_events() called first to handle target-specific asynchronous events,
- transition_halt_to_exec() called after a halted CPU has detected pending work and is about to resume execution. Either callback is optional; targets that don't implement them fall back to the existing cpu_exec_halt() callback for backward compatibility. cpu_has_work_after_processing_async_events() orchestrates these callbacks: process async events, check for work, transition from halt, and clear the halted flag. Inspired-by: Paolo Bonzini <[email protected]> Signed-off-by: Philippe Mathieu-Daudé <[email protected]> --- include/accel/tcg/cpu-ops.h | 17 ++++++++++++++++- accel/tcg/cpu-exec.c | 21 +++++++++++++++++---- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index 3ff6e6810e0..16c19da997d 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -169,6 +169,20 @@ struct TCGCPUOps { */ vaddr (*untagged_addr)(CPUState *cs, vaddr addr); #else + /** + * @process_async_events: Process target-specific asynchronous CPU events. + * + * Called at the start of cpu_exec() to handle target-specific event + * processing before instruction execution begins. + */ + void (*process_async_events)(CPUState *cpu); + /** + * @transition_halt_to_exec: Prepare CPU state when exiting halt. + * + * Called after a halted CPU has detected pending work and is about to + * resume execution. Target-specific cleanup and state synchronization. + */ + void (*transition_halt_to_exec)(CPUState *cpu); /** @do_interrupt: Callback for interrupt handling. */ void (*do_interrupt)(CPUState *cpu); /** @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec */ @@ -185,7 +199,8 @@ struct TCGCPUOps { * if it should remain in the halted state. (This should generally * be the same value that cpu_has_work() would return.) * - * This method must be provided. If the target does not need to + * Either %transition_halt_to_exec() or this method must be provided. + * If the target does not need to * do anything special for halt, the same function used for its * SysemuCPUOps::has_work method can be used here, as they have the * same function signature. diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 1a942664895..54561ed31c1 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -48,6 +48,7 @@ #include "internal-common.h" #if !defined(CONFIG_USER_ONLY) #include "accel/tcg/iommu.h" +#include "hw/core/sysemu-cpu-ops.h" #endif /* -icount align implementation. */ @@ -657,10 +658,22 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, static bool cpu_has_work_after_processing_async_events(CPUState *cpu) { const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; - bool leave_halt = tcg_ops->cpu_exec_halt(cpu); - if (!leave_halt) { - return false; + if (tcg_ops->transition_halt_to_exec) { + assert(!tcg_ops->cpu_exec_halt); + if (tcg_ops->process_async_events) { + tcg_ops->process_async_events(cpu); + } + if (!cpu_has_work(cpu)) { + return false; + } + tcg_ops->transition_halt_to_exec(cpu); + } else { + assert(!tcg_ops->process_async_events); + assert(cpu->cc->sysemu_ops->has_work == tcg_ops->cpu_exec_halt); + if (!tcg_ops->cpu_exec_halt(cpu)) { + return false; + } } cpu->halted = 0; /* allow execution */ @@ -1059,7 +1072,7 @@ bool tcg_exec_realizefn(CPUState *cpu, Error **errp) /* Check mandatory TCGCPUOps handlers */ const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; #ifndef CONFIG_USER_ONLY - assert(tcg_ops->cpu_exec_halt); + assert(tcg_ops->cpu_exec_halt || tcg_ops->transition_halt_to_exec); assert(tcg_ops->cpu_exec_interrupt); assert(tcg_ops->cpu_exec_reset); assert(tcg_ops->pointer_wrap); -- 2.53.0
