diff options
Diffstat (limited to 'arch/x86/kvm/vmx.c')
-rw-r--r-- | arch/x86/kvm/vmx.c | 64 |
1 files changed, 63 insertions, 1 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8535519d0352..3a14d8a0ee46 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -375,6 +375,23 @@ struct pi_desc { | |||
375 | u32 rsvd[7]; | 375 | u32 rsvd[7]; |
376 | } __aligned(64); | 376 | } __aligned(64); |
377 | 377 | ||
378 | static bool pi_test_and_set_on(struct pi_desc *pi_desc) | ||
379 | { | ||
380 | return test_and_set_bit(POSTED_INTR_ON, | ||
381 | (unsigned long *)&pi_desc->control); | ||
382 | } | ||
383 | |||
384 | static bool pi_test_and_clear_on(struct pi_desc *pi_desc) | ||
385 | { | ||
386 | return test_and_clear_bit(POSTED_INTR_ON, | ||
387 | (unsigned long *)&pi_desc->control); | ||
388 | } | ||
389 | |||
390 | static int pi_test_and_set_pir(int vector, struct pi_desc *pi_desc) | ||
391 | { | ||
392 | return test_and_set_bit(vector, (unsigned long *)pi_desc->pir); | ||
393 | } | ||
394 | |||
378 | struct vcpu_vmx { | 395 | struct vcpu_vmx { |
379 | struct kvm_vcpu vcpu; | 396 | struct kvm_vcpu vcpu; |
380 | unsigned long host_rsp; | 397 | unsigned long host_rsp; |
@@ -639,6 +656,7 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu, | |||
639 | struct kvm_segment *var, int seg); | 656 | struct kvm_segment *var, int seg); |
640 | static bool guest_state_valid(struct kvm_vcpu *vcpu); | 657 | static bool guest_state_valid(struct kvm_vcpu *vcpu); |
641 | static u32 vmx_segment_access_rights(struct kvm_segment *var); | 658 | static u32 vmx_segment_access_rights(struct kvm_segment *var); |
659 | static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu); | ||
642 | 660 | ||
643 | static DEFINE_PER_CPU(struct vmcs *, vmxarea); | 661 | static DEFINE_PER_CPU(struct vmcs *, vmxarea); |
644 | static DEFINE_PER_CPU(struct vmcs *, current_vmcs); | 662 | static DEFINE_PER_CPU(struct vmcs *, current_vmcs); |
@@ -2846,8 +2864,11 @@ static __init int hardware_setup(void) | |||
2846 | 2864 | ||
2847 | if (enable_apicv) | 2865 | if (enable_apicv) |
2848 | kvm_x86_ops->update_cr8_intercept = NULL; | 2866 | kvm_x86_ops->update_cr8_intercept = NULL; |
2849 | else | 2867 | else { |
2850 | kvm_x86_ops->hwapic_irr_update = NULL; | 2868 | kvm_x86_ops->hwapic_irr_update = NULL; |
2869 | kvm_x86_ops->deliver_posted_interrupt = NULL; | ||
2870 | kvm_x86_ops->sync_pir_to_irr = vmx_sync_pir_to_irr_dummy; | ||
2871 | } | ||
2851 | 2872 | ||
2852 | if (nested) | 2873 | if (nested) |
2853 | nested_vmx_setup_ctls_msrs(); | 2874 | nested_vmx_setup_ctls_msrs(); |
@@ -3909,6 +3930,45 @@ static int vmx_vm_has_apicv(struct kvm *kvm) | |||
3909 | } | 3930 | } |
3910 | 3931 | ||
3911 | /* | 3932 | /* |
3933 | * Send interrupt to vcpu via posted interrupt way. | ||
3934 | * 1. If target vcpu is running(non-root mode), send posted interrupt | ||
3935 | * notification to vcpu and hardware will sync PIR to vIRR atomically. | ||
3936 | * 2. If target vcpu isn't running(root mode), kick it to pick up the | ||
3937 | * interrupt from PIR in next vmentry. | ||
3938 | */ | ||
3939 | static void vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector) | ||
3940 | { | ||
3941 | struct vcpu_vmx *vmx = to_vmx(vcpu); | ||
3942 | int r; | ||
3943 | |||
3944 | if (pi_test_and_set_pir(vector, &vmx->pi_desc)) | ||
3945 | return; | ||
3946 | |||
3947 | r = pi_test_and_set_on(&vmx->pi_desc); | ||
3948 | kvm_make_request(KVM_REQ_EVENT, vcpu); | ||
3949 | if (!r && (vcpu->mode == IN_GUEST_MODE)) | ||
3950 | apic->send_IPI_mask(get_cpu_mask(vcpu->cpu), | ||
3951 | POSTED_INTR_VECTOR); | ||
3952 | else | ||
3953 | kvm_vcpu_kick(vcpu); | ||
3954 | } | ||
3955 | |||
3956 | static void vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu) | ||
3957 | { | ||
3958 | struct vcpu_vmx *vmx = to_vmx(vcpu); | ||
3959 | |||
3960 | if (!pi_test_and_clear_on(&vmx->pi_desc)) | ||
3961 | return; | ||
3962 | |||
3963 | kvm_apic_update_irr(vcpu, vmx->pi_desc.pir); | ||
3964 | } | ||
3965 | |||
3966 | static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu) | ||
3967 | { | ||
3968 | return; | ||
3969 | } | ||
3970 | |||
3971 | /* | ||
3912 | * Set up the vmcs's constant host-state fields, i.e., host-state fields that | 3972 | * Set up the vmcs's constant host-state fields, i.e., host-state fields that |
3913 | * will not change in the lifetime of the guest. | 3973 | * will not change in the lifetime of the guest. |
3914 | * Note that host-state that does change is set elsewhere. E.g., host-state | 3974 | * Note that host-state that does change is set elsewhere. E.g., host-state |
@@ -7784,6 +7844,8 @@ static struct kvm_x86_ops vmx_x86_ops = { | |||
7784 | .load_eoi_exitmap = vmx_load_eoi_exitmap, | 7844 | .load_eoi_exitmap = vmx_load_eoi_exitmap, |
7785 | .hwapic_irr_update = vmx_hwapic_irr_update, | 7845 | .hwapic_irr_update = vmx_hwapic_irr_update, |
7786 | .hwapic_isr_update = vmx_hwapic_isr_update, | 7846 | .hwapic_isr_update = vmx_hwapic_isr_update, |
7847 | .sync_pir_to_irr = vmx_sync_pir_to_irr, | ||
7848 | .deliver_posted_interrupt = vmx_deliver_posted_interrupt, | ||
7787 | 7849 | ||
7788 | .set_tss_addr = vmx_set_tss_addr, | 7850 | .set_tss_addr = vmx_set_tss_addr, |
7789 | .get_tdp_level = get_ept_level, | 7851 | .get_tdp_level = get_ept_level, |