Commit 49def500 authored by Sean Christopherson's avatar Sean Christopherson Committed by Paolo Bonzini

KVM: VMX: Read cached VM-Exit reason to detect external interrupt

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: default avatarSean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 2ea72039
...@@ -115,6 +115,12 @@ static inline bool is_nmi(u32 intr_info) ...@@ -115,6 +115,12 @@ static inline bool is_nmi(u32 intr_info)
== (INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK); == (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 { enum vmcs_field_width {
VMCS_FIELD_WIDTH_U16 = 0, VMCS_FIELD_WIDTH_U16 = 0,
VMCS_FIELD_WIDTH_U64 = 1, VMCS_FIELD_WIDTH_U64 = 1,
......
...@@ -6127,42 +6127,46 @@ static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx) ...@@ -6127,42 +6127,46 @@ static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
static void vmx_handle_external_intr(struct kvm_vcpu *vcpu) static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
{ {
u32 exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); unsigned int vector;
unsigned long entry;
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);
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
unsigned long tmp; unsigned long tmp;
#endif #endif
gate_desc *desc;
u32 intr_info;
vector = exit_intr_info & INTR_INFO_VECTOR_MASK; if (to_vmx(vcpu)->exit_reason != EXIT_REASON_EXTERNAL_INTERRUPT)
desc = (gate_desc *)vmx->host_idt_base + vector; return;
entry = gate_offset(desc);
asm volatile( 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 #ifdef CONFIG_X86_64
"mov %%" _ASM_SP ", %[sp]\n\t" "mov %%" _ASM_SP ", %[sp]\n\t"
"and $0xfffffffffffffff0, %%" _ASM_SP "\n\t" "and $0xfffffffffffffff0, %%" _ASM_SP "\n\t"
"push $%c[ss]\n\t" "push $%c[ss]\n\t"
"push %[sp]\n\t" "push %[sp]\n\t"
#endif #endif
"pushf\n\t" "pushf\n\t"
__ASM_SIZE(push) " $%c[cs]\n\t" __ASM_SIZE(push) " $%c[cs]\n\t"
CALL_NOSPEC CALL_NOSPEC
: :
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
[sp]"=&r"(tmp), [sp]"=&r"(tmp),
#endif #endif
ASM_CALL_CONSTRAINT ASM_CALL_CONSTRAINT
: :
THUNK_TARGET(entry), THUNK_TARGET(entry),
[ss]"i"(__KERNEL_DS), [ss]"i"(__KERNEL_DS),
[cs]"i"(__KERNEL_CS) [cs]"i"(__KERNEL_CS)
); );
}
} }
STACK_FRAME_NON_STANDARD(vmx_handle_external_intr); STACK_FRAME_NON_STANDARD(vmx_handle_external_intr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment