Re: x86/microcode update on systems without INITRD

Thomas Voegtle
2016-01-20T09:14:58Z

On Tue, 19 Jan 2016, Borislav Petkov wrote:

> On Thu, Jan 07, 2016 at 01:12:16PM +0100, Thomas Voegtle wrote:
>> I just diffed my 4.3 config with the 4.4 config and saw that the whole
>> Microcode stuff was silently dropped by a normal "make oldconfig".
>
> Ok, here's a different version.

I checked that in several ways, took my old 4.3-config, ran it through
"make oldconfig" and the others, etc.

Works like a charm.

Thank you,

Thomas

>
> It takes care of the oldconfig aspect, you'd still need to either
> prepare an initrd with the microcode or build it into the kernel. Ask if
> something's not clear.
>
> It works fine in qemu+kvm but I'll run it on my boxes before I queue it
> for stable.
>
> Thanks.
>
> ---
> From: Borislav Petkov <bp@suse.de>
> Date: Mon, 18 Jan 2016 19:07:08 +0100
> Subject: [PATCH] x86/microcode: Untangle from BLK_DEV_INITRD
>
> Thomas Voegtle reported that doing oldconfig with a .config which has
> CONFIG_MICROCODE enabled but BLK_DEV_INITRD disabled prevents the
> microcode loading mechanism from being built.
>
> So untangle it from the BLK_DEV_INITRD dependency so that oldconfig
> doesn't turn it off and add an explanatory text to its Kconfig help what
> the supported methods for supplying microcode are.
>
> Follow-on work will do the same with CONFIG_FW_LOADER. This patch is
> kept minimal for stable backporting.
>
> Reported-by: Thomas Voegtle <tv@lio96.de>
> Signed-off-by: Borislav Petkov <bp@suse.de>
> Cc: <stable@vger.kernel.org> # 4.4
> ---
> arch/x86/Kconfig | 12 ++++++------
> arch/x86/include/asm/microcode.h | 26 ++++++++++++++++++++++++++
> arch/x86/kernel/cpu/microcode/intel.c | 14 ++++----------
> 3 files changed, 36 insertions(+), 16 deletions(-)
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index db3622f22b61..9743b8bb500e 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -1126,10 +1126,8 @@ config MICROCODE
> bool "CPU microcode loading support"
> default y
> depends on CPU_SUP_AMD || CPU_SUP_INTEL
> - depends on BLK_DEV_INITRD
> select FW_LOADER
> ---help---
> -
> If you say Y here, you will be able to update the microcode on
> certain Intel and AMD processors. The Intel support is for the
> IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4,
> @@ -1137,11 +1135,13 @@ config MICROCODE
> obviously need the actual microcode binary data itself which is not
> shipped with the Linux kernel.
>
> - This option selects the general module only, you need to select
> - at least one vendor specific module as well.
> + The preferred method to load microcode is described in
> + Documentation/x86/early-microcode.txt. For that you need to enable
> + CONFIG_BLK_DEV_INITRD in order for the loader to be able to scan the
> + initrd for microcode blobs.
>
> - To compile this driver as a module, choose M here: the module
> - will be called microcode.
> + Alternatively, you can build-in the microcode into the kernel. For
> + that you need the functionality behind CONFIG_FW_LOADER.
>
> config MICROCODE_INTEL
> bool "Intel microcode loading support"
> diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
> index 34e62b1dcfce..712b24ed3a64 100644
> --- a/arch/x86/include/asm/microcode.h
> +++ b/arch/x86/include/asm/microcode.h
> @@ -2,6 +2,7 @@
> #define _ASM_X86_MICROCODE_H
>
> #include <linux/earlycpio.h>
> +#include <linux/initrd.h>
>
> #define native_rdmsr(msr, val1, val2) \
> do { \
> @@ -168,4 +169,29 @@ static inline void reload_early_microcode(void) { }
> 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/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
> index ce47402eb2f9..eea5978a0e33 100644
> --- a/arch/x86/kernel/cpu/microcode/intel.c
> +++ b/arch/x86/kernel/cpu/microcode/intel.c
> @@ -694,7 +694,7 @@ int __init save_microcode_in_initrd_intel(void)
> if (count == 0)
> return ret;
>
> - copy_initrd_ptrs(mc_saved, mc_saved_in_initrd, initrd_start, count);
> + copy_initrd_ptrs(mc_saved, mc_saved_in_initrd, get_initrd_start(), count);
> ret = save_microcode(&mc_saved_data, mc_saved, count);
> if (ret)
> pr_err("Cannot save microcode patches from initrd.\n");
> @@ -752,20 +752,14 @@ void load_ucode_intel_ap(void)
> struct mc_saved_data *mc_saved_data_p;
> struct ucode_cpu_info uci;
> unsigned long *mc_saved_in_initrd_p;
> - unsigned long initrd_start_addr;
> enum ucode_state ret;
> #ifdef CONFIG_X86_32
> - unsigned long *initrd_start_p;
>
> - mc_saved_in_initrd_p =
> - (unsigned long *)__pa_nodebug(mc_saved_in_initrd);
> + mc_saved_in_initrd_p = (unsigned long *)__pa_nodebug(mc_saved_in_initrd);
> mc_saved_data_p = (struct mc_saved_data *)__pa_nodebug(&mc_saved_data);
> - initrd_start_p = (unsigned long *)__pa_nodebug(&initrd_start);
> - initrd_start_addr = (unsigned long)__pa_nodebug(*initrd_start_p);
> #else
> - mc_saved_data_p = &mc_saved_data;
> mc_saved_in_initrd_p = mc_saved_in_initrd;
> - initrd_start_addr = initrd_start;
> + mc_saved_data_p = &mc_saved_data;
> #endif
>
> /*
> @@ -777,7 +771,7 @@ void load_ucode_intel_ap(void)
>
> collect_cpu_info_early(&uci);
> ret = load_microcode(mc_saved_data_p, mc_saved_in_initrd_p,
> - initrd_start_addr, &uci);
> + get_initrd_start_addr(), &uci);
>
> if (ret != UCODE_OK)
> return;
>

Thomas

--
Thomas V