summaryrefslogtreecommitdiff
path: root/arch/x86/kernel/cpu/microcode/core.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2023-10-17 23:24:16 +0200
committerBorislav Petkov (AMD) <bp@alien8.de>2023-10-24 15:05:55 +0200
commit9407bda845dd19756e276d4f3abc15a20777ba45 (patch)
tree6bde9bdf4bacb4aedc78fbca49dad5dd0ed184e7 /arch/x86/kernel/cpu/microcode/core.c
parent8f849ff63bcbc77670da03cb8f2b78b06257f455 (diff)
x86/microcode: Prepare for minimal revision check
Applying microcode late can be fatal for the running kernel when the update changes functionality which is in use already in a non-compatible way, e.g. by removing a CPUID bit. There is no way for admins which do not have access to the vendors deep technical support to decide whether late loading of such a microcode is safe or not. Intel has added a new field to the microcode header which tells the minimal microcode revision which is required to be active in the CPU in order to be safe. Provide infrastructure for handling this in the core code and a command line switch which allows to enforce it. If the update is considered safe the kernel is not tainted and the annoying warning message not emitted. If it's enforced and the currently loaded microcode revision is not safe for late loading then the load is aborted. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Link: https://lore.kernel.org/r/20231017211724.079611170@linutronix.de
Diffstat (limited to 'arch/x86/kernel/cpu/microcode/core.c')
-rw-r--r--arch/x86/kernel/cpu/microcode/core.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 718d6487a433..666d25bbc5ad 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -46,6 +46,9 @@
static struct microcode_ops *microcode_ops;
bool dis_ucode_ldr = true;
+bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV);
+module_param(force_minrev, bool, S_IRUSR | S_IWUSR);
+
/*
* Synchronization.
*
@@ -531,15 +534,17 @@ static int load_cpus_stopped(void *unused)
return 0;
}
-static int load_late_stop_cpus(void)
+static int load_late_stop_cpus(bool is_safe)
{
unsigned int cpu, updated = 0, failed = 0, timedout = 0, siblings = 0;
unsigned int nr_offl, offline = 0;
int old_rev = boot_cpu_data.microcode;
struct cpuinfo_x86 prev_info;
- pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n");
- pr_err("You should switch to early loading, if possible.\n");
+ if (!is_safe) {
+ pr_err("Late microcode loading without minimal revision check.\n");
+ pr_err("You should switch to early loading, if possible.\n");
+ }
atomic_set(&late_cpus_in, num_online_cpus());
atomic_set(&offline_in_nmi, 0);
@@ -589,7 +594,9 @@ static int load_late_stop_cpus(void)
return -EIO;
}
- add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
+ if (!is_safe || failed || timedout)
+ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
+
pr_info("load: updated on %u primary CPUs with %u siblings\n", updated, siblings);
if (failed || timedout) {
pr_err("load incomplete. %u CPUs timed out or failed\n",
@@ -679,7 +686,9 @@ static int load_late_locked(void)
switch (microcode_ops->request_microcode_fw(0, &microcode_pdev->dev)) {
case UCODE_NEW:
- return load_late_stop_cpus();
+ return load_late_stop_cpus(false);
+ case UCODE_NEW_SAFE:
+ return load_late_stop_cpus(true);
case UCODE_NFOUND:
return -ENOENT;
default: