zfsbootmenu/docs/general/uefi-booting.rst

163 lines
8.8 KiB
ReStructuredText

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 <https://github.com/rhboot/efibootmgr>`_ or via a third-party boot manager like
`rEFInd <http://www.rodsbooks.com/refind/>`_.
efibootmgr
----------
.. code-block::
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 :doc:`config.yaml </man/generate-zbm.5>`
governs the creation of bundled UEFI executables. The default configuration disables this option; to enable it, set
``EFI.Enabled: true``:
.. code-block:: yaml
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 the ``EFI``
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 of ``generate-zbm``, it is probably best to disabling ``Versions`` by setting its value to ``false``
or ``0``. See the :ref:`description of this key in manual page <config-components>` 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 when creating a bundled executable. Both ``gummiboot``
and its descendant ``systemd-boot`` provide stub loaders; ``gummiboot``, for example, tends to store the loader at
``/usr/lib/gummiboot/linuxx64.efi.stub``. If this key is omitted (as it is by default), ``dracut`` will attempt to
find either the ``systemd-boot`` or ``gummiboot`` version at their expected locations. This key is useful when
automatic detection fails.
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 called ``vmlinuz.EFI`` in the configured ``ImageDir``, while the kernel ``/boot/vmlinuz-lts-<version>`` will
produce a bundle called ``vmlinuz-lts.EFI``.
* ``CommandLine`` provides the command-line arguments that will be encoded in the bundle and passed to the kernel during
boot. The ``dracut`` configuration option ``kernel_cmdline`` also provides a mechanism for encoding the kernel
command-line; if the ZFSBootMenu configuration specifies ``Kernel.CommandLine`` and the ``dracut`` configuration for
ZFSBootMenu specifies ``kernel_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.
..
vim: softtabstop=2 shiftwidth=2 textwidth=120