Commit efebca0b authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'x86_microcode_for_v6.3_rc1' of git://git.kernel.org/pub/scm/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
parents aa8c3db4 f33e0c89
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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

+2 −2
Original line number Diff line number Diff line
@@ -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 */
+2 −1
Original line number Diff line number Diff line
@@ -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,
+30 −15
Original line number Diff line number Diff line
@@ -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");
+37 −39
Original line number Diff line number Diff line
@@ -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
@@ -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) {
@@ -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
@@ -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;
}

@@ -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];
@@ -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;
@@ -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;
@@ -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)
@@ -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)
{
@@ -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);

@@ -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)
{
@@ -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;

@@ -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;
}
@@ -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);

@@ -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);
Loading