From: Thomas Gleixner <tglx@linutronix.de>
To: LKML <linux-kernel@vger.kernel.org>
Cc: x86@kernel.org, Borislav Petkov <bp@alien8.de>
Subject: [patch V5 35/39] x86/microcode: Protect against instrumentation
Date: Tue, 17 Oct 2023 23:24:12 +0200 (CEST) [thread overview]
Message-ID: <20231017211723.912645011@linutronix.de> (raw)
In-Reply-To: 20231017200758.877560658@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 rendezvous is trying to achieve.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/kernel/cpu/microcode/core.c | 111 ++++++++++++++++++++++++++---------
1 file changed, 83 insertions(+), 28 deletions(-)
---
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -272,54 +272,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 rendezvous 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;
}
/*
@@ -329,9 +340,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("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.
@@ -343,6 +378,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)
@@ -380,25 +416,43 @@ 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 rendezvous 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();
}
@@ -425,6 +479,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
next prev parent reply other threads:[~2023-10-17 21:26 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-17 21:23 [patch V5 00/39] x86/microcode: Cleanup and late loading enhancements Thomas Gleixner
2023-10-17 21:23 ` [patch V5 01/39] x86/boot/32: Disable stackprotector and tracing for mk_early_pgtbl_32() Thomas Gleixner
2023-10-17 21:23 ` [patch V5 02/39] x86/boot: Use __pa_nodebug() in mk_early_pgtbl_32() Thomas Gleixner
2023-10-20 11:38 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 03/39] x86/boot/32: De-uglify the 2/3 level paging difference " Thomas Gleixner
2023-10-18 10:00 ` Borislav Petkov
2023-10-18 13:20 ` Thomas Gleixner
2023-10-18 16:28 ` Borislav Petkov
2023-10-20 11:38 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 04/39] x86/boot/32: Restructure mk_early_pgtbl_32() Thomas Gleixner
2023-10-20 11:38 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 05/39] x86/microcode: Provide CONFIG_MICROCODE_INITRD32 Thomas Gleixner
2023-10-20 11:38 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 06/39] x86/boot/32: Temporarily map initrd for microcode loading Thomas Gleixner
2023-10-20 11:38 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 07/39] x86/microcode/32: Move early loading after paging enable Thomas Gleixner
2023-10-20 11:38 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 08/39] x86/microcode/intel: Rip out mixed stepping support for Intel CPUs Thomas Gleixner
2023-10-20 11:38 ` [tip: x86/microcode] " tip-bot2 for Ashok Raj
2023-10-17 21:23 ` [patch V5 09/39] x86/microcode/intel: Simplify scan_microcode() Thomas Gleixner
2023-10-17 21:23 ` [patch V5 10/39] x86/microcode/intel: Simplify and rename generic_load_microcode() Thomas Gleixner
2023-10-17 21:23 ` [patch V5 11/39] x86/microcode/intel: Cleanup code further Thomas Gleixner
2023-10-17 21:23 ` [patch V5 12/39] x86/microcode/intel: Simplify early loading Thomas Gleixner
2023-10-20 11:38 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-24 13:21 ` tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 13/39] x86/microcode/intel: Save the microcode only after a successful late-load Thomas Gleixner
2023-10-17 21:23 ` [patch V5 14/39] x86/microcode/intel: Switch to kvmalloc() Thomas Gleixner
2023-10-17 21:23 ` [patch V5 15/39] x86/microcode/intel: Unify microcode apply() functions Thomas Gleixner
2023-10-20 11:37 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-24 13:21 ` tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 16/39] x86/microcode/intel: Rework intel_cpu_collect_info() Thomas Gleixner
2023-10-20 11:37 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-24 13:21 ` tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 17/39] x86/microcode/intel: Reuse intel_cpu_collect_info() Thomas Gleixner
2023-10-17 21:23 ` [patch V5 18/39] x86/microcode/intel: Rework intel_find_matching_signature() Thomas Gleixner
2023-10-17 21:23 ` [patch V5 19/39] x86/microcode: Remove pointless apply() invocation Thomas Gleixner
2023-10-20 11:37 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-24 13:21 ` tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 20/39] x86/microcode/amd: Use correct per CPU ucode_cpu_info Thomas Gleixner
2023-10-17 21:23 ` [patch V5 21/39] x86/microcode/amd: Cache builtin microcode too Thomas Gleixner
2023-10-17 21:23 ` [patch V5 22/39] x86/microcode/amd: Cache builtin/initrd microcode early Thomas Gleixner
2023-10-20 11:37 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-24 13:21 ` tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 23/39] x86/microcode/amd: Use cached microcode for AP load Thomas Gleixner
2023-10-20 11:37 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-24 13:21 ` tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 24/39] x86/microcode: Mop up early loading leftovers Thomas Gleixner
2023-10-20 11:37 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-24 13:20 ` tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 25/39] x86/microcode: Get rid of the schedule work indirection Thomas Gleixner
2023-10-20 11:37 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-24 13:20 ` tip-bot2 for Thomas Gleixner
2023-10-17 21:23 ` [patch V5 26/39] x86/microcode: Clean up mc_cpu_down_prep() Thomas Gleixner
2023-10-17 21:24 ` [patch V5 27/39] x86/microcode: Handle "nosmt" correctly Thomas Gleixner
2023-10-17 21:24 ` [patch V5 28/39] x86/microcode: Clarify the late load logic Thomas Gleixner
2023-10-17 21:24 ` [patch V5 29/39] x86/microcode: Sanitize __wait_for_cpus() Thomas Gleixner
2023-10-17 21:24 ` [patch V5 30/39] x86/microcode: Add per CPU result state Thomas Gleixner
2023-10-20 11:37 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-24 13:20 ` tip-bot2 for Thomas Gleixner
2023-10-17 21:24 ` [patch V5 31/39] x86/microcode: Add per CPU control field Thomas Gleixner
2023-10-17 21:24 ` [patch V5 32/39] x86/microcode: Provide new control functions Thomas Gleixner
2023-10-17 21:24 ` [patch V5 33/39] x86/microcode: Replace the all-in-one rendevous handler Thomas Gleixner
2023-10-17 21:24 ` [patch V5 34/39] x86/microcode: Rendezvous and load in NMI Thomas Gleixner
2023-10-17 21:24 ` Thomas Gleixner [this message]
2023-10-17 21:24 ` [patch V5 36/39] x86/apic: Provide apic_force_nmi_on_cpu() Thomas Gleixner
2023-10-17 21:24 ` [patch V5 37/39] x86/microcode: Handle "offline" CPUs correctly Thomas Gleixner
2023-10-17 21:24 ` [patch V5 38/39] x86/microcode: Prepare for minimal revision check Thomas Gleixner
2023-10-20 11:37 ` [tip: x86/microcode] " tip-bot2 for Thomas Gleixner
2023-10-24 13:20 ` tip-bot2 for Thomas Gleixner
2023-10-17 21:24 ` [patch V5 39/39] x86/microcode/intel: Add a minimum required revision for late loading Thomas Gleixner
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=20231017211723.912645011@linutronix.de \
--to=tglx@linutronix.de \
--cc=bp@alien8.de \
--cc=linux-kernel@vger.kernel.org \
--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