diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-10 18:01:43 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-10 18:01:43 -0500 |
| commit | 3a5dc1fafb016560315fe45bb4ef8bde259dd1bc (patch) | |
| tree | 6de33857df82f8b7f2200345192cf58939cb5823 | |
| parent | 3100e448e7d74489a96cb7b45d88fe6962774eaa (diff) | |
| parent | 25cdb9c86826f8d035d8aaa07fc36832e76bd8a0 (diff) | |
Merge branch 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 microcode loading updates from Ingo Molnar:
"The main changes in this cycle are:
- Reload microcode when resuming and the case when only the early
loader has been utilized. (Borislav Petkov)
- Also, do not load the driver on paravirt guests. (Boris
Ostrovsky)"
* 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/microcode/intel: Fish out the stashed microcode for the BSP
x86, microcode: Reload microcode on resume
x86, microcode: Don't initialize microcode code on paravirt
x86, microcode, intel: Drop unused parameter
x86, microcode, AMD: Do not use smp_processor_id() in preemtible context
| -rw-r--r-- | arch/x86/include/asm/microcode.h | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/microcode_amd.h | 4 | ||||
| -rw-r--r-- | arch/x86/include/asm/microcode_intel.h | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/microcode/amd.c | 8 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/microcode/amd_early.c | 20 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/microcode/core.c | 12 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/microcode/core_early.c | 21 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/microcode/intel_early.c | 42 |
8 files changed, 87 insertions, 24 deletions
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index 64dc362506b7..201b520521ed 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h | |||
| @@ -78,6 +78,7 @@ static inline void __exit exit_amd_microcode(void) {} | |||
| 78 | extern void __init load_ucode_bsp(void); | 78 | extern void __init load_ucode_bsp(void); |
| 79 | extern void load_ucode_ap(void); | 79 | extern void load_ucode_ap(void); |
| 80 | extern int __init save_microcode_in_initrd(void); | 80 | extern int __init save_microcode_in_initrd(void); |
| 81 | void reload_early_microcode(void); | ||
| 81 | #else | 82 | #else |
| 82 | static inline void __init load_ucode_bsp(void) {} | 83 | static inline void __init load_ucode_bsp(void) {} |
| 83 | static inline void load_ucode_ap(void) {} | 84 | static inline void load_ucode_ap(void) {} |
| @@ -85,6 +86,7 @@ static inline int __init save_microcode_in_initrd(void) | |||
| 85 | { | 86 | { |
| 86 | return 0; | 87 | return 0; |
| 87 | } | 88 | } |
| 89 | static inline void reload_early_microcode(void) {} | ||
| 88 | #endif | 90 | #endif |
| 89 | 91 | ||
| 90 | #endif /* _ASM_X86_MICROCODE_H */ | 92 | #endif /* _ASM_X86_MICROCODE_H */ |
diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h index b7b10b82d3e5..af935397e053 100644 --- a/arch/x86/include/asm/microcode_amd.h +++ b/arch/x86/include/asm/microcode_amd.h | |||
| @@ -59,7 +59,7 @@ static inline u16 find_equiv_id(struct equiv_cpu_entry *equiv_cpu_table, | |||
| 59 | 59 | ||
| 60 | extern int __apply_microcode_amd(struct microcode_amd *mc_amd); | 60 | extern int __apply_microcode_amd(struct microcode_amd *mc_amd); |
| 61 | extern int apply_microcode_amd(int cpu); | 61 | extern int apply_microcode_amd(int cpu); |
| 62 | extern enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size); | 62 | extern enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size); |
| 63 | 63 | ||
| 64 | #define PATCH_MAX_SIZE PAGE_SIZE | 64 | #define PATCH_MAX_SIZE PAGE_SIZE |
| 65 | extern u8 amd_ucode_patch[PATCH_MAX_SIZE]; | 65 | extern u8 amd_ucode_patch[PATCH_MAX_SIZE]; |
| @@ -68,10 +68,12 @@ extern u8 amd_ucode_patch[PATCH_MAX_SIZE]; | |||
| 68 | extern void __init load_ucode_amd_bsp(void); | 68 | extern void __init load_ucode_amd_bsp(void); |
| 69 | extern void load_ucode_amd_ap(void); | 69 | extern void load_ucode_amd_ap(void); |
| 70 | extern int __init save_microcode_in_initrd_amd(void); | 70 | extern int __init save_microcode_in_initrd_amd(void); |
| 71 | void reload_ucode_amd(void); | ||
| 71 | #else | 72 | #else |
| 72 | static inline void __init load_ucode_amd_bsp(void) {} | 73 | static inline void __init load_ucode_amd_bsp(void) {} |
| 73 | static inline void load_ucode_amd_ap(void) {} | 74 | static inline void load_ucode_amd_ap(void) {} |
| 74 | static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; } | 75 | static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; } |
| 76 | void reload_ucode_amd(void) {} | ||
| 75 | #endif | 77 | #endif |
| 76 | 78 | ||
| 77 | #endif /* _ASM_X86_MICROCODE_AMD_H */ | 79 | #endif /* _ASM_X86_MICROCODE_AMD_H */ |
diff --git a/arch/x86/include/asm/microcode_intel.h b/arch/x86/include/asm/microcode_intel.h index bbe296e0bce1..dd4c20043ce7 100644 --- a/arch/x86/include/asm/microcode_intel.h +++ b/arch/x86/include/asm/microcode_intel.h | |||
| @@ -68,11 +68,13 @@ extern void __init load_ucode_intel_bsp(void); | |||
| 68 | extern void load_ucode_intel_ap(void); | 68 | extern void load_ucode_intel_ap(void); |
| 69 | extern void show_ucode_info_early(void); | 69 | extern void show_ucode_info_early(void); |
| 70 | extern int __init save_microcode_in_initrd_intel(void); | 70 | extern int __init save_microcode_in_initrd_intel(void); |
| 71 | void reload_ucode_intel(void); | ||
| 71 | #else | 72 | #else |
| 72 | static inline __init void load_ucode_intel_bsp(void) {} | 73 | static inline __init void load_ucode_intel_bsp(void) {} |
| 73 | static inline void load_ucode_intel_ap(void) {} | 74 | static inline void load_ucode_intel_ap(void) {} |
| 74 | static inline void show_ucode_info_early(void) {} | 75 | static inline void show_ucode_info_early(void) {} |
| 75 | static inline int __init save_microcode_in_initrd_intel(void) { return -EINVAL; } | 76 | static inline int __init save_microcode_in_initrd_intel(void) { return -EINVAL; } |
| 77 | static inline void reload_ucode_intel(void) {} | ||
| 76 | #endif | 78 | #endif |
| 77 | 79 | ||
| 78 | #if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU) | 80 | #if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU) |
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 8fffd845e22b..bfbbe6195e2d 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c | |||
| @@ -376,7 +376,7 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, | |||
| 376 | return UCODE_OK; | 376 | return UCODE_OK; |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size) | 379 | enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size) |
| 380 | { | 380 | { |
| 381 | enum ucode_state ret; | 381 | enum ucode_state ret; |
| 382 | 382 | ||
| @@ -390,8 +390,8 @@ enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size) | |||
| 390 | 390 | ||
| 391 | #if defined(CONFIG_MICROCODE_AMD_EARLY) && defined(CONFIG_X86_32) | 391 | #if defined(CONFIG_MICROCODE_AMD_EARLY) && defined(CONFIG_X86_32) |
| 392 | /* save BSP's matching patch for early load */ | 392 | /* save BSP's matching patch for early load */ |
| 393 | if (cpu_data(smp_processor_id()).cpu_index == boot_cpu_data.cpu_index) { | 393 | if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) { |
| 394 | struct ucode_patch *p = find_patch(smp_processor_id()); | 394 | struct ucode_patch *p = find_patch(cpu); |
| 395 | if (p) { | 395 | if (p) { |
| 396 | memset(amd_ucode_patch, 0, PATCH_MAX_SIZE); | 396 | memset(amd_ucode_patch, 0, PATCH_MAX_SIZE); |
| 397 | memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data), | 397 | memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data), |
| @@ -444,7 +444,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device, | |||
| 444 | goto fw_release; | 444 | goto fw_release; |
| 445 | } | 445 | } |
| 446 | 446 | ||
| 447 | ret = load_microcode_amd(c->x86, fw->data, fw->size); | 447 | ret = load_microcode_amd(cpu, c->x86, fw->data, fw->size); |
| 448 | 448 | ||
| 449 | fw_release: | 449 | fw_release: |
| 450 | release_firmware(fw); | 450 | release_firmware(fw); |
diff --git a/arch/x86/kernel/cpu/microcode/amd_early.c b/arch/x86/kernel/cpu/microcode/amd_early.c index 06674473b0e6..737737edbd1e 100644 --- a/arch/x86/kernel/cpu/microcode/amd_early.c +++ b/arch/x86/kernel/cpu/microcode/amd_early.c | |||
| @@ -389,7 +389,7 @@ int __init save_microcode_in_initrd_amd(void) | |||
| 389 | eax = cpuid_eax(0x00000001); | 389 | eax = cpuid_eax(0x00000001); |
| 390 | eax = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff); | 390 | eax = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff); |
| 391 | 391 | ||
| 392 | ret = load_microcode_amd(eax, container, container_size); | 392 | ret = load_microcode_amd(smp_processor_id(), eax, container, container_size); |
| 393 | if (ret != UCODE_OK) | 393 | if (ret != UCODE_OK) |
| 394 | retval = -EINVAL; | 394 | retval = -EINVAL; |
| 395 | 395 | ||
| @@ -402,3 +402,21 @@ int __init save_microcode_in_initrd_amd(void) | |||
| 402 | 402 | ||
| 403 | return retval; | 403 | return retval; |
| 404 | } | 404 | } |
| 405 | |||
| 406 | void reload_ucode_amd(void) | ||
| 407 | { | ||
| 408 | struct microcode_amd *mc; | ||
| 409 | u32 rev, eax; | ||
| 410 | |||
| 411 | rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax); | ||
| 412 | |||
| 413 | mc = (struct microcode_amd *)amd_ucode_patch; | ||
| 414 | |||
| 415 | if (mc && rev < mc->hdr.patch_id) { | ||
| 416 | if (!__apply_microcode_amd(mc)) { | ||
| 417 | ucode_new_rev = mc->hdr.patch_id; | ||
| 418 | pr_info("microcode: reload patch_level=0x%08x\n", | ||
| 419 | ucode_new_rev); | ||
| 420 | } | ||
| 421 | } | ||
| 422 | } | ||
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 08fe6e8a726e..15c29096136b 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c | |||
| @@ -465,16 +465,8 @@ static void mc_bp_resume(void) | |||
| 465 | 465 | ||
| 466 | if (uci->valid && uci->mc) | 466 | if (uci->valid && uci->mc) |
| 467 | microcode_ops->apply_microcode(cpu); | 467 | microcode_ops->apply_microcode(cpu); |
| 468 | #ifdef CONFIG_X86_64 | ||
| 469 | else if (!uci->mc) | 468 | else if (!uci->mc) |
| 470 | /* | 469 | reload_early_microcode(); |
| 471 | * We might resume and not have applied late microcode but still | ||
| 472 | * have a newer patch stashed from the early loader. We don't | ||
| 473 | * have it in uci->mc so we have to load it the same way we're | ||
| 474 | * applying patches early on the APs. | ||
| 475 | */ | ||
| 476 | load_ucode_ap(); | ||
| 477 | #endif | ||
| 478 | } | 470 | } |
| 479 | 471 | ||
| 480 | static struct syscore_ops mc_syscore_ops = { | 472 | static struct syscore_ops mc_syscore_ops = { |
| @@ -559,7 +551,7 @@ static int __init microcode_init(void) | |||
| 559 | struct cpuinfo_x86 *c = &cpu_data(0); | 551 | struct cpuinfo_x86 *c = &cpu_data(0); |
| 560 | int error; | 552 | int error; |
| 561 | 553 | ||
| 562 | if (dis_ucode_ldr) | 554 | if (paravirt_enabled() || dis_ucode_ldr) |
| 563 | return 0; | 555 | return 0; |
| 564 | 556 | ||
| 565 | if (c->x86_vendor == X86_VENDOR_INTEL) | 557 | if (c->x86_vendor == X86_VENDOR_INTEL) |
diff --git a/arch/x86/kernel/cpu/microcode/core_early.c b/arch/x86/kernel/cpu/microcode/core_early.c index 2c017f242a78..d45df4bd16ab 100644 --- a/arch/x86/kernel/cpu/microcode/core_early.c +++ b/arch/x86/kernel/cpu/microcode/core_early.c | |||
| @@ -176,3 +176,24 @@ int __init save_microcode_in_initrd(void) | |||
| 176 | 176 | ||
| 177 | return 0; | 177 | return 0; |
| 178 | } | 178 | } |
| 179 | |||
| 180 | void reload_early_microcode(void) | ||
| 181 | { | ||
| 182 | int vendor, x86; | ||
| 183 | |||
| 184 | vendor = x86_vendor(); | ||
| 185 | x86 = x86_family(); | ||
| 186 | |||
| 187 | switch (vendor) { | ||
| 188 | case X86_VENDOR_INTEL: | ||
| 189 | if (x86 >= 6) | ||
| 190 | reload_ucode_intel(); | ||
| 191 | break; | ||
| 192 | case X86_VENDOR_AMD: | ||
| 193 | if (x86 >= 0x10) | ||
| 194 | reload_ucode_amd(); | ||
| 195 | break; | ||
| 196 | default: | ||
| 197 | break; | ||
| 198 | } | ||
| 199 | } | ||
diff --git a/arch/x86/kernel/cpu/microcode/intel_early.c b/arch/x86/kernel/cpu/microcode/intel_early.c index b88343f7a3b3..ec9df6f9cd47 100644 --- a/arch/x86/kernel/cpu/microcode/intel_early.c +++ b/arch/x86/kernel/cpu/microcode/intel_early.c | |||
| @@ -650,8 +650,7 @@ static inline void print_ucode(struct ucode_cpu_info *uci) | |||
| 650 | } | 650 | } |
| 651 | #endif | 651 | #endif |
| 652 | 652 | ||
| 653 | static int apply_microcode_early(struct mc_saved_data *mc_saved_data, | 653 | static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) |
| 654 | struct ucode_cpu_info *uci) | ||
| 655 | { | 654 | { |
| 656 | struct microcode_intel *mc_intel; | 655 | struct microcode_intel *mc_intel; |
| 657 | unsigned int val[2]; | 656 | unsigned int val[2]; |
| @@ -680,7 +679,10 @@ static int apply_microcode_early(struct mc_saved_data *mc_saved_data, | |||
| 680 | #endif | 679 | #endif |
| 681 | uci->cpu_sig.rev = val[1]; | 680 | uci->cpu_sig.rev = val[1]; |
| 682 | 681 | ||
| 683 | print_ucode(uci); | 682 | if (early) |
| 683 | print_ucode(uci); | ||
| 684 | else | ||
| 685 | print_ucode_info(uci, mc_intel->hdr.date); | ||
| 684 | 686 | ||
| 685 | return 0; | 687 | return 0; |
| 686 | } | 688 | } |
| @@ -715,12 +717,17 @@ _load_ucode_intel_bsp(struct mc_saved_data *mc_saved_data, | |||
| 715 | unsigned long initrd_end_early, | 717 | unsigned long initrd_end_early, |
| 716 | struct ucode_cpu_info *uci) | 718 | struct ucode_cpu_info *uci) |
| 717 | { | 719 | { |
| 720 | enum ucode_state ret; | ||
| 721 | |||
| 718 | collect_cpu_info_early(uci); | 722 | collect_cpu_info_early(uci); |
| 719 | scan_microcode(initrd_start_early, initrd_end_early, mc_saved_data, | 723 | scan_microcode(initrd_start_early, initrd_end_early, mc_saved_data, |
| 720 | mc_saved_in_initrd, uci); | 724 | mc_saved_in_initrd, uci); |
| 721 | load_microcode(mc_saved_data, mc_saved_in_initrd, | 725 | |
| 722 | initrd_start_early, uci); | 726 | ret = load_microcode(mc_saved_data, mc_saved_in_initrd, |
| 723 | apply_microcode_early(mc_saved_data, uci); | 727 | initrd_start_early, uci); |
| 728 | |||
| 729 | if (ret == UCODE_OK) | ||
| 730 | apply_microcode_early(uci, true); | ||
| 724 | } | 731 | } |
| 725 | 732 | ||
| 726 | void __init | 733 | void __init |
| @@ -749,7 +756,8 @@ load_ucode_intel_bsp(void) | |||
| 749 | initrd_end_early = initrd_start_early + ramdisk_size; | 756 | initrd_end_early = initrd_start_early + ramdisk_size; |
| 750 | 757 | ||
| 751 | _load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd, | 758 | _load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd, |
| 752 | initrd_start_early, initrd_end_early, &uci); | 759 | initrd_start_early, initrd_end_early, |
| 760 | &uci); | ||
| 753 | #endif | 761 | #endif |
| 754 | } | 762 | } |
| 755 | 763 | ||
| @@ -783,5 +791,23 @@ void load_ucode_intel_ap(void) | |||
| 783 | collect_cpu_info_early(&uci); | 791 | collect_cpu_info_early(&uci); |
| 784 | load_microcode(mc_saved_data_p, mc_saved_in_initrd_p, | 792 | load_microcode(mc_saved_data_p, mc_saved_in_initrd_p, |
| 785 | initrd_start_addr, &uci); | 793 | initrd_start_addr, &uci); |
| 786 | apply_microcode_early(mc_saved_data_p, &uci); | 794 | apply_microcode_early(&uci, true); |
| 795 | } | ||
| 796 | |||
| 797 | void reload_ucode_intel(void) | ||
| 798 | { | ||
| 799 | struct ucode_cpu_info uci; | ||
| 800 | enum ucode_state ret; | ||
| 801 | |||
| 802 | if (!mc_saved_data.mc_saved_count) | ||
| 803 | return; | ||
| 804 | |||
| 805 | collect_cpu_info_early(&uci); | ||
| 806 | |||
| 807 | ret = generic_load_microcode_early(mc_saved_data.mc_saved, | ||
| 808 | mc_saved_data.mc_saved_count, &uci); | ||
| 809 | if (ret != UCODE_OK) | ||
| 810 | return; | ||
| 811 | |||
| 812 | apply_microcode_early(&uci, false); | ||
| 787 | } | 813 | } |
