Commit 2613f36e authored by Borislav Petkov's avatar Borislav Petkov Committed by Thomas Gleixner

x86/microcode: Attempt late loading only when new microcode is present

Return UCODE_NEW from the scanning functions to denote that new microcode
was found and only then attempt the expensive synchronization dance.
Reported-by: default avatarEmanuel Czirai <xftroxgpx@protonmail.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Tested-by: default avatarEmanuel Czirai <xftroxgpx@protonmail.com>
Tested-by: default avatarAshok Raj <ashok.raj@intel.com>
Tested-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Link: https://lkml.kernel.org/r/20180314183615.17629-1-bp@alien8.de
parent e3b3121f
...@@ -39,6 +39,7 @@ struct device; ...@@ -39,6 +39,7 @@ struct device;
enum ucode_state { enum ucode_state {
UCODE_OK = 0, UCODE_OK = 0,
UCODE_NEW,
UCODE_UPDATED, UCODE_UPDATED,
UCODE_NFOUND, UCODE_NFOUND,
UCODE_ERROR, UCODE_ERROR,
......
...@@ -339,7 +339,7 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax) ...@@ -339,7 +339,7 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
return -EINVAL; return -EINVAL;
ret = load_microcode_amd(true, x86_family(cpuid_1_eax), desc.data, desc.size); ret = load_microcode_amd(true, x86_family(cpuid_1_eax), desc.data, desc.size);
if (ret != UCODE_OK) if (ret > UCODE_UPDATED)
return -EINVAL; return -EINVAL;
return 0; return 0;
...@@ -683,27 +683,35 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, ...@@ -683,27 +683,35 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
static enum ucode_state static enum ucode_state
load_microcode_amd(bool save, u8 family, const u8 *data, size_t size) load_microcode_amd(bool save, u8 family, const u8 *data, size_t size)
{ {
struct ucode_patch *p;
enum ucode_state ret; enum ucode_state ret;
/* free old equiv table */ /* free old equiv table */
free_equiv_cpu_table(); free_equiv_cpu_table();
ret = __load_microcode_amd(family, data, size); ret = __load_microcode_amd(family, data, size);
if (ret != UCODE_OK) {
if (ret != UCODE_OK)
cleanup(); cleanup();
return ret;
}
p = find_patch(0);
if (!p) {
return ret;
} else {
if (boot_cpu_data.microcode == p->patch_id)
return ret;
ret = UCODE_NEW;
}
#ifdef CONFIG_X86_32
/* save BSP's matching patch for early load */ /* save BSP's matching patch for early load */
if (save) { if (!save)
struct ucode_patch *p = find_patch(0); return ret;
if (p) {
memset(amd_ucode_patch, 0, PATCH_MAX_SIZE); memset(amd_ucode_patch, 0, PATCH_MAX_SIZE);
memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data), memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data), PATCH_MAX_SIZE));
PATCH_MAX_SIZE));
}
}
#endif
return ret; return ret;
} }
......
...@@ -607,7 +607,7 @@ static ssize_t reload_store(struct device *dev, ...@@ -607,7 +607,7 @@ static ssize_t reload_store(struct device *dev,
return size; return size;
tmp_ret = microcode_ops->request_microcode_fw(bsp, &microcode_pdev->dev, true); tmp_ret = microcode_ops->request_microcode_fw(bsp, &microcode_pdev->dev, true);
if (tmp_ret != UCODE_OK) if (tmp_ret != UCODE_NEW)
return size; return size;
get_online_cpus(); get_online_cpus();
...@@ -691,10 +691,8 @@ static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw) ...@@ -691,10 +691,8 @@ static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw)
if (system_state != SYSTEM_RUNNING) if (system_state != SYSTEM_RUNNING)
return UCODE_NFOUND; return UCODE_NFOUND;
ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev, ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev, refresh_fw);
refresh_fw); if (ustate == UCODE_NEW) {
if (ustate == UCODE_OK) {
pr_debug("CPU%d updated upon init\n", cpu); pr_debug("CPU%d updated upon init\n", cpu);
apply_microcode_on_target(cpu); apply_microcode_on_target(cpu);
} }
......
...@@ -862,6 +862,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, ...@@ -862,6 +862,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
unsigned int leftover = size; unsigned int leftover = size;
unsigned int curr_mc_size = 0, new_mc_size = 0; unsigned int curr_mc_size = 0, new_mc_size = 0;
unsigned int csig, cpf; unsigned int csig, cpf;
enum ucode_state ret = UCODE_OK;
while (leftover) { while (leftover) {
struct microcode_header_intel mc_header; struct microcode_header_intel mc_header;
...@@ -903,6 +904,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, ...@@ -903,6 +904,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
new_mc = mc; new_mc = mc;
new_mc_size = mc_size; new_mc_size = mc_size;
mc = NULL; /* trigger new vmalloc */ mc = NULL; /* trigger new vmalloc */
ret = UCODE_NEW;
} }
ucode_ptr += mc_size; ucode_ptr += mc_size;
...@@ -932,7 +934,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, ...@@ -932,7 +934,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
cpu, new_rev, uci->cpu_sig.rev); cpu, new_rev, uci->cpu_sig.rev);
return UCODE_OK; return ret;
} }
static int get_ucode_fw(void *to, const void *from, size_t n) static int get_ucode_fw(void *to, const void *from, size_t n)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment