All of lore.kernel.org
 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 V4 26/30] x86/microcode: Protect against instrumentation
Date: Mon,  2 Oct 2023 14:00:06 +0200 (CEST)	[thread overview]
Message-ID: <20231002115903.545969323@linutronix.de> (raw)
In-Reply-To: 20231002115506.217091296@linutronix.de

From: Thomas Gleixner <tglx@linutronix.de>

The wait for control loop in which the siblings are waiting for the
microcode update on the primary thread must be protected against
instrumentation as instrumentation can end up in #INT3, #DB or #PF, which
then returns with IRET. That IRET reenables NMI which is the opposite of
what the NMI rendezvouz is trying to achieve.

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

---
 arch/x86/kernel/cpu/microcode/core.c |  110 ++++++++++++++++++++++++++---------
 1 file changed, 82 insertions(+), 28 deletions(-)
---
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -301,54 +301,65 @@ struct microcode_ctrl {
 
 DEFINE_STATIC_KEY_FALSE(microcode_nmi_handler_enable);
 static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl);
+static unsigned int loops_per_usec;
 static atomic_t late_cpus_in;
 
-static bool wait_for_cpus(atomic_t *cnt)
+static noinstr bool wait_for_cpus(atomic_t *cnt)
 {
-	unsigned int timeout;
+	unsigned int timeout, loops;
 
-	WARN_ON_ONCE(atomic_dec_return(cnt) < 0);
+	WARN_ON_ONCE(raw_atomic_dec_return(cnt) < 0);
 
 	for (timeout = 0; timeout < USEC_PER_SEC; timeout++) {
-		if (!atomic_read(cnt))
+		if (!raw_atomic_read(cnt))
 			return true;
 
-		udelay(1);
+		for (loops = 0; loops < loops_per_usec; loops++)
+			cpu_relax();
 
 		/* If invoked directly, tickle the NMI watchdog */
-		if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC))
+		if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) {
+			instrumentation_begin();
 			touch_nmi_watchdog();
+			instrumentation_end();
+		}
 	}
 	/* Prevent the late comers from making progress and let them time out */
-	atomic_inc(cnt);
+	raw_atomic_inc(cnt);
 	return false;
 }
 
-static bool wait_for_ctrl(void)
+static noinstr bool wait_for_ctrl(void)
 {
-	unsigned int timeout;
+	unsigned int timeout, loops;
 
 	for (timeout = 0; timeout < USEC_PER_SEC; timeout++) {
-		if (this_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT)
+		if (raw_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT)
 			return true;
-		udelay(1);
+
+		for (loops = 0; loops < loops_per_usec; loops++)
+			cpu_relax();
+
 		/* If invoked directly, tickle the NMI watchdog */
-		if (!microcode_ops->use_nmi && !(timeout % 1000))
+		if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) {
+			instrumentation_begin();
 			touch_nmi_watchdog();
+			instrumentation_end();
+		}
 	}
 	return false;
 }
 
-static void load_secondary(unsigned int cpu)
+/*
+ * Protected against instrumentation up to the point where the primary
+ * thread completed the update. See microcode_nmi_handler() for details.
+ */
+static noinstr bool load_secondary_wait(unsigned int ctrl_cpu)
 {
-	unsigned int ctrl_cpu = this_cpu_read(ucode_ctrl.ctrl_cpu);
-	enum ucode_state ret;
-
 	/* Initial rendezvouz to ensure that all CPUs have arrived */
 	if (!wait_for_cpus(&late_cpus_in)) {
-		pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1);
-		this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT);
-		return;
+		raw_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT);
+		return false;
 	}
 
 	/*
@@ -358,9 +369,33 @@ static void load_secondary(unsigned int
 	 * scheduler, watchdogs etc. There is no way to safely evacuate the
 	 * machine.
 	 */
-	if (!wait_for_ctrl())
-		panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu);
+	if (wait_for_ctrl())
+		return true;
+
+	instrumentation_begin();
+	panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu);
+	instrumentation_end();
+}
 
+/*
+ * Protected against instrumentation up to the point where the primary
+ * thread completed the update. See microcode_nmi_handler() for details.
+ */
+static noinstr void load_secondary(unsigned int cpu)
+{
+	unsigned int ctrl_cpu = raw_cpu_read(ucode_ctrl.ctrl_cpu);
+	enum ucode_state ret;
+
+	if (!load_secondary_wait(ctrl_cpu)) {
+		instrumentation_begin();
+		pr_err_once("Microcode load: %d CPUs timed out\n",
+			    atomic_read(&late_cpus_in) - 1);
+		instrumentation_end();
+		return;
+	}
+
+	/* Primary thread completed. Allow to invoke instrumentable code */
+	instrumentation_begin();
 	/*
 	 * If the primary succeeded then invoke the apply() callback,
 	 * otherwise copy the state from the primary thread.
@@ -372,6 +407,7 @@ static void load_secondary(unsigned int
 
 	this_cpu_write(ucode_ctrl.result, ret);
 	this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE);
+	instrumentation_end();
 }
 
 static void load_primary(unsigned int cpu)
@@ -409,25 +445,42 @@ static void load_primary(unsigned int cp
 	}
 }
 
-static bool microcode_update_handler(void)
+static noinstr bool microcode_update_handler(void)
 {
-	unsigned int cpu = smp_processor_id();
+	unsigned int cpu = raw_smp_processor_id();
 
-	if (this_cpu_read(ucode_ctrl.ctrl_cpu) == cpu)
+	if (raw_cpu_read(ucode_ctrl.ctrl_cpu) == cpu) {
+		instrumentation_begin();
 		load_primary(cpu);
-	else
+		instrumentation_end();
+	} else {
 		load_secondary(cpu);
+	}
 
+	instrumentation_begin();
 	touch_nmi_watchdog();
+	instrumentation_end();
 	return true;
 }
 
-bool microcode_nmi_handler(void)
+/*
+ * Protection against instrumentation is required for CPUs which are not
+ * safe against an NMI which is delivered to the secondary SMT sibling
+ * while the primary thread updates the microcode. Instrumentation can end
+ * up in #INT3, #DB and #PF. The IRET from those exceptions reenables NMI
+ * which is the opposite of what the NMI rendevouz is trying to achieve.
+ *
+ * The primary thread is safe versus instrumentation as the actual
+ * microcode update handles this correctly. It's only the sibling code
+ * path which must be NMI safe until the primary thread completed the
+ * update.
+ */
+bool noinstr microcode_nmi_handler(void)
 {
-	if (!this_cpu_read(ucode_ctrl.nmi_enabled))
+	if (!raw_cpu_read(ucode_ctrl.nmi_enabled))
 		return false;
 
-	this_cpu_write(ucode_ctrl.nmi_enabled, false);
+	raw_cpu_write(ucode_ctrl.nmi_enabled, false);
 	return microcode_update_handler();
 }
 
@@ -454,6 +507,7 @@ static int load_late_stop_cpus(void)
 	pr_err("You should switch to early loading, if possible.\n");
 
 	atomic_set(&late_cpus_in, num_online_cpus());
+	loops_per_usec = loops_per_jiffy / (TICK_NSEC / 1000);
 
 	/*
 	 * Take a snapshot before the microcode update in order to compare and


  parent reply	other threads:[~2023-10-02 12:01 UTC|newest]

Thread overview: 102+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-02 11:59 [patch V4 00/30] x86/microcode: Cleanup and late loading enhancements Thomas Gleixner
2023-10-02 11:59 ` [patch V4 01/30] x86/microcode/32: Move early loading after paging enable Thomas Gleixner
2023-10-02 11:59 ` [patch V4 02/30] x86/boot/32: Disable stackprotector and tracing for mk_early_pgtbl_32() Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:38   ` tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 03/30] x86/microcode/intel: Rip out mixed stepping support for Intel CPUs Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Ashok Raj
2023-10-02 11:59 ` [patch V4 04/30] x86/microcode/intel: Simplify scan_microcode() Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:38   ` tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 05/30] x86/microcode/intel: Simplify and rename generic_load_microcode() Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:38   ` tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 06/30] x86/microcode/intel: Cleanup code further Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:38   ` tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 07/30] x86/microcode/intel: Simplify early loading Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 08/30] x86/microcode/intel: Save the microcode only after a successful late-load Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:21   ` tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 09/30] x86/microcode/intel: Switch to kvmalloc() Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:21   ` tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 10/30] x86/microcode/intel: Unify microcode apply() functions Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 11/30] x86/microcode/intel: Rework intel_cpu_collect_info() Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 12/30] x86/microcode/intel: Reuse intel_cpu_collect_info() Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:21   ` tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 13/30] x86/microcode/intel: Rework intel_find_matching_signature() Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:21   ` tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 14/30] x86/microcode/amd: Read revision from hardware in collect_cpu_info_amd() Thomas Gleixner
2023-10-04  8:32   ` Borislav Petkov
2023-10-02 11:59 ` [patch V4 15/30] x86/microcode: Remove pointless apply() invocation Thomas Gleixner
2023-10-06 13:26   ` Borislav Petkov
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 16/30] x86/microcode: Get rid of the schedule work indirection Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 17/30] x86/microcode: Clean up mc_cpu_down_prep() Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:20   ` tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 18/30] x86/microcode: Handle "nosmt" correctly Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:20   ` tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 19/30] x86/microcode: Clarify the late load logic Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:20   ` tip-bot2 for Thomas Gleixner
2023-10-02 11:59 ` [patch V4 20/30] x86/microcode: Sanitize __wait_for_cpus() Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:20   ` tip-bot2 for Thomas Gleixner
2023-10-02 12:00 ` [patch V4 21/30] x86/microcode: Add per CPU result state Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-02 12:00 ` [patch V4 22/30] x86/microcode: Add per CPU control field Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:20   ` tip-bot2 for Thomas Gleixner
2023-10-02 12:00 ` [patch V4 23/30] x86/microcode: Provide new control functions Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:20   ` tip-bot2 for Thomas Gleixner
2023-10-02 12:00 ` [patch V4 24/30] x86/microcode: Replace the all in one rendevouz handler Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] x86/microcode: Replace the all-in-one rendevous handler tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:20   ` tip-bot2 for Thomas Gleixner
2023-10-02 12:00 ` [patch V4 25/30] x86/microcode: Rendezvous and load in NMI Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:20   ` tip-bot2 for Thomas Gleixner
2023-10-02 12:00 ` Thomas Gleixner [this message]
2023-10-09 12:29   ` [tip: x86/microcode] x86/microcode: Protect against instrumentation tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:20   ` tip-bot2 for Thomas Gleixner
2023-10-02 12:00 ` [patch V4 27/30] x86/apic: Provide apic_force_nmi_on_cpu() Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:20   ` tip-bot2 for Thomas Gleixner
2023-10-02 12:00 ` [patch V4 28/30] x86/microcode: Handle "offline" CPUs correctly Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-20 11:37   ` tip-bot2 for Thomas Gleixner
2023-10-24 13:20   ` tip-bot2 for Thomas Gleixner
2023-10-02 12:00 ` [patch V4 29/30] x86/microcode: Prepare for minimal revision check Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-02 12:00 ` [patch V4 30/30] x86/microcode/intel: Add a minimum required revision for late-loads Thomas Gleixner
2023-10-09 12:29   ` [tip: x86/microcode] x86/microcode/intel: Add a minimum required revision for late loading tip-bot2 for Ashok Raj
2023-10-20 11:37   ` tip-bot2 for Ashok Raj
2023-10-24 13:20   ` tip-bot2 for Ashok Raj
2023-10-08  8:54 ` [patch V4 00/30] x86/microcode: Cleanup and late loading enhancements Qiuxu Zhuo
2023-10-08 13:08   ` Borislav Petkov
2023-10-09  5:03     ` Zhuo, Qiuxu
2023-10-10  8:00     ` Zhuo, Qiuxu
2023-10-10  8:11       ` 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=20231002115903.545969323@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.