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>
Mohamed Mediouni committed
Apr 22, 2026 at 23:42 UTC
480681f91608454ee1bdf925231335e4c7e3435c
1 file changed
+26
-1
target/i386/whpx/whpx-all.c
+26
-1
@@ -52,6 +52,7 @@
52
/* for kernel-irqchip=off */
53
#define HV_X64_MSR_APIC_FREQUENCY 0x40000023
54
#define HV_X64_MSR_VP_ASSIST_PAGE 0x40000073
55
+#define HV_X64_MSR_GUEST_IDLE 0x400000f0
56
57
static bool is_modern_os = true;
58
@@ -1648,6 +1649,15 @@ static int whpx_handle_halt(CPUState *cpu)
1649
return ret;
1650
}
1651
1652
+static int whpx_handle_hyperv_guestidle(CPUState *cpu)
1653
+{
1654
+ X86CPU *x86_cpu = X86_CPU(cpu);
1655
+ CPUX86State *env = &x86_cpu->env;
1656
+
1657
+ env->hflags2 |= HF2_HYPERV_HLT_MASK;
1658
+ return whpx_handle_halt(cpu);
1659
+}
1660
+
1661
static void whpx_vcpu_kick_out_of_hlt(CPUState *cpu)
1662
{
1663
WHV_REGISTER_VALUE reg;
@@ -1851,9 +1861,10 @@ static void whpx_vcpu_process_async_events(CPUState *cpu)
1861
}
1862
1863
if ((cpu_test_interrupt(cpu, CPU_INTERRUPT_HARD) &&
1854
- (env->eflags & IF_MASK)) ||
1864
+ ((env->eflags & IF_MASK) || (env->hflags2 & HF2_HYPERV_HLT_MASK))) ||
1865
cpu_test_interrupt(cpu, CPU_INTERRUPT_NMI)) {
1866
cpu->halted = false;
1867
+ env->hflags2 &= ~HF2_HYPERV_HLT_MASK;
1868
}
1869
1870
if (cpu_test_interrupt(cpu, CPU_INTERRUPT_SIPI)) {
@@ -2128,6 +2139,20 @@ int whpx_vcpu_run(CPUState *cpu)
2139
}
2140
}
2141
2142
+ /*
2143
+ * Windows and Linux both use this MSR.
2144
+ * Windows 11 25H2 uses it even when not advertised.
2145
+ */
2146
+ if (vcpu->exit_ctx.MsrAccess.MsrNumber == HV_X64_MSR_GUEST_IDLE
2147
+ && !vcpu->exit_ctx.MsrAccess.AccessInfo.IsWrite
2148
+ && !whpx_irqchip_in_kernel()
2149
+ && whpx->hyperv_enlightenments_enabled) {
2150
+ is_known_msr = 1;
2151
+ whpx_bump_rip(cpu, &vcpu->exit_ctx);
2152
+ ret = whpx_handle_hyperv_guestidle(cpu);
2153
+ break;
2154
+ }
2155
+
2156
/*
2157
* Linux tries to use it anyway even when not exposed.
2158
* Ignore the write as the VP assist page is not used.