KVM: VMX: Avoid vmx_recover_nmi_blocking() when unneeded
authorAvi Kivity <avi@redhat.com>
Mon, 7 Mar 2011 14:52:07 +0000 (16:52 +0200)
committerAvi Kivity <avi@redhat.com>
Wed, 11 May 2011 11:56:56 +0000 (07:56 -0400)
When we haven't injected an interrupt, we don't need to recover
the nmi blocking state (since the guest can't set it by itself).
This allows us to avoid a VMREAD later on.

Signed-off-by: Avi Kivity <avi@redhat.com>
arch/x86/kvm/vmx.c

index 8f9e77edc01651c202d4d6db14417a8525fc35e0..53bf6ae493e3be85f9f99158f7394abe44a4f091 100644 (file)
@@ -129,6 +129,7 @@ struct vcpu_vmx {
        int                   launched;
        u8                    fail;
        u8                    cpl;
+       bool                  nmi_known_unmasked;
        u32                   exit_intr_info;
        u32                   idt_vectoring_info;
        ulong                 rflags;
@@ -2959,6 +2960,7 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
        }
 
        ++vcpu->stat.nmi_injections;
+       vmx->nmi_known_unmasked = false;
        if (vmx->rmode.vm86_active) {
                if (kvm_inject_realmode_interrupt(vcpu, NMI_VECTOR) != EMULATE_DONE)
                        kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
@@ -2983,6 +2985,8 @@ static bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu)
 {
        if (!cpu_has_virtual_nmis())
                return to_vmx(vcpu)->soft_vnmi_blocked;
+       if (to_vmx(vcpu)->nmi_known_unmasked)
+               return false;
        return vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_NMI;
 }
 
@@ -2996,6 +3000,7 @@ static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
                        vmx->vnmi_blocked_time = 0;
                }
        } else {
+               vmx->nmi_known_unmasked = !masked;
                if (masked)
                        vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
                                      GUEST_INTR_STATE_NMI);
@@ -3527,9 +3532,11 @@ static int handle_task_switch(struct kvm_vcpu *vcpu)
                switch (type) {
                case INTR_TYPE_NMI_INTR:
                        vcpu->arch.nmi_injected = false;
-                       if (cpu_has_virtual_nmis())
+                       if (cpu_has_virtual_nmis()) {
                                vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
                                              GUEST_INTR_STATE_NMI);
+                               vmx->nmi_known_unmasked = false;
+                       }
                        break;
                case INTR_TYPE_EXT_INTR:
                case INTR_TYPE_SOFT_INTR:
@@ -3916,6 +3923,8 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
        idtv_info_valid = vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK;
 
        if (cpu_has_virtual_nmis()) {
+               if (vmx->nmi_known_unmasked)
+                       return;
                unblock_nmi = (exit_intr_info & INTR_INFO_UNBLOCK_NMI) != 0;
                vector = exit_intr_info & INTR_INFO_VECTOR_MASK;
                /*
@@ -3932,6 +3941,10 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
                    vector != DF_VECTOR && !idtv_info_valid)
                        vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
                                      GUEST_INTR_STATE_NMI);
+               else
+                       vmx->nmi_known_unmasked =
+                               !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO)
+                                 & GUEST_INTR_STATE_NMI);
        } else if (unlikely(vmx->soft_vnmi_blocked))
                vmx->vnmi_blocked_time +=
                        ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time));
@@ -3970,6 +3983,7 @@ static void __vmx_complete_interrupts(struct vcpu_vmx *vmx,
                 */
                vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO,
                                GUEST_INTR_STATE_NMI);
+               vmx->nmi_known_unmasked = true;
                break;
        case INTR_TYPE_SOFT_EXCEPTION:
                vmx->vcpu.arch.event_exit_inst_len =