Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/microcode: Parse built-in microcode early

Apparently, people do build microcode into the kernel image, i.e.
CONFIG_FIRMWARE_IN_KERNEL=y.

Make that work in the early loader which is where microcode should be
preferably loaded anyway.

Note that you need to specify the microcode filename with the path
relative to the toplevel firmware directory (the same like the late
loading method) in CONFIG_EXTRA_FIRMWARE=y so that early loader can
find it.

I.e., something like this (Intel variant):

CONFIG_FIRMWARE_IN_KERNEL=y
CONFIG_EXTRA_FIRMWARE="intel-ucode/06-3a-09"
CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware/"

While at it, add me to the loader copyright boilerplate.

Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Daniel J Blueman <daniel@numascale.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Borislav Petkov and committed by
Ingo Molnar
760d765b da9b5076

+68 -9
+7 -1
arch/x86/include/asm/microcode.h
··· 1 1 #ifndef _ASM_X86_MICROCODE_H 2 2 #define _ASM_X86_MICROCODE_H 3 3 4 + #include <linux/earlycpio.h> 5 + 4 6 #define native_rdmsr(msr, val1, val2) \ 5 7 do { \ 6 8 u64 __val = native_read_msr((msr)); \ ··· 154 152 extern void load_ucode_ap(void); 155 153 extern int __init save_microcode_in_initrd(void); 156 154 void reload_early_microcode(void); 155 + extern bool get_builtin_firmware(struct cpio_data *cd, const char *name); 157 156 #else 158 157 static inline void __init load_ucode_bsp(void) {} 159 158 static inline void load_ucode_ap(void) {} ··· 163 160 return 0; 164 161 } 165 162 static inline void reload_early_microcode(void) {} 163 + static inline bool get_builtin_firmware(struct cpio_data *cd, const char *name) 164 + { 165 + return false; 166 + } 166 167 #endif 167 - 168 168 #endif /* _ASM_X86_MICROCODE_H */
+2 -2
arch/x86/include/asm/microcode_amd.h
··· 65 65 extern u8 amd_ucode_patch[PATCH_MAX_SIZE]; 66 66 67 67 #ifdef CONFIG_MICROCODE_AMD_EARLY 68 - extern void __init load_ucode_amd_bsp(void); 68 + extern void __init load_ucode_amd_bsp(int family); 69 69 extern void load_ucode_amd_ap(void); 70 70 extern int __init save_microcode_in_initrd_amd(void); 71 71 void reload_ucode_amd(void); 72 72 #else 73 - static inline void __init load_ucode_amd_bsp(void) {} 73 + static inline void __init load_ucode_amd_bsp(int family) {} 74 74 static inline void load_ucode_amd_ap(void) {} 75 75 static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; } 76 76 void reload_ucode_amd(void) {}
+16 -3
arch/x86/kernel/cpu/microcode/amd_early.c
··· 228 228 } 229 229 } 230 230 231 - void __init load_ucode_amd_bsp(void) 231 + static bool __init load_builtin_amd_microcode(struct cpio_data *cp, int family) 232 + { 233 + char fw_name[36] = "amd-ucode/microcode_amd.bin"; 234 + 235 + if (family >= 0x15) 236 + snprintf(fw_name, sizeof(fw_name), 237 + "amd-ucode/microcode_amd_fam%.2xh.bin", family); 238 + 239 + return get_builtin_firmware(cp, fw_name); 240 + } 241 + 242 + void __init load_ucode_amd_bsp(int family) 232 243 { 233 244 struct cpio_data cp; 234 245 void **data; ··· 254 243 #endif 255 244 256 245 cp = find_ucode_in_initrd(); 257 - if (!cp.data) 258 - return; 246 + if (!cp.data) { 247 + if (!load_builtin_amd_microcode(&cp, family)) 248 + return; 249 + } 259 250 260 251 *data = cp.data; 261 252 *size = cp.size;
+22 -1
arch/x86/kernel/cpu/microcode/core_early.c
··· 3 3 * 4 4 * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com> 5 5 * H Peter Anvin" <hpa@zytor.com> 6 + * (C) 2015 Borislav Petkov <bp@alien8.de> 6 7 * 7 8 * This driver allows to early upgrade microcode on Intel processors 8 9 * belonging to IA-32 family - PentiumPro, Pentium II, ··· 18 17 * 2 of the License, or (at your option) any later version. 19 18 */ 20 19 #include <linux/module.h> 20 + #include <linux/firmware.h> 21 21 #include <asm/microcode.h> 22 22 #include <asm/microcode_intel.h> 23 23 #include <asm/microcode_amd.h> ··· 45 43 return *res; 46 44 } 47 45 46 + extern struct builtin_fw __start_builtin_fw[]; 47 + extern struct builtin_fw __end_builtin_fw[]; 48 + 49 + bool get_builtin_firmware(struct cpio_data *cd, const char *name) 50 + { 51 + #ifdef CONFIG_FW_LOADER 52 + struct builtin_fw *b_fw; 53 + 54 + for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) { 55 + if (!strcmp(name, b_fw->name)) { 56 + cd->size = b_fw->size; 57 + cd->data = b_fw->data; 58 + return true; 59 + } 60 + } 61 + #endif 62 + return false; 63 + } 64 + 48 65 void __init load_ucode_bsp(void) 49 66 { 50 67 int vendor, family; ··· 84 63 break; 85 64 case X86_VENDOR_AMD: 86 65 if (family >= 0x10) 87 - load_ucode_amd_bsp(); 66 + load_ucode_amd_bsp(family); 88 67 break; 89 68 default: 90 69 break;
+21 -2
arch/x86/kernel/cpu/microcode/intel_early.c
··· 521 521 EXPORT_SYMBOL_GPL(save_mc_for_early); 522 522 #endif 523 523 524 + static bool __init load_builtin_intel_microcode(struct cpio_data *cp) 525 + { 526 + u32 eax = 0x00000001, ebx, ecx = 0, edx; 527 + int family, model, stepping; 528 + char name[30]; 529 + 530 + native_cpuid(&eax, &ebx, &ecx, &edx); 531 + 532 + family = __x86_family(eax); 533 + model = x86_model(eax); 534 + stepping = eax & 0xf; 535 + 536 + sprintf(name, "intel-ucode/%02x-%02x-%02x", family, model, stepping); 537 + 538 + return get_builtin_firmware(cp, name); 539 + } 540 + 524 541 static __initdata char ucode_name[] = "kernel/x86/microcode/GenuineIntel.bin"; 525 542 static __init enum ucode_state 526 543 scan_microcode(struct mc_saved_data *mc_saved_data, unsigned long *initrd, ··· 556 539 cd.size = 0; 557 540 558 541 cd = find_cpio_data(p, (void *)start, size, &offset); 559 - if (!cd.data) 560 - return UCODE_ERROR; 542 + if (!cd.data) { 543 + if (!load_builtin_intel_microcode(&cd)) 544 + return UCODE_ERROR; 545 + } 561 546 562 547 return get_matching_model_microcode(0, start, cd.data, cd.size, 563 548 mc_saved_data, initrd, uci);