HLT uses DISAS_NORETURN because the corresponding helper calls
cpu_loop_exit(). However, while gen_eob() clears HF_RF_MASK and
synthesizes a #DB exception if single-step is active, none of this is
done by HLT. Note that the single-step trap is generated after the halt
is finished.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/tcg/sysemu/misc_helper.c | 2 +-
target/i386/tcg/sysemu/seg_helper.c | 17 ++++++++++++++---
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c
index 093cc2d0f90..7fa0c5a06de 100644
--- a/target/i386/tcg/sysemu/misc_helper.c
+++ b/target/i386/tcg/sysemu/misc_helper.c
@@ -520,7 +520,7 @@ G_NORETURN void helper_hlt(CPUX86State *env)
{
CPUState *cs = env_cpu(env);
- env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
+ do_end_instruction(env);
cs->halted = 1;
cs->exception_index = EXCP_HLT;
cpu_loop_exit(cs);
diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c
index 9ba94deb3aa..05174a79e73 100644
--- a/target/i386/tcg/sysemu/seg_helper.c
+++ b/target/i386/tcg/sysemu/seg_helper.c
@@ -130,15 +130,26 @@ void x86_cpu_do_interrupt(CPUState *cs)
bool x86_cpu_exec_halt(CPUState *cpu)
{
- if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
- X86CPU *x86_cpu = X86_CPU(cpu);
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
bql_lock();
apic_poll_irq(x86_cpu->apic_state);
cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
bql_unlock();
}
- return cpu_has_work(cpu);
+
+ if (!cpu_has_work(cpu)) {
+ return false;
+ }
+
+ /* Complete HLT instruction. */
+ if (env->eflags & TF_MASK) {
+ env->dr[6] |= DR6_BS;
+ do_interrupt_all(x86_cpu, EXCP01_DB, 0, 0, env->eip, 0);
+ }
+ return true;
}
bool x86_need_replay_interrupt(int interrupt_request)
--
2.45.1