Skip to content

Commit 9407bda

Browse files
KAGA-KOKObp3tk0v
authored andcommitted
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 <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 8f849ff commit 9407bda

File tree

6 files changed

+49
-6
lines changed

6 files changed

+49
-6
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3275,6 +3275,11 @@
32753275

32763276
mga= [HW,DRM]
32773277

3278+
microcode.force_minrev= [X86]
3279+
Format: <bool>
3280+
Enable or disable the microcode minimal revision
3281+
enforcement for the runtime microcode loader.
3282+
32783283
min_addr=nn[KMG] [KNL,BOOT,IA-64] All physical memory below this
32793284
physical address is ignored.
32803285

arch/x86/Kconfig

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,28 @@ config MICROCODE_LATE_LOADING
13261326
is a tricky business and should be avoided if possible. Just the sequence
13271327
of synchronizing all cores and SMT threads is one fragile dance which does
13281328
not guarantee that cores might not softlock after the loading. Therefore,
1329-
use this at your own risk. Late loading taints the kernel too.
1329+
use this at your own risk. Late loading taints the kernel unless the
1330+
microcode header indicates that it is safe for late loading via the
1331+
minimal revision check. This minimal revision check can be enforced on
1332+
the kernel command line with "microcode.minrev=Y".
1333+
1334+
config MICROCODE_LATE_FORCE_MINREV
1335+
bool "Enforce late microcode loading minimal revision check"
1336+
default n
1337+
depends on MICROCODE_LATE_LOADING
1338+
help
1339+
To prevent that users load microcode late which modifies already
1340+
in use features, newer microcode patches have a minimum revision field
1341+
in the microcode header, which tells the kernel which minimum
1342+
revision must be active in the CPU to safely load that new microcode
1343+
late into the running system. If disabled the check will not
1344+
be enforced but the kernel will be tainted when the minimal
1345+
revision check fails.
1346+
1347+
This minimal revision check can also be controlled via the
1348+
"microcode.minrev" parameter on the kernel command line.
1349+
1350+
If unsure say Y.
13301351

13311352
config X86_MSR
13321353
tristate "/dev/cpu/*/msr - Model-specific register support"

arch/x86/kernel/cpu/microcode/amd.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,9 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device)
888888
enum ucode_state ret = UCODE_NFOUND;
889889
const struct firmware *fw;
890890

891+
if (force_minrev)
892+
return UCODE_NFOUND;
893+
891894
if (c->x86 >= 0x15)
892895
snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
893896

arch/x86/kernel/cpu/microcode/core.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@
4646
static struct microcode_ops *microcode_ops;
4747
bool dis_ucode_ldr = true;
4848

49+
bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV);
50+
module_param(force_minrev, bool, S_IRUSR | S_IWUSR);
51+
4952
/*
5053
* Synchronization.
5154
*
@@ -531,15 +534,17 @@ static int load_cpus_stopped(void *unused)
531534
return 0;
532535
}
533536

534-
static int load_late_stop_cpus(void)
537+
static int load_late_stop_cpus(bool is_safe)
535538
{
536539
unsigned int cpu, updated = 0, failed = 0, timedout = 0, siblings = 0;
537540
unsigned int nr_offl, offline = 0;
538541
int old_rev = boot_cpu_data.microcode;
539542
struct cpuinfo_x86 prev_info;
540543

541-
pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n");
542-
pr_err("You should switch to early loading, if possible.\n");
544+
if (!is_safe) {
545+
pr_err("Late microcode loading without minimal revision check.\n");
546+
pr_err("You should switch to early loading, if possible.\n");
547+
}
543548

544549
atomic_set(&late_cpus_in, num_online_cpus());
545550
atomic_set(&offline_in_nmi, 0);
@@ -589,7 +594,9 @@ static int load_late_stop_cpus(void)
589594
return -EIO;
590595
}
591596

592-
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
597+
if (!is_safe || failed || timedout)
598+
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
599+
593600
pr_info("load: updated on %u primary CPUs with %u siblings\n", updated, siblings);
594601
if (failed || timedout) {
595602
pr_err("load incomplete. %u CPUs timed out or failed\n",
@@ -679,7 +686,9 @@ static int load_late_locked(void)
679686

680687
switch (microcode_ops->request_microcode_fw(0, &microcode_pdev->dev)) {
681688
case UCODE_NEW:
682-
return load_late_stop_cpus();
689+
return load_late_stop_cpus(false);
690+
case UCODE_NEW_SAFE:
691+
return load_late_stop_cpus(true);
683692
case UCODE_NFOUND:
684693
return -ENOENT;
685694
default:

arch/x86/kernel/cpu/microcode/intel.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,9 @@ static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter)
480480
unsigned int curr_mc_size = 0;
481481
u8 *new_mc = NULL, *mc = NULL;
482482

483+
if (force_minrev)
484+
return UCODE_NFOUND;
485+
483486
while (iov_iter_count(iter)) {
484487
struct microcode_header_intel mc_header;
485488
unsigned int mc_size, data_size;

arch/x86/kernel/cpu/microcode/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ struct device;
1313
enum ucode_state {
1414
UCODE_OK = 0,
1515
UCODE_NEW,
16+
UCODE_NEW_SAFE,
1617
UCODE_UPDATED,
1718
UCODE_NFOUND,
1819
UCODE_ERROR,
@@ -88,6 +89,7 @@ static inline unsigned int x86_cpuid_family(void)
8889
}
8990

9091
extern bool dis_ucode_ldr;
92+
extern bool force_minrev;
9193

9294
#ifdef CONFIG_CPU_SUP_AMD
9395
void load_ucode_amd_bsp(unsigned int family);

0 commit comments

Comments
 (0)