mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de>
To: LKML <linux-kernel@vger.kernel.org>
Cc: x86@kernel.org, Borislav Petkov <bp@alien8.de>,
	"Chang S. Bae" <chang.seok.bae@intel.com>,
	Arjan van de Ven <arjan@linux.intel.com>,
	Nikolay Borisov <nik.borisov@suse.com>
Subject: [patch V3 25/30] x86/microcode: Rendezvous and load in NMI
Date: Tue, 12 Sep 2023 09:58:23 +0200 (CEST)	[thread overview]
Message-ID: <20230912065502.327149876@linutronix.de> (raw)
In-Reply-To: <20230912065249.695681286@linutronix.de>

From: Thomas Gleixner <tglx@linutronix.de>

stop_machine() does not prevent the spin-waiting sibling from handling an
NMI, which is obviously violating the whole concept of rendezvous.

Implement a static branch right in the beginning of the NMI handler which
is NOOPed except when enabled by the late loading mechanism.

The later loader enables the static branch before stop_machine() is
invoked. Each CPU has an nmi_enable in its control structure which
indicates whether the CPU should go into the update routine.

This is required to bridge the gap between enabling the branch and actually
being at the point where it makes sense.

Each CPU which arrives in the stopper thread function sets that flag and
issues a self NMI right after that. If the NMI function sees the flag
clear, it returns. If it's set it clears the flag and enters the rendezvous.

This is safe against a real NMI which hits in between setting the flag and
sending the NMI to itself. The real NMI will be swallowed by the microcode
update and the self NMI will then let stuff continue. Otherwise this would
end up with a spurious NMI.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

---
 arch/x86/include/asm/microcode.h         |   12 ++++++++
 arch/x86/kernel/cpu/microcode/core.c     |   42 ++++++++++++++++++++++++++++---
 arch/x86/kernel/cpu/microcode/intel.c    |    1 
 arch/x86/kernel/cpu/microcode/internal.h |    3 +-
 arch/x86/kernel/nmi.c                    |    4 ++
 5 files changed, 57 insertions(+), 5 deletions(-)
---
--- a/arch/x86/include/asm/microcode.h
+++ b/arch/x86/include/asm/microcode.h
@@ -70,4 +70,16 @@ static inline u32 intel_get_microcode_re
 }
 #endif /* !CONFIG_CPU_SUP_INTEL */
 
+bool microcode_nmi_handler(void);
+
+#ifdef CONFIG_MICROCODE_LATE_LOADING
+DECLARE_STATIC_KEY_FALSE(microcode_nmi_handler_enable);
+static __always_inline bool microcode_nmi_handler_enabled(void)
+{
+	return static_branch_unlikely(&microcode_nmi_handler_enable);
+}
+#else
+static __always_inline bool microcode_nmi_handler_enabled(void) { return false; }
+#endif
+
 #endif /* _ASM_X86_MICROCODE_H */
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -23,6 +23,7 @@
 #include <linux/miscdevice.h>
 #include <linux/capability.h>
 #include <linux/firmware.h>
+#include <linux/cpumask.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
@@ -31,6 +32,7 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 
+#include <asm/apic.h>
 #include <asm/cpu_device_id.h>
 #include <asm/perf_event.h>
 #include <asm/processor.h>
@@ -312,8 +314,10 @@ struct ucode_ctrl {
 	enum sibling_ctrl	ctrl;
 	enum ucode_state	result;
 	unsigned int		ctrl_cpu;
+	bool			nmi_enabled;
 };
 
+DEFINE_STATIC_KEY_FALSE(microcode_nmi_handler_enable);
 static DEFINE_PER_CPU(struct ucode_ctrl, ucode_ctrl);
 static atomic_t late_cpus_in;
 
@@ -327,7 +331,8 @@ static bool wait_for_cpus(atomic_t *cnt)
 		if (!atomic_read(cnt))
 			return true;
 		udelay(1);
-		if (!(timeout % 1000))
+		/* If invoked directly, tickle the NMI watchdog */
+		if (!microcode_ops->use_nmi && !(timeout % 1000))
 			touch_nmi_watchdog();
 	}
 	/* Prevent the late comers to make progress and let them time out */
@@ -343,7 +348,8 @@ static bool wait_for_ctrl(void)
 		if (this_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT)
 			return true;
 		udelay(1);
-		if (!(timeout % 1000))
+		/* If invoked directly, tickle the NMI watchdog */
+		if (!microcode_ops->use_nmi && !(timeout % 1000))
 			touch_nmi_watchdog();
 	}
 	return false;
@@ -421,7 +427,7 @@ static void ucode_load_primary(unsigned
 	}
 }
 
-static int ucode_load_cpus_stopped(void *unused)
+static bool microcode_update_handler(void)
 {
 	unsigned int cpu = smp_processor_id();
 
@@ -430,7 +436,29 @@ static int ucode_load_cpus_stopped(void
 	else
 		ucode_load_secondary(cpu);
 
-	/* No point to wait here. The CPUs will all wait in stop_machine(). */
+	touch_nmi_watchdog();
+	return true;
+}
+
+bool microcode_nmi_handler(void)
+{
+	if (!this_cpu_read(ucode_ctrl.nmi_enabled))
+		return false;
+
+	this_cpu_write(ucode_ctrl.nmi_enabled, false);
+	return microcode_update_handler();
+}
+
+static int ucode_load_cpus_stopped(void *unused)
+{
+	if (microcode_ops->use_nmi) {
+		/* Enable the NMI handler and raise NMI */
+		this_cpu_write(ucode_ctrl.nmi_enabled, true);
+		apic->send_IPI(smp_processor_id(), NMI_VECTOR);
+	} else {
+		/* Just invoke the handler directly */
+		microcode_update_handler();
+	}
 	return 0;
 }
 
@@ -451,8 +479,14 @@ static int ucode_load_late_stop_cpus(voi
 	 */
 	store_cpu_caps(&prev_info);
 
+	if (microcode_ops->use_nmi)
+		static_branch_enable_cpuslocked(&microcode_nmi_handler_enable);
+
 	stop_machine_cpuslocked(ucode_load_cpus_stopped, NULL, cpu_online_mask);
 
+	if (microcode_ops->use_nmi)
+		static_branch_disable_cpuslocked(&microcode_nmi_handler_enable);
+
 	/* Analyze the results */
 	for_each_cpu_and(cpu, cpu_present_mask, &cpus_booted_once_mask) {
 		switch (per_cpu(ucode_ctrl.result, cpu)) {
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -601,6 +601,7 @@ static struct microcode_ops microcode_in
 	.collect_cpu_info	= collect_cpu_info,
 	.apply_microcode	= apply_microcode_late,
 	.finalize_late_load	= finalize_late_load,
+	.use_nmi		= IS_ENABLED(CONFIG_X86_64),
 };
 
 static __init void calc_llc_size_per_core(struct cpuinfo_x86 *c)
--- a/arch/x86/kernel/cpu/microcode/internal.h
+++ b/arch/x86/kernel/cpu/microcode/internal.h
@@ -31,7 +31,8 @@ struct microcode_ops {
 	enum ucode_state	(*apply_microcode)(int cpu);
 	int			(*collect_cpu_info)(int cpu, struct cpu_signature *csig);
 	void			(*finalize_late_load)(int result);
-	unsigned int		nmi_safe	: 1;
+	unsigned int		nmi_safe	: 1,
+				use_nmi		: 1;
 };
 
 extern struct ucode_cpu_info ucode_cpu_info[];
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -33,6 +33,7 @@
 #include <asm/reboot.h>
 #include <asm/cache.h>
 #include <asm/nospec-branch.h>
+#include <asm/microcode.h>
 #include <asm/sev.h>
 
 #define CREATE_TRACE_POINTS
@@ -343,6 +344,9 @@ static noinstr void default_do_nmi(struc
 
 	instrumentation_begin();
 
+	if (microcode_nmi_handler_enabled() && microcode_nmi_handler())
+		goto out;
+
 	handled = nmi_handle(NMI_LOCAL, regs);
 	__this_cpu_add(nmi_stats.normal, handled);
 	if (handled) {


  parent reply	other threads:[~2023-09-12  8:00 UTC|newest]

Thread overview: 71+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-09-12  7:57 [patch V3 00/30] x86/microcode: Cleanup and late loading enhancements Thomas Gleixner
2023-09-12  7:57 ` [patch V3 01/30] x86/microcode/32: Move early loading after paging enable Thomas Gleixner
2023-09-13 15:06   ` Borislav Petkov
2023-09-16  9:03   ` Chang S. Bae
2023-09-17 19:17     ` Thomas Gleixner
2023-09-19 14:54       ` [patch V3a " Thomas Gleixner
2023-09-12  7:57 ` [patch V3 02/30] x86/boot/32: Disable stackprotector and tracing for mk_early_pgtbl_32() Thomas Gleixner
2023-09-18 17:12   ` Borislav Petkov
2023-09-12  7:57 ` [patch V3 03/30] x86/microcode/intel: Rip out mixed stepping support for Intel CPUs Thomas Gleixner
2023-09-25 15:19   ` Qiuxu Zhuo
2023-09-12  7:57 ` [patch V3 04/30] x86/microcode/intel: Simplify scan_microcode() Thomas Gleixner
2023-09-19 12:52   ` Borislav Petkov
2023-09-12  7:57 ` [patch V3 05/30] x86/microcode/intel: Simplify and rename generic_load_microcode() Thomas Gleixner
2023-09-12  7:57 ` [patch V3 06/30] x86/microcode/intel: Cleanup code further Thomas Gleixner
2023-09-19 14:13   ` Borislav Petkov
2023-09-12  7:57 ` [patch V3 07/30] x86/microcode/intel: Simplify early loading Thomas Gleixner
2023-09-19 14:32   ` Borislav Petkov
2023-09-19 14:57     ` Thomas Gleixner
2023-09-19 17:35       ` Thomas Gleixner
2023-09-12  7:57 ` [patch V3 08/30] x86/microcode/intel: Save the microcode only after a successful late-load Thomas Gleixner
2023-09-20 14:39   ` Borislav Petkov
2023-09-25 15:30   ` Subject: " Qiuxu Zhuo
2023-09-12  7:57 ` [patch V3 09/30] x86/microcode/intel: Switch to kvmalloc() Thomas Gleixner
2023-09-25 15:43   ` Subject: " Qiuxu Zhuo
2023-09-12  7:57 ` [patch V3 10/30] x86/microcode/intel: Unify microcode apply() functions Thomas Gleixner
2023-09-21 10:07   ` Borislav Petkov
2023-09-12  7:58 ` [patch V3 11/30] x86/microcode/intel: Rework intel_cpu_collect_info() Thomas Gleixner
2023-09-12  7:58 ` [patch V3 12/30] x86/microcode/intel: Reuse intel_cpu_collect_info() Thomas Gleixner
2023-09-21 10:42   ` Borislav Petkov
2023-09-25 10:47     ` Thomas Gleixner
2023-10-03 14:14       ` Borislav Petkov
2023-10-03 14:23         ` Borislav Petkov
2023-09-12  7:58 ` [patch V3 13/30] x86/microcode/intel: Rework intel_find_matching_signature() Thomas Gleixner
2023-09-12  7:58 ` [patch V3 14/30] x86/microcode/amd: Read revision from hardware in collect_cpu_info_amd() Thomas Gleixner
2023-09-12  7:58 ` [patch V3 15/30] x86/microcode: Remove pointless apply() invocation Thomas Gleixner
2023-09-12  7:58 ` [patch V3 16/30] x86/microcode: Get rid of the schedule work indirection Thomas Gleixner
2023-09-12  7:58 ` [patch V3 17/30] x86/microcode: Clean up mc_cpu_down_prep() Thomas Gleixner
2023-09-12  7:58 ` [patch V3 18/30] x86/microcode: Handle "nosmt" correctly Thomas Gleixner
2023-09-22 13:42   ` Borislav Petkov
2023-09-12  7:58 ` [patch V3 19/30] x86/microcode: Clarify the late load logic Thomas Gleixner
2023-09-22 15:59   ` Borislav Petkov
2023-09-12  7:58 ` [patch V3 20/30] x86/microcode: Sanitize __wait_for_cpus() Thomas Gleixner
2023-09-22 16:24   ` Borislav Petkov
2023-09-26  8:51     ` Thomas Gleixner
2023-09-27  7:56       ` Borislav Petkov
2023-09-12  7:58 ` [patch V3 21/30] x86/microcode: Add per CPU result state Thomas Gleixner
2023-09-24  6:29   ` Borislav Petkov
2023-09-26  9:09     ` Thomas Gleixner
2023-09-27 11:28       ` Borislav Petkov
2023-09-12  7:58 ` [patch V3 22/30] x86/microcode: Add per CPU control field Thomas Gleixner
2023-09-24  6:47   ` Borislav Petkov
2023-09-12  7:58 ` [patch V3 23/30] x86/microcode: Provide new control functions Thomas Gleixner
2023-09-24  6:58   ` Borislav Petkov
2023-09-26  9:42     ` Thomas Gleixner
2023-09-27 11:50       ` Borislav Petkov
2023-09-12  7:58 ` [patch V3 24/30] x86/microcode: Replace the all in one rendevouz handler Thomas Gleixner
2023-09-27 16:47   ` Borislav Petkov
2023-09-12  7:58 ` Thomas Gleixner [this message]
2023-09-27 17:17   ` [patch V3 25/30] x86/microcode: Rendezvous and load in NMI Borislav Petkov
2023-09-28  9:33     ` Thomas Gleixner
2023-09-12  7:58 ` [patch V3 26/30] x86/microcode: Protect against instrumentation Thomas Gleixner
2023-09-28 10:52   ` Borislav Petkov
2023-09-12  7:58 ` [patch V3 27/30] x86/apic: Provide apic_force_nmi_on_cpu() Thomas Gleixner
2023-09-12  7:58 ` [patch V3 28/30] x86/microcode: Handle "offline" CPUs correctly Thomas Gleixner
2023-09-12  7:58 ` [patch V3 29/30] x86/microcode: Prepare for minimal revision check Thomas Gleixner
2023-09-28 11:47   ` Borislav Petkov
2023-10-02  9:42     ` Thomas Gleixner
2023-09-12  7:58 ` [patch V3 30/30] x86/microcode/intel: Add a minimum required revision for late-loads Thomas Gleixner
2023-09-25 16:20   ` Qiuxu Zhuo
2023-09-25 17:02 ` [patch V3 00/30] x86/microcode: Cleanup and late loading enhancements Qiuxu Zhuo
2023-09-28 12:00 ` Borislav Petkov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230912065502.327149876@linutronix.de \
    --to=tglx@linutronix.de \
    --cc=arjan@linux.intel.com \
    --cc=bp@alien8.de \
    --cc=chang.seok.bae@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nik.borisov@suse.com \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome