From 86f5993bc9aac58bb3fa504296d95fad8d4f7f27 Mon Sep 17 00:00:00 2001 From: "Li, Fei1" Date: Fri, 10 May 2019 07:51:14 +0800 Subject: [PATCH] hv: vlapic: fix tpr virtualization when VID is not enabled. 1) According SDM Vol 3, Chap 29.1.2, Any VM exit caused by TPR virtualization is trap-like: the instruction causing TPR virtualization completes before the VM exit occurs (for example, the value of CS:RIP saved in the guest-state area of the VMCS references the next instruction). So we need to retain the RIP. 2) The previous implement only consides the situation the guest will reduce the TPR. However, the guest will increase it. So we need to update the PPR before we find a deliverable interrupt. For examples: a) if the guest increase the TPR before a irq windows vmexit, we need to update the PPR when check whether there has a pending delivery interrupt or not; b) if the guest increase the TPR, then an external irq raised, we need to update the PPR when check whether there has a deliverable interrupt to inject to guest. Tracked-On: #1842 Signed-off-by: Li, Fei1 Reviewed-by: Yu Wang Reviewed-by: Jason Chen CJ Acked-by: Anthony Xu --- hypervisor/arch/x86/guest/vlapic.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index 7c94e1ff9..eb67236ea 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -2212,6 +2212,7 @@ static bool apicv_basic_inject_intr(struct acrn_vlapic *vlapic, uint32_t vector = 0U; bool ret = injected; if (guest_irq_enabled && (!injected)) { + vlapic_update_ppr(vlapic); if (vlapic_find_deliverable_intr(vlapic, &vector)) { exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD, VMX_INT_INFO_VALID | vector); vlapic_get_deliverable_intr(vlapic, vector); @@ -2321,6 +2322,8 @@ static bool apicv_basic_has_pending_delivery_intr(struct acrn_vcpu *vcpu) uint32_t vector; struct acrn_vlapic *vlapic = vcpu_vlapic(vcpu); + vlapic_update_ppr(vlapic); + /* check and raise request if we have a deliverable irq in LAPIC IRR */ if (vlapic_find_deliverable_intr(vlapic, &vector)) { /* we have pending IRR */ @@ -2535,16 +2538,8 @@ void vlapic_update_tpr_threshold(const struct acrn_vlapic *vlapic) int32_t tpr_below_threshold_vmexit_handler(struct acrn_vcpu *vcpu) { - struct acrn_vlapic *vlapic = vcpu_vlapic(vcpu); - - vlapic_update_ppr(vlapic); - /* - * Once we come here, the vTPR must small than IRR. - * set TPR threshold to 0 to bypass VM-Execution Control Fields check - * since vcpu_inject_vlapic_int will update TPR threshold aright. - */ - exec_vmwrite32(VMX_TPR_THRESHOLD, 0U); vcpu_make_request(vcpu, ACRN_REQUEST_EVENT); + vcpu_retain_rip(vcpu); return 0; }