Gentoo Linux: Building/rebuilding a kernel and Intel CPU microcode in an installation with initramfs

In a 2014 post I explained how to update the Intel CPU microcode in a Gentoo Linux installation with an initramfs (I use sys-kernel/genkernel to build the kernel in the installation on my Compal NBLB2 laptop, which is running the Testing Branch of Gentoo Linux although the branch is not important). The initscript method (Method 1 in that post) for updating the CPU microcode is no longer valid, and the behaviour of the tool sys-apps/iucode_tool for updating the CPU microcode (Method 2 in that post) has changed, hence this update.

Although not essential I normally perform the microcode upgrade procedure when I either rebuild or upgrade the Linux kernel, therefore I explain both procedures contiguously here.

These days the grub-mkconfig command edits the file /boot/grub/grub.cfg to add a line to the GRUB menu entries, to load the CPU microcode at boot, but nevertheless I prefer to follow a slightly different method that works reliably for me.

Below is the procedure I follow to build/rebuild the kernel and the Intel CPU microcode. Others may have a different approach, but this has always worked well for me, even if some of the steps are sometimes nugatory.

If they are not already installed, you need to merge a couple of packages before starting the main procedure:

root # emerge app-arch/lzma # Needed to build bzImage.
root # emerge iucode_tool

1. Mount the boot directory if it is on a separate partition

root # mount /dev/sda3 /boot

2. Check which kernel sources are installed and which of those sources is currently selected

root # eselect kernel list

3. Make a back-up configuration file for the current running kernel

root # zcat /proc/config.gz > /usr/src/config

4. Select the kernel sources I want to build

root # eselect kernel set <n>

5. Build the kernel image and the initramfs image

root # genkernel --kernel-config=/usr/src/config --clean --menuconfig --microcode=intel --no-splash --module-rebuild all

I have configured the following kernel options relating to the early loading of the Intel CPU microcode (see later):

root # grep CONFIG_BLK_DEV_INITRD /usr/src/linux/.config
CONFIG_BLK_DEV_INITRD=y
root # # grep CONFIG_MICROCODE /usr/src/linux/.config
CONFIG_MICROCODE=y
CONFIG_MICROCODE_INTEL=y
# CONFIG_MICROCODE_AMD is not set
# CONFIG_MICROCODE_OLD_INTERFACE is not set
# grep CONFIG_INITRAMFS_SOURCE /usr/src/linux/.config
CONFIG_INITRAMFS_SOURCE=""

6. Rebuild the X Windows Server and X Windows drivers

I always do this even though not always necessary. One less thing to think about (not rebuilding them has sometimes caused me problems).

root # emerge xorg-server xorg-drivers

7. Rebuild NetworkManager if it is installed

I always do this even though not always necessary. One less thing to think about (not rebuilding it has sometimes caused me problems).

root # emerge networkmanager

8. If there is a new version of the Intel CPU microcode, generate it and copy it to the boot directory

For several years updates to the package sys-kernel/linux-firmware have not resulted in a change to the version of Intel CPU microcode for the legacy Intel Core i7-720QM CPU in my Compal NBLB2 laptop, as Intel no longer supports that version of CPU. Nevertheless it does no harm to repeat the procedure.

root # emerge sys-firmware/intel-microcode
root # rm /boot/microcode.cpio
root # iucode_tool -S --write-earlyfw=/boot/microcode.cpio /lib/firmware/intel-ucode/*
root # rm /boot/intel-uc.img

(The fourth command is to stop the grub-mkconfig command (see Step 9.2) adding intel-uc.img to the initrd line in the grub.cfg file.)

Note the USE flags for that I have set and cleared for sys-firmware/intel-microcode:

root # equery uses intel-microcode
[ Legend : U - final flag setting for installation]
[        : I - package is installed with flag     ]
[ Colors : set, unset                             ]
 * Found these USE flags for sys-firmware/intel-microcode-20210608_p20210830:
 U I
 - - hostonly    : only install ucode(s) supported by currently available (=online) processor(s) 
 - - initramfs   : install a small initramfs for use with CONFIG_MICROCODE_EARLY 
 + + split-ucode : install the split binary ucode files (used by the kernel directly) 
 - - vanilla     : install only microcode updates from Intel's official microcode tarball

9. Create a new grub.cfg file

9.1 First check the contents of /etc/default/grub to make sure it will be OK for the new version of the kernel

root # nano /etc/default/grub

Modify the contents of /etc/default/grub if necessary for the kernel version that has just been built.

9.2 Generate a new grub.cfg file

root # grub-mkconfig -o /boot/grub/grub.cfg

9.3 Check the new grub.cfg file includes the loading of the CPU microcode

root # nano /boot/grub/grub.cfg

The last line for each menu entry (i.e. the line before the closing curly bracket of the menu entry) should contain:

initrd /microcode.cpio /initramfs-<kernel version>-gentoo-x86_64.img

as shown in the example file excerpt below:

[...]
### BEGIN /etc/grub.d/10_linux ###
menuentry 'Gentoo GNU/Linux' --class gentoo --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-9db2f668-a682-4d6f-abc5-ed6f6c515b95' {
load_video
set gfxpayload=1024x768
insmod gzio
insmod part_msdos
insmod ext2
set root='hd0,msdos3'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos3 --hint-efi=hd0,msdos3 --hint-baremetal=ahci0,msdos3  597e8c88-8d50-443f-ae19-f510844f5d4e
else
search --no-floppy --fs-uuid --set=root 597e8c88-8d50-443f-ae19-f510844f5d4e
fi
echo	'Loading Linux 5.15.0-gentoo-x86_64 ...'
linux	/vmlinuz-5.15.0-gentoo-x86_64 root=/dev/sda6 ro BOOT_IMAGE=/kernel-genkernel-x86_64-5.15.0-gentoo root=/dev/ram0 ramdisk=8192 real_root=/dev/sda6 init=/linuxrc resume=swap:/dev/sda5 real_resume=/dev/sda5 intel_iommu=off net.ifnames=0 snd_hda_intel.power_save=0 radeon.modeset=1
echo	'Loading initial ramdisk ...'
initrd	/microcode.cpio /initramfs-5.15.0-gentoo-x86_64.img
}
submenu 'Advanced options for Gentoo GNU/Linux' $menuentry_id_option 'gnulinux-advanced-9db2f668-a682-4d6f-abc5-ed6f6c515b95' {
menuentry 'Gentoo GNU/Linux, with Linux 5.15.0-gentoo-x86_64' --class gentoo --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-gentoo-x86_64-advanced-9db2f668-a682-4d6f-abc5-ed6f6c515b95' {
load_video
set gfxpayload=1024x768
insmod gzio
insmod part_msdos
insmod ext2
set root='hd0,msdos3'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos3 --hint-efi=hd0,msdos3 --hint-baremetal=ahci0,msdos3  597e8c88-8d50-443f-ae19-f510844f5d4e
else
search --no-floppy --fs-uuid --set=root 597e8c88-8d50-443f-ae19-f510844f5d4e
fi
echo	'Loading Linux 5.15.0-gentoo-x86_64 ...'
linux	/vmlinuz-5.15.0-gentoo-x86_64 root=/dev/sda6 ro BOOT_IMAGE=/kernel-genkernel-x86_64-5.15.0-gentoo root=/dev/ram0 ramdisk=8192 real_root=/dev/sda6 init=/linuxrc resume=swap:/dev/sda5 real_resume=/dev/sda5 intel_iommu=off net.ifnames=0 snd_hda_intel.power_save=0 radeon.modeset=1
echo	'Loading initial ramdisk ...'
initrd	/microcode.cpio /initramfs-5.15.0-gentoo-x86_64.img
}
menuentry 'Gentoo GNU/Linux, with Linux 5.15.0-gentoo-x86_64 (recovery mode)' --class gentoo --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-gentoo-x86_64-recovery-9db2f668-a682-4d6f-abc5-ed6f6c515b95' {
load_video
set gfxpayload=1024x768
insmod gzio
insmod part_msdos
insmod ext2
set root='hd0,msdos3'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos3 --hint-efi=hd0,msdos3 --hint-baremetal=ahci0,msdos3  597e8c88-8d50-443f-ae19-f510844f5d4e
else
search --no-floppy --fs-uuid --set=root 597e8c88-8d50-443f-ae19-f510844f5d4e
fi
echo	'Loading Linux 5.15.0-gentoo-x86_64 ...'
linux	/vmlinuz-5.15.0-gentoo-x86_64 root=/dev/sda6 ro single BOOT_IMAGE=/kernel-genkernel-x86_64-5.15.0-gentoo root=/dev/ram0 ramdisk=8192 real_root=/dev/sda6 init=/linuxrc resume=swap:/dev/sda5 real_resume=/dev/sda5 intel_iommu=off net.ifnames=0 snd_hda_intel.power_save=0 radeon.modeset=1
echo	'Loading initial ramdisk ...'
initrd	/microcode.cpio /initramfs-5.15.0-gentoo-x86_64.img
}
}

### END /etc/grub.d/10_linux ###
[...]

10. Reboot

11. Rebuild VirtualBox if it is installed

root # emerge virtualbox

12. Check the current version of the Intel CPU microcode

Either:

root # dmesg | grep microcode

or:

root # grep microcode /proc/cpuinfo

For example:

root # dmesg | grep microcode
[    0.000000] microcode: microcode updated early to revision 0xa, date = 2018-05-08
[    0.127937] MDS: Vulnerable: Clear CPU buffers attempted, no microcode
[    1.558008] microcode: sig=0x106e5, pf=0x10, revision=0xa
[    1.559335] microcode: Microcode Update Driver: v2.2.
root # grep microcode /proc/cpuinfo
microcode       : 0xa
microcode       : 0xa
microcode       : 0xa
microcode       : 0xa
microcode       : 0xa
microcode       : 0xa
microcode       : 0xa
microcode       : 0xa

Note from the output of the dmesg command that this specific CPU model is susceptible to the MDS (Microarchitectural Data Sampling) vulnerability.

13. Edit /var/lib/portage/world and add (or change) the specific kernel sources package version

I do this in order to ensure the command ‘emerge --depclean‘ does not remove a specific kernel’s source code during a world update. I want Portage always to install the latest version of gentoo-sources but not to delete the version of gentoo-sources that corresponds to the kernel my installation is currently using.

For example, let’s say I have just replaced a kernel built from gentoo-sources:5.15.11 with a kernel built from gentoo-sources:5.15.12. My world file would initially contain the following:

[...]
sys-kernel/gentoo-sources
sys-kernel/gentoo-sources:5.15.11
[...]

If, following a successful reboot with kernel 5.15.12, I want to delete the files for kernel 5.15.11 in /boot/ (initramfs-5.15.11-gentoo-x86_64.img, System.map-5.15.11-gentoo-x86_64 and vmlinuz-5.15.11-gentoo-x86_64) and to edit the file /boot/grub/grub.cfg to remove the menu entries for kernel 5.15.11, I would change the world file’s contents to:

[...]
sys-kernel/gentoo-sources
sys-kernel/gentoo-sources:5.15.12
[...]

On the other hand, if, following a successful reboot, I want to keep the files for both kernel 5.15.11 and kernel 5.15.12, I would change the world file’s contents to:

[...]
sys-kernel/gentoo-sources
sys-kernel/gentoo-sources:5.15.11
sys-kernel/gentoo-sources:5.15.12
[...]