Skip to content

Commit bd91417

Browse files
committed
Merge tag 'x86_microcode_for_v6.18_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 microcode loading updates from Borislav Petkov: - Add infrastructure to be able to debug the microcode loader in a guest - Refresh Intel old microcode revisions * tag 'x86_microcode_for_v6.18_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/microcode: Add microcode loader debugging functionality x86/microcode: Add microcode= cmdline parsing x86/microcode/intel: Refresh the revisions that determine old_microcode
2 parents 45d96dd + 43181a4 commit bd91417

6 files changed

Lines changed: 174 additions & 69 deletions

File tree

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3767,8 +3767,16 @@
37673767

37683768
mga= [HW,DRM]
37693769

3770-
microcode.force_minrev= [X86]
3771-
Format: <bool>
3770+
microcode= [X86] Control the behavior of the microcode loader.
3771+
Available options, comma separated:
3772+
3773+
base_rev=X - with <X> with format: <u32>
3774+
Set the base microcode revision of each thread when in
3775+
debug mode.
3776+
3777+
dis_ucode_ldr: disable the microcode loader
3778+
3779+
force_minrev:
37723780
Enable or disable the microcode minimal revision
37733781
enforcement for the runtime microcode loader.
37743782

arch/x86/Kconfig

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,7 +1321,7 @@ config MICROCODE_LATE_LOADING
13211321
use this at your own risk. Late loading taints the kernel unless the
13221322
microcode header indicates that it is safe for late loading via the
13231323
minimal revision check. This minimal revision check can be enforced on
1324-
the kernel command line with "microcode.minrev=Y".
1324+
the kernel command line with "microcode=force_minrev".
13251325

13261326
config MICROCODE_LATE_FORCE_MINREV
13271327
bool "Enforce late microcode loading minimal revision check"
@@ -1337,10 +1337,22 @@ config MICROCODE_LATE_FORCE_MINREV
13371337
revision check fails.
13381338

13391339
This minimal revision check can also be controlled via the
1340-
"microcode.minrev" parameter on the kernel command line.
1340+
"microcode=force_minrev" parameter on the kernel command line.
13411341

13421342
If unsure say Y.
13431343

1344+
config MICROCODE_DBG
1345+
bool "Enable microcode loader debugging"
1346+
default n
1347+
depends on MICROCODE
1348+
help
1349+
Enable code which allows for debugging the microcode loader in
1350+
a guest. Meaning the patch loading is simulated but everything else
1351+
related to patch parsing and handling is done as on baremetal with
1352+
the purpose of debugging solely the software side of things.
1353+
1354+
You almost certainly want to say n here.
1355+
13441356
config X86_MSR
13451357
tristate "/dev/cpu/*/msr - Model-specific register support"
13461358
help

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

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -269,15 +269,6 @@ static bool verify_sha256_digest(u32 patch_id, u32 cur_rev, const u8 *data, unsi
269269
return true;
270270
}
271271

272-
static u32 get_patch_level(void)
273-
{
274-
u32 rev, dummy __always_unused;
275-
276-
native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
277-
278-
return rev;
279-
}
280-
281272
static union cpuid_1_eax ucode_rev_to_cpuid(unsigned int val)
282273
{
283274
union zen_patch_rev p;
@@ -295,6 +286,30 @@ static union cpuid_1_eax ucode_rev_to_cpuid(unsigned int val)
295286
return c;
296287
}
297288

289+
static u32 get_patch_level(void)
290+
{
291+
u32 rev, dummy __always_unused;
292+
293+
if (IS_ENABLED(CONFIG_MICROCODE_DBG)) {
294+
int cpu = smp_processor_id();
295+
296+
if (!microcode_rev[cpu]) {
297+
if (!base_rev)
298+
base_rev = cpuid_to_ucode_rev(bsp_cpuid_1_eax);
299+
300+
microcode_rev[cpu] = base_rev;
301+
302+
ucode_dbg("CPU%d, base_rev: 0x%x\n", cpu, base_rev);
303+
}
304+
305+
return microcode_rev[cpu];
306+
}
307+
308+
native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
309+
310+
return rev;
311+
}
312+
298313
static u16 find_equiv_id(struct equiv_cpu_table *et, u32 sig)
299314
{
300315
unsigned int i;
@@ -324,13 +339,13 @@ static bool verify_container(const u8 *buf, size_t buf_size)
324339
u32 cont_magic;
325340

326341
if (buf_size <= CONTAINER_HDR_SZ) {
327-
pr_debug("Truncated microcode container header.\n");
342+
ucode_dbg("Truncated microcode container header.\n");
328343
return false;
329344
}
330345

331346
cont_magic = *(const u32 *)buf;
332347
if (cont_magic != UCODE_MAGIC) {
333-
pr_debug("Invalid magic value (0x%08x).\n", cont_magic);
348+
ucode_dbg("Invalid magic value (0x%08x).\n", cont_magic);
334349
return false;
335350
}
336351

@@ -355,8 +370,8 @@ static bool verify_equivalence_table(const u8 *buf, size_t buf_size)
355370

356371
cont_type = hdr[1];
357372
if (cont_type != UCODE_EQUIV_CPU_TABLE_TYPE) {
358-
pr_debug("Wrong microcode container equivalence table type: %u.\n",
359-
cont_type);
373+
ucode_dbg("Wrong microcode container equivalence table type: %u.\n",
374+
cont_type);
360375
return false;
361376
}
362377

@@ -365,7 +380,7 @@ static bool verify_equivalence_table(const u8 *buf, size_t buf_size)
365380
equiv_tbl_len = hdr[2];
366381
if (equiv_tbl_len < sizeof(struct equiv_cpu_entry) ||
367382
buf_size < equiv_tbl_len) {
368-
pr_debug("Truncated equivalence table.\n");
383+
ucode_dbg("Truncated equivalence table.\n");
369384
return false;
370385
}
371386

@@ -385,7 +400,7 @@ static bool __verify_patch_section(const u8 *buf, size_t buf_size, u32 *sh_psize
385400
const u32 *hdr;
386401

387402
if (buf_size < SECTION_HDR_SIZE) {
388-
pr_debug("Truncated patch section.\n");
403+
ucode_dbg("Truncated patch section.\n");
389404
return false;
390405
}
391406

@@ -394,13 +409,13 @@ static bool __verify_patch_section(const u8 *buf, size_t buf_size, u32 *sh_psize
394409
p_size = hdr[1];
395410

396411
if (p_type != UCODE_UCODE_TYPE) {
397-
pr_debug("Invalid type field (0x%x) in container file section header.\n",
398-
p_type);
412+
ucode_dbg("Invalid type field (0x%x) in container file section header.\n",
413+
p_type);
399414
return false;
400415
}
401416

402417
if (p_size < sizeof(struct microcode_header_amd)) {
403-
pr_debug("Patch of size %u too short.\n", p_size);
418+
ucode_dbg("Patch of size %u too short.\n", p_size);
404419
return false;
405420
}
406421

@@ -477,12 +492,12 @@ static int verify_patch(const u8 *buf, size_t buf_size, u32 *patch_size)
477492
* size sh_psize, as the section claims.
478493
*/
479494
if (buf_size < sh_psize) {
480-
pr_debug("Patch of size %u truncated.\n", sh_psize);
495+
ucode_dbg("Patch of size %u truncated.\n", sh_psize);
481496
return -1;
482497
}
483498

484499
if (!__verify_patch_size(sh_psize, buf_size)) {
485-
pr_debug("Per-family patch size mismatch.\n");
500+
ucode_dbg("Per-family patch size mismatch.\n");
486501
return -1;
487502
}
488503

@@ -496,6 +511,9 @@ static int verify_patch(const u8 *buf, size_t buf_size, u32 *patch_size)
496511

497512
proc_id = mc_hdr->processor_rev_id;
498513
patch_fam = 0xf + (proc_id >> 12);
514+
515+
ucode_dbg("Patch-ID 0x%08x: family: 0x%x\n", mc_hdr->patch_id, patch_fam);
516+
499517
if (patch_fam != family)
500518
return 1;
501519

@@ -566,9 +584,14 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc)
566584
}
567585

568586
mc = (struct microcode_amd *)(buf + SECTION_HDR_SIZE);
587+
588+
ucode_dbg("patch_id: 0x%x\n", mc->hdr.patch_id);
589+
569590
if (mc_patch_matches(mc, eq_id)) {
570591
desc->psize = patch_size;
571592
desc->mc = mc;
593+
594+
ucode_dbg(" match: size: %d\n", patch_size);
572595
}
573596

574597
skip:
@@ -639,8 +662,14 @@ static bool __apply_microcode_amd(struct microcode_amd *mc, u32 *cur_rev,
639662
invlpg(p_addr_end);
640663
}
641664

665+
if (IS_ENABLED(CONFIG_MICROCODE_DBG))
666+
microcode_rev[smp_processor_id()] = mc->hdr.patch_id;
667+
642668
/* verify patch application was successful */
643669
*cur_rev = get_patch_level();
670+
671+
ucode_dbg("updated rev: 0x%x\n", *cur_rev);
672+
644673
if (*cur_rev != mc->hdr.patch_id)
645674
return false;
646675

@@ -1026,7 +1055,7 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover,
10261055
patch->patch_id = mc_hdr->patch_id;
10271056
patch->equiv_cpu = proc_id;
10281057

1029-
pr_debug("%s: Adding patch_id: 0x%08x, proc_id: 0x%04x\n",
1058+
ucode_dbg("%s: Adding patch_id: 0x%08x, proc_id: 0x%04x\n",
10301059
__func__, patch->patch_id, proc_id);
10311060

10321061
/* ... and add to cache. */
@@ -1169,7 +1198,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device)
11691198
snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
11701199

11711200
if (request_firmware_direct(&fw, (const char *)fw_name, device)) {
1172-
pr_debug("failed to load file %s\n", fw_name);
1201+
ucode_dbg("failed to load file %s\n", fw_name);
11731202
goto out;
11741203
}
11751204

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

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,19 @@
4343
#include "internal.h"
4444

4545
static struct microcode_ops *microcode_ops;
46-
static bool dis_ucode_ldr = false;
46+
static bool dis_ucode_ldr;
4747

4848
bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV);
49-
module_param(force_minrev, bool, S_IRUSR | S_IWUSR);
49+
50+
/*
51+
* Those below should be behind CONFIG_MICROCODE_DBG ifdeffery but in
52+
* order to not uglify the code with ifdeffery and use IS_ENABLED()
53+
* instead, leave them in. When microcode debugging is not enabled,
54+
* those are meaningless anyway.
55+
*/
56+
/* base microcode revision for debugging */
57+
u32 base_rev;
58+
u32 microcode_rev[NR_CPUS] = {};
5059

5160
/*
5261
* Synchronization.
@@ -119,20 +128,48 @@ bool __init microcode_loader_disabled(void)
119128
* overwritten.
120129
*/
121130
if (!cpuid_feature() ||
122-
native_cpuid_ecx(1) & BIT(31) ||
131+
((native_cpuid_ecx(1) & BIT(31)) &&
132+
!IS_ENABLED(CONFIG_MICROCODE_DBG)) ||
123133
amd_check_current_patch_level())
124134
dis_ucode_ldr = true;
125135

126136
return dis_ucode_ldr;
127137
}
128138

139+
static void early_parse_cmdline(void)
140+
{
141+
char cmd_buf[64] = {};
142+
char *s, *p = cmd_buf;
143+
144+
if (cmdline_find_option(boot_command_line, "microcode", cmd_buf, sizeof(cmd_buf)) > 0) {
145+
while ((s = strsep(&p, ","))) {
146+
if (IS_ENABLED(CONFIG_MICROCODE_DBG)) {
147+
if (strstr(s, "base_rev=")) {
148+
/* advance to the option arg */
149+
strsep(&s, "=");
150+
if (kstrtouint(s, 16, &base_rev)) { ; }
151+
}
152+
}
153+
154+
if (!strcmp("force_minrev", s))
155+
force_minrev = true;
156+
157+
if (!strcmp(s, "dis_ucode_ldr"))
158+
dis_ucode_ldr = true;
159+
}
160+
}
161+
162+
/* old, compat option */
163+
if (cmdline_find_option_bool(boot_command_line, "dis_ucode_ldr") > 0)
164+
dis_ucode_ldr = true;
165+
}
166+
129167
void __init load_ucode_bsp(void)
130168
{
131169
unsigned int cpuid_1_eax;
132170
bool intel = true;
133171

134-
if (cmdline_find_option_bool(boot_command_line, "dis_ucode_ldr") > 0)
135-
dis_ucode_ldr = true;
172+
early_parse_cmdline();
136173

137174
if (microcode_loader_disabled())
138175
return;

0 commit comments

Comments
 (0)