x86/entry: KVM: Use dedicated VMX NMI entry for 32-bit kernels too
authorSean Christopherson <seanjc@google.com>
Tue, 13 Dec 2022 06:09:10 +0000 (06:09 +0000)
committerSean Christopherson <seanjc@google.com>
Tue, 24 Jan 2023 18:36:40 +0000 (10:36 -0800)
Use a dedicated entry for invoking the NMI handler from KVM VMX's VM-Exit
path for 32-bit even though using a dedicated entry for 32-bit isn't
strictly necessary.  Exposing a single symbol will allow KVM to reference
the entry point in assembly code without having to resort to more #ifdefs
(or #defines).  identry.h is intended to be included from asm files only
once, and so simply including idtentry.h in KVM assembly isn't an option.

Bypassing the ESP fixup and CR3 switching in the standard NMI entry code
is safe as KVM always handles NMIs that occur in the guest on a kernel
stack, with a kernel CR3.

Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Lai Jiangshan <jiangshanlai@gmail.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20221213060912.654668-6-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/include/asm/idtentry.h
arch/x86/kernel/nmi.c
arch/x86/kvm/vmx/vmx.c

index 72184b0b2219e88502bad42ee77fec36bede52c3..b241af4ce9b401268bd1b32e1841c146a40068dc 100644 (file)
@@ -582,18 +582,14 @@ DECLARE_IDTENTRY_RAW(X86_TRAP_MC, xenpv_exc_machine_check);
 
 /* NMI */
 
-#if defined(CONFIG_X86_64) && IS_ENABLED(CONFIG_KVM_INTEL)
+#if IS_ENABLED(CONFIG_KVM_INTEL)
 /*
- * Special NOIST entry point for VMX which invokes this on the kernel
- * stack. asm_exc_nmi() requires an IST to work correctly vs. the NMI
- * 'executing' marker.
- *
- * On 32bit this just uses the regular NMI entry point because 32-bit does
- * not have ISTs.
+ * Special entry point for VMX which invokes this on the kernel stack, even for
+ * 64-bit, i.e. without using an IST.  asm_exc_nmi() requires an IST to work
+ * correctly vs. the NMI 'executing' marker.  Used for 32-bit kernels as well
+ * to avoid more ifdeffery.
  */
-DECLARE_IDTENTRY(X86_TRAP_NMI,         exc_nmi_noist);
-#else
-#define asm_exc_nmi_noist              asm_exc_nmi
+DECLARE_IDTENTRY(X86_TRAP_NMI,         exc_nmi_kvm_vmx);
 #endif
 
 DECLARE_IDTENTRY_NMI(X86_TRAP_NMI,     exc_nmi);
index cec0bfa3bc04fa21fbf741d5c6fca0464956bf1d..e37faba95bb52f59199671e8ff648e91d01c5d91 100644 (file)
@@ -527,14 +527,14 @@ nmi_restart:
                mds_user_clear_cpu_buffers();
 }
 
-#if defined(CONFIG_X86_64) && IS_ENABLED(CONFIG_KVM_INTEL)
-DEFINE_IDTENTRY_RAW(exc_nmi_noist)
+#if IS_ENABLED(CONFIG_KVM_INTEL)
+DEFINE_IDTENTRY_RAW(exc_nmi_kvm_vmx)
 {
        exc_nmi(regs);
 }
-#endif
 #if IS_MODULE(CONFIG_KVM_INTEL)
-EXPORT_SYMBOL_GPL(asm_exc_nmi_noist);
+EXPORT_SYMBOL_GPL(asm_exc_nmi_kvm_vmx);
+#endif
 #endif
 
 void stop_nmi(void)
index 59a051350f8f5f0fdf0ad1a7b1f6ee38a079aa99..84e808af892a864f426c4fc0806a77a47880c067 100644 (file)
@@ -6866,7 +6866,7 @@ 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;
+       bool is_nmi = entry == (unsigned long)asm_exc_nmi_kvm_vmx;
 
        kvm_before_interrupt(vcpu, is_nmi ? KVM_HANDLING_NMI : KVM_HANDLING_IRQ);
        vmx_do_interrupt_nmi_irqoff(entry);
@@ -6895,7 +6895,7 @@ static void handle_nm_fault_irqoff(struct kvm_vcpu *vcpu)
 
 static void handle_exception_nmi_irqoff(struct vcpu_vmx *vmx)
 {
-       const unsigned long nmi_entry = (unsigned long)asm_exc_nmi_noist;
+       const unsigned long nmi_entry = (unsigned long)asm_exc_nmi_kvm_vmx;
        u32 intr_info = vmx_get_intr_info(&vmx->vcpu);
 
        /* if exit due to PF check for async PF */