From 6c5456474e7f0b63be66d44b0595001e2a8b44d5 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 6 Jun 2016 17:10:42 +0200 Subject: x86/microcode: Fix loading precedence So it can happen that even with builtin microcode, CONFIG_BLK_DEV_INITRD=y gets forgotten enabled. Or, even with that disabled, an initrd image gets supplied by the boot loader, by omission or is simply forgotten there. And since we do look at boot_params.hdr.ramdisk_* to know whether we have received an initrd, we might get puzzled. So let's just make the loader look for builtin microcode first and if found, ignore the ramdisk image. If no builtin found, it falls back to scanning the supplied initrd, of course. For that, we move all the initrd scanning in a separate __scan_microcode_initrd() function and fall back to it only if load_builtin_intel_microcode() has failed. Reported-and-tested-by: Gabriel Craciunescu Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465225850-7352-2-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar --- arch/x86/include/asm/microcode.h | 24 ----- arch/x86/kernel/cpu/microcode/amd.c | 28 +++--- arch/x86/kernel/cpu/microcode/intel.c | 183 ++++++++++++++++++++++------------ 3 files changed, 133 insertions(+), 102 deletions(-) diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index 9d3a96c4da78..ca2af7ed6cbf 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h @@ -145,28 +145,4 @@ static inline bool get_builtin_firmware(struct cpio_data *cd, const char *name) { return false; } #endif -static inline unsigned long get_initrd_start(void) -{ -#ifdef CONFIG_BLK_DEV_INITRD - return initrd_start; -#else - return 0; -#endif -} - -static inline unsigned long get_initrd_start_addr(void) -{ -#ifdef CONFIG_BLK_DEV_INITRD -#ifdef CONFIG_X86_32 - unsigned long *initrd_start_p = (unsigned long *)__pa_nodebug(&initrd_start); - - return (unsigned long)__pa_nodebug(*initrd_start_p); -#else - return get_initrd_start(); -#endif -#else /* CONFIG_BLK_DEV_INITRD */ - return 0; -#endif -} - #endif /* _ASM_X86_MICROCODE_H */ diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 8581963894c7..11dd1cc8e444 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -61,19 +61,20 @@ static u16 this_equiv_id; static struct cpio_data ucode_cpio; -/* - * Microcode patch container file is prepended to the initrd in cpio format. - * See Documentation/x86/early-microcode.txt - */ -static __initdata char ucode_path[] = "kernel/x86/microcode/AuthenticAMD.bin"; - static struct cpio_data __init find_ucode_in_initrd(void) { +#ifdef CONFIG_BLK_DEV_INITRD long offset = 0; char *path; void *start; size_t size; + /* + * Microcode patch container file is prepended to the initrd in cpio + * format. See Documentation/x86/early-microcode.txt + */ + static __initdata char ucode_path[] = "kernel/x86/microcode/AuthenticAMD.bin"; + #ifdef CONFIG_X86_32 struct boot_params *p; @@ -89,9 +90,12 @@ static struct cpio_data __init find_ucode_in_initrd(void) path = ucode_path; start = (void *)(boot_params.hdr.ramdisk_image + PAGE_OFFSET); size = boot_params.hdr.ramdisk_size; -#endif +#endif /* !CONFIG_X86_32 */ return find_cpio_data(path, start, size, &offset); +#else + return (struct cpio_data){ NULL, 0, "" }; +#endif } static size_t compute_container_size(u8 *data, u32 total_size) @@ -289,11 +293,11 @@ void __init load_ucode_amd_bsp(unsigned int family) size = &ucode_cpio.size; #endif - cp = find_ucode_in_initrd(); - if (!cp.data) { - if (!load_builtin_amd_microcode(&cp, family)) - return; - } + if (!load_builtin_amd_microcode(&cp, family)) + cp = find_ucode_in_initrd(); + + if (!(cp.data && cp.size)) + return; *data = cp.data; *size = cp.size; diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 65cbbcd48fe4..5835d5b0db81 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -51,6 +51,12 @@ static struct mc_saved_data { struct microcode_intel **mc_saved; } mc_saved_data; +/* Microcode blobs within the initrd. 0 if builtin. */ +static struct ucode_blobs { + unsigned long start; + bool valid; +} blobs; + static enum ucode_state load_microcode_early(struct microcode_intel **saved, unsigned int num_saved, struct ucode_cpu_info *uci) @@ -532,37 +538,6 @@ static bool __init load_builtin_intel_microcode(struct cpio_data *cp) #endif } -static __initdata char ucode_name[] = "kernel/x86/microcode/GenuineIntel.bin"; -static __init enum ucode_state -scan_microcode(struct mc_saved_data *mcs, unsigned long *mc_ptrs, - unsigned long start, unsigned long size, - struct ucode_cpu_info *uci) -{ - struct cpio_data cd; - long offset = 0; -#ifdef CONFIG_X86_32 - char *p = (char *)__pa_nodebug(ucode_name); -#else - char *p = ucode_name; -#endif - - cd.data = NULL; - cd.size = 0; - - /* try built-in microcode if no initrd */ - if (!size) { - if (!load_builtin_intel_microcode(&cd)) - return UCODE_ERROR; - } else { - cd = find_cpio_data(p, (void *)start, size, &offset); - if (!cd.data) - return UCODE_ERROR; - } - - return get_matching_model_microcode(start, cd.data, cd.size, - mcs, mc_ptrs, uci); -} - /* * Print ucode update info. */ @@ -680,14 +655,22 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) */ int __init save_microcode_in_initrd_intel(void) { - unsigned int count = mc_saved_data.num_saved; struct microcode_intel *mc_saved[MAX_UCODE_COUNT]; - int ret = 0; + unsigned int count = mc_saved_data.num_saved; + unsigned long offset = 0; + int ret; if (!count) - return ret; + return 0; - copy_ptrs(mc_saved, mc_tmp_ptrs, get_initrd_start(), count); + /* + * We have found a valid initrd but it might've been relocated in the + * meantime so get its updated address. + */ + if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && blobs.valid) + offset = initrd_start; + + copy_ptrs(mc_saved, mc_tmp_ptrs, offset, count); ret = save_microcode(&mc_saved_data, mc_saved, count); if (ret) @@ -698,20 +681,92 @@ int __init save_microcode_in_initrd_intel(void) return ret; } +static __init enum ucode_state +__scan_microcode_initrd(struct cpio_data *cd, struct ucode_blobs *blbp) +{ +#ifdef CONFIG_BLK_DEV_INITRD + long offset = 0; + static __initdata char ucode_name[] = "kernel/x86/microcode/GenuineIntel.bin"; + char *p = IS_ENABLED(CONFIG_X86_32) ? (char *)__pa_nodebug(ucode_name) + : ucode_name; +# ifdef CONFIG_X86_32 + unsigned long start = 0, size; + struct boot_params *params; + + params = (struct boot_params *)__pa_nodebug(&boot_params); + size = params->hdr.ramdisk_size; + + /* + * Set start only if we have an initrd image. We cannot use initrd_start + * because it is not set that early yet. + */ + start = (size ? params->hdr.ramdisk_image : 0); + +# else /* CONFIG_X86_64 */ + unsigned long start = 0, size; + + size = (u64)boot_params.ext_ramdisk_size << 32; + size |= boot_params.hdr.ramdisk_size; + + if (size) { + start = (u64)boot_params.ext_ramdisk_image << 32; + start |= boot_params.hdr.ramdisk_image; + + start += PAGE_OFFSET; + } +# endif + + *cd = find_cpio_data(p, (void *)start, size, &offset); + if (cd->data) { + blbp->start = start; + blbp->valid = true; + + return UCODE_OK; + } else +#endif /* CONFIG_BLK_DEV_INITRD */ + return UCODE_ERROR; +} + +static __init enum ucode_state +scan_microcode(struct mc_saved_data *mcs, unsigned long *mc_ptrs, + struct ucode_cpu_info *uci, struct ucode_blobs *blbp) +{ + struct cpio_data cd = { NULL, 0, "" }; + enum ucode_state ret; + + /* try built-in microcode first */ + if (load_builtin_intel_microcode(&cd)) + /* + * Invalidate blobs as we might've gotten an initrd too, + * supplied by the boot loader, by mistake or simply forgotten + * there. That's fine, we ignore it since we've found builtin + * microcode already. + */ + blbp->valid = false; + else { + ret = __scan_microcode_initrd(&cd, blbp); + if (ret != UCODE_OK) + return ret; + } + + return get_matching_model_microcode(blbp->start, cd.data, cd.size, + mcs, mc_ptrs, uci); +} + static void __init _load_ucode_intel_bsp(struct mc_saved_data *mcs, unsigned long *mc_ptrs, - unsigned long start, unsigned long size) + struct ucode_blobs *blbp) { struct ucode_cpu_info uci; enum ucode_state ret; collect_cpu_info_early(&uci); - ret = scan_microcode(mcs, mc_ptrs, start, size, &uci); + ret = scan_microcode(mcs, mc_ptrs, &uci, blbp); if (ret != UCODE_OK) return; - ret = load_microcode(mcs, mc_ptrs, start, &uci); + ret = load_microcode(mcs, mc_ptrs, blbp->start, &uci); if (ret != UCODE_OK) return; @@ -720,54 +775,50 @@ _load_ucode_intel_bsp(struct mc_saved_data *mcs, unsigned long *mc_ptrs, void __init load_ucode_intel_bsp(void) { - u64 start, size; -#ifdef CONFIG_X86_32 - struct boot_params *p; - - p = (struct boot_params *)__pa_nodebug(&boot_params); - size = p->hdr.ramdisk_size; - - /* - * Set start only if we have an initrd image. We cannot use initrd_start - * because it is not set that early yet. - */ - start = (size ? p->hdr.ramdisk_image : 0); + struct ucode_blobs *blobs_p; + struct mc_saved_data *mcs; + unsigned long *ptrs; - _load_ucode_intel_bsp((struct mc_saved_data *)__pa_nodebug(&mc_saved_data), - (unsigned long *)__pa_nodebug(&mc_tmp_ptrs), - start, size); +#ifdef CONFIG_X86_32 + mcs = (struct mc_saved_data *)__pa_nodebug(&mc_saved_data); + ptrs = (unsigned long *)__pa_nodebug(&mc_tmp_ptrs); + blobs_p = (struct ucode_blobs *)__pa_nodebug(&blobs); #else - size = boot_params.hdr.ramdisk_size; - start = (size ? boot_params.hdr.ramdisk_image + PAGE_OFFSET : 0); - - _load_ucode_intel_bsp(&mc_saved_data, mc_tmp_ptrs, start, size); + mcs = &mc_saved_data; + ptrs = mc_tmp_ptrs; + blobs_p = &blobs; #endif + + _load_ucode_intel_bsp(mcs, ptrs, blobs_p); } void load_ucode_intel_ap(void) { - unsigned long *mcs_tmp_p; - struct mc_saved_data *mcs_p; + struct ucode_blobs *blobs_p; + struct mc_saved_data *mcs; struct ucode_cpu_info uci; enum ucode_state ret; -#ifdef CONFIG_X86_32 + unsigned long *ptrs; - mcs_tmp_p = (unsigned long *)__pa_nodebug(mc_tmp_ptrs); - mcs_p = (struct mc_saved_data *)__pa_nodebug(&mc_saved_data); +#ifdef CONFIG_X86_32 + mcs = (struct mc_saved_data *)__pa_nodebug(&mc_saved_data); + ptrs = (unsigned long *)__pa_nodebug(mc_tmp_ptrs); + blobs_p = (struct ucode_blobs *)__pa_nodebug(&blobs); #else - mcs_tmp_p = mc_tmp_ptrs; - mcs_p = &mc_saved_data; + mcs = &mc_saved_data; + ptrs = mc_tmp_ptrs; + blobs_p = &blobs; #endif /* * If there is no valid ucode previously saved in memory, no need to * update ucode on this AP. */ - if (!mcs_p->num_saved) + if (!mcs->num_saved) return; collect_cpu_info_early(&uci); - ret = load_microcode(mcs_p, mcs_tmp_p, get_initrd_start_addr(), &uci); + ret = load_microcode(mcs, ptrs, blobs_p->start, &uci); if (ret != UCODE_OK) return; -- cgit v1.2.3 From 4b703305d98bf7350d4b2953ee39a3aa2eeb1778 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 6 Jun 2016 17:10:43 +0200 Subject: x86/microcode: Fix suspend to RAM with builtin microcode Usually, after we have found the proper microcode blob for the current machine, we stash it away for later use with save_microcode_in_initrd(). However, with builtin microcode which doesn't come from the initrd, we don't call that function because CONFIG_BLK_DEV_INITRD=n and even if set, we don't have a valid initrd. In order to fix this, let's make save_microcode_in_initrd() an fs_initcall which runs before rootfs_initcall() as this was the time it was called previously through: rootfs_initcall(populate_rootfs) |-> free_initrd() |-> free_initrd_mem() |-> save_microcode_in_initrd() Also, we make it run independently from initrd functionality being present or not. And since it is called in the microcode loader only now, we can also make it static. Reported-and-tested-by: Jim Bos Signed-off-by: Borislav Petkov Cc: # v4.6 Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465225850-7352-3-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar --- arch/x86/include/asm/microcode.h | 2 -- arch/x86/kernel/cpu/microcode/core.c | 3 ++- arch/x86/mm/init.c | 7 ------- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index ca2af7ed6cbf..da0d81fa0b54 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h @@ -133,13 +133,11 @@ static inline unsigned int x86_cpuid_family(void) #ifdef CONFIG_MICROCODE extern void __init load_ucode_bsp(void); extern void load_ucode_ap(void); -extern int __init save_microcode_in_initrd(void); void reload_early_microcode(void); extern bool get_builtin_firmware(struct cpio_data *cd, const char *name); #else static inline void __init load_ucode_bsp(void) { } static inline void load_ucode_ap(void) { } -static inline int __init save_microcode_in_initrd(void) { return 0; } static inline void reload_early_microcode(void) { } static inline bool get_builtin_firmware(struct cpio_data *cd, const char *name) { return false; } diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index ac360bfbbdb6..12823b6ebd6d 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -175,7 +175,7 @@ void load_ucode_ap(void) } } -int __init save_microcode_in_initrd(void) +static int __init save_microcode_in_initrd(void) { struct cpuinfo_x86 *c = &boot_cpu_data; @@ -691,4 +691,5 @@ int __init microcode_init(void) return error; } +fs_initcall(save_microcode_in_initrd); late_initcall(microcode_init); diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 372aad2b3291..dffd162db0a4 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -695,13 +695,6 @@ void free_initmem(void) #ifdef CONFIG_BLK_DEV_INITRD void __init free_initrd_mem(unsigned long start, unsigned long end) { - /* - * Remember, initrd memory may contain microcode or other useful things. - * Before we lose initrd mem, we need to find a place to hold them - * now that normal virtual memory is enabled. - */ - save_microcode_in_initrd(); - /* * end could be not aligned, and We can not align that, * decompresser could be confused by aligned initrd_end -- cgit v1.2.3 From 7557933e6b99d381c19b196901ed537b00f6d121 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 6 Jun 2016 17:10:44 +0200 Subject: lib/cpio: Make find_cpio_data()'s offset arg optional Some callers don't use it so make it optional. Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465225850-7352-4-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar --- lib/earlycpio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/earlycpio.c b/lib/earlycpio.c index 3eb3e4722b8e..db283ba4d2c1 100644 --- a/lib/earlycpio.c +++ b/lib/earlycpio.c @@ -125,7 +125,10 @@ struct cpio_data find_cpio_data(const char *path, void *data, if ((ch[C_MODE] & 0170000) == 0100000 && ch[C_NAMESIZE] >= mypathsize && !memcmp(p, path, mypathsize)) { - *nextoff = (long)nptr - (long)data; + + if (nextoff) + *nextoff = (long)nptr - (long)data; + if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) { pr_warn( "File %s exceeding MAX_CPIO_FILE_NAME [%d]\n", -- cgit v1.2.3 From 852ad5b94524fd76d49944b9db0a93f7c9ee5814 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 6 Jun 2016 17:10:45 +0200 Subject: x86/microcode: Get rid of find_cpio_data()'s dummy offset arg The microcode loader doesn't use it and now that that arg has been made optional in find_cpio_data(), get rid of it here. No functionality change. Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465225850-7352-5-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/microcode/amd.c | 3 +-- arch/x86/kernel/cpu/microcode/intel.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 11dd1cc8e444..b1d1e345f5f5 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -64,7 +64,6 @@ static struct cpio_data ucode_cpio; static struct cpio_data __init find_ucode_in_initrd(void) { #ifdef CONFIG_BLK_DEV_INITRD - long offset = 0; char *path; void *start; size_t size; @@ -92,7 +91,7 @@ static struct cpio_data __init find_ucode_in_initrd(void) size = boot_params.hdr.ramdisk_size; #endif /* !CONFIG_X86_32 */ - return find_cpio_data(path, start, size, &offset); + return find_cpio_data(path, start, size, NULL); #else return (struct cpio_data){ NULL, 0, "" }; #endif diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 5835d5b0db81..2ad40b73c8df 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -685,7 +685,6 @@ static __init enum ucode_state __scan_microcode_initrd(struct cpio_data *cd, struct ucode_blobs *blbp) { #ifdef CONFIG_BLK_DEV_INITRD - long offset = 0; static __initdata char ucode_name[] = "kernel/x86/microcode/GenuineIntel.bin"; char *p = IS_ENABLED(CONFIG_X86_32) ? (char *)__pa_nodebug(ucode_name) : ucode_name; @@ -716,7 +715,7 @@ __scan_microcode_initrd(struct cpio_data *cd, struct ucode_blobs *blbp) } # endif - *cd = find_cpio_data(p, (void *)start, size, &offset); + *cd = find_cpio_data(p, (void *)start, size, NULL); if (cd->data) { blbp->start = start; blbp->valid = true; -- cgit v1.2.3 From fa6788b8c681ffe0a1bf9f99dddc2c447069241c Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 6 Jun 2016 17:10:46 +0200 Subject: x86/microcode: Propagate save_microcode_in_initrd() retval Will be used in a later patch. No functionality change. Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465225850-7352-6-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/microcode/core.c | 6 +++--- arch/x86/kernel/cpu/microcode/intel.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 12823b6ebd6d..9ae7fcac70ab 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -182,17 +182,17 @@ static int __init save_microcode_in_initrd(void) switch (c->x86_vendor) { case X86_VENDOR_INTEL: if (c->x86 >= 6) - save_microcode_in_initrd_intel(); + return save_microcode_in_initrd_intel(); break; case X86_VENDOR_AMD: if (c->x86 >= 0x10) - save_microcode_in_initrd_amd(); + return save_microcode_in_initrd_amd(); break; default: break; } - return 0; + return -EINVAL; } void reload_early_microcode(void) diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 2ad40b73c8df..d852ca984f87 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -675,8 +675,8 @@ int __init save_microcode_in_initrd_intel(void) ret = save_microcode(&mc_saved_data, mc_saved, count); if (ret) pr_err("Cannot save microcode patches from initrd.\n"); - - show_saved_mc(); + else + show_saved_mc(); return ret; } -- cgit v1.2.3 From 9198251af1554c21fae8e43a940a8bed435ee1b3 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 6 Jun 2016 17:10:47 +0200 Subject: x86/microcode/intel: Rename load_microcode_early() to find_microcode_patch() This function does exactly that: it goes through the previously saved array of microcode blobs and finds the proper one for the current CPU. Rename it accordingly. No functionality change. Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465225850-7352-7-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/microcode/intel.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index d852ca984f87..b5759a3f0aa8 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -58,7 +58,7 @@ static struct ucode_blobs { } blobs; static enum ucode_state -load_microcode_early(struct microcode_intel **saved, +find_microcode_patch(struct microcode_intel **saved, unsigned int num_saved, struct ucode_cpu_info *uci) { struct microcode_intel *ucode_ptr, *new_mc = NULL; @@ -127,13 +127,13 @@ load_microcode(struct mc_saved_data *mcs, unsigned long *mc_ptrs, if (!mcs->mc_saved) { copy_ptrs(mc_saved_tmp, mc_ptrs, offset, count); - return load_microcode_early(mc_saved_tmp, count, uci); + return find_microcode_patch(mc_saved_tmp, count, uci); } else { #ifdef CONFIG_X86_32 microcode_phys(mc_saved_tmp, mcs); - return load_microcode_early(mc_saved_tmp, count, uci); + return find_microcode_patch(mc_saved_tmp, count, uci); #else - return load_microcode_early(mcs->mc_saved, count, uci); + return find_microcode_patch(mcs->mc_saved, count, uci); #endif } } @@ -834,7 +834,7 @@ void reload_ucode_intel(void) collect_cpu_info_early(&uci); - ret = load_microcode_early(mc_saved_data.mc_saved, + ret = find_microcode_patch(mc_saved_data.mc_saved, mc_saved_data.num_saved, &uci); if (ret != UCODE_OK) return; -- cgit v1.2.3 From 0c5fa827f1130d05858f158022c21e9e7e5cff92 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 6 Jun 2016 17:10:48 +0200 Subject: x86/microcode/intel: Unexport save_mc_for_early() It is used only in intel.c, drop the CONFIG_HOTPLUG_CPU ifdeffery from the header and turn it into a void function because its return value wasn't being used anyway. No functionality change. Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465225850-7352-8-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar --- arch/x86/include/asm/microcode_intel.h | 5 ----- arch/x86/kernel/cpu/microcode/intel.c | 15 ++++++--------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/arch/x86/include/asm/microcode_intel.h b/arch/x86/include/asm/microcode_intel.h index 603417f8dd6c..5e69154c9f07 100644 --- a/arch/x86/include/asm/microcode_intel.h +++ b/arch/x86/include/asm/microcode_intel.h @@ -70,9 +70,4 @@ static inline int __init save_microcode_in_initrd_intel(void) { return -EINVAL; static inline void reload_ucode_intel(void) {} #endif -#ifdef CONFIG_HOTPLUG_CPU -extern int save_mc_for_early(u8 *mc); -#else -static inline int save_mc_for_early(u8 *mc) { return 0; } -#endif #endif /* _ASM_X86_MICROCODE_INTEL_H */ diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index b5759a3f0aa8..359e2034b558 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -456,8 +456,6 @@ static void show_saved_mc(void) #endif } -#ifdef CONFIG_HOTPLUG_CPU -static DEFINE_MUTEX(x86_cpu_microcode_mutex); /* * Save this mc into mc_saved_data. So it will be loaded early when a CPU is * hot added or resumes. @@ -465,14 +463,16 @@ static DEFINE_MUTEX(x86_cpu_microcode_mutex); * Please make sure this mc should be a valid microcode patch before calling * this function. */ -int save_mc_for_early(u8 *mc) +static void save_mc_for_early(u8 *mc) { +#ifdef CONFIG_HOTPLUG_CPU + static DEFINE_MUTEX(x86_cpu_microcode_mutex); + struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT]; unsigned int mc_saved_count_init; unsigned int num_saved; struct microcode_intel **mc_saved; - int ret = 0; - int i; + int ret, i; /* * Hold hotplug lock so mc_saved_data is not accessed by a CPU in @@ -515,11 +515,8 @@ int save_mc_for_early(u8 *mc) out: mutex_unlock(&x86_cpu_microcode_mutex); - - return ret; -} -EXPORT_SYMBOL_GPL(save_mc_for_early); #endif +} static bool __init load_builtin_intel_microcode(struct cpio_data *cp) { -- cgit v1.2.3 From a13004a2449c56a83d5816e81d850ea92b6837c2 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 6 Jun 2016 17:10:49 +0200 Subject: x86/microcode/AMD: Make amd_ucode_patch[] static It is used only in amd.c now. No functionality change. Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465225850-7352-9-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar --- arch/x86/include/asm/microcode_amd.h | 1 - arch/x86/kernel/cpu/microcode/amd.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h index adfc847a395e..15eb75484cc0 100644 --- a/arch/x86/include/asm/microcode_amd.h +++ b/arch/x86/include/asm/microcode_amd.h @@ -62,7 +62,6 @@ extern int apply_microcode_amd(int cpu); extern enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size); #define PATCH_MAX_SIZE PAGE_SIZE -extern u8 amd_ucode_patch[PATCH_MAX_SIZE]; #ifdef CONFIG_MICROCODE_AMD extern void __init load_ucode_amd_bsp(unsigned int family); diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index b1d1e345f5f5..27a0228c9cae 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -56,7 +56,7 @@ static u8 *container; static size_t container_size; static u32 ucode_new_rev; -u8 amd_ucode_patch[PATCH_MAX_SIZE]; +static u8 amd_ucode_patch[PATCH_MAX_SIZE]; static u16 this_equiv_id; static struct cpio_data ucode_cpio; -- cgit v1.2.3 From 9f3cc2a0772d7744d1d7195d39ac4794af622fe6 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 6 Jun 2016 17:10:50 +0200 Subject: Documentation/microcode: Document some aspects for more clarity Document that builtin microcode is 64-bit only. Also, improve/add comments to places. Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-doc@vger.kernel.org Link: http://lkml.kernel.org/r/1465225850-7352-10-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar --- Documentation/x86/early-microcode.txt | 5 ++++- arch/x86/kernel/cpu/microcode/intel.c | 16 +++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Documentation/x86/early-microcode.txt b/Documentation/x86/early-microcode.txt index c956d99cf1de..07749e7f3d50 100644 --- a/Documentation/x86/early-microcode.txt +++ b/Documentation/x86/early-microcode.txt @@ -45,7 +45,10 @@ Builtin microcode ================= We can also load builtin microcode supplied through the regular firmware -builtin method CONFIG_FIRMWARE_IN_KERNEL. Here's an example: +builtin method CONFIG_FIRMWARE_IN_KERNEL. Only 64-bit is currently +supported. + +Here's an example: CONFIG_FIRMWARE_IN_KERNEL=y CONFIG_EXTRA_FIRMWARE="intel-ucode/06-3a-09 amd-ucode/microcode_amd_fam15h.bin" diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 359e2034b558..8962d6acee39 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -40,9 +40,13 @@ #include /* - * Temporary microcode blobs pointers storage. We note here the pointers to - * microcode blobs we've got from whatever storage (detached initrd, builtin). - * Later on, we put those into final storage mc_saved_data.mc_saved. + * Temporary microcode blobs pointers storage. We note here during early load + * the pointers to microcode blobs we've got from whatever storage (detached + * initrd, builtin). Later on, we put those into final storage + * mc_saved_data.mc_saved. + * + * Important: those are offsets from the beginning of initrd or absolute + * addresses within the kernel image when built-in. */ static unsigned long mc_tmp_ptrs[MAX_UCODE_COUNT]; @@ -57,6 +61,7 @@ static struct ucode_blobs { bool valid; } blobs; +/* Go through saved patches and find the one suitable for the current CPU. */ static enum ucode_state find_microcode_patch(struct microcode_intel **saved, unsigned int num_saved, struct ucode_cpu_info *uci) @@ -466,6 +471,7 @@ static void show_saved_mc(void) static void save_mc_for_early(u8 *mc) { #ifdef CONFIG_HOTPLUG_CPU + /* Synchronization during CPU hotplug. */ static DEFINE_MUTEX(x86_cpu_microcode_mutex); struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT]; @@ -474,10 +480,6 @@ static void save_mc_for_early(u8 *mc) struct microcode_intel **mc_saved; int ret, i; - /* - * Hold hotplug lock so mc_saved_data is not accessed by a CPU in - * hotplug. - */ mutex_lock(&x86_cpu_microcode_mutex); mc_saved_count_init = mc_saved_data.num_saved; -- cgit v1.2.3 From 354542d034ab2a849a284edcc661e76b753a57dc Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 9 Jun 2016 06:41:41 -0700 Subject: x86/microcode/intel: Do not issue microcode updates messages on each CPU On large systems the microcode driver is very noisy, because it prints a line for each CPU. The lines are redundant because usually all CPUs are updated to the same microcode revision. All other subsystems have been patched previously to not print a line for each CPU. Only the microcode driver is left. Only print an microcode revision update when something changed. This results in typically only a single line being printed. Signed-off-by: Andi Kleen Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Cc: elliott@hpe.com Cc: hmh@hmh.eng.br Link: http://lkml.kernel.org/r/20160609134141.5981-1-andi@firstfloor.org Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/microcode/intel.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 8962d6acee39..6515c802346a 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -843,6 +843,7 @@ void reload_ucode_intel(void) static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) { + static struct cpu_signature prev; struct cpuinfo_x86 *c = &cpu_data(cpu_num); unsigned int val[2]; @@ -857,8 +858,13 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) } csig->rev = c->microcode; - pr_info("CPU%d sig=0x%x, pf=0x%x, revision=0x%x\n", - cpu_num, csig->sig, csig->pf, csig->rev); + + /* No extra locking on prev, races are harmless. */ + if (csig->sig != prev.sig || csig->pf != prev.pf || csig->rev != prev.rev) { + pr_info("sig=0x%x, pf=0x%x, revision=0x%x\n", + csig->sig, csig->pf, csig->rev); + prev = *csig; + } return 0; } @@ -887,6 +893,7 @@ static int apply_microcode_intel(int cpu) struct ucode_cpu_info *uci; struct cpuinfo_x86 *c; unsigned int val[2]; + static int prev_rev; /* We should bind the task to the CPU */ if (WARN_ON(raw_smp_processor_id() != cpu)) @@ -921,11 +928,14 @@ static int apply_microcode_intel(int cpu) return -1; } - pr_info("CPU%d updated to revision 0x%x, date = %04x-%02x-%02x\n", - cpu, val[1], - mc->hdr.date & 0xffff, - mc->hdr.date >> 24, - (mc->hdr.date >> 16) & 0xff); + if (val[1] != prev_rev) { + pr_info("updated to revision 0x%x, date = %04x-%02x-%02x\n", + val[1], + mc->hdr.date & 0xffff, + mc->hdr.date >> 24, + (mc->hdr.date >> 16) & 0xff); + prev_rev = val[1]; + } c = &cpu_data(cpu); -- cgit v1.2.3 From eb06158ee1457a27fcc981a37f23b50f19015a8a Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 4 Jul 2016 19:05:51 +0200 Subject: x86/microcode: Remove unused symbol exports It is not a module anymore and those can be retracted. No functionality change. Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160704170551.GC7261@pd.tnic Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/microcode/core.c | 1 - arch/x86/kernel/cpu/microcode/intel_lib.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 9ae7fcac70ab..df04b2d033f6 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -60,7 +60,6 @@ static bool dis_ucode_ldr; static DEFINE_MUTEX(microcode_mutex); struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; -EXPORT_SYMBOL_GPL(ucode_cpu_info); /* * Operations that are run on a target cpu: diff --git a/arch/x86/kernel/cpu/microcode/intel_lib.c b/arch/x86/kernel/cpu/microcode/intel_lib.c index 2ce1a7dc45b7..406cb6c0d9dd 100644 --- a/arch/x86/kernel/cpu/microcode/intel_lib.c +++ b/arch/x86/kernel/cpu/microcode/intel_lib.c @@ -141,7 +141,6 @@ int microcode_sanity_check(void *mc, int print_err) } return 0; } -EXPORT_SYMBOL_GPL(microcode_sanity_check); /* * Returns 1 if update has been found, 0 otherwise. @@ -183,4 +182,3 @@ int has_newer_microcode(void *mc, unsigned int csig, int cpf, int new_rev) return find_matching_signature(mc, csig, cpf); } -EXPORT_SYMBOL_GPL(has_newer_microcode); -- cgit v1.2.3 From efaad554b4ffae1840a2759e09e21325ddbc8b05 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 26 Jul 2016 11:51:38 +0200 Subject: x86/microcode/intel: Fix initrd loading with CONFIG_RANDOMIZE_MEMORY=y CONFIG_RANDOMIZE_MEMORY=y randomizes the physical memmap and thus the address where the initrd is located. Therefore, we need to add the offset KASLR put us to in order to find the initrd again on the AP path. In the future, we will get rid of the initrd address caching and query the address on both the BSP and AP paths but that would need more work. Thanks to Nicolai Stange for the good bisection and debugging work. Reported-and-tested-by: Nicolai Stange Signed-off-by: Borislav Petkov Cc: Kees Cook Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160726095138.3470-1-bp@alien8.de Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/microcode/intel.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 6515c802346a..0f97ae93441b 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -793,10 +793,10 @@ void __init load_ucode_intel_bsp(void) void load_ucode_intel_ap(void) { struct ucode_blobs *blobs_p; + unsigned long *ptrs, start = 0; struct mc_saved_data *mcs; struct ucode_cpu_info uci; enum ucode_state ret; - unsigned long *ptrs; #ifdef CONFIG_X86_32 mcs = (struct mc_saved_data *)__pa_nodebug(&mc_saved_data); @@ -815,8 +815,20 @@ void load_ucode_intel_ap(void) if (!mcs->num_saved) return; + if (blobs_p->valid) { + start = blobs_p->start; + +#ifdef CONFIG_RANDOMIZE_MEMORY + /* + * Pay attention to CONFIG_RANDOMIZE_MEMORY=y as it shuffles + * physmem mapping too and there we have the initrd. + */ + start += PAGE_OFFSET - __PAGE_OFFSET_BASE; +#endif + } + collect_cpu_info_early(&uci); - ret = load_microcode(mcs, ptrs, blobs_p->start, &uci); + ret = load_microcode(mcs, ptrs, start, &uci); if (ret != UCODE_OK) return; -- cgit v1.2.3 From 4a1a8e1b8f9f37bdbba416eb0a5ff3f47d31cb28 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 27 Jul 2016 14:09:39 +0200 Subject: x86/asm, x86/microcode: Add __PAGE_OFFSET_BASE define on 32-bit ... in order to avoid #ifdeffery in code computing the ASLR randomization offset. Remove that #ifdeffery in the microcode loader. Suggested-by: Kees Cook Signed-off-by: Borislav Petkov Cc: Linus Torvalds Cc: Nicolai Stange Cc: Peter Zijlstra Cc: Thomas Garnier Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160727120939.GA18911@nazgul.tnic Signed-off-by: Ingo Molnar --- arch/x86/include/asm/page_32_types.h | 3 ++- arch/x86/kernel/cpu/microcode/intel.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/page_32_types.h b/arch/x86/include/asm/page_32_types.h index 3a52ee0e726d..3bae4969ac65 100644 --- a/arch/x86/include/asm/page_32_types.h +++ b/arch/x86/include/asm/page_32_types.h @@ -13,7 +13,8 @@ * If you want more physical memory than this then see the CONFIG_HIGHMEM4G * and CONFIG_HIGHMEM64G options in the kernel configuration. */ -#define __PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL) +#define __PAGE_OFFSET_BASE _AC(CONFIG_PAGE_OFFSET, UL) +#define __PAGE_OFFSET __PAGE_OFFSET_BASE #define __START_KERNEL_map __PAGE_OFFSET diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 0f97ae93441b..cdc0deab00c9 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -818,13 +818,11 @@ void load_ucode_intel_ap(void) if (blobs_p->valid) { start = blobs_p->start; -#ifdef CONFIG_RANDOMIZE_MEMORY /* * Pay attention to CONFIG_RANDOMIZE_MEMORY=y as it shuffles * physmem mapping too and there we have the initrd. */ start += PAGE_OFFSET - __PAGE_OFFSET_BASE; -#endif } collect_cpu_info_early(&uci); -- cgit v1.2.3