Commit 480681f916 for qemu.org
commit 480681f91608454ee1bdf925231335e4c7e3435c
Author: Mohamed Mediouni <mohamed@unpredictable.fr>
Date: Wed Apr 22 23:42:10 2026 +0200
whpx: i386: add HV_X64_MSR_GUEST_IDLE when !kernel-irqchip
Add support for an oddball HV_X64_MSR_GUEST_IDLE not-quite-an-HLT
that wakes the vCPU even if EFLAGS.IF is set.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Link: https://lore.kernel.org/r/20260422214225.2242-23-mohamed@unpredictable.fr
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index bc8d673c31..593a707e21 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -52,6 +52,7 @@
/* for kernel-irqchip=off */
#define HV_X64_MSR_APIC_FREQUENCY 0x40000023
#define HV_X64_MSR_VP_ASSIST_PAGE 0x40000073
+#define HV_X64_MSR_GUEST_IDLE 0x400000f0
static bool is_modern_os = true;
@@ -1648,6 +1649,15 @@ static int whpx_handle_halt(CPUState *cpu)
return ret;
}
+static int whpx_handle_hyperv_guestidle(CPUState *cpu)
+{
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+
+ env->hflags2 |= HF2_HYPERV_HLT_MASK;
+ return whpx_handle_halt(cpu);
+}
+
static void whpx_vcpu_kick_out_of_hlt(CPUState *cpu)
{
WHV_REGISTER_VALUE reg;
@@ -1851,9 +1861,10 @@ static void whpx_vcpu_process_async_events(CPUState *cpu)
}
if ((cpu_test_interrupt(cpu, CPU_INTERRUPT_HARD) &&
- (env->eflags & IF_MASK)) ||
+ ((env->eflags & IF_MASK) || (env->hflags2 & HF2_HYPERV_HLT_MASK))) ||
cpu_test_interrupt(cpu, CPU_INTERRUPT_NMI)) {
cpu->halted = false;
+ env->hflags2 &= ~HF2_HYPERV_HLT_MASK;
}
if (cpu_test_interrupt(cpu, CPU_INTERRUPT_SIPI)) {
@@ -2128,6 +2139,20 @@ int whpx_vcpu_run(CPUState *cpu)
}
}
+ /*
+ * Windows and Linux both use this MSR.
+ * Windows 11 25H2 uses it even when not advertised.
+ */
+ if (vcpu->exit_ctx.MsrAccess.MsrNumber == HV_X64_MSR_GUEST_IDLE
+ && !vcpu->exit_ctx.MsrAccess.AccessInfo.IsWrite
+ && !whpx_irqchip_in_kernel()
+ && whpx->hyperv_enlightenments_enabled) {
+ is_known_msr = 1;
+ whpx_bump_rip(cpu, &vcpu->exit_ctx);
+ ret = whpx_handle_hyperv_guestidle(cpu);
+ break;
+ }
+
/*
* Linux tries to use it anyway even when not exposed.
* Ignore the write as the VP assist page is not used.