Skip to content

Commit

Permalink
x86/microcode: Consolidate the loader enablement checking
Browse files Browse the repository at this point in the history
Consolidate the whole logic which determines whether the microcode loader
should be enabled or not into a single function and call it everywhere.

Well, almost everywhere - not in mk_early_pgtbl_32() because there the kernel
is running without paging enabled and checking dis_ucode_ldr et al would
require physical addresses and uglification of the code.

But since this is 32-bit, the easier thing to do is to simply map the initrd
unconditionally especially since that mapping is getting removed later anyway
by zap_early_initrd_mapping() and avoid the uglification.

In doing so, address the issue of old 486er machines without CPUID
support, not booting current kernels.

  [ mingo: Fix no previous prototype for ‘microcode_loader_disabled’ [-Wmissing-prototypes] ]

Fixes: 4c585af ("x86/boot/32: Temporarily map initrd for microcode loading")
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Cc: <stable@kernel.org>
Link: https://lore.kernel.org/r/CANpbe9Wm3z8fy9HbgS8cuhoj0TREYEEkBipDuhgkWFvqX0UoVQ@mail.gmail.com
  • Loading branch information
Borislav Petkov (AMD) committed May 5, 2025
1 parent 92a09c4 commit 5214a9f
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 32 deletions.
2 changes: 2 additions & 0 deletions arch/x86/include/asm/microcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ struct ucode_cpu_info {
void load_ucode_bsp(void);
void load_ucode_ap(void);
void microcode_bsp_resume(void);
bool __init microcode_loader_disabled(void);
#else
static inline void load_ucode_bsp(void) { }
static inline void load_ucode_ap(void) { }
static inline void microcode_bsp_resume(void) { }
static inline bool __init microcode_loader_disabled(void) { return false; }
#endif

extern unsigned long initrd_start_early;
Expand Down
6 changes: 4 additions & 2 deletions arch/x86/kernel/cpu/microcode/amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1098,15 +1098,17 @@ static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t siz

static int __init save_microcode_in_initrd(void)
{
unsigned int cpuid_1_eax = native_cpuid_eax(1);
struct cpuinfo_x86 *c = &boot_cpu_data;
struct cont_desc desc = { 0 };
unsigned int cpuid_1_eax;
enum ucode_state ret;
struct cpio_data cp;

if (dis_ucode_ldr || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10)
if (microcode_loader_disabled() || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10)
return 0;

cpuid_1_eax = native_cpuid_eax(1);

if (!find_blobs_in_containers(&cp))
return -EINVAL;

Expand Down
58 changes: 34 additions & 24 deletions arch/x86/kernel/cpu/microcode/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@

#include "internal.h"

static struct microcode_ops *microcode_ops;
bool dis_ucode_ldr = true;
static struct microcode_ops *microcode_ops;
static bool dis_ucode_ldr = false;

bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV);
module_param(force_minrev, bool, S_IRUSR | S_IWUSR);
Expand Down Expand Up @@ -84,6 +84,9 @@ static bool amd_check_current_patch_level(void)
u32 lvl, dummy, i;
u32 *levels;

if (x86_cpuid_vendor() != X86_VENDOR_AMD)
return false;

native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy);

levels = final_levels;
Expand All @@ -95,27 +98,29 @@ static bool amd_check_current_patch_level(void)
return false;
}

static bool __init check_loader_disabled_bsp(void)
bool __init microcode_loader_disabled(void)
{
static const char *__dis_opt_str = "dis_ucode_ldr";
const char *cmdline = boot_command_line;
const char *option = __dis_opt_str;
if (dis_ucode_ldr)
return true;

/*
* CPUID(1).ECX[31]: reserved for hypervisor use. This is still not
* completely accurate as xen pv guests don't see that CPUID bit set but
* that's good enough as they don't land on the BSP path anyway.
* Disable when:
*
* 1) The CPU does not support CPUID.
*
* 2) Bit 31 in CPUID[1]:ECX is clear
* The bit is reserved for hypervisor use. This is still not
* completely accurate as XEN PV guests don't see that CPUID bit
* set, but that's good enough as they don't land on the BSP
* path anyway.
*
* 3) Certain AMD patch levels are not allowed to be
* overwritten.
*/
if (native_cpuid_ecx(1) & BIT(31))
return true;

if (x86_cpuid_vendor() == X86_VENDOR_AMD) {
if (amd_check_current_patch_level())
return true;
}

if (cmdline_find_option_bool(cmdline, option) <= 0)
dis_ucode_ldr = false;
if (!have_cpuid_p() ||
native_cpuid_ecx(1) & BIT(31) ||
amd_check_current_patch_level())
dis_ucode_ldr = true;

return dis_ucode_ldr;
}
Expand All @@ -125,7 +130,10 @@ void __init load_ucode_bsp(void)
unsigned int cpuid_1_eax;
bool intel = true;

if (!have_cpuid_p())
if (cmdline_find_option_bool(boot_command_line, "dis_ucode_ldr") > 0)
dis_ucode_ldr = true;

if (microcode_loader_disabled())
return;

cpuid_1_eax = native_cpuid_eax(1);
Expand All @@ -146,9 +154,6 @@ void __init load_ucode_bsp(void)
return;
}

if (check_loader_disabled_bsp())
return;

if (intel)
load_ucode_intel_bsp(&early_data);
else
Expand All @@ -159,6 +164,11 @@ void load_ucode_ap(void)
{
unsigned int cpuid_1_eax;

/*
* Can't use microcode_loader_disabled() here - .init section
* hell. It doesn't have to either - the BSP variant must've
* parsed cmdline already anyway.
*/
if (dis_ucode_ldr)
return;

Expand Down Expand Up @@ -810,7 +820,7 @@ static int __init microcode_init(void)
struct cpuinfo_x86 *c = &boot_cpu_data;
int error;

if (dis_ucode_ldr)
if (microcode_loader_disabled())
return -EINVAL;

if (c->x86_vendor == X86_VENDOR_INTEL)
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/cpu/microcode/intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ static int __init save_builtin_microcode(void)
if (xchg(&ucode_patch_va, NULL) != UCODE_BSP_LOADED)
return 0;

if (dis_ucode_ldr || boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
if (microcode_loader_disabled() || boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
return 0;

uci.mc = get_microcode_blob(&uci, true);
Expand Down
1 change: 0 additions & 1 deletion arch/x86/kernel/cpu/microcode/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ static inline unsigned int x86_cpuid_family(void)
return x86_family(eax);
}

extern bool dis_ucode_ldr;
extern bool force_minrev;

#ifdef CONFIG_CPU_SUP_AMD
Expand Down
4 changes: 0 additions & 4 deletions arch/x86/kernel/head32.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,6 @@ void __init __no_stack_protector mk_early_pgtbl_32(void)
*ptr = (unsigned long)ptep + PAGE_OFFSET;

#ifdef CONFIG_MICROCODE_INITRD32
/* Running on a hypervisor? */
if (native_cpuid_ecx(1) & BIT(31))
return;

params = (struct boot_params *)__pa_nodebug(&boot_params);
if (!params->hdr.ramdisk_size || !params->hdr.ramdisk_image)
return;
Expand Down

0 comments on commit 5214a9f

Please sign in to comment.