vmm: fix HLT loop while vcpu has requested virtual interrupts

This fixes the detection of pending interrupts when pirval is 0 and the
pending bit is set

More information how this situation occurs, can be found here:
https://github.com/freebsd/freebsd-src/blob/c5b5f2d8086f540fefe4826da013dd31d4e45fe8/sys/amd64/vmm/intel/vmx.c#L4016-L4031

Reviewed by:		corvink, markj
Fixes:			02cc877968bbcd57695035c67114a67427f54549 ("Recognize a pending virtual interrupt while emulating the halt instruction.")
MFC after:		1 week
Sponsored by:		vStack
Differential Revision:	https://reviews.freebsd.org/D39620
This commit is contained in:
Vitaliy Gusev
2023-04-26 10:17:50 +02:00
committed by Corvin Köhne
parent b9600db494
commit 0912408a28
+19 -25
View File
@@ -3763,7 +3763,8 @@ vmx_pending_intr(struct vlapic *vlapic, int *vecptr)
struct pir_desc *pir_desc; struct pir_desc *pir_desc;
struct LAPIC *lapic; struct LAPIC *lapic;
uint64_t pending, pirval; uint64_t pending, pirval;
uint32_t ppr, vpr; uint8_t ppr, vpr, rvi;
struct vm_exit *vmexit;
int i; int i;
/* /*
@@ -3774,31 +3775,26 @@ vmx_pending_intr(struct vlapic *vlapic, int *vecptr)
vlapic_vtx = (struct vlapic_vtx *)vlapic; vlapic_vtx = (struct vlapic_vtx *)vlapic;
pir_desc = vlapic_vtx->pir_desc; pir_desc = vlapic_vtx->pir_desc;
lapic = vlapic->apic_page;
/*
* While a virtual interrupt may have already been
* processed the actual delivery maybe pending the
* interruptibility of the guest. Recognize a pending
* interrupt by reevaluating virtual interrupts
* following Section 30.2.1 in the Intel SDM Volume 3.
*/
vmexit = vm_exitinfo(vlapic->vcpu);
KASSERT(vmexit->exitcode == VM_EXITCODE_HLT,
("vmx_pending_intr: exitcode not 'HLT'"));
rvi = vmexit->u.hlt.intr_status & APIC_TPR_INT;
ppr = lapic->ppr & APIC_TPR_INT;
if (rvi > ppr)
return (1);
pending = atomic_load_acq_long(&pir_desc->pending); pending = atomic_load_acq_long(&pir_desc->pending);
if (!pending) { if (!pending)
/*
* While a virtual interrupt may have already been
* processed the actual delivery maybe pending the
* interruptibility of the guest. Recognize a pending
* interrupt by reevaluating virtual interrupts
* following Section 29.2.1 in the Intel SDM Volume 3.
*/
struct vm_exit *vmexit;
uint8_t rvi, ppr;
vmexit = vm_exitinfo(vlapic->vcpu);
KASSERT(vmexit->exitcode == VM_EXITCODE_HLT,
("vmx_pending_intr: exitcode not 'HLT'"));
rvi = vmexit->u.hlt.intr_status & APIC_TPR_INT;
lapic = vlapic->apic_page;
ppr = lapic->ppr & APIC_TPR_INT;
if (rvi > ppr) {
return (1);
}
return (0); return (0);
}
/* /*
* If there is an interrupt pending then it will be recognized only * If there is an interrupt pending then it will be recognized only
@@ -3807,8 +3803,6 @@ vmx_pending_intr(struct vlapic *vlapic, int *vecptr)
* Special case: if the processor priority is zero then any pending * Special case: if the processor priority is zero then any pending
* interrupt will be recognized. * interrupt will be recognized.
*/ */
lapic = vlapic->apic_page;
ppr = lapic->ppr & APIC_TPR_INT;
if (ppr == 0) if (ppr == 0)
return (1); return (1);