Unified kernel image

From ArchWiki
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

A unified kernel image is a single executable which can be booted directly from UEFI firmware, or automatically sourced by boot-loaders with little or no configuration.

Although Arch supported kernels themselves can be loaded by UEFI firmware, a unified image allows to incorporate:

The resulting executable, and therefore all these elements can then be easily signed for use with Secure Boot.

Note: In the entire article esp denotes the mountpoint of the EFI system partition.

Preparing a unified kernel image

mkinitpcio

.preset file

First, modify /etc/mkinitcpio.d/linux.preset, or the preset that you are using, as follows, with the appropriate mount point of the EFI system partition :

  • If your system requires Microcode, add ALL_microcode=(/boot/*-ucode.img) to tell mkinitcpio where to find it.
  • Add a PRESET_efi_image= parameter for each item in PRESETS=, i.e. default_efi_image="esp/EFI/Linux/archlinux-linux.efi" and fallback_efi_image="esp/EFI/Linux/archlinux-linux-fallback.efi". This sets the executable filename.
  • Optionally, append --splash /usr/share/systemd/bootctl/splash-arch.bmp to each PRESET_options= line to add a splash image, i.e. default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp" and fallback_options="-S autodetect --splash /usr/share/systemd/bootctl/splash-arch.bmp".

Here is a working example linux.preset for the linux kernel and the Arch splash screen.

/etc/mkinitcpio.d/linux.preset
# mkinitcpio preset file for the 'linux' package

 ALL_config="/etc/mkinitcpio.conf"
 ALL_kver="/boot/vmlinuz-linux"
 ALL_microcode=(/boot/*-ucode.img)

 PRESETS=('default' 'fallback')

 default_image="/boot/initramfs-linux.img"
 default_efi_image="esp/EFI/Linux/archlinux-linux.efi"
 default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp"

 fallback_image="/boot/initramfs-linux-fallback.img"
 fallback_efi_image="esp/EFI/Linux/archlinux-linux-fallback.efi"
 fallback_options="-S autodetect --splash /usr/share/systemd/bootctl/splash-arch.bmp"

This second example builds a default image for linux and a fallback image for linux-lts :

/etc/mkinitcpio.d/linux.preset
ALL_config="/etc/mkinitcpio.conf"
ALL_microcode=(/boot/*-ucode.img)

PRESETS=('default' 'fallback')

default_kver="/boot/vmlinuz-linux"
default_image="/boot/initramfs-linux.img"
default_efi_image="/boot/EFI/Linux/archlinux-linux.efi"
default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp"

fallback_kver="/boot/vmlinuz-linux-lts"
fallback_image="/boot/initramfs-linux-lts-fallback.img"
fallback_efi_image="/boot/EFI/Linux/archlinux-linux-lts-fallback.efi"
fallback_options="-S autodetect --splash /usr/share/systemd/bootctl/splash-arch.bmp"
Tip: If you are using multiple kernels, make sure your ESP has enough space, as mkinitcpio currently builds both the initramfs-*.img and the *.efi executable, thereby doubling the space used. See [1]

Kernel command line

Next, create /etc/kernel/cmdline with your kernel parameters.

# cp /proc/cmdline /etc/kernel/cmdline
Warning: initrd entries pointing at microcode and the initramfs need to be removed.

For example:

/etc/kernel/cmdline
rw quiet bgrt_disable
Tip: The bgrt_disable parameter tells Linux to not display the OEM logo after loading the ACPI tables.

Finally, regenerate the initramfs.

dracut

Place your command line parameters in ie. /etc/dracut.conf.d/cmdline.conf

Generate the image with:

# dracut -f -q --uefi --uefi-splash-image /usr/share/systemd/bootctl/splash-arch.bmp

Also see dracut#Generate a new initramfs on kernel upgrade.

Manually

Put the kernel command line you want to use in a file, and create the bundle file using objcopy(1).

For microcode, first concatenate the microcode file and your initrd, as follows:

$ cat /boot/cpu_manufacturer-ucode.img /boot/initramfs-linux.img > /tmp/combined_initrd.img

When building the unified kernel image, passing /tmp/combined_initrd.img as the initrd. This file can be afterwards.

$ objcopy \
    --add-section .osrel="/usr/lib/os-release" --change-section-vma .osrel=0x20000 \
    --add-section .cmdline="/etc/kernel/cmdline" --change-section-vma .cmdline=0x30000 \
    --add-section .splash="/usr/share/systemd/bootctl/splash-arch.bmp" --change-section-vma .splash=0x40000 \
    --add-section .linux="vmlinuz-file" --change-section-vma .linux=0x2000000 \
    --add-section .initrd="initrd-file" --change-section-vma .initrd=0x3000000 \
    "/usr/lib/systemd/boot/efi/linuxx64.efi.stub" "linux.efi"

See [2] for an explanation on why these exact numbers were chosen.

After creating the image, copy it to the EFI system partition:

# cp linux.efi esp/EFI/Linux/

Booting

systemd-boot

systemd-boot searches in esp/EFI/Linux/ for unified kernel images, and there is no further configuration needed. See sd-boot(7) § FILES

Directly from UEFI

efibootmgr can be used to create a UEFI boot entry for the .efi file:

# efibootmgr --create --disk /dev/sdX --part partition_number --label "label" --loader 'EFI\Linux\file.efi' --verbose

See efibootmgr(8) for an explanation of the options.

See also