aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel/tcg/cpu-exec.c7
-rw-r--r--include/hw/core/tcg-cpu-ops.h15
-rw-r--r--target/i386/tcg/helper-tcg.h2
-rw-r--r--target/i386/tcg/sysemu/seg_helper.c3
4 files changed, 21 insertions, 6 deletions
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 2972f75b96..6711b58e0b 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -682,11 +682,14 @@ static inline bool cpu_handle_halt(CPUState *cpu)
#ifndef CONFIG_USER_ONLY
if (cpu->halted) {
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
+ bool leave_halt;
if (tcg_ops->cpu_exec_halt) {
- tcg_ops->cpu_exec_halt(cpu);
+ leave_halt = tcg_ops->cpu_exec_halt(cpu);
+ } else {
+ leave_halt = cpu_has_work(cpu);
}
- if (!cpu_has_work(cpu)) {
+ if (!leave_halt) {
return true;
}
diff --git a/include/hw/core/tcg-cpu-ops.h b/include/hw/core/tcg-cpu-ops.h
index 9387d38748..099de3375e 100644
--- a/include/hw/core/tcg-cpu-ops.h
+++ b/include/hw/core/tcg-cpu-ops.h
@@ -115,8 +115,19 @@ struct TCGCPUOps {
void (*do_interrupt)(CPUState *cpu);
/** @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec */
bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request);
- /** @cpu_exec_halt: Callback for handling halt in cpu_exec */
- void (*cpu_exec_halt)(CPUState *cpu);
+ /**
+ * @cpu_exec_halt: Callback for handling halt in cpu_exec.
+ *
+ * The target CPU should do any special processing here that it needs
+ * to do when the CPU is in the halted state.
+ *
+ * Return true to indicate that the CPU should now leave halt, false
+ * if it should remain in the halted state.
+ *
+ * If this method is not provided, the default is to do nothing, and
+ * to leave halt if cpu_has_work() returns true.
+ */
+ bool (*cpu_exec_halt)(CPUState *cpu);
/**
* @tlb_fill: Handle a softmmu tlb miss
*
diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h
index effc2c1c98..85957943bf 100644
--- a/target/i386/tcg/helper-tcg.h
+++ b/target/i386/tcg/helper-tcg.h
@@ -39,7 +39,7 @@ QEMU_BUILD_BUG_ON(TCG_PHYS_ADDR_BITS > TARGET_PHYS_ADDR_SPACE_BITS);
*/
void x86_cpu_do_interrupt(CPUState *cpu);
#ifndef CONFIG_USER_ONLY
-void x86_cpu_exec_halt(CPUState *cpu);
+bool x86_cpu_exec_halt(CPUState *cpu);
bool x86_need_replay_interrupt(int interrupt_request);
bool x86_cpu_exec_interrupt(CPUState *cpu, int int_req);
#endif
diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c
index 2db8083748..9ba94deb3a 100644
--- a/target/i386/tcg/sysemu/seg_helper.c
+++ b/target/i386/tcg/sysemu/seg_helper.c
@@ -128,7 +128,7 @@ void x86_cpu_do_interrupt(CPUState *cs)
}
}
-void x86_cpu_exec_halt(CPUState *cpu)
+bool x86_cpu_exec_halt(CPUState *cpu)
{
if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
X86CPU *x86_cpu = X86_CPU(cpu);
@@ -138,6 +138,7 @@ void x86_cpu_exec_halt(CPUState *cpu)
cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
bql_unlock();
}
+ return cpu_has_work(cpu);
}
bool x86_need_replay_interrupt(int interrupt_request)