OSDN Git Service

KVM: VMX: Read cached VM-Exit reason to detect external interrupt
authorSean Christopherson <sean.j.christopherson@intel.com>
Sat, 20 Apr 2019 05:50:56 +0000 (22:50 -0700)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 18 Jun 2019 09:46:02 +0000 (11:46 +0200)
Generic x86 code invokes the kvm_x86_ops external interrupt handler on
all VM-Exits regardless of the actual exit type.  Use the already-cached
EXIT_REASON to determine if the VM-Exit was due to an interrupt, thus
avoiding an extra VMREAD (to query VM_EXIT_INTR_INFO) for all other
types of VM-Exit.

In addition to avoiding the extra VMREAD, checking the EXIT_REASON
instead of VM_EXIT_INTR_INFO makes it more obvious that
vmx_handle_external_intr() is called for all VM-Exits, e.g. someone
unfamiliar with the flow might wonder under what condition(s)
VM_EXIT_INTR_INFO does not contain a valid interrupt, which is
simply not possible since KVM always runs with "ack interrupt on exit".

WARN once if VM_EXIT_INTR_INFO doesn't contain a valid interrupt on
an EXTERNAL_INTERRUPT VM-Exit, as such a condition would indicate a
hardware bug.

Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx/vmcs.h
arch/x86/kvm/vmx/vmx.c

index cb6079f..971a46c 100644 (file)
@@ -115,6 +115,12 @@ static inline bool is_nmi(u32 intr_info)
                == (INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK);
 }
 
+static inline bool is_external_intr(u32 intr_info)
+{
+       return (intr_info & (INTR_INFO_VALID_MASK | INTR_INFO_INTR_TYPE_MASK))
+               == (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR);
+}
+
 enum vmcs_field_width {
        VMCS_FIELD_WIDTH_U16 = 0,
        VMCS_FIELD_WIDTH_U64 = 1,
index da6c829..b541fe2 100644 (file)
@@ -6127,42 +6127,46 @@ static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
 
 static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
 {
-       u32 exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
-
-       if ((exit_intr_info & (INTR_INFO_VALID_MASK | INTR_INFO_INTR_TYPE_MASK))
-                       == (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR)) {
-               unsigned int vector;
-               unsigned long entry;
-               gate_desc *desc;
-               struct vcpu_vmx *vmx = to_vmx(vcpu);
+       unsigned int vector;
+       unsigned long entry;
 #ifdef CONFIG_X86_64
-               unsigned long tmp;
+       unsigned long tmp;
 #endif
+       gate_desc *desc;
+       u32 intr_info;
 
-               vector =  exit_intr_info & INTR_INFO_VECTOR_MASK;
-               desc = (gate_desc *)vmx->host_idt_base + vector;
-               entry = gate_offset(desc);
-               asm volatile(
+       if (to_vmx(vcpu)->exit_reason != EXIT_REASON_EXTERNAL_INTERRUPT)
+               return;
+
+       intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
+       if (WARN_ONCE(!is_external_intr(intr_info),
+           "KVM: unexpected VM-Exit interrupt info: 0x%x", intr_info))
+               return;
+
+       vector = intr_info & INTR_INFO_VECTOR_MASK;
+       desc = (gate_desc *)vmx->host_idt_base + vector;
+       entry = gate_offset(desc);
+
+       asm volatile(
 #ifdef CONFIG_X86_64
-                       "mov %%" _ASM_SP ", %[sp]\n\t"
-                       "and $0xfffffffffffffff0, %%" _ASM_SP "\n\t"
-                       "push $%c[ss]\n\t"
-                       "push %[sp]\n\t"
+               "mov %%" _ASM_SP ", %[sp]\n\t"
+               "and $0xfffffffffffffff0, %%" _ASM_SP "\n\t"
+               "push $%c[ss]\n\t"
+               "push %[sp]\n\t"
 #endif
-                       "pushf\n\t"
-                       __ASM_SIZE(push) " $%c[cs]\n\t"
-                       CALL_NOSPEC
-                       :
+               "pushf\n\t"
+               __ASM_SIZE(push) " $%c[cs]\n\t"
+               CALL_NOSPEC
+               :
 #ifdef CONFIG_X86_64
-                       [sp]"=&r"(tmp),
+               [sp]"=&r"(tmp),
 #endif
-                       ASM_CALL_CONSTRAINT
-                       :
-                       THUNK_TARGET(entry),
-                       [ss]"i"(__KERNEL_DS),
-                       [cs]"i"(__KERNEL_CS)
-                       );
-       }
+               ASM_CALL_CONSTRAINT
+               :
+               THUNK_TARGET(entry),
+               [ss]"i"(__KERNEL_DS),
+               [cs]"i"(__KERNEL_CS)
+       );
 }
 STACK_FRAME_NON_STANDARD(vmx_handle_external_intr);