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 <pbonz...@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