diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2024-05-25 10:47:31 +0200 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2024-06-08 10:33:38 +0200 |
commit | 6dd7d8c6490b73dcc33dfb1fe76c081e7e2eb820 (patch) | |
tree | e5649c25c1304f50734bd91ef5e937bc986b7201 | |
parent | 3718523d011e898d414f09a4ed43cf13d76de0b4 (diff) | |
download | qemu-6dd7d8c6490b73dcc33dfb1fe76c081e7e2eb820.zip qemu-6dd7d8c6490b73dcc33dfb1fe76c081e7e2eb820.tar.gz qemu-6dd7d8c6490b73dcc33dfb1fe76c081e7e2eb820.tar.bz2 |
target/i386: fix TF/RF handling for HLT
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>
-rw-r--r-- | target/i386/tcg/sysemu/misc_helper.c | 2 | ||||
-rw-r--r-- | 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 093cc2d..7fa0c5a 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 9ba94de..05174a7 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) |