Re: x86/microcode update on systems without INITRD

Borislav Petkov
2016-01-19T17:44:31Z

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.

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;
--
2.3.5

SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
--