Bug 85081
Summary: | Early microcode loading ignores microcode provided in embedded initramfs | ||
---|---|---|---|
Product: | Platform Specific/Hardware | Reporter: | klondike (klondike+kernel) |
Component: | x86-64 | Assignee: | Borislav Petkov (bp) |
Status: | RESOLVED CODE_FIX | ||
Severity: | normal | CC: | bp, hpa, kernel, mattst88, stevenhoneyman, szg00000 |
Priority: | P1 | ||
Hardware: | Intel | ||
OS: | Linux | ||
Kernel Version: | 3.15.8 | Subsystem: | |
Regression: | No | Bisected commit-id: | |
Attachments: | config-4.5.2-gentoo |
Description
klondike
2014-09-24 04:06:55 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! 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. (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. This is definitely broken. We should scan the internal initramfs as well as the external one. 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. 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. (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? (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? $ 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... (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 (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 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. 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. 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. 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. |