@samitouri / QOSamiQemu / commits / 8e7b708bdd

target: i386: HLT type that ignores EFLAGS.IF

The TLFS says: > A partition which possesses the AccessGuestIdleMsr privilege may trigger > entry into the virtual processor idle sleep state through a read to the > hypervisor-defined MSR HV_X64_MSR_GUEST_IDLE. The virtual processor will > be woken when an interrupt arrives, regardless of whether the interrupt > is enabled on the virtual processor or not. Meanwhile, Windows 24H2+ calls this MSR anyway without the privilege being set. Add the infrastructure to support it on the generic QEMU side. Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr> Link: https://lore.kernel.org/r/20260422214225.2242-22-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Mohamed Mediouni committed Apr 22, 2026 at 23:42 UTC 8e7b708bdd502de998a41d2cc4b46fc3b1b6da0d
4 files changed +19 -9
target/i386/cpu.c
+4 -6
@@ -10617,14 +10617,12 @@ int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request)
10617 (((env->hflags2 & HF2_VINTR_MASK) &&
10618 (env->hflags2 & HF2_HIF_MASK)) ||
10619 (!(env->hflags2 & HF2_VINTR_MASK) &&
10620 - (env->eflags & IF_MASK &&
10621 - !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
10620 + x86_cpu_interrupts_enabled(env)))) {
10621 return CPU_INTERRUPT_HARD;
10622 } else if (env->hflags2 & HF2_VGIF_MASK) {
10624 - if((interrupt_request & CPU_INTERRUPT_VIRQ) &&
10625 - (env->eflags & IF_MASK) &&
10626 - !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
10627 - return CPU_INTERRUPT_VIRQ;
10623 + if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
10624 + x86_cpu_interrupts_enabled(env)) {
10625 + return CPU_INTERRUPT_VIRQ;
10626 }
10627 }
10628 }
target/i386/cpu.h
+9
@@ -225,6 +225,7 @@ typedef enum X86Seg {
225 #define HF2_NPT_SHIFT 6 /* Nested Paging enabled */
226 #define HF2_IGNNE_SHIFT 7 /* Ignore CR0.NE=0 */
227 #define HF2_VGIF_SHIFT 8 /* Can take VIRQ*/
228 +#define HF2_HYPERV_HLT_SHIFT 9 /* Hyper-V HV_X64_MSR_GUEST_IDLE */
229
230 #define HF2_GIF_MASK (1 << HF2_GIF_SHIFT)
231 #define HF2_HIF_MASK (1 << HF2_HIF_SHIFT)
@@ -235,6 +236,7 @@ typedef enum X86Seg {
236 #define HF2_NPT_MASK (1 << HF2_NPT_SHIFT)
237 #define HF2_IGNNE_MASK (1 << HF2_IGNNE_SHIFT)
238 #define HF2_VGIF_MASK (1 << HF2_VGIF_SHIFT)
239 +#define HF2_HYPERV_HLT_MASK (1 << HF2_HYPERV_HLT_SHIFT)
240
241 #define CR0_PE_SHIFT 0
242 #define CR0_MP_SHIFT 1
@@ -3085,6 +3087,13 @@ static inline bool ctl_has_irq(CPUX86State *env)
3087 return (env->int_ctl & V_IRQ_MASK) && (int_prio >= tpr);
3088 }
3089
3090 +static inline bool x86_cpu_interrupts_enabled(CPUX86State *env)
3091 +{
3092 + return ((env->eflags & IF_MASK) &&
3093 + !(env->hflags & HF_INHIBIT_IRQ_MASK)) ||
3094 + (env->hflags2 & HF2_HYPERV_HLT_MASK);
3095 +}
3096 +
3097 #if defined(TARGET_X86_64) && \
3098 defined(CONFIG_USER_ONLY) && \
3099 defined(CONFIG_LINUX)
target/i386/hvf/x86hvf.c
+2 -2
@@ -405,9 +405,9 @@ bool hvf_inject_interrupts(CPUState *cs)
405 }
406 }
407
408 - if (!(env->hflags & HF_INHIBIT_IRQ_MASK) &&
408 + if (x86_cpu_interrupts_enabled(env) &&
409 cpu_test_interrupt(cs, CPU_INTERRUPT_HARD) &&
410 - (env->eflags & IF_MASK) && !(info & VMCS_INTR_VALID)) {
410 + !(info & VMCS_INTR_VALID)) {
411 int line = cpu_get_pic_interrupt(env);
412 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
413 if (line >= 0) {
target/i386/whpx/whpx-all.c
+4 -1
@@ -1630,11 +1630,14 @@ static vaddr whpx_vcpu_get_pc(CPUState *cpu, bool exit_context_valid)
1630
1631 static int whpx_handle_halt(CPUState *cpu)
1632 {
1633 + X86CPU *x86_cpu = X86_CPU(cpu);
1634 + CPUX86State *env = &x86_cpu->env;
1635 +
1636 int ret = 0;
1637
1638 bql_lock();
1639 if (!(cpu_test_interrupt(cpu, CPU_INTERRUPT_HARD) &&
1637 - (cpu_env(cpu)->eflags & IF_MASK)) &&
1640 + x86_cpu_interrupts_enabled(env)) &&
1641 !cpu_test_interrupt(cpu, CPU_INTERRUPT_NMI)) {
1642 cpu->exception_index = EXCP_HLT;
1643 cpu->halted = true;