hv: apicv: avoid enable interrupt window if interrupt delivery enabled

If the "virtual-interrupt delivery" is enabled for vmx apicv, then need
avoid to enable interrupt-window exiting. From SDM Vol3, 29.2.1, the
evaluation of pending virtual interrupts only be trigger if
"interrupt-window exiting" is 0.

The original code will enable interrupt-window vmexit if any pending
vlapic interrupts even the "virtual-interrupt delivery" is enabled. It
will cause the pending interrupts can't be evaluate immediately until
guest triggered interrupt-window vmexit.

For "virtual-interrupt delivery" enabled case, just need sync the
pending interrupts to irr and update rvi if needed. And CPU will
evaluate and automatic injecct virtual interrupt at appropriate time. It
doesn't rely on interrupt-window vmexit.

For "virtual-interrupt delivery" disabled case, need to check if satisfy
the virtual interrupt injection conditions before doing the interrupt
injection. If not, then need to enable interrupt-window vmexit and
re-check the conditions in the next time vmexit.

Tracked-On: #1187
Signed-off-by: Yu Wang <yu1.wang@intel.com>
Acked-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
Yu Wang 2018-09-06 02:52:13 +00:00 committed by lijinxia
parent f5ca1896b3
commit 46c3276ec8

View File

@ -109,15 +109,18 @@ void vcpu_make_request(struct vcpu *vcpu, uint16_t eventid)
}
}
static int vcpu_do_pending_event(struct vcpu *vcpu)
static int vcpu_inject_vlapic_int(struct vcpu *vcpu)
{
struct acrn_vlapic *vlapic = vcpu->arch_vcpu.vlapic;
uint32_t vector = 0U;
int ret = 0;
/*
* This function used for inject virtual interrupt
* through vmcs.
*/
if (is_apicv_intr_delivery_supported()) {
vlapic_apicv_inject_pir(vlapic);
return 0;
return -1;
}
/* Query vLapic to get vector to inject */
@ -383,11 +386,11 @@ int acrn_handle_pending_request(struct vcpu *vcpu)
{
int ret = 0;
uint32_t tmp;
bool intr_pending = false;
uint32_t intr_info;
uint32_t error_code;
struct vcpu_arch * arch_vcpu = &vcpu->arch_vcpu;
uint64_t *pending_req_bits = &arch_vcpu->pending_req;
struct acrn_vlapic *vlapic = vcpu->arch_vcpu.vlapic;
if (bitmap_test_and_clear_lock(ACRN_REQUEST_TRP_FAULT, pending_req_bits)) {
pr_fatal("Triple fault happen -> shutdown!");
@ -446,6 +449,19 @@ int acrn_handle_pending_request(struct vcpu *vcpu)
goto INTR_WIN;
}
/*
* If the "virtual-interrupt delivery" is enabled,
* sync the pending interrupts to irr and update rvi if needed.
* Then CPU will start evaluate the pending virtual interrupts
* in the later vm-entry.
*
*/
if (is_apicv_intr_delivery_supported() &&
bitmap_test_and_clear_lock(ACRN_REQUEST_EVENT,
pending_req_bits)) {
vlapic_apicv_inject_pir(vlapic);
}
/* Guest interruptable or not */
if (is_guest_irq_enabled(vcpu)) {
/* Inject external interrupt first */
@ -456,11 +472,15 @@ int acrn_handle_pending_request(struct vcpu *vcpu)
goto INTR_WIN;
}
/* Inject vLAPIC vectors */
if (bitmap_test_and_clear_lock(ACRN_REQUEST_EVENT,
pending_req_bits)) {
/* has pending vLAPIC interrupts */
ret = vcpu_do_pending_event(vcpu);
/*
* For "virtual-interrupt delivery" disabled case, if
* the virtual interrupt injection conditions are satified,
* then inject through vmcs.
*/
if (!is_apicv_intr_delivery_supported() &&
bitmap_test_and_clear_lock(ACRN_REQUEST_EVENT,
pending_req_bits)) {
ret = vcpu_inject_vlapic_int(vcpu);
goto INTR_WIN;
}
}
@ -470,11 +490,19 @@ int acrn_handle_pending_request(struct vcpu *vcpu)
goto INTR_WIN;
INTR_WIN:
/* check if we have new interrupt pending for next VMExit */
intr_pending = vcpu_pending_request(vcpu);
/*
* If "virtual-interrupt delivered" is enabled, CPU will evaluate
* and automatic inject the virtual interrupts in appropriate time.
* And from SDM Vol3 29.2.1, the apicv only trigger evaluation of
* pending virtual interrupts when "interrupt-window exiting" is 0.
*/
if (is_apicv_intr_delivery_supported() ||
!vcpu_pending_request(vcpu)) {
return ret;
}
/* Enable interrupt window exiting if pending */
if (intr_pending && arch_vcpu->irq_window_enabled == 0U) {
if (arch_vcpu->irq_window_enabled == 0U) {
arch_vcpu->irq_window_enabled = 1U;
tmp = exec_vmread32(VMX_PROC_VM_EXEC_CONTROLS);
tmp |= VMX_PROCBASED_CTLS_IRQ_WIN;