Patch "x86/microcode: Check CPU capabilities after late microcode update correctly" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    x86/microcode: Check CPU capabilities after late microcode update correctly

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     x86-microcode-check-cpu-capabilities-after-late-micr.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit da5caf6c815f31da791da39beeb8d481fb216832
Author: Ashok Raj <ashok.raj@xxxxxxxxx>
Date:   Mon Jan 9 07:35:51 2023 -0800

    x86/microcode: Check CPU capabilities after late microcode update correctly
    
    [ Upstream commit c0dd9245aa9e25a697181f6085692272c9ec61bc ]
    
    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: 1008c52c09dc ("x86/CPU: Add a microcode loader callback")
    Signed-off-by: Ashok Raj <ashok.raj@xxxxxxxxx>
    Signed-off-by: Borislav Petkov (AMD) <bp@xxxxxxxxx>
    Link: https://lore.kernel.org/r/20230109153555.4986-3-ashok.raj@xxxxxxxxx
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index eb6d6d1057929..3e3bd5b7d5dbe 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -836,6 +836,7 @@ bool xen_set_default_idle(void);
 
 void __noreturn stop_this_cpu(void *dummy);
 void microcode_check(struct cpuinfo_x86 *prev_info);
+void store_cpu_caps(struct cpuinfo_x86 *info);
 
 enum l1tf_mitigations {
 	L1TF_MITIGATION_OFF,
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index f2cd244d31311..f7b4bbe71cdf9 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -2150,6 +2150,25 @@ void cpu_init_secondary(void)
 #endif
 
 #ifdef CONFIG_MICROCODE_LATE_LOADING
+/**
+ * store_cpu_caps() - Store a snapshot of CPU capabilities
+ * @curr_info: Pointer where to store it
+ *
+ * Returns: None
+ */
+void store_cpu_caps(struct cpuinfo_x86 *curr_info)
+{
+	/* Reload CPUID max function as it might've changed. */
+	curr_info->cpuid_level = cpuid_eax(0);
+
+	/* Copy all capability leafs and pick up the synthetic ones. */
+	memcpy(&curr_info->x86_capability, &boot_cpu_data.x86_capability,
+	       sizeof(curr_info->x86_capability));
+
+	/* Get the hardware CPUID leafs */
+	get_cpu_cap(curr_info);
+}
+
 /**
  * microcode_check() - Check if any CPU capabilities changed after an update.
  * @prev_info:	CPU capabilities stored before an update.
@@ -2162,22 +2181,13 @@ void cpu_init_secondary(void)
  */
 void microcode_check(struct cpuinfo_x86 *prev_info)
 {
-	perf_check_microcode();
-
-	/* Reload CPUID max function as it might've changed. */
-	prev_info->cpuid_level = cpuid_eax(0);
+	struct cpuinfo_x86 curr_info;
 
-	/*
-	 * Copy all capability leafs to pick up the synthetic ones so that
-	 * memcmp() below doesn't fail on that. The ones coming from CPUID will
-	 * get overwritten in get_cpu_cap().
-	 */
-	memcpy(&prev_info->x86_capability, &boot_cpu_data.x86_capability,
-	       sizeof(prev_info->x86_capability));
+	perf_check_microcode();
 
-	get_cpu_cap(prev_info);
+	store_cpu_caps(&curr_info);
 
-	if (!memcmp(&prev_info->x86_capability, &boot_cpu_data.x86_capability,
+	if (!memcmp(&prev_info->x86_capability, &curr_info.x86_capability,
 		    sizeof(prev_info->x86_capability)))
 		return;
 
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 9592dbf628b43..30d1bd36934dd 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -514,6 +514,12 @@ static int microcode_reload_late(void)
 	atomic_set(&late_cpus_in,  0);
 	atomic_set(&late_cpus_out, 0);
 
+	/*
+	 * Take a snapshot before the microcode update in order to compare and
+	 * check whether any bits changed after an update.
+	 */
+	store_cpu_caps(&prev_info);
+
 	ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask);
 	if (ret == 0)
 		microcode_check(&prev_info);



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux