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:
committed by
Corvin Köhne
parent
b9600db494
commit
0912408a28
+19
-25
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user