lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250612214849.3950094-6-sohil.mehta@intel.com>
Date: Thu, 12 Jun 2025 14:48:44 -0700
From: Sohil Mehta <sohil.mehta@...el.com>
To: x86@...nel.org,
	linux-kernel@...r.kernel.org
Cc: Xin Li <xin@...or.com>,
	"H . Peter Anvin" <hpa@...or.com>,
	Andy Lutomirski <luto@...nel.org>,
	Thomas Gleixner <tglx@...utronix.de>,
	Ingo Molnar <mingo@...hat.com>,
	Borislav Petkov <bp@...en8.de>,
	Dave Hansen <dave.hansen@...ux.intel.com>,
	Peter Zijlstra <peterz@...radead.org>,
	Sean Christopherson <seanjc@...gle.com>,
	Adrian Hunter <adrian.hunter@...el.com>,
	Kan Liang <kan.liang@...ux.intel.com>,
	Tony Luck <tony.luck@...el.com>,
	Zhang Rui <rui.zhang@...el.com>,
	Steven Rostedt <rostedt@...dmis.org>,
	Sohil Mehta <sohil.mehta@...el.com>,
	Andrew Cooper <andrew.cooper3@...rix.com>,
	"Kirill A . Shutemov" <kirill.shutemov@...ux.intel.com>,
	Jacob Pan <jacob.pan@...ux.microsoft.com>,
	Andi Kleen <ak@...ux.intel.com>,
	Kai Huang <kai.huang@...el.com>,
	Sandipan Das <sandipan.das@....com>,
	linux-perf-users@...r.kernel.org,
	linux-edac@...r.kernel.org,
	kvm@...r.kernel.org,
	linux-pm@...r.kernel.org,
	linux-trace-kernel@...r.kernel.org
Subject: [PATCH v7 05/10] x86/nmi: Assign and register NMI-source vectors

Prior to NMI-source support, the vector information was ignored by the
hardware while delivering NMIs. With NMI-source reporting, the initial
architecture supports a 16-bit source bitmap to identify the source of
the NMI. Upon receiving an NMI, this bitmap is delivered to the kernel
as part of the FRED event delivery mechanism.

Assign a vector space of 1-15 that is specific to NMI-source and
independent of the IDT vector space. Though unlikely, the hardware may
extend the NMI-source bitmap in the future. Add a code comment to
clarify how the kernel support can be easily extended.

Being a bitmap, the NMI-source vectors do not have any inherent priority
associated with them. The order of executing the NMI handlers is up to
the kernel. Existing NMI handling already has a priority mechanism for
the NMI handlers, with CPU-specific (NMI_LOCAL) handlers executed first,
followed by platform NMI handlers and unknown NMI (NMI_UNKNOWN) handlers
being last. Within each of these NMI types, the handlers registered with
NMI_FLAG_FIRST are given priority.

NMI-source follows the same priority scheme to avoid unnecessary
complexity. Therefore, the NMI-source vectors are assigned arbitrarily,
except for vector 2.

Vector 2 is reserved for external NMIs corresponding to the Local APIC -
LINT1 pin. Some third-party chipsets may send NMI messages with a fixed
vector value of 2. Using vector 2 for something else would lead to
confusion about the exact source. Do not assign it to any handler.

NMI-source vectors are only assigned for NMI_LOCAL type handlers.
Platform NMI handlers have a single handler registered per type. They
don't need additional source information to differentiate among them.

Use the assigned vectors to register the respective NMI handlers. Warn
if the vector values are unexpected.

A couple of NMI handlers, such as the microcode rendezvous and the crash
reboot, do not use the typical NMI registration interface. Leave them
as-is for now.

Originally-by: Jacob Pan <jacob.jun.pan@...ux.intel.com>
Signed-off-by: Sohil Mehta <sohil.mehta@...el.com>
Reviewed-by: Xin Li (Intel) <xin@...or.com>
---
v7: Use an enum to define the NMI-source vectors. (DaveH)
    Add a BUILD_BUG_ON to validate the allocated vector count. (DaveH)
    Add review tag from Xin.

v6: Store source vector unconditionally. (PeterZ)
    Add a warning for unexpected source vector values. (PeterZ)

v5: Move the vector defines to nmi.h.
    Combine vector allocation and registration into one patch.
    Simplify NMI vector names.
    Describe usage of vector 2 for external NMIs.
    Get rid of vector priorities.
---
 arch/x86/events/core.c           |  2 +-
 arch/x86/include/asm/nmi.h       | 46 ++++++++++++++++++++++++++++++++
 arch/x86/kernel/apic/hw_nmi.c    |  2 +-
 arch/x86/kernel/cpu/mce/inject.c |  2 +-
 arch/x86/kernel/kgdb.c           |  2 +-
 arch/x86/kernel/nmi.c            |  7 +++++
 arch/x86/kernel/nmi_selftest.c   |  2 +-
 arch/x86/kernel/smp.c            |  2 +-
 8 files changed, 59 insertions(+), 6 deletions(-)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index ec59837d10d1..dd42fe7bce9c 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -2129,7 +2129,7 @@ static int __init init_hw_perf_events(void)
 		x86_pmu.config_mask = X86_RAW_EVENT_MASK;
 
 	perf_events_lapic_init();
-	register_nmi_handler(NMI_LOCAL, perf_event_nmi_handler, 0, "PMI", NMIS_NO_SOURCE);
+	register_nmi_handler(NMI_LOCAL, perf_event_nmi_handler, 0, "PMI", NMIS_VECTOR_PMI);
 
 	unconstrained = (struct event_constraint)
 		__EVENT_CONSTRAINT(0, x86_pmu.cntr_mask64,
diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h
index 42820c4f59b9..a48958a236fd 100644
--- a/arch/x86/include/asm/nmi.h
+++ b/arch/x86/include/asm/nmi.h
@@ -53,12 +53,58 @@ typedef int (*nmi_handler_t)(unsigned int, struct pt_regs *);
  * origin of an NMI and to route the NMI directly to the appropriate
  * handler.
  *
+ * On CPUs that support NMI-source reporting with FRED, receiving an NMI
+ * with a valid vector sets the corresponding bit in the NMI-source
+ * bitmap. The bitmap is delivered as FRED event data on the stack.
+ *
+ * Multiple NMIs are coalesced in the NMI-source bitmap until the next
+ * NMI delivery. If an NMI is received without a vector or beyond the
+ * defined range, the CPU sets bit 0 of the NMI-source bitmap.
+ *
+ * Third-party chipsets may send NMI messages with a fixed vector of 2.
+ * Using vector 2 for some other purpose would cause confusion between
+ * those external NMI messages and the other purpose. Avoid using it.
+ *
+ * The vectors are in no particular priority order. Add new vector
+ * assignments sequentially in the list below before the COUNT.
+ *
  * @NMIS_NO_SOURCE:        Reserved for undefined or unidentified sources.
+ * @NMIS_VECTOR_TEST:      NMI selftest.
+ * @NMIS_VECTOR_EXTERNAL:  Reserved to match external NMI vector 2.
+ * @NMIS_VECTOR_SMP_STOP:  Panic stop CPU.
+ * @NMIS_VECTOR_BT:        CPU backtrace.
+ * @NMIS_VECTOR_KGDB:      Kernel debugger.
+ * @NMIS_VECTOR_MCE:       MCE injection.
+ * @NMIS_VECTOR_PMI:       PerfMon counters.
+ *
+ * @NMIS_VECTOR_COUNT:     Count of the defined vectors.
  */
 enum nmi_source_vectors {
 	NMIS_NO_SOURCE		= 0,
+	NMIS_VECTOR_TEST,
+	NMIS_VECTOR_EXTERNAL	= 2,
+	NMIS_VECTOR_SMP_STOP,
+	NMIS_VECTOR_BT,
+	NMIS_VECTOR_KGDB,
+	NMIS_VECTOR_MCE,
+	NMIS_VECTOR_PMI,
+
+	NMIS_VECTOR_COUNT
 };
 
+/*
+ * The early (and likely all future) hardware implementations of
+ * NMI-source reporting would only support a 16-bit source bitmap, with
+ * 1-15 being valid source vectors.
+ *
+ * If the hardware ever supports a larger bitmap, the kernel support can
+ * easily be extended to 64 bits by modifying the MAX below. However,
+ * care must be taken to reallocate the latency sensitive NMI sources
+ * within the first 15 vectors. Any source vector beyond the supported
+ * maximum on prior systems would set bit 0 in the NMI-source bitmap.
+ */
+#define NMIS_VECTORS_MAX	16
+
 struct nmiaction {
 	struct list_head	list;
 	nmi_handler_t		handler;
diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c
index d09e771723ed..4e04f13d2de9 100644
--- a/arch/x86/kernel/apic/hw_nmi.c
+++ b/arch/x86/kernel/apic/hw_nmi.c
@@ -53,7 +53,7 @@ NOKPROBE_SYMBOL(nmi_cpu_backtrace_handler);
 
 static int __init register_nmi_cpu_backtrace_handler(void)
 {
-	register_nmi_handler(NMI_LOCAL, nmi_cpu_backtrace_handler, 0, "arch_bt", NMIS_NO_SOURCE);
+	register_nmi_handler(NMI_LOCAL, nmi_cpu_backtrace_handler, 0, "arch_bt", NMIS_VECTOR_BT);
 	return 0;
 }
 early_initcall(register_nmi_cpu_backtrace_handler);
diff --git a/arch/x86/kernel/cpu/mce/inject.c b/arch/x86/kernel/cpu/mce/inject.c
index ba70ef8a1964..320068e01c22 100644
--- a/arch/x86/kernel/cpu/mce/inject.c
+++ b/arch/x86/kernel/cpu/mce/inject.c
@@ -775,7 +775,7 @@ static int __init inject_init(void)
 
 	debugfs_init();
 
-	register_nmi_handler(NMI_LOCAL, mce_raise_notify, 0, "mce_notify", NMIS_NO_SOURCE);
+	register_nmi_handler(NMI_LOCAL, mce_raise_notify, 0, "mce_notify", NMIS_VECTOR_MCE);
 	mce_register_injector_chain(&inject_nb);
 
 	setup_inj_struct(&i_mce);
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index ae28fdeefc7f..dfde434d2992 100644
--- a/arch/x86/kernel/kgdb.c
+++ b/arch/x86/kernel/kgdb.c
@@ -602,7 +602,7 @@ int kgdb_arch_init(void)
 	if (retval)
 		goto out;
 
-	retval = register_nmi_handler(NMI_LOCAL, kgdb_nmi_handler, 0, "kgdb", NMIS_NO_SOURCE);
+	retval = register_nmi_handler(NMI_LOCAL, kgdb_nmi_handler, 0, "kgdb", NMIS_VECTOR_KGDB);
 	if (retval)
 		goto out1;
 
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index be93ec7255bf..8071ad32aa11 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -182,6 +182,13 @@ int __register_nmi_handler(unsigned int type, struct nmiaction *action)
 	if (WARN_ON_ONCE(!action->handler || !list_empty(&action->list)))
 		return -EINVAL;
 
+	/* NMI-source reporting should only be used for NMI_LOCAL */
+	WARN_ON_ONCE((type != NMI_LOCAL) && (action->source_vector != NMIS_NO_SOURCE));
+
+	/* Check for valid vector values. See comment above NMIS_VECTORS_MAX */
+	BUILD_BUG_ON(NMIS_VECTOR_COUNT > NMIS_VECTORS_MAX);
+	WARN_ON_ONCE(action->source_vector >= NMIS_VECTOR_COUNT);
+
 	raw_spin_lock_irqsave(&desc->lock, flags);
 
 	/*
diff --git a/arch/x86/kernel/nmi_selftest.c b/arch/x86/kernel/nmi_selftest.c
index c4fffa868160..f3918888e494 100644
--- a/arch/x86/kernel/nmi_selftest.c
+++ b/arch/x86/kernel/nmi_selftest.c
@@ -64,7 +64,7 @@ static void __init test_nmi_ipi(struct cpumask *mask)
 	unsigned long timeout;
 
 	if (register_nmi_handler(NMI_LOCAL, test_nmi_ipi_callback, NMI_FLAG_FIRST,
-				 "nmi_selftest", NMIS_NO_SOURCE, __initdata)) {
+				 "nmi_selftest", NMIS_VECTOR_TEST, __initdata)) {
 		nmi_fail = FAILURE;
 		return;
 	}
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index c9435730dfb0..1ed065b78467 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -143,7 +143,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_reboot)
 static int register_stop_handler(void)
 {
 	return register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback, NMI_FLAG_FIRST,
-				    "smp_stop", NMIS_NO_SOURCE);
+				    "smp_stop", NMIS_VECTOR_SMP_STOP);
 }
 
 static void native_stop_other_cpus(int wait)
-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ