Skip to content

Commit c0dd924

Browse files
ashok-rajbp3tk0v
authored andcommitted
x86/microcode: Check CPU capabilities after late microcode update correctly
The kernel caches each CPU's feature bits at boot in an x86_capability[] structure. However, the capabilities in the BSP's copy can be turned off as a result of certain command line parameters or configuration restrictions, for example the SGX bit. This can cause a mismatch when comparing the values before and after the microcode update. Another example is X86_FEATURE_SRBDS_CTRL which gets added only after microcode update: --- cpuid.before 2023-01-21 14:54:15.652000747 +0100 +++ cpuid.after 2023-01-21 14:54:26.632001024 +0100 @@ -10,7 +10,7 @@ CPU: 0x00000004 0x04: eax=0x00000000 ebx=0x00000000 ecx=0x00000000 edx=0x00000000 0x00000005 0x00: eax=0x00000040 ebx=0x00000040 ecx=0x00000003 edx=0x11142120 0x00000006 0x00: eax=0x000027f7 ebx=0x00000002 ecx=0x00000001 edx=0x00000000 - 0x00000007 0x00: eax=0x00000000 ebx=0x029c6fbf ecx=0x40000000 edx=0xbc002400 + 0x00000007 0x00: eax=0x00000000 ebx=0x029c6fbf ecx=0x40000000 edx=0xbc002e00 ^^^ and which proves for a gazillionth time that late loading is a bad bad idea. microcode_check() is called after an update to report any previously cached CPUID bits which might have changed due to the update. Therefore, store the cached CPU caps before the update and compare them with the CPU caps after the microcode update has succeeded. Thus, the comparison is done between the CPUID *hardware* bits before and after the upgrade instead of using the cached, possibly runtime modified values in BSP's boot_cpu_data copy. As a result, false warnings about CPUID bits changes are avoided. [ bp: - Massage. - Add SRBDS_CTRL example. - Add kernel-doc. - Incorporate forgotten review feedback from dhansen. ] Fixes: 1008c52 ("x86/CPU: Add a microcode loader callback") Signed-off-by: Ashok Raj <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent ab31c74 commit c0dd924

File tree

3 files changed

+30
-13
lines changed

3 files changed

+30
-13
lines changed

arch/x86/include/asm/processor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,7 @@ bool xen_set_default_idle(void);
698698

699699
void __noreturn stop_this_cpu(void *dummy);
700700
void microcode_check(struct cpuinfo_x86 *prev_info);
701+
void store_cpu_caps(struct cpuinfo_x86 *info);
701702

702703
enum l1tf_mitigations {
703704
L1TF_MITIGATION_OFF,

arch/x86/kernel/cpu/common.c

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2297,6 +2297,25 @@ void cpu_init_secondary(void)
22972297
#endif
22982298

22992299
#ifdef CONFIG_MICROCODE_LATE_LOADING
2300+
/**
2301+
* store_cpu_caps() - Store a snapshot of CPU capabilities
2302+
* @curr_info: Pointer where to store it
2303+
*
2304+
* Returns: None
2305+
*/
2306+
void store_cpu_caps(struct cpuinfo_x86 *curr_info)
2307+
{
2308+
/* Reload CPUID max function as it might've changed. */
2309+
curr_info->cpuid_level = cpuid_eax(0);
2310+
2311+
/* Copy all capability leafs and pick up the synthetic ones. */
2312+
memcpy(&curr_info->x86_capability, &boot_cpu_data.x86_capability,
2313+
sizeof(curr_info->x86_capability));
2314+
2315+
/* Get the hardware CPUID leafs */
2316+
get_cpu_cap(curr_info);
2317+
}
2318+
23002319
/**
23012320
* microcode_check() - Check if any CPU capabilities changed after an update.
23022321
* @prev_info: CPU capabilities stored before an update.
@@ -2309,22 +2328,13 @@ void cpu_init_secondary(void)
23092328
*/
23102329
void microcode_check(struct cpuinfo_x86 *prev_info)
23112330
{
2312-
perf_check_microcode();
2313-
2314-
/* Reload CPUID max function as it might've changed. */
2315-
prev_info->cpuid_level = cpuid_eax(0);
2331+
struct cpuinfo_x86 curr_info;
23162332

2317-
/*
2318-
* Copy all capability leafs to pick up the synthetic ones so that
2319-
* memcmp() below doesn't fail on that. The ones coming from CPUID will
2320-
* get overwritten in get_cpu_cap().
2321-
*/
2322-
memcpy(&prev_info->x86_capability, &boot_cpu_data.x86_capability,
2323-
sizeof(prev_info->x86_capability));
2333+
perf_check_microcode();
23242334

2325-
get_cpu_cap(prev_info);
2335+
store_cpu_caps(&curr_info);
23262336

2327-
if (!memcmp(&prev_info->x86_capability, &boot_cpu_data.x86_capability,
2337+
if (!memcmp(&prev_info->x86_capability, &curr_info.x86_capability,
23282338
sizeof(prev_info->x86_capability)))
23292339
return;
23302340

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,12 @@ static int microcode_reload_late(void)
446446
atomic_set(&late_cpus_in, 0);
447447
atomic_set(&late_cpus_out, 0);
448448

449+
/*
450+
* Take a snapshot before the microcode update in order to compare and
451+
* check whether any bits changed after an update.
452+
*/
453+
store_cpu_caps(&prev_info);
454+
449455
ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask);
450456
if (ret == 0)
451457
microcode_check(&prev_info);

0 commit comments

Comments
 (0)