aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBorislav Petkov <bp@suse.de>2018-03-14 14:36:14 -0400
committerThomas Gleixner <tglx@linutronix.de>2018-03-16 15:55:51 -0400
commit2613f36ed965d0e5a595a1d931fd3b480e82d6fd (patch)
tree47c242f71716d90d80c84f6e8c2ac576737fc4a3
parente3b3121fa8da94cb20f9e0c64ab7981ae47fd085 (diff)
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: Emanuel Czirai <xftroxgpx@protonmail.com> Signed-off-by: Borislav Petkov <bp@suse.de> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Emanuel Czirai <xftroxgpx@protonmail.com> Tested-by: Ashok Raj <ashok.raj@intel.com> Tested-by: Tom Lendacky <thomas.lendacky@amd.com> Link: https://lkml.kernel.org/r/20180314183615.17629-1-bp@alien8.de
-rw-r--r--arch/x86/include/asm/microcode.h1
-rw-r--r--arch/x86/kernel/cpu/microcode/amd.c34
-rw-r--r--arch/x86/kernel/cpu/microcode/core.c8
-rw-r--r--arch/x86/kernel/cpu/microcode/intel.c4
4 files changed, 28 insertions, 19 deletions
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
index 7fb1047d61c7..6cf0e4cb7b97 100644
--- a/arch/x86/include/asm/microcode.h
+++ b/arch/x86/include/asm/microcode.h
@@ -39,6 +39,7 @@ struct device;
39 39
40enum ucode_state { 40enum ucode_state {
41 UCODE_OK = 0, 41 UCODE_OK = 0,
42 UCODE_NEW,
42 UCODE_UPDATED, 43 UCODE_UPDATED,
43 UCODE_NFOUND, 44 UCODE_NFOUND,
44 UCODE_ERROR, 45 UCODE_ERROR,
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
index a998e1a7d46f..48179928ff38 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -339,7 +339,7 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
339 return -EINVAL; 339 return -EINVAL;
340 340
341 ret = load_microcode_amd(true, x86_family(cpuid_1_eax), desc.data, desc.size); 341 ret = load_microcode_amd(true, x86_family(cpuid_1_eax), desc.data, desc.size);
342 if (ret != UCODE_OK) 342 if (ret > UCODE_UPDATED)
343 return -EINVAL; 343 return -EINVAL;
344 344
345 return 0; 345 return 0;
@@ -683,27 +683,35 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
683static enum ucode_state 683static enum ucode_state
684load_microcode_amd(bool save, u8 family, const u8 *data, size_t size) 684load_microcode_amd(bool save, u8 family, const u8 *data, size_t size)
685{ 685{
686 struct ucode_patch *p;
686 enum ucode_state ret; 687 enum ucode_state ret;
687 688
688 /* free old equiv table */ 689 /* free old equiv table */
689 free_equiv_cpu_table(); 690 free_equiv_cpu_table();
690 691
691 ret = __load_microcode_amd(family, data, size); 692 ret = __load_microcode_amd(family, data, size);
692 693 if (ret != UCODE_OK) {
693 if (ret != UCODE_OK)
694 cleanup(); 694 cleanup();
695 return ret;
696 }
695 697
696#ifdef CONFIG_X86_32 698 p = find_patch(0);
697 /* save BSP's matching patch for early load */ 699 if (!p) {
698 if (save) { 700 return ret;
699 struct ucode_patch *p = find_patch(0); 701 } else {
700 if (p) { 702 if (boot_cpu_data.microcode == p->patch_id)
701 memset(amd_ucode_patch, 0, PATCH_MAX_SIZE); 703 return ret;
702 memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data), 704
703 PATCH_MAX_SIZE)); 705 ret = UCODE_NEW;
704 }
705 } 706 }
706#endif 707
708 /* save BSP's matching patch for early load */
709 if (!save)
710 return ret;
711
712 memset(amd_ucode_patch, 0, PATCH_MAX_SIZE);
713 memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data), PATCH_MAX_SIZE));
714
707 return ret; 715 return ret;
708} 716}
709 717
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 70ecbc8099c9..9f0fe5bb450d 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -607,7 +607,7 @@ static ssize_t reload_store(struct device *dev,
607 return size; 607 return size;
608 608
609 tmp_ret = microcode_ops->request_microcode_fw(bsp, &microcode_pdev->dev, true); 609 tmp_ret = microcode_ops->request_microcode_fw(bsp, &microcode_pdev->dev, true);
610 if (tmp_ret != UCODE_OK) 610 if (tmp_ret != UCODE_NEW)
611 return size; 611 return size;
612 612
613 get_online_cpus(); 613 get_online_cpus();
@@ -691,10 +691,8 @@ static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw)
691 if (system_state != SYSTEM_RUNNING) 691 if (system_state != SYSTEM_RUNNING)
692 return UCODE_NFOUND; 692 return UCODE_NFOUND;
693 693
694 ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev, 694 ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev, refresh_fw);
695 refresh_fw); 695 if (ustate == UCODE_NEW) {
696
697 if (ustate == UCODE_OK) {
698 pr_debug("CPU%d updated upon init\n", cpu); 696 pr_debug("CPU%d updated upon init\n", cpu);
699 apply_microcode_on_target(cpu); 697 apply_microcode_on_target(cpu);
700 } 698 }
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index 2aded9db1d42..32b8e5724f96 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -862,6 +862,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
862 unsigned int leftover = size; 862 unsigned int leftover = size;
863 unsigned int curr_mc_size = 0, new_mc_size = 0; 863 unsigned int curr_mc_size = 0, new_mc_size = 0;
864 unsigned int csig, cpf; 864 unsigned int csig, cpf;
865 enum ucode_state ret = UCODE_OK;
865 866
866 while (leftover) { 867 while (leftover) {
867 struct microcode_header_intel mc_header; 868 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 new_mc = mc; 904 new_mc = mc;
904 new_mc_size = mc_size; 905 new_mc_size = mc_size;
905 mc = NULL; /* trigger new vmalloc */ 906 mc = NULL; /* trigger new vmalloc */
907 ret = UCODE_NEW;
906 } 908 }
907 909
908 ucode_ptr += mc_size; 910 ucode_ptr += mc_size;
@@ -932,7 +934,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
932 pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", 934 pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
933 cpu, new_rev, uci->cpu_sig.rev); 935 cpu, new_rev, uci->cpu_sig.rev);
934 936
935 return UCODE_OK; 937 return ret;
936} 938}
937 939
938static int get_ucode_fw(void *to, const void *from, size_t n) 940static int get_ucode_fw(void *to, const void *from, size_t n)