Unified kernel image - ArchWiki

Jump to content

# Unified kernel image

From ArchWiki

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:

- a UEFI stub loader like systemd-stub(7),
- a kernel image,
- an initramfs image.
- the kernel command line,
- optionally, a splash screen.

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

One can test the feature by running as an example

    # mkinitcpio -p linux -- --uefi esp/EFI/Linux/test-systemd.efi

This would produce a kernel image for the linux preset.

#### .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

- mkinitcpio v31 and UEFI stubs

Category:

- Boot loaders