UEFI Booting#
Although ZFSBootMenu images can be booted on legacy BIOS systems or (on other platforms) alternative firmware, ZFSBootMenu integrates nicely with modern UEFI systems. ZFSBootMenu builds a custom initramfs image around a standard Linux kernel. Most distributions compile the Linux kernel with an EFI stub loader; the ZFSBootMenu kernel and initramfs pair can therefore be booted directly by most UEFI implementations or by EFI boot managers like rEFInd or gummiboot (systemd-boot).
When generating ZFSBootMenu images from a local host, it is possible to edit /etc/zfsbootmenu/config.yaml
to copy
the ZFSBootMenu kernel and initramfs directly to your EFI system partition. Suppose that the directory listing for your
current /boot
looks like:
# ls /boot
config-5.3.18_1
config-5.4.6_1
efi
initramfs-5.3.18_1.img
initramfs-5.4.6_1.img
System.map-5.3.18_1
System.map-5.4.6_1
vmlinuz-5.3.18_1
vmlinuz-5.4.6_1
Typically, EFI system partitions (ESP) are mounted at /boot/efi
, as is shown above. An ESP may contain a number of
sub-directories, including an EFI
directory that often contains multiple independent EFI executables. In this
example layout, /boot/efi/EFI/zbm
may hold ZFSBootMenu kernels and initramfs images. After setting the ImageDir
property of the Components
section of /etc/zfsbootmenu/config.yaml
to /boot/efi/EFI/zbm
, running
generate-zbm
will cause ZFSBootMenu kernel and initramfs pairs to be installed in the desired location:
# lsblk -f /dev/sda
NAME FSTYPE LABEL UUID FSAVAIL FSUSE% MOUNTPOINT
sdg
├─sda1 vfat AFC2-35EE 7.9G 1% /boot/efi
└─sda2 swap 412401b6-4aec-4452-a6bd-6fc20fbdc2a5 [SWAP]
# ls /boot/efi/EFI/zbm/
initramfs-1.12.0_1.img
initramfs-1.12.0_2.img
vmlinuz-1.12.0_1
vmlinuz-1.12.0_2
After the kernel and initramfs pairs are made available on the ESP, you'll need a way to boot them on your system. This can be done directly via efibootmgr or via a third-party boot manager like rEFInd.
efibootmgr#
efibootmgr --disk /dev/sda \
--part 1 \
--create \
--label "ZFSBootMenu" \
--loader '\EFI\zbm\vmlinuz-1.12.0_2' \
--unicode 'zbm.prefer=zroot ro initrd=\EFI\zbm\initramfs-1.12.0_2.img quiet' \
--verbose
Take note to adjust the arguments to --disk
and --part
, the path to the kernel in --loader
, and the
initramfs path (initrd=
) and pool preference (zbm.prefer=
) to match your system configuration.
Each time ZFSBootMenu is updated, a new EFI entry will need to be manually added, unless you disable versioning in the ZFSBootMenu configuration.
rEFInd#
rEFInd
is considerably easier to install and manage. Refer to your distribution's packages for installation. Once
rEFInd has been installed, you can create refind_linux.conf
in the directory holding the ZFSBootMenu files
(/boot/efi/EFI/zbm
in our example):
"Boot default" "zbm.prefer=zroot ro quiet loglevel=0 zbm.skip"
"Boot to menu" "zbm.prefer=zroot ro quiet loglevel=0 zbm.show"
As with the efibootmgr section, the zbm.prefer=
option needs to be configured to match your environment.
This file will configure rEFInd
to create two entries for each kernel and initramfs pair it finds. The first will
directly boot into the environment set via the bootfs
pool property. The second will force ZFSBootMenu to display
its interactive user interface and allow you to boot alternate environments, kernels and snapshots.
Avoiding an Intermediate Boot Manager#
On most UEFI systems, booting ZFSBootMenu without the use of an intermediate boot manager like rEFInd is possible. Linux kernels typically include an EFI stub and can be invoked as UEFI executables directly by the firmware. Unfortunately, while some UEFI implementations allow passing of command-line arguments to the UEFI kernel, others (from Dell, for example) seem to ignore all configured command-line arguments, making it impossible to specify needed options (such as the path to the ZFSBootMenu initramfs). Even those implementations that do respect configured arguments may provide no firmware interface to alter these arguments, which means booting a backup ZFSBootMenu image may not be possible if it wasn't configured in advance from a Linux installation.
These limitations are easily avoided if ZFSBootMenu is packaged as a bundled UEFI executable that encapsulates the
Linux kernel, ZFSBootMenu initramfs and all needed command-line arguments. Dracut facilitates the creation of a bundled
UEFI executable, and the generate-zbm
script exposes this capability.
Creation of a Bundled UEFI Executable#
The EFI
section of the ZFSBootMenu config.yaml
governs the creation of bundled UEFI executables. The default configuration disables this option; to enable it, set
EFI.Enabled: true
:
EFI:
Enabled: true
The remaining keys in the EFI
section allow control over where and how UEFI bundles are created:
ImageDir
is the location where the bundle will be written, and should generally be a subdirectory of theEFI
subdirectory of your EFI system partition. The default,/boot/efi/EFI/void
, is fine if the ESP is mounted at/boot/efi
(and you are either running Void Linux or don't care if the directory name matches your distribution name).Versions
controls whether UEFI bundles include a version and revision number in their name and, if so, how many prior versioned executables are retained. Because the firmware is not automatically reconfigured to boot the latest version after runs ofgenerate-zbm
, it is probably best to disablingVersions
by setting its value tofalse
or0
. See the description of this key in manual page for more details about its behavior. Even when versioning is disabled,generate-zbm
still makes a backup of your existing boot image by replacing its.EFI
extension with-backup.EFI
to provide a fallback.Stub
specifies the location of the UEFI stub loader required while creating a bundled executable when the default location of thesystemd-boot
needs to be changed.
In addition, two options in the Kernel
section of the configuration file are used during bundle creation:
Prefix
provides the base name for the output bundle file. If this is omitted, the base name will be derived from the name of the kernel used to create the image; for example, the kernel/boot/vmlinuz-<version>
will produce a bundle calledvmlinuz.EFI
in the configuredImageDir
, while the kernel/boot/vmlinuz-lts-<version>
will produce a bundle calledvmlinuz-lts.EFI
.CommandLine
provides the command-line arguments that will be encoded in the bundle and passed to the kernel during boot. Thedracut
configuration optionkernel_cmdline
also provides a mechanism for encoding the kernel command-line; if the ZFSBootMenu configuration specifiesKernel.CommandLine
and thedracut
configuration for ZFSBootMenu specifieskernel_cmdline
, the two values will be concatenated.
After adjusting the configuration options as desired, run generate-zbm
and a bundled UEFI executable will be created
in EFI.ImageDir
.
Booting the Bundled Executable#
The efibootmgr utility provides a means to configure your firmware to boot the bundled executable. For example:
efibootmgr -c -d /dev/sda -p 1 -L "ZFSBootMenu" -l '\EFI\VOID\VMLINUZ.EFI'
will create a new entry that will boot the executable written to /boot/efi/EFI/void/vmlinuz.EFI
if your EFI system
partition is /dev/sda1
and is mounted at /boot/efi
. (Remember that the EFI system partition should be a FAT
volume, so the path separators are backslashes and paths should be case-insensitive.) For good measure, create an
alternative entry that points at the backup image:
efibootmgr -c -d /dev/sda -p 1 -L "ZFSBootMenu (Backup)" -l '\EFI\VOID\VMLINUZ-BACKUP.EFI'
The firmware should provide some means to select between these alternatives.
It is also generally possible to configure the boot sequence from your firmware setup interface. Simply find and select the path to the bundled EFI executable from this interface.