Bug 85081 - Early microcode loading ignores microcode provided in embedded initramfs
Summary: Early microcode loading ignores microcode provided in embedded initramfs
Status: RESOLVED CODE_FIX
Alias: None
Product: Platform Specific/Hardware
Classification: Unclassified
Component: x86-64 (show other bugs)
Hardware: Intel Linux
: P1 normal
Assignee: Borislav Petkov
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-09-24 04:06 UTC by klondike
Modified: 2016-04-23 11:38 UTC (History)
6 users (show)

See Also:
Kernel Version: 3.15.8
Subsystem:
Regression: No
Bisected commit-id:


Attachments
config-4.5.2-gentoo (77.36 KB, text/plain)
2016-04-22 18:35 UTC, Matt Whitlock
Details

Description klondike 2014-09-24 04:06:55 UTC
The early microcode driver will ignore any updates provided in an embedded initramfs (provided using a .cpio file).

That same initramfs .cpio file will work properly (i.e. the driver will load the microcode) when not embedded.
Comment 1 Steven Honeyman 2014-10-14 22:51:03 UTC
I'm seeing this problem in 3.17 still. After the recent Intel problem, I tried to embed the microcode update into the kernel image. I disabled gzip compression of the builtin initramfs, and it extracts correctly even though the microcode loader doesn't see it (a minimal initramfs gets /kernel/x86/microcode/GenuineIntel.bin extracted by the kernel)

I found that:

WORKS: external ucode.cpio, rootfs as real disk
       external ucode.cpio, internal initramfs, no rootfs
       external (ucode.cpio+initramfs), no rootfs

FAILS: internal ucode.cpio, rootfs as real disk
       internal ucode.cpio, external initramfs, no rootfs
       internal (ucode.cpio+initramfs), no rootfs

There are two failure points depending on which of those is used:
If no external initramfs is used, then
arch/x86/kernel/setup.c  /* No initrd provided by bootloader */
(which is technically true I suppose!)
If you do use an external initramfs, but keep the microcode cpio in the kernel, then the microcode loader sees the correct size, but gets the location wrong in memory, causing
lib/earlycpio.c  goto quit; /* Invalid hexadecimal */
(Which intel_early.c sees as "No cpio data found")

So maybe there are two bugs in 1 here!
Comment 2 Borislav Petkov 2015-01-13 20:55:12 UTC
The only method we ever did for early microcode loading is this one:

https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/x86/early-microcode.txt

I'd guess that's what you call external ucode.cpio.

Can someone enlighten me why do we need to support the other methods?
Don't be afraid to be verbose :-)

Thanks.
Comment 3 Steven Honeyman 2015-01-13 21:09:24 UTC
(In reply to Borislav Petkov from comment #2)
> The only method we ever did for early microcode loading is this one:
> 
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/
> Documentation/x86/early-microcode.txt
> 
> I'd guess that's what you call external ucode.cpio.
> 
> Can someone enlighten me why do we need to support the other methods?
> Don't be afraid to be verbose :-)
> 
> Thanks.

Personally, I do not use an initramfs - my "usual" kernel has everything it needs inbuilt... apart from microcode updates (due to this bug)

It's the same method, but the difference is embedding the initramfs image in the kernel breaks microcode loading. I just want to embed the tiny extra file to make it look neater; it wouldn't be functionally different.
Comment 4 H. Peter Anvin 2015-01-13 21:15:58 UTC
This is definitely broken.  We should scan the internal initramfs as well as the external one.
Comment 5 Borislav Petkov 2016-02-02 22:12:34 UTC
Just to update people on what we've been working on/discussing recently,
here's the text that's going into the Kconfig help text:

  The preferred method to load microcode from a detached initrd 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.

  In addition, you can build-in the microcode into the kernel. For that you
  need to enable FIRMWARE_IN_KERNEL and add the vendor-supplied microcode
  to the CONFIG_EXTRA_FIRMWARE config option.

I probably should also give detailed examples for it in that file too.
Comment 6 Matt Whitlock 2016-04-20 17:21:03 UTC
For what it's worth, I tried the FIRMWARE_IN_KERNEL+CONFIG_EXTRA_FIRMWARE approach described in Comment #5, and it does appear to work on Linux 4.5.1. (I do not boot into an initramfs.)

It's a little odd, though, in that I see no kernel log messages informing me that the microcode was updated.

On kernel 4.1.15, I would see the following in the kernel log (quite late in the boot process):

microcode: CPU0 sig=0x6fb, pf=0x10, revision=0xb6
microcode: CPU0 sig=0x6fb, pf=0x10, revision=0xb6
microcode: CPU0 updated to revision 0xba, date = 2010-10-03
microcode: CPU1 sig=0x6fb, pf=0x10, revision=0xb6
microcode: CPU1 sig=0x6fb, pf=0x10, revision=0xb6
microcode: CPU1 updated to revision 0xba, date = 2010-10-03
microcode: CPU2 sig=0x6fb, pf=0x10, revision=0xb6
microcode: CPU2 sig=0x6fb, pf=0x10, revision=0xb6
microcode: CPU2 updated to revision 0xba, date = 2010-10-03
microcode: CPU3 sig=0x6fb, pf=0x10, revision=0xb6
microcode: CPU3 sig=0x6fb, pf=0x10, revision=0xb6
microcode: CPU3 updated to revision 0xba, date = 2010-10-03
microcode: Microcode Update Driver: v2.00 <tigran@aivazian.fsnet.co.uk>, Peter Oruba

On kernel 4.5.1, I was seeing the following (in the middle of the boot process, before the root file system is mounted):

microcode: CPU0 sig=0x6fb, pf=0x10, revision=0xb6
microcode: CPU1 sig=0x6fb, pf=0x10, revision=0xb6
microcode: CPU2 sig=0x6fb, pf=0x10, revision=0xb6
microcode: CPU3 sig=0x6fb, pf=0x10, revision=0xb6
microcode: Microcode Update Driver: v2.01 <tigran@aivazian.fsnet.co.uk>, Peter Oruba

The microcode was no longer being updated from /lib/firmware/intel-ucode/.

Then I built the applicable ucode file into my kernel using CONFIG_EXTRA_FIRMWARE, and now I see this:

microcode: CPU0 sig=0x6fb, pf=0x10, revision=0xba
microcode: CPU1 sig=0x6fb, pf=0x10, revision=0xba
microcode: CPU2 sig=0x6fb, pf=0x10, revision=0xba
microcode: CPU3 sig=0x6fb, pf=0x10, revision=0xba
microcode: Microcode Update Driver: v2.01 <tigran@aivazian.fsnet.co.uk>, Peter Oruba

The revision shown is now the latest, though no "updated to revision" messages are emitted.
Comment 7 Borislav Petkov 2016-04-22 11:21:14 UTC
(In reply to Matt Whitlock from comment #6)
> The revision shown is now the latest, though no "updated to revision"
> messages are emitted.

what does

$ dmesg | grep -i microcode

say?
Comment 8 Matt Whitlock 2016-04-22 12:24:59 UTC
(In reply to Borislav Petkov from comment #7)
> what does
> 
> $ dmesg | grep -i microcode
> 
> say?

That's how I was getting those lines. I've seen other logs that mention "early" microcode updates, but mine don't show that. Do I need to enable CONFIG_EARLY_PRINTK to see those messages?
Comment 9 Borislav Petkov 2016-04-22 13:28:52 UTC
$ dmesg | grep -i microcode
[    0.000000] microcode: microcode updated early to revision 0x1b, date = 2014-05-29
[    0.955595] microcode: CPU0 sig=0x306a9, pf=0x10, revision=0x1b
[    0.955678] microcode: CPU1 sig=0x306a9, pf=0x10, revision=0x1b
[    0.955751] microcode: CPU2 sig=0x306a9, pf=0x10, revision=0x1b
[    0.955801] microcode: CPU3 sig=0x306a9, pf=0x10, revision=0x1b
[    0.956112] microcode: Microcode Update Driver: v2.01 <tigran@aivazian.fsnet.co.uk>, Peter Oruba

$ grep -v "^#" .config | grep -Ei "(firmware|initrd)"
CONFIG_FIRMWARE_IN_KERNEL=y
CONFIG_EXTRA_FIRMWARE="intel-ucode/06-3a-09"
CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware"
CONFIG_FIRMWARE_EDID=y
CONFIG_FIRMWARE_MEMMAP=y

I guess I need to see your .config...
Comment 10 Matt Whitlock 2016-04-22 16:15:02 UTC
(In reply to Borislav Petkov from comment #9)
> I guess I need to see your .config...

$ zgrep -Ei '^[^#].*(firmware|initrd)' /proc/config.gz
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FIRMWARE_IN_KERNEL=y
CONFIG_EXTRA_FIRMWARE="intel-ucode/06-0f-0b"
CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware"
CONFIG_FIRMWARE_MEMMAP=y
Comment 11 Borislav Petkov 2016-04-22 18:24:21 UTC
(In reply to Matt Whitlock from comment #10)
> (In reply to Borislav Petkov from comment #9)
> > I guess I need to see your .config...
> 
> $ zgrep -Ei '^[^#].*(firmware|initrd)' /proc/config.gz

I meant your *whole* .config. It seems you're missing some options
as 4.5.1 actually issues the early line twice here (I removed that
repetition in 4.6):

$ dmesg | grep -i microcode
[    0.000000] microcode: CPU0 microcode updated early to revision 0x1b, date = 2014-05-29
[    0.195782] microcode: CPU2 microcode updated early to revision 0x1b, date = 2014-05-29
[    0.787403] microcode: CPU0 sig=0x306a9, pf=0x10, revision=0x1b
[    0.787447] microcode: CPU1 sig=0x306a9, pf=0x10, revision=0x1b
[    0.787478] microcode: CPU2 sig=0x306a9, pf=0x10, revision=0x1b
[    0.787526] microcode: CPU3 sig=0x306a9, pf=0x10, revision=0x1b
[    0.787807] microcode: Microcode Update Driver: v2.01 <tigran@aivazian.fsnet.co.uk>, Peter Oruba
Comment 12 Matt Whitlock 2016-04-22 18:35:50 UTC
Created attachment 213691 [details]
config-4.5.2-gentoo

(In reply to Borislav Petkov from comment #11)
> I meant your *whole* .config.

Attached.

> It seems you're missing some options

It seems to be only a matter of logging, as the microcode update is being performed correctly. I don't really care whether I get a log line saying "microcode updated"; I'm just mentioning it here in case it's something that can be fixed easily.
Comment 13 Borislav Petkov 2016-04-22 19:13:52 UTC
Yeah, I was curious to know what causes that "early" line to not go
out (CONFIG_EARLY_PRINTK isn't it as this call is a normal printk()).

And the only other way to know whether the update succeeded or not is
to know what the microcode version supplied by your BIOS is and then
compare it with the microcode version which got applied. Last you can
get either from dmesg or from /proc/cpuinfo.

Anyway, this bug is fixed, let me close it. If anyone has other
microcode loader issues, then anyone please open another bug and add me
to CC.

Thanks.
Comment 14 Matt Whitlock 2016-04-22 19:55:43 UTC
If I do a warm reboot (shutdown -r), does this reset the microcode on the CPUs? Maybe I'm not seeing the early update messages because I haven't actually hard reset the system, so there's nothing to update?

I'll look for the early microcode update messages next time my machine locks up and I have to push the hard reset button (which hopefully won't be for a long, long time).

Thanks for your consideration and your work.
Comment 15 Matt Whitlock 2016-04-23 11:38:15 UTC
Epilogue: My kernel log ring buffer was too small for me to see the early microcode update message by the time userspace had come up.

Note You need to log in before you can comment on or make changes to this bug.