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>
This commit is contained in:
Mohamed Mediouni
2026-04-22 23:42:09 +02:00
committed by Paolo Bonzini
parent 95b8738e31
commit 8e7b708bdd
4 changed files with 19 additions and 9 deletions

View File

@@ -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;
}
}
}

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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;