lkml.org 
[lkml]   [2022]   [Aug]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v8 081/103] KVM: VMX: Move NMI/exception handler to common helper
    Date
    From: Sean Christopherson <sean.j.christopherson@intel.com>

    TDX mostly handles NMI/exception exit mostly the same to VMX case. The
    difference is how to retrieve exit qualification. To share the code with
    TDX, move NMI/exception to a common header, common.h.

    Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
    Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
    ---
    arch/x86/kvm/vmx/common.h | 70 ++++++++++++++++++++++++++++++++++
    arch/x86/kvm/vmx/vmx.c | 79 ++++-----------------------------------
    2 files changed, 78 insertions(+), 71 deletions(-)

    diff --git a/arch/x86/kvm/vmx/common.h b/arch/x86/kvm/vmx/common.h
    index 1522e9e6851b..fd5ed3c0f894 100644
    --- a/arch/x86/kvm/vmx/common.h
    +++ b/arch/x86/kvm/vmx/common.h
    @@ -4,8 +4,78 @@

    #include <linux/kvm_host.h>

    +#include <asm/traps.h>
    +
    #include "posted_intr.h"
    #include "mmu.h"
    +#include "vmcs.h"
    +#include "x86.h"
    +
    +extern unsigned long vmx_host_idt_base;
    +void vmx_do_interrupt_nmi_irqoff(unsigned long entry);
    +
    +static inline void vmx_handle_interrupt_nmi_irqoff(struct kvm_vcpu *vcpu,
    + unsigned long entry)
    +{
    + bool is_nmi = entry == (unsigned long)asm_exc_nmi_noist;
    +
    + kvm_before_interrupt(vcpu, is_nmi ? KVM_HANDLING_NMI : KVM_HANDLING_IRQ);
    + vmx_do_interrupt_nmi_irqoff(entry);
    + kvm_after_interrupt(vcpu);
    +}
    +
    +static inline void vmx_handle_nm_fault_irqoff(struct kvm_vcpu *vcpu)
    +{
    + /*
    + * Save xfd_err to guest_fpu before interrupt is enabled, so the
    + * MSR value is not clobbered by the host activity before the guest
    + * has chance to consume it.
    + *
    + * Do not blindly read xfd_err here, since this exception might
    + * be caused by L1 interception on a platform which doesn't
    + * support xfd at all.
    + *
    + * Do it conditionally upon guest_fpu::xfd. xfd_err matters
    + * only when xfd contains a non-zero value.
    + *
    + * Queuing exception is done in vmx_handle_exit. See comment there.
    + */
    + if (vcpu->arch.guest_fpu.fpstate->xfd)
    + rdmsrl(MSR_IA32_XFD_ERR, vcpu->arch.guest_fpu.xfd_err);
    +}
    +
    +static inline void vmx_handle_exception_nmi_irqoff(struct kvm_vcpu *vcpu,
    + u32 intr_info)
    +{
    + const unsigned long nmi_entry = (unsigned long)asm_exc_nmi_noist;
    +
    + /* if exit due to PF check for async PF */
    + if (is_page_fault(intr_info))
    + vcpu->arch.apf.host_apf_flags = kvm_read_and_reset_apf_flags();
    + /* if exit due to NM, handle before interrupts are enabled */
    + else if (is_nm_fault(intr_info))
    + vmx_handle_nm_fault_irqoff(vcpu);
    + /* Handle machine checks before interrupts are enabled */
    + else if (is_machine_check(intr_info))
    + kvm_machine_check();
    + /* We need to handle NMIs before interrupts are enabled */
    + else if (is_nmi(intr_info))
    + vmx_handle_interrupt_nmi_irqoff(vcpu, nmi_entry);
    +}
    +
    +static inline void vmx_handle_external_interrupt_irqoff(struct kvm_vcpu *vcpu,
    + u32 intr_info)
    +{
    + unsigned int vector = intr_info & INTR_INFO_VECTOR_MASK;
    + gate_desc *desc = (gate_desc *)vmx_host_idt_base + vector;
    +
    + if (KVM_BUG(!is_external_intr(intr_info), vcpu->kvm,
    + "KVM: unexpected VM-Exit interrupt info: 0x%x", intr_info))
    + return;
    +
    + vmx_handle_interrupt_nmi_irqoff(vcpu, gate_offset(desc));
    + vcpu->arch.at_instruction_boundary = true;
    +}

    static inline int __vmx_handle_ept_violation(struct kvm_vcpu *vcpu, gpa_t gpa,
    unsigned long exit_qualification)
    diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
    index 4ff998bf374b..e5aa805f6db4 100644
    --- a/arch/x86/kvm/vmx/vmx.c
    +++ b/arch/x86/kvm/vmx/vmx.c
    @@ -527,7 +527,7 @@ static inline void vmx_segment_cache_clear(struct vcpu_vmx *vmx)
    vmx->segment_cache.bitmask = 0;
    }

    -static unsigned long host_idt_base;
    +unsigned long vmx_host_idt_base;

    #if IS_ENABLED(CONFIG_HYPERV)
    static bool __read_mostly enlightened_vmcs = true;
    @@ -4186,7 +4186,7 @@ void vmx_set_constant_host_state(struct vcpu_vmx *vmx)
    vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS); /* 22.2.4 */
    vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8); /* 22.2.4 */

    - vmcs_writel(HOST_IDTR_BASE, host_idt_base); /* 22.2.4 */
    + vmcs_writel(HOST_IDTR_BASE, vmx_host_idt_base); /* 22.2.4 */

    vmcs_writel(HOST_RIP, (unsigned long)vmx_vmexit); /* 22.2.5 */

    @@ -5065,10 +5065,10 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
    intr_info = vmx_get_intr_info(vcpu);

    if (is_machine_check(intr_info) || is_nmi(intr_info))
    - return 1; /* handled by handle_exception_nmi_irqoff() */
    + return 1; /* handled by vmx_handle_exception_nmi_irqoff() */

    /*
    - * Queue the exception here instead of in handle_nm_fault_irqoff().
    + * Queue the exception here instead of in vmx_handle_nm_fault_irqoff().
    * This ensures the nested_vmx check is not skipped so vmexit can
    * be reflected to L1 (when it intercepts #NM) before reaching this
    * point.
    @@ -6741,70 +6741,6 @@ void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
    vmcs_write64(EOI_EXIT_BITMAP3, eoi_exit_bitmap[3]);
    }

    -void vmx_do_interrupt_nmi_irqoff(unsigned long entry);
    -
    -static void handle_interrupt_nmi_irqoff(struct kvm_vcpu *vcpu,
    - unsigned long entry)
    -{
    - bool is_nmi = entry == (unsigned long)asm_exc_nmi_noist;
    -
    - kvm_before_interrupt(vcpu, is_nmi ? KVM_HANDLING_NMI : KVM_HANDLING_IRQ);
    - vmx_do_interrupt_nmi_irqoff(entry);
    - kvm_after_interrupt(vcpu);
    -}
    -
    -static void handle_nm_fault_irqoff(struct kvm_vcpu *vcpu)
    -{
    - /*
    - * Save xfd_err to guest_fpu before interrupt is enabled, so the
    - * MSR value is not clobbered by the host activity before the guest
    - * has chance to consume it.
    - *
    - * Do not blindly read xfd_err here, since this exception might
    - * be caused by L1 interception on a platform which doesn't
    - * support xfd at all.
    - *
    - * Do it conditionally upon guest_fpu::xfd. xfd_err matters
    - * only when xfd contains a non-zero value.
    - *
    - * Queuing exception is done in vmx_handle_exit. See comment there.
    - */
    - if (vcpu->arch.guest_fpu.fpstate->xfd)
    - rdmsrl(MSR_IA32_XFD_ERR, vcpu->arch.guest_fpu.xfd_err);
    -}
    -
    -static void handle_exception_nmi_irqoff(struct kvm_vcpu *vcpu, u32 intr_info)
    -{
    - const unsigned long nmi_entry = (unsigned long)asm_exc_nmi_noist;
    -
    - /* if exit due to PF check for async PF */
    - if (is_page_fault(intr_info))
    - vcpu->arch.apf.host_apf_flags = kvm_read_and_reset_apf_flags();
    - /* if exit due to NM, handle before interrupts are enabled */
    - else if (is_nm_fault(intr_info))
    - handle_nm_fault_irqoff(vcpu);
    - /* Handle machine checks before interrupts are enabled */
    - else if (is_machine_check(intr_info))
    - kvm_machine_check();
    - /* We need to handle NMIs before interrupts are enabled */
    - else if (is_nmi(intr_info))
    - handle_interrupt_nmi_irqoff(vcpu, nmi_entry);
    -}
    -
    -static void handle_external_interrupt_irqoff(struct kvm_vcpu *vcpu,
    - u32 intr_info)
    -{
    - unsigned int vector = intr_info & INTR_INFO_VECTOR_MASK;
    - gate_desc *desc = (gate_desc *)host_idt_base + vector;
    -
    - if (KVM_BUG(!is_external_intr(intr_info), vcpu->kvm,
    - "KVM: unexpected VM-Exit interrupt info: 0x%x", intr_info))
    - return;
    -
    - handle_interrupt_nmi_irqoff(vcpu, gate_offset(desc));
    - vcpu->arch.at_instruction_boundary = true;
    -}
    -
    void vmx_handle_exit_irqoff(struct kvm_vcpu *vcpu)
    {
    struct vcpu_vmx *vmx = to_vmx(vcpu);
    @@ -6813,9 +6749,10 @@ void vmx_handle_exit_irqoff(struct kvm_vcpu *vcpu)
    return;

    if (vmx->exit_reason.basic == EXIT_REASON_EXTERNAL_INTERRUPT)
    - handle_external_interrupt_irqoff(vcpu, vmx_get_intr_info(vcpu));
    + vmx_handle_external_interrupt_irqoff(vcpu,
    + vmx_get_intr_info(vcpu));
    else if (vmx->exit_reason.basic == EXIT_REASON_EXCEPTION_NMI)
    - handle_exception_nmi_irqoff(vcpu, vmx_get_intr_info(vcpu));
    + vmx_handle_exception_nmi_irqoff(vcpu, vmx_get_intr_info(vcpu));
    }

    /*
    @@ -8072,7 +8009,7 @@ __init int vmx_hardware_setup(void)
    int r;

    store_idt(&dt);
    - host_idt_base = dt.address;
    + vmx_host_idt_base = dt.address;

    vmx_setup_user_return_msrs();

    --
    2.25.1
    \
     
     \ /
      Last update: 2022-08-08 00:10    [W:3.241 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site