diff options
author | Borislav Petkov <bp@suse.de> | 2018-03-14 14:36:14 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2018-03-16 15:55:51 -0400 |
commit | 2613f36ed965d0e5a595a1d931fd3b480e82d6fd (patch) | |
tree | 47c242f71716d90d80c84f6e8c2ac576737fc4a3 | |
parent | e3b3121fa8da94cb20f9e0c64ab7981ae47fd085 (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.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/microcode/amd.c | 34 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/microcode/core.c | 8 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/microcode/intel.c | 4 |
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 | ||
40 | enum ucode_state { | 40 | enum 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, | |||
683 | static enum ucode_state | 683 | static enum ucode_state |
684 | load_microcode_amd(bool save, u8 family, const u8 *data, size_t size) | 684 | load_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, µcode_pdev->dev, true); | 609 | tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_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, µcode_pdev->dev, | 694 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_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 | ||
938 | static int get_ucode_fw(void *to, const void *from, size_t n) | 940 | static int get_ucode_fw(void *to, const void *from, size_t n) |