Skip to content

Commit

Permalink
Merge tag 'x86_microcode_for_v6.3_rc1' of git://git.kernel.org/pub/sc…
Browse files Browse the repository at this point in the history
…m/linux/kernel/git/tip/tip

Pull x86 microcode loader updates from Borislav Petkov:

 - Fix mixed steppings support on AMD which got broken somewhere along
   the way

 - Improve revision reporting

 - Properly check CPUID capabilities after late microcode upgrade to
   avoid false positives

 - A garden variety of other small fixes

* tag 'x86_microcode_for_v6.3_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/microcode/core: Return an error only when necessary
  x86/microcode/AMD: Fix mixed steppings support
  x86/microcode/AMD: Add a @cpu parameter to the reloading functions
  x86/microcode/amd: Remove load_microcode_amd()'s bsp parameter
  x86/microcode: Allow only "1" as a late reload trigger value
  x86/microcode/intel: Print old and new revision during early boot
  x86/microcode/intel: Pass the microcode revision to print_ucode_info() directly
  x86/microcode: Adjust late loading result reporting message
  x86/microcode: Check CPU capabilities after late microcode update correctly
  x86/microcode: Add a parameter to microcode_check() to store CPU capabilities
  x86/microcode: Use the DEVICE_ATTR_RO() macro
  x86/microcode/AMD: Handle multiple glued containers properly
  x86/microcode/AMD: Rename a couple of functions
  • Loading branch information
torvalds committed Feb 21, 2023
2 parents aa8c3db + f33e0c8 commit efebca0
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 104 deletions.
4 changes: 2 additions & 2 deletions arch/x86/include/asm/microcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,13 @@ static inline unsigned int x86_cpuid_family(void)
#ifdef CONFIG_MICROCODE
extern void __init load_ucode_bsp(void);
extern void load_ucode_ap(void);
void reload_early_microcode(void);
void reload_early_microcode(unsigned int cpu);
extern bool initrd_gone;
void microcode_bsp_resume(void);
#else
static inline void __init load_ucode_bsp(void) { }
static inline void load_ucode_ap(void) { }
static inline void reload_early_microcode(void) { }
static inline void reload_early_microcode(unsigned int cpu) { }
static inline void microcode_bsp_resume(void) { }
#endif

Expand Down
4 changes: 2 additions & 2 deletions arch/x86/include/asm/microcode_amd.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ struct microcode_amd {
extern void __init load_ucode_amd_bsp(unsigned int family);
extern void load_ucode_amd_ap(unsigned int family);
extern int __init save_microcode_in_initrd_amd(unsigned int family);
void reload_ucode_amd(void);
void reload_ucode_amd(unsigned int cpu);
#else
static inline void __init load_ucode_amd_bsp(unsigned int family) {}
static inline void load_ucode_amd_ap(unsigned int family) {}
static inline int __init
save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; }
static inline void reload_ucode_amd(void) {}
static inline void reload_ucode_amd(unsigned int cpu) {}
#endif
#endif /* _ASM_X86_MICROCODE_AMD_H */
3 changes: 2 additions & 1 deletion arch/x86/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,8 @@ bool xen_set_default_idle(void);
#endif

void __noreturn stop_this_cpu(void *dummy);
void microcode_check(void);
void microcode_check(struct cpuinfo_x86 *prev_info);
void store_cpu_caps(struct cpuinfo_x86 *info);

enum l1tf_mitigations {
L1TF_MITIGATION_OFF,
Expand Down
45 changes: 30 additions & 15 deletions arch/x86/kernel/cpu/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -2302,30 +2302,45 @@ 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.
*
* The microcode loader calls this upon late microcode load to recheck features,
* only when microcode has been updated. Caller holds microcode_mutex and CPU
* hotplug lock.
*
* Return: None
*/
void microcode_check(void)
void microcode_check(struct cpuinfo_x86 *prev_info)
{
struct cpuinfo_x86 info;
struct cpuinfo_x86 curr_info;

perf_check_microcode();

/* Reload CPUID max function as it might've changed. */
info.cpuid_level = cpuid_eax(0);

/*
* 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(&info.x86_capability, &boot_cpu_data.x86_capability, sizeof(info.x86_capability));

get_cpu_cap(&info);
store_cpu_caps(&curr_info);

if (!memcmp(&info.x86_capability, &boot_cpu_data.x86_capability, sizeof(info.x86_capability)))
if (!memcmp(&prev_info->x86_capability, &curr_info.x86_capability,
sizeof(prev_info->x86_capability)))
return;

pr_warn("x86/CPU: CPU features have changed after loading microcode, but might not take effect.\n");
Expand Down
76 changes: 37 additions & 39 deletions arch/x86/kernel/cpu/microcode/amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ struct cont_desc {
};

static u32 ucode_new_rev;
static u8 amd_ucode_patch[PATCH_MAX_SIZE];

/* One blob per node. */
static u8 amd_ucode_patch[MAX_NUMNODES][PATCH_MAX_SIZE];

/*
* Microcode patch container file is prepended to the initrd in cpio
Expand Down Expand Up @@ -330,8 +332,9 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc)
ret = verify_patch(x86_family(desc->cpuid_1_eax), buf, size, &patch_size, true);
if (ret < 0) {
/*
* Patch verification failed, skip to the next
* container, if there's one:
* Patch verification failed, skip to the next container, if
* there is one. Before exit, check whether that container has
* found a patch already. If so, use it.
*/
goto out;
} else if (ret > 0) {
Expand All @@ -350,6 +353,7 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc)
size -= patch_size + SECTION_HDR_SIZE;
}

out:
/*
* If we have found a patch (desc->mc), it means we're looking at the
* container which has a patch for this CPU so return 0 to mean, @ucode
Expand All @@ -364,7 +368,6 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc)
return 0;
}

out:
return orig_size - size;
}

Expand Down Expand Up @@ -414,8 +417,7 @@ static int __apply_microcode_amd(struct microcode_amd *mc)
*
* Returns true if container found (sets @desc), false otherwise.
*/
static bool
apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size, bool save_patch)
static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size, bool save_patch)
{
struct cont_desc desc = { 0 };
u8 (*patch)[PATCH_MAX_SIZE];
Expand All @@ -428,7 +430,7 @@ apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size, bool save_p
patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch);
#else
new_rev = &ucode_new_rev;
patch = &amd_ucode_patch;
patch = &amd_ucode_patch[0];
#endif

desc.cpuid_1_eax = cpuid_1_eax;
Expand Down Expand Up @@ -481,7 +483,7 @@ static bool get_builtin_microcode(struct cpio_data *cp, unsigned int family)
return false;
}

static void __load_ucode_amd(unsigned int cpuid_1_eax, struct cpio_data *ret)
static void find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpio_data *ret)
{
struct ucode_cpu_info *uci;
struct cpio_data cp;
Expand Down Expand Up @@ -511,11 +513,11 @@ void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax)
{
struct cpio_data cp = { };

__load_ucode_amd(cpuid_1_eax, &cp);
find_blobs_in_containers(cpuid_1_eax, &cp);
if (!(cp.data && cp.size))
return;

apply_microcode_early_amd(cpuid_1_eax, cp.data, cp.size, true);
early_apply_microcode(cpuid_1_eax, cp.data, cp.size, true);
}

void load_ucode_amd_ap(unsigned int cpuid_1_eax)
Expand Down Expand Up @@ -546,15 +548,14 @@ void load_ucode_amd_ap(unsigned int cpuid_1_eax)
}
}

__load_ucode_amd(cpuid_1_eax, &cp);
find_blobs_in_containers(cpuid_1_eax, &cp);
if (!(cp.data && cp.size))
return;

apply_microcode_early_amd(cpuid_1_eax, cp.data, cp.size, false);
early_apply_microcode(cpuid_1_eax, cp.data, cp.size, false);
}

static enum ucode_state
load_microcode_amd(bool save, u8 family, const u8 *data, size_t size);
static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size);

int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
{
Expand All @@ -572,19 +573,19 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
if (!desc.mc)
return -EINVAL;

ret = load_microcode_amd(true, x86_family(cpuid_1_eax), desc.data, desc.size);
ret = load_microcode_amd(x86_family(cpuid_1_eax), desc.data, desc.size);
if (ret > UCODE_UPDATED)
return -EINVAL;

return 0;
}

void reload_ucode_amd(void)
void reload_ucode_amd(unsigned int cpu)
{
struct microcode_amd *mc;
u32 rev, dummy __always_unused;
struct microcode_amd *mc;

mc = (struct microcode_amd *)amd_ucode_patch;
mc = (struct microcode_amd *)amd_ucode_patch[cpu_to_node(cpu)];

rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);

Expand Down Expand Up @@ -816,6 +817,7 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover,
return 0;
}

/* Scan the blob in @data and add microcode patches to the cache. */
static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
size_t size)
{
Expand Down Expand Up @@ -850,9 +852,10 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
return UCODE_OK;
}

static enum ucode_state
load_microcode_amd(bool save, u8 family, const u8 *data, size_t size)
static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size)
{
struct cpuinfo_x86 *c;
unsigned int nid, cpu;
struct ucode_patch *p;
enum ucode_state ret;

Expand All @@ -865,22 +868,22 @@ load_microcode_amd(bool save, u8 family, const u8 *data, size_t size)
return ret;
}

p = find_patch(0);
if (!p) {
return ret;
} else {
if (boot_cpu_data.microcode >= p->patch_id)
return ret;
for_each_node(nid) {
cpu = cpumask_first(cpumask_of_node(nid));
c = &cpu_data(cpu);

ret = UCODE_NEW;
}
p = find_patch(cpu);
if (!p)
continue;

/* save BSP's matching patch for early load */
if (!save)
return ret;
if (c->microcode >= p->patch_id)
continue;

memset(amd_ucode_patch, 0, PATCH_MAX_SIZE);
memcpy(amd_ucode_patch, p->data, min_t(u32, p->size, PATCH_MAX_SIZE));
ret = UCODE_NEW;

memset(&amd_ucode_patch[nid], 0, PATCH_MAX_SIZE);
memcpy(&amd_ucode_patch[nid], p->data, min_t(u32, p->size, PATCH_MAX_SIZE));
}

return ret;
}
Expand All @@ -905,14 +908,9 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device)
{
char fw_name[36] = "amd-ucode/microcode_amd.bin";
struct cpuinfo_x86 *c = &cpu_data(cpu);
bool bsp = c->cpu_index == boot_cpu_data.cpu_index;
enum ucode_state ret = UCODE_NFOUND;
const struct firmware *fw;

/* reload ucode container only on the boot cpu */
if (!bsp)
return UCODE_OK;

if (c->x86 >= 0x15)
snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);

Expand All @@ -925,7 +923,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device)
if (!verify_container(fw->data, fw->size, false))
goto fw_release;

ret = load_microcode_amd(bsp, c->x86, fw->data, fw->size);
ret = load_microcode_amd(c->x86, fw->data, fw->size);

fw_release:
release_firmware(fw);
Expand Down
Loading

0 comments on commit efebca0

Please sign in to comment.