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
@@ -3763,7 +3763,8 @@ vmx_pending_intr(struct vlapic *vlapic, int *vecptr)
|
||||
struct pir_desc *pir_desc;
|
||||
struct LAPIC *lapic;
|
||||
uint64_t pending, pirval;
|
||||
uint32_t ppr, vpr;
|
||||
uint8_t ppr, vpr, rvi;
|
||||
struct vm_exit *vmexit;
|
||||
int i;
|
||||
|
||||
/*
|
||||
@@ -3774,31 +3775,26 @@ vmx_pending_intr(struct vlapic *vlapic, int *vecptr)
|
||||
|
||||
vlapic_vtx = (struct vlapic_vtx *)vlapic;
|
||||
pir_desc = vlapic_vtx->pir_desc;
|
||||
lapic = vlapic->apic_page;
|
||||
|
||||
pending = atomic_load_acq_long(&pir_desc->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.
|
||||
* following Section 30.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) {
|
||||
if (rvi > ppr)
|
||||
return (1);
|
||||
}
|
||||
|
||||
pending = atomic_load_acq_long(&pir_desc->pending);
|
||||
if (!pending)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* interrupt will be recognized.
|
||||
*/
|
||||
lapic = vlapic->apic_page;
|
||||
ppr = lapic->ppr & APIC_TPR_INT;
|
||||
if (ppr == 0)
|
||||
return (1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user