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


Reply via email to