Commit 8e7b708bdd for qemu.org

commit 8e7b708bdd502de998a41d2cc4b46fc3b1b6da0d
Author: Mohamed Mediouni <mohamed@unpredictable.fr>
Date:   Wed Apr 22 23:42:09 2026 +0200

    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>

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 7ea80f07c7..efe7ba014d 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -10617,14 +10617,12 @@ int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request)
                    (((env->hflags2 & HF2_VINTR_MASK) &&
                      (env->hflags2 & HF2_HIF_MASK)) ||
                     (!(env->hflags2 & HF2_VINTR_MASK) &&
-                     (env->eflags & IF_MASK &&
-                      !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
+                     x86_cpu_interrupts_enabled(env)))) {
             return CPU_INTERRUPT_HARD;
         } else if (env->hflags2 & HF2_VGIF_MASK) {
-            if((interrupt_request & CPU_INTERRUPT_VIRQ) &&
-                   (env->eflags & IF_MASK) &&
-                   !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
-                        return CPU_INTERRUPT_VIRQ;
+            if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
+                x86_cpu_interrupts_enabled(env)) {
+                return CPU_INTERRUPT_VIRQ;
             }
         }
     }
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 6401028e70..c14237967b 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -225,6 +225,7 @@ typedef enum X86Seg {
 #define HF2_NPT_SHIFT            6 /* Nested Paging enabled */
 #define HF2_IGNNE_SHIFT          7 /* Ignore CR0.NE=0 */
 #define HF2_VGIF_SHIFT           8 /* Can take VIRQ*/
+#define HF2_HYPERV_HLT_SHIFT     9 /* Hyper-V HV_X64_MSR_GUEST_IDLE */

 #define HF2_GIF_MASK            (1 << HF2_GIF_SHIFT)
 #define HF2_HIF_MASK            (1 << HF2_HIF_SHIFT)
@@ -235,6 +236,7 @@ typedef enum X86Seg {
 #define HF2_NPT_MASK            (1 << HF2_NPT_SHIFT)
 #define HF2_IGNNE_MASK          (1 << HF2_IGNNE_SHIFT)
 #define HF2_VGIF_MASK           (1 << HF2_VGIF_SHIFT)
+#define HF2_HYPERV_HLT_MASK     (1 << HF2_HYPERV_HLT_SHIFT)

 #define CR0_PE_SHIFT 0
 #define CR0_MP_SHIFT 1
@@ -3085,6 +3087,13 @@ static inline bool ctl_has_irq(CPUX86State *env)
     return (env->int_ctl & V_IRQ_MASK) && (int_prio >= tpr);
 }

+static inline bool x86_cpu_interrupts_enabled(CPUX86State *env)
+{
+    return ((env->eflags & IF_MASK) &&
+            !(env->hflags & HF_INHIBIT_IRQ_MASK)) ||
+           (env->hflags2 & HF2_HYPERV_HLT_MASK);
+}
+
 #if defined(TARGET_X86_64) && \
     defined(CONFIG_USER_ONLY) && \
     defined(CONFIG_LINUX)
diff --git a/target/i386/hvf/x86hvf.c b/target/i386/hvf/x86hvf.c
index bb480311b0..16b810f3c2 100644
--- a/target/i386/hvf/x86hvf.c
+++ b/target/i386/hvf/x86hvf.c
@@ -405,9 +405,9 @@ bool hvf_inject_interrupts(CPUState *cs)
         }
     }

-    if (!(env->hflags & HF_INHIBIT_IRQ_MASK) &&
+    if (x86_cpu_interrupts_enabled(env) &&
         cpu_test_interrupt(cs, CPU_INTERRUPT_HARD) &&
-        (env->eflags & IF_MASK) && !(info & VMCS_INTR_VALID)) {
+        !(info & VMCS_INTR_VALID)) {
         int line = cpu_get_pic_interrupt(env);
         cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
         if (line >= 0) {
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 11c9d8729f..bc8d673c31 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -1630,11 +1630,14 @@ static vaddr whpx_vcpu_get_pc(CPUState *cpu, bool exit_context_valid)

 static int whpx_handle_halt(CPUState *cpu)
 {
+    X86CPU *x86_cpu = X86_CPU(cpu);
+    CPUX86State *env = &x86_cpu->env;
+
     int ret = 0;

     bql_lock();
     if (!(cpu_test_interrupt(cpu, CPU_INTERRUPT_HARD) &&
-          (cpu_env(cpu)->eflags & IF_MASK)) &&
+          x86_cpu_interrupts_enabled(env)) &&
         !cpu_test_interrupt(cpu, CPU_INTERRUPT_NMI)) {
         cpu->exception_index = EXCP_HLT;
         cpu->halted = true;