Note: This is a public test instance of Red Hat Bugzilla. The data contained within is a snapshot of the live data so any changes you make will not be reflected in the production Bugzilla. Email is disabled so feel free to test any aspect of the site that you want. File any problems you find or give feedback at bugzilla.redhat.com.

Bug 1083716

Summary: kernel config for early microcode loading
Product: [Fedora] Fedora Reporter: Jeff Bastian <jbastian>
Component: kernelAssignee: Kernel Maintainer List <kernel-maint>
Status: CLOSED ERRATA QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: low Docs Contact:
Priority: medium    
Version: rawhideCC: arapov, gansalmon, harald, itamar, jonathan, kernel-maint, madhu.chinakonda, mchehab, nobody, nonamedotc
Target Milestone: ---   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: dracut-038-29.git20140903.fc21 Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2014-09-29 04:04:58 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
Patch to enable early-microcode in dracut by default none

Description Jeff Bastian 2014-04-02 19:39:56 UTC
Description of problem:
The current Fedora kernel config-x86-generic contains
  CONFIG_MICROCODE_INTEL_EARLY=y

However, this is ineffective because microcode itself is built as a module
  CONFIG_MICROCODE=m

And the MICROCODE_EARLY option depends on it being built-in, not as a module; from arch/x86/Kconfig:

config MICROCODE_EARLY
        bool "Early load microcode"
        depends on MICROCODE=y && BLK_DEV_INITRD
        select MICROCODE_INTEL_EARLY if MICROCODE_INTEL
        select MICROCODE_AMD_EARLY if MICROCODE_AMD
        default y

To fully enable early-microcode-loading, the config should have at least

CONFIG_MICROCODE=y
CONFIG_MICROCODE_EARLY=y
CONFIG_MICROCODE_INTEL=y
CONFIG_MICROCODE_INTEL_EARLY=y
CONFIG_MICROCODE_AMD=y
CONFIG_MICROCODE_AMD_EARLY=y


Version-Release number of selected component (if applicable):
rawhide (3.15.0-0.rc0.git5.1 as of this writing)

How reproducible:
every time

Steps to Reproduce:
1. dmesg | grep microcode

Actual results:
the dmesg timestamps show the microcode is updated "late" in boot (after 0 seconds), e.g. it updates the microcode at about 12.7 seconds on this system:
    ~]# dmesg | grep microcode
    [   11.450546] microcode: CPU0: patch_level=0x01000086
    [   12.699927] microcode: CPU0: new patch_level=0x010000db

Expected results:
it should update the microcode almost immediately on boot, e.g.
    ~]# dmesg | grep microcode
    [    0.000001] microcode: CPU0: patch_level=0x01000086
    [    0.000001] microcode: CPU0: new patch_level=0x010000db

Additional info:
The initramfs must have the microcode prefixed to the image.  dracut can do this with the --early-microcode option.

~]# dracut -v -f --early-microcode

Comment 1 Josh Boyer 2014-04-02 20:05:07 UTC
Well spotted.  CC'ing Harald.

OK, so if we wanted (needed?) this we'd have to make sure that kernel-install called dracut appropriately.  At the least the kernel-install/dracut changes should land first.

From a practical point of view, do we really need early microcode loading?  What benefit does it get us other than "it's loaded earlier"?

Comment 2 Jeff Bastian 2014-04-02 20:50:30 UTC
A better option for dracut is to update the
  /usr/lib/dracut/dracut.conf.d/01-dist.conf
file and set
  early_microcode="yes"


The benefit is a shorter window where code is subject to problems due to a hardware errata.  On systems where I've tested this, the dmesg logs show that the microcode is updated almost immediately on boot with CPU0 happening right at 0.0 seconds:

[    0.000000] CPU0 microcode updated early to revision 0x29, date = 2013-06-12
[    0.048193] CPU1 microcode updated early to revision 0x29, date = 2013-06-12
[    0.061528] CPU2 microcode updated early to revision 0x29, date = 2013-06-12
[    0.074800] CPU3 microcode updated early to revision 0x29, date = 2013-06-12


Compare to the current method which updates when the microcode.ko module is loaded which happened at about 7 seconds after boot on this same system:

[    6.912947] microcode: CPU0 sig=0x206a7, pf=0x2, revision=0x28
[    7.089009] microcode: CPU0 sig=0x206a7, pf=0x2, revision=0x28
[    7.089468] microcode: CPU0 updated to revision 0x29, date = 2013-06-12


If this benefit isn't worth it, then the config-x86-generic file should remove the setting CONFIG_MICROCODE_INTEL_EARLY=y since that's a bit misleading.

Comment 3 Jeff Bastian 2014-04-02 20:54:27 UTC
Oh, and if the initramfs image is missing the microcode data, it is possible to update the microcode later in boot by running
    echo 1 > /sys/devices/system/cpu/microcode/reload

A systemd one-shot service can run this as a failsafe later in boot, for example:

=========================================
/usr/lib/systemd/system/microcode.service
=========================================
[Unit]
Description=Load CPU microcode update
After=basic.target
ConditionVirtualization=false

[Service]
Type=oneshot
RemainAfterExit=no
ExecStart=/usr/bin/bash -c "echo 1 > /sys/devices/system/cpu/microcode/reload"

[Install]
WantedBy=basic.target

Comment 4 Josh Boyer 2014-04-03 00:08:28 UTC
(In reply to Jeff Bastian from comment #2)
> A better option for dracut is to update the
>   /usr/lib/dracut/dracut.conf.d/01-dist.conf
> file and set
>   early_microcode="yes"

Sure.  Still requires a dracut change.

> The benefit is a shorter window where code is subject to problems due to a
> hardware errata.  On systems where I've tested this, the dmesg logs show

Which, in reality, has happened how often?  I honestly don't know, but I can't imagine it is very often or we'd have heard of it long before now.

> that the microcode is updated almost immediately on boot with CPU0 happening
> right at 0.0 seconds:
> 
> [    0.000000] CPU0 microcode updated early to revision 0x29, date =
> 2013-06-12
> [    0.048193] CPU1 microcode updated early to revision 0x29, date =
> 2013-06-12
> [    0.061528] CPU2 microcode updated early to revision 0x29, date =
> 2013-06-12
> [    0.074800] CPU3 microcode updated early to revision 0x29, date =
> 2013-06-12
> 
> 
> Compare to the current method which updates when the microcode.ko module is
> loaded which happened at about 7 seconds after boot on this same system:
> 
> [    6.912947] microcode: CPU0 sig=0x206a7, pf=0x2, revision=0x28
> [    7.089009] microcode: CPU0 sig=0x206a7, pf=0x2, revision=0x28
> [    7.089468] microcode: CPU0 updated to revision 0x29, date = 2013-06-12

Right, that just shows the config option does what it says it does.

> If this benefit isn't worth it, then the config-x86-generic file should
> remove the setting CONFIG_MICROCODE_INTEL_EARLY=y since that's a bit
> misleading.

I'm not saying it's not worthwhile.  I'm just curious how much it will actually change.  It seems to be a somewhat precautionary thing to do and I'm concerned about changing this at this point.  Also, AMD has an early option as well.  I need to figure out what happens when we build both Intel and AMD early microcode support into the kernel.

I do agree we should drop the current config setting if we don't build MICROCODE=y

Comment 5 Josh Boyer 2014-04-03 00:11:11 UTC
(In reply to Jeff Bastian from comment #3)
> Oh, and if the initramfs image is missing the microcode data, it is possible
> to update the microcode later in boot by running
>     echo 1 > /sys/devices/system/cpu/microcode/reload
> 
> A systemd one-shot service can run this as a failsafe later in boot, for
> example:
> 
> =========================================
> /usr/lib/systemd/system/microcode.service
> =========================================
> [Unit]
> Description=Load CPU microcode update
> After=basic.target
> ConditionVirtualization=false
> 
> [Service]
> Type=oneshot
> RemainAfterExit=no
> ExecStart=/usr/bin/bash -c "echo 1 >
> /sys/devices/system/cpu/microcode/reload"
> 
> [Install]
> WantedBy=basic.target

Ugh...  is that _required_ to get any microcode loaded if it isn't in the initramfs, or does the kernel try early, then automatically try later if it didn't find anything early?  I'll try looking tomorrow but if you happen to know, I'd appreciate it.

I would rather dislike having to ship a systemd service just to get microcode loaded when it's currently loaded without it now.  Particularly since that one-shot isn't needed if the microcode _is_ loaded early.

Comment 6 Jeff Bastian 2014-04-03 12:29:03 UTC
As best I can tell, the service is required, unfortunately.

In the current setup, the microcode update happens when the microcode.ko module is loaded.  If the microcode driver is built-in, the kernel checks when the system boots which means it's needed in the initramfs image, and if it's not there it does not get updated.

Personally, I don't care either way -- built-in or module -- I just noticed the conflict in the config settings.

Comment 7 Josh Boyer 2014-04-03 13:22:22 UTC
Seems this was all done in RHEL7 already.  Why it wasn't done in Fedora first, I have no idea....

So in RHEL7 it seems this requires changes in 3 components:

1) The kernel configs and Requires
2) dracut to both create and understand (lsinitrd) initramfses with microcode attached
3) microcode_ctl to install the service mentioned and toggle the default for dracut to on for microcode.

Item 1 is "easy" to do from a config standpoint.  We need to adjust the Requires on dracut to >= 033 I think, which would cover item 2.  Harald is that correct?  If so, this won't work on F19 as dracut is too old.  F20 and rawhide would be OK.

Item 3 requires Anton (now CC'd) to update microcode_ctl and add the conf and service files.

Thinking about this more, it would seem better to me to have the kernel microcode loader do one last automatic check if/when the kernel pivots out of the initramfs to the real root.  That would eliminate the need for the service file.  I'll see if I can bug upstream about that.

Comment 8 Harald Hoyer 2014-04-04 11:28:41 UTC
dracut in RHEL-7 and rawhide is ready.
F20 with https://admin.fedoraproject.org/updates/FEDORA-2014-4704/dracut-037-10.git20140402.fc20

Comment 9 Josh Boyer 2014-09-19 18:46:50 UTC
OK, with the haswell TSX issue, we clearly have a need for this.  I should have done this a long time ago, so my apologies.

I've enabled the kernel options today, and confirmed that rebuilding the initramfs by passing --early-microcode works.

[jwboyer@nuc-i7 ~]$ dmesg | grep micro
[    0.000000] CPU0 microcode updated early to revision 0x18, date = 2014-05-23
[    0.145247] CPU1 microcode updated early to revision 0x18, date = 2014-05-23
[    0.952104] microcode: CPU0 sig=0x40651, pf=0x40, revision=0x18
[    0.952127] microcode: CPU1 sig=0x40651, pf=0x40, revision=0x18
[    0.952152] microcode: CPU2 sig=0x40651, pf=0x40, revision=0x18
[    0.952179] microcode: CPU3 sig=0x40651, pf=0x40, revision=0x18
[    0.952414] microcode: Microcode Update Driver: v2.00 <tigran.co.uk>, Peter Oruba
[jwboyer@nuc-i7 ~]$ 


So now the question is, how do we get this option enabled by default in dracut and/or how do we pass it via kernel-install?

We'll likely also need the one-shot service, but that can probably wait.

Comment 10 Josh Boyer 2014-09-25 17:10:07 UTC
Created attachment 941217 [details]
Patch to enable early-microcode in dracut by default

Thinking about it more, if we're always going to enable it on kernel install then it might as well be the default in dracut as well.  The attached patch switches this on by default in dracut.

I tested a local build of F21 kernel and dracut with this change and it performed as expected.  To make it easier for others to test I started a COPR that included these packages.  You can find it here (once the builds complete):

https://copr.fedoraproject.org/coprs/jwboyer/early-microcode/

Comment 11 Fedora Update System 2014-09-26 18:32:29 UTC
dracut-038-29.git20140903.fc21,kernel-3.16.3-302.fc21 has been submitted as an update for Fedora 21.
https://admin.fedoraproject.org/updates/dracut-038-29.git20140903.fc21,kernel-3.16.3-302.fc21

Comment 12 Jeff Bastian 2014-09-26 20:51:01 UTC
I don't have a Haswell system handy, but I using your copr packages I did verify that the microcode loaded early on my Lenovo T60:

[jmbastia@firefly ~]$ uname -r
3.16.3-301.fc21.x86_64

[jmbastia@firefly ~]$ rpm -q dracut
dracut-038-29.git20140903.fc21.x86_64

[jmbastia@firefly ~]$ dmesg | grep -i microcode
[    0.000000] CPU0 microcode updated early to revision 0xd1, date = 2010-10-01
[    0.002000] CPU1 microcode updated early to revision 0xd1, date = 2010-10-01
[    0.499953] microcode: CPU0 sig=0x6f6, pf=0x20, revision=0xd1
[    0.499964] microcode: CPU1 sig=0x6f6, pf=0x20, revision=0xd1
[    0.500064] microcode: Microcode Update Driver: v2.00 <tigran.co.uk>, Peter Oruba

[jmbastia@firefly ~]$ sudo cat /sys/devices/system/cpu/cpu0/microcode/version
0xd1

Comment 13 Fedora Update System 2014-09-27 10:01:41 UTC
Package dracut-038-29.git20140903.fc21, kernel-3.16.3-302.fc21:
* should fix your issue,
* was pushed to the Fedora 21 testing repository,
* should be available at your local mirror within two days.
Update it with:
# su -c 'yum update --enablerepo=updates-testing dracut-038-29.git20140903.fc21 kernel-3.16.3-302.fc21'
as soon as you are able to, then reboot.
Please go to the following url:
https://admin.fedoraproject.org/updates/FEDORA-2014-11661/dracut-038-29.git20140903.fc21,kernel-3.16.3-302.fc21
then log in and leave karma (feedback).

Comment 14 Fedora Update System 2014-09-29 04:04:58 UTC
dracut-038-29.git20140903.fc21, kernel-3.16.3-302.fc21 has been pushed to the Fedora 21 stable repository.  If problems still persist, please make note of it in this bug report.