|
@@ -375,6 +375,23 @@ struct pi_desc {
|
|
|
u32 rsvd[7];
|
|
|
} __aligned(64);
|
|
|
|
|
|
+static bool pi_test_and_set_on(struct pi_desc *pi_desc)
|
|
|
+{
|
|
|
+ return test_and_set_bit(POSTED_INTR_ON,
|
|
|
+ (unsigned long *)&pi_desc->control);
|
|
|
+}
|
|
|
+
|
|
|
+static bool pi_test_and_clear_on(struct pi_desc *pi_desc)
|
|
|
+{
|
|
|
+ return test_and_clear_bit(POSTED_INTR_ON,
|
|
|
+ (unsigned long *)&pi_desc->control);
|
|
|
+}
|
|
|
+
|
|
|
+static int pi_test_and_set_pir(int vector, struct pi_desc *pi_desc)
|
|
|
+{
|
|
|
+ return test_and_set_bit(vector, (unsigned long *)pi_desc->pir);
|
|
|
+}
|
|
|
+
|
|
|
struct vcpu_vmx {
|
|
|
struct kvm_vcpu vcpu;
|
|
|
unsigned long host_rsp;
|
|
@@ -639,6 +656,7 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
|
|
|
struct kvm_segment *var, int seg);
|
|
|
static bool guest_state_valid(struct kvm_vcpu *vcpu);
|
|
|
static u32 vmx_segment_access_rights(struct kvm_segment *var);
|
|
|
+static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu);
|
|
|
|
|
|
static DEFINE_PER_CPU(struct vmcs *, vmxarea);
|
|
|
static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
|
|
@@ -2846,8 +2864,11 @@ static __init int hardware_setup(void)
|
|
|
|
|
|
if (enable_apicv)
|
|
|
kvm_x86_ops->update_cr8_intercept = NULL;
|
|
|
- else
|
|
|
+ else {
|
|
|
kvm_x86_ops->hwapic_irr_update = NULL;
|
|
|
+ kvm_x86_ops->deliver_posted_interrupt = NULL;
|
|
|
+ kvm_x86_ops->sync_pir_to_irr = vmx_sync_pir_to_irr_dummy;
|
|
|
+ }
|
|
|
|
|
|
if (nested)
|
|
|
nested_vmx_setup_ctls_msrs();
|
|
@@ -3908,6 +3929,45 @@ static int vmx_vm_has_apicv(struct kvm *kvm)
|
|
|
return enable_apicv && irqchip_in_kernel(kvm);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Send interrupt to vcpu via posted interrupt way.
|
|
|
+ * 1. If target vcpu is running(non-root mode), send posted interrupt
|
|
|
+ * notification to vcpu and hardware will sync PIR to vIRR atomically.
|
|
|
+ * 2. If target vcpu isn't running(root mode), kick it to pick up the
|
|
|
+ * interrupt from PIR in next vmentry.
|
|
|
+ */
|
|
|
+static void vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
|
|
|
+{
|
|
|
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
|
|
|
+ int r;
|
|
|
+
|
|
|
+ if (pi_test_and_set_pir(vector, &vmx->pi_desc))
|
|
|
+ return;
|
|
|
+
|
|
|
+ r = pi_test_and_set_on(&vmx->pi_desc);
|
|
|
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
|
|
|
+ if (!r && (vcpu->mode == IN_GUEST_MODE))
|
|
|
+ apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
|
|
|
+ POSTED_INTR_VECTOR);
|
|
|
+ else
|
|
|
+ kvm_vcpu_kick(vcpu);
|
|
|
+}
|
|
|
+
|
|
|
+static void vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
|
|
|
+{
|
|
|
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
|
|
|
+
|
|
|
+ if (!pi_test_and_clear_on(&vmx->pi_desc))
|
|
|
+ return;
|
|
|
+
|
|
|
+ kvm_apic_update_irr(vcpu, vmx->pi_desc.pir);
|
|
|
+}
|
|
|
+
|
|
|
+static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu)
|
|
|
+{
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Set up the vmcs's constant host-state fields, i.e., host-state fields that
|
|
|
* will not change in the lifetime of the guest.
|
|
@@ -7784,6 +7844,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
|
|
|
.load_eoi_exitmap = vmx_load_eoi_exitmap,
|
|
|
.hwapic_irr_update = vmx_hwapic_irr_update,
|
|
|
.hwapic_isr_update = vmx_hwapic_isr_update,
|
|
|
+ .sync_pir_to_irr = vmx_sync_pir_to_irr,
|
|
|
+ .deliver_posted_interrupt = vmx_deliver_posted_interrupt,
|
|
|
|
|
|
.set_tss_addr = vmx_set_tss_addr,
|
|
|
.get_tdp_level = get_ept_level,
|