Otherwise, interrupts processed through the cancel vCPU and inject path will not cause the vCPU to go out of its halt state.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/whpx/whpx-all.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index bd3a1c49c6..650d65c61e 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -1475,6 +1475,16 @@ static void whpx_vcpu_post_run(CPUState *cpu)
!vcpu->exit_ctx.VpContext.ExecutionState.InterruptShadow;
}
+static void whpx_vcpu_kick_out_of_hlt(CPUState *cpu)
+{
+ WHV_REGISTER_VALUE reg;
+ whpx_get_reg(cpu, WHvRegisterInternalActivityState, ®);
+ if (reg.InternalActivity.HaltSuspend) {
+ reg.InternalActivity.HaltSuspend = 0;
+ whpx_set_reg(cpu, WHvRegisterInternalActivityState, reg);
+ }
+}
+
static void whpx_vcpu_process_async_events(CPUState *cpu)
{
X86CPU *x86_cpu = X86_CPU(cpu);
@@ -1760,6 +1770,25 @@ int whpx_vcpu_run(CPUState *cpu)
cpu->exception_index = EXCP_INTERRUPT;
ret = 1;
}
+ /*
+ * When the Hyper-V APIC is enabled, to get out of HLT we
+ * either have to request an interrupt or manually get it away
+ * from HLT.
+ *
+ * We also manually do inject some interrupts via WHvRegisterPendingEvent
+ * instead of WHVRequestInterrupt, which does not reset the HLT state.
+ *
+ * However, even with this done, if the guest does an HLT without
+ * interrupts enabled (which the test_sti_inhibit KVM unit test does)
+ * then the guest will stay in HLT forever.
+ *
+ * Keep it this way for now, with perhaps adding a heartbeat later
+ * so that we get the CPU time savings from having Hyper-V handle HLT
+ * instead of going away from it as soon as possible.
+ */
+ if (whpx_irqchip_in_kernel()) {
+ whpx_vcpu_kick_out_of_hlt(cpu);
+ }
break;
case WHvRunVpExitReasonX64MsrAccess: {
WHV_REGISTER_VALUE reg_values[3] = {0};
--
2.50.1 (Apple Git-155)
Am 26. Februar 2026 18:19:29 UTC schrieb Mohamed Mediouni <mohamed@unpredictable.fr>:
>Otherwise, interrupts processed through the cancel vCPU and inject path will not cause the vCPU to go out of its halt state.
Yay, thanks for tackling this!
>
>Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
It probably resolves https://gitlab.com/qemu-project/qemu/-/issues/346 , though that would need to be confirmed by testing.
Best regards,
Bernhard
>---
> target/i386/whpx/whpx-all.c | 29 +++++++++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
>
>diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
>index bd3a1c49c6..650d65c61e 100644
>--- a/target/i386/whpx/whpx-all.c
>+++ b/target/i386/whpx/whpx-all.c
>@@ -1475,6 +1475,16 @@ static void whpx_vcpu_post_run(CPUState *cpu)
> !vcpu->exit_ctx.VpContext.ExecutionState.InterruptShadow;
> }
>
>+static void whpx_vcpu_kick_out_of_hlt(CPUState *cpu)
>+{
>+ WHV_REGISTER_VALUE reg;
>+ whpx_get_reg(cpu, WHvRegisterInternalActivityState, ®);
>+ if (reg.InternalActivity.HaltSuspend) {
>+ reg.InternalActivity.HaltSuspend = 0;
>+ whpx_set_reg(cpu, WHvRegisterInternalActivityState, reg);
>+ }
>+}
>+
> static void whpx_vcpu_process_async_events(CPUState *cpu)
> {
> X86CPU *x86_cpu = X86_CPU(cpu);
>@@ -1760,6 +1770,25 @@ int whpx_vcpu_run(CPUState *cpu)
> cpu->exception_index = EXCP_INTERRUPT;
> ret = 1;
> }
>+ /*
>+ * When the Hyper-V APIC is enabled, to get out of HLT we
>+ * either have to request an interrupt or manually get it away
>+ * from HLT.
>+ *
>+ * We also manually do inject some interrupts via WHvRegisterPendingEvent
>+ * instead of WHVRequestInterrupt, which does not reset the HLT state.
>+ *
>+ * However, even with this done, if the guest does an HLT without
>+ * interrupts enabled (which the test_sti_inhibit KVM unit test does)
>+ * then the guest will stay in HLT forever.
>+ *
>+ * Keep it this way for now, with perhaps adding a heartbeat later
>+ * so that we get the CPU time savings from having Hyper-V handle HLT
>+ * instead of going away from it as soon as possible.
>+ */
>+ if (whpx_irqchip_in_kernel()) {
>+ whpx_vcpu_kick_out_of_hlt(cpu);
>+ }
> break;
> case WHvRunVpExitReasonX64MsrAccess: {
> WHV_REGISTER_VALUE reg_values[3] = {0};
© 2016 - 2026 Red Hat, Inc.