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 <fei1.li@intel.com>
Reviewed-by: Yu Wang <yu1.wang@intel.com>
Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com>
Acked-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
Li, Fei1 2019-05-10 07:51:14 +08:00 committed by wenlingz
parent a68dadb74a
commit 86f5993bc9

View File

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