Boot Gentoo Using EFI Stub

Fast and Clean System Boot

Published on 02 November 2024 by Jing Huang.

1. Background

In order to boot the Linux kernel, one traditionally needs a bootloader like Grub or chainloader like rEFInd. However, these are ugly (text-only ones look alright, but graphic ones with low resolution images really don’t look good), slow and no longer necessary.

Modern PC comes with UEFI support, which enables us to directly load kernel images from the EFI partition without the need for any bootloader or chainloaders.

2. Linux Kernal

2.1. Configuration

You should enable native EFI support and EFI stub support for the kernel.

  |Processor type and features --->
  |   [*] EFI runtime service support
  |   [*]   EFI stub support
  |   [ ]     EFI mixed-mode support

You are also recommended to embed the root partition information into the kernel.

  |Processor type and features --->
  |   [*] Built-in kernel command line
  |       (root=/dev/nvme0n1p3)

2.2. Install

Rebuild the kernel and install the kernel modules.

  |make -j && make modules_install

2.3. Initramfs

An initramfs regeneration might be necessary. For example if you embedded the root partition information into the kernel, or if you use BTRFS subvolumes.

3. EFI Partition

Create an EFI system partition if you don’t have one. This ESP should then be mounted at /efi. Then make the below directory structure:

  |/efi
  |└── EFI
  |    └── Gentoo
  |        ├── initramfs.img
5 |        └── bzImage.efi

The bzImage.efi should be copied from /usr/src/linux/arch/x86/boot/bzImage. The initramfs.img is optional, copied from the initramfs only when needed.

There can be more than one subdirectories containing stub images for more than one system inside the EFI directory.

3. EFI Variables Filesystem

The tool we use to create and manage the boot entries requires the EFI variables filesystem to be accessible (i.e., properly mounted).

Run the following command to check if it is mounted properly:

  |mount | grep efivars

If it is mounted as ro, remount it with rw so that we can create and modify EFI boot entries.

4. Create Boot Entry

First execute efibootmgr without any options to list the existing boot entries. Remove unnecessary or obsolete ones with:

  |efibootmgr -b 2 -B # select the `Bootx002' entry and remove it

Then create an entry for our system.

  |efibootmgr -c -d /dev/nvme0n1 -p 2 -L "Linux EFI Stub" -l '\EFI\gentoo\bzImage.efi' -u 'root=/dev/nvme0n1p3' # without initramfs
  |efibootmgr -c -d /dev/nvme0n1 -p 2 -L "Linux EFI Stub" -l '\EFI\gentoo\bzImage.efi' -u 'initrd=\EFI\gentoo\initramfs.img' # with initramfs

After checking if the system can successfully boot, you can unmerge efibootmgr. Just copy new kernel images and initramfs to the same position on the EFI partition.

5. Troubleshoot

If you encountered the common VFS: Cannot open root device or unknown block error, don’t panic.

  1. Remember to supply the kernel with root=/dev/<block> using -u option of efibootmgr or the kernel built-in command line. An initramfs generated by for instance dracut might also contain one.
  2. If you specified the system root partition using kernel build-in command line or by UUID, you need an initramfs.
  3. If you use BTRFS subvolumes, you need an initramfs.
  4. Try the rootwait option if an initramfs is not used and the root filesystem is on an MTD device (such as an NVME drive) to make the kernel wait for asynchronous initialization of the device.