Unified kernel image: Difference between revisions
m (→Kernel command line: links) |
|||
(82 intermediate revisions by 27 users not shown) | |||
Line 1: | Line 1: | ||
[[Category:Boot loaders]] | [[Category:Boot loaders]] | ||
[[ja: | [[ja:ユニファイドカーネルイメージ]] | ||
[[pt:Unified kernel image]] | [[pt:Unified kernel image]] | ||
A [https://uapi-group.org/specifications/specs/ | A [https://uapi-group.org/specifications/specs/unified_kernel_image unified kernel image] (UKI) is a single executable which can be booted directly from [[UEFI]] firmware, or automatically sourced by boot loaders with little or no configuration. It is the combination of a UEFI boot stub program like {{man|7|systemd-stub}}, a Linux [[Arch boot process#Kernel|kernel image]], an [[Arch boot process#initramfs|initrd]], and [https://uapi-group.org/specifications/specs/unified_kernel_image/#uki-components further resources] in a single UEFI PE file. | ||
This file, and therefore all these elements can then easily be [[Unified Extensible Firmware Interface/Secure Boot#Signing EFI binaries|signed]] for use with [[Secure Boot]]. | |||
{{Note|In the entire article {{ic|''esp''}} denotes the mountpoint of the [[EFI system partition]].}} | |||
== Preparing a unified kernel image == | |||
There are several ways to generate a UKI image and install it to the proper place (the ''esp/Linux'' directory). Currently several tools compete for doing this functionality, so choose one of the following based on your needs and your likings. | |||
{{Note|You only need to perform one of the subsections.}} | |||
=== mkinitcpio === | === mkinitcpio === | ||
Line 23: | Line 18: | ||
==== Kernel command line ==== | ==== Kernel command line ==== | ||
[[mkinitcpio]] supports reading [[kernel parameters]] from command line files in the {{ic|/etc/cmdline.d}} directory. Mkinitcpio will concatenate the contents of all files with a {{ic|.conf}} extension in this directory and use them to generate the kernel command line. Any lines in the command line file that start with a '''#''' character are treated as comments and ignored by mkinitcpio. Take care to '''remove entries''' pointing to microcode and initramfs. | [[mkinitcpio]] supports reading [[kernel parameters]] from command line files in the {{ic|/etc/cmdline.d}} directory. Mkinitcpio will concatenate the contents of all files with a {{ic|.conf}} extension in this directory and use them to generate the kernel command line. Any lines in the command line file that start with a '''#''' character are treated as comments and ignored by mkinitcpio. Take care to '''remove entries''' pointing to microcode and initramfs. | ||
For example: | For example: | ||
Line 29: | Line 24: | ||
{{hc|/etc/cmdline.d/root.conf|2= | {{hc|/etc/cmdline.d/root.conf|2= | ||
root=UUID=0a3407de-014b-458b-b5c1-848e92a327a3 rw | root=UUID=0a3407de-014b-458b-b5c1-848e92a327a3 rw | ||
}} | |||
{{Tip| | |||
* If your root file system is on a non-default Btrfs subvolume, make sure to set necessary mount flags in {{ic|rootflags}}. For example, if your system subvolume ID is {{ic|256}}, you should add {{ic|1=rootflags=subvolid=256}} to the kernel command line. See [[Btrfs#Mounting subvolume as root]]. | |||
* It is not necessary to copy all flags in {{ic|/etc/fstab}} since {{ic|rootflags}} is only used during boot. Systemd will read fstab, remount and apply flags listed there automatically after boot. | |||
}} | }} | ||
Line 51: | Line 51: | ||
==== .preset file ==== | ==== .preset file ==== | ||
Next, modify {{ic|/etc/mkinitcpio.d/linux.preset}}, or the preset that you are using, as follows, with the appropriate mount point of the [[EFI system partition]] : | Next, modify {{ic|/etc/mkinitcpio.d/linux.preset}}, or the preset that you are using, as follows, with the appropriate mount point of the [[EFI system partition]]: | ||
* Un-comment (i.e. remove {{ic|#}}) the {{ic|1=''PRESET''_uki=}} parameter for each item in {{ic|1=PRESETS=}}, | * Un-comment (i.e. remove {{ic|#}}) the {{ic|1=''PRESET''_uki=}} parameter for each item in {{ic|1=PRESETS=}}, | ||
Line 59: | Line 59: | ||
Here is a working example {{ic|linux.preset}} for the {{Pkg|linux}} kernel and the Arch splash screen. | Here is a working example {{ic|linux.preset}} for the {{Pkg|linux}} kernel and the Arch splash screen. | ||
{{hc|/etc/mkinitcpio.d/linux.preset|2= | {{hc|/etc/mkinitcpio.d/linux.preset|2= | ||
# mkinitcpio preset file for the 'linux' package | # mkinitcpio preset file for the 'linux' package | ||
#ALL_config="/etc/mkinitcpio.conf" | #ALL_config="/etc/mkinitcpio.conf" | ||
ALL_kver="/boot/vmlinuz-linux" | ALL_kver="/boot/vmlinuz-linux" | ||
PRESETS=('default' 'fallback') | PRESETS=('default' 'fallback') | ||
Line 81: | Line 80: | ||
{{Tip| | {{Tip| | ||
* If all you want to do is boot from the unified kernel images, you can [[EFI system partition#Typical mount points|mount the ESP]] to {{ic|/efi}} and only those need to reside on the [[ESP]] partition. | * If all you want to do is boot from the unified kernel images, you can [[EFI system partition#Typical mount points|mount the ESP]] to {{ic|/efi}} and only those need to reside on the [[ESP]] partition. | ||
* You can append {{ic|--cmdline /etc/kernel/''fallback_cmdline''}} to {{ic|fallback_options}} to use | * You can append {{ic|--cmdline /etc/kernel/''fallback_cmdline''}} to {{ic|fallback_options}} to use a different [[#Kernel command line|cmdline]] than above for the fallback image (e.g. without {{ic|quiet}}). | ||
* To omit embedding the kernel command line, add {{ic|--no-cmdline}} to {{ic|''PRESET''_options{{=}}}}. Kernel parameters will need to be passed via the boot loader. | * To omit embedding the kernel command line, add {{ic|--no-cmdline}} to {{ic|''PRESET''_options{{=}}}}. Kernel parameters will need to be passed via the boot loader. | ||
}} | }} | ||
{{Note|{{ic|''PRESET''_uki}} options were previously known as {{ic|''PRESET''_efi_image}}, | {{Note|{{ic|''PRESET''_uki}} options were previously known as {{ic|''PRESET''_efi_image}}, changed November 2022 (see {{Issue|archlinux/mkinitcpio/mkinitcpio|134}}), with older option deprecated but working for now.}} | ||
==== pacman hook ==== | |||
[ | Updates to systemd-stub (part of {{pkg|systemd}}), microcode (both {{pkg|intel-ucode}} and {{pkg|amd-ucode}}), and {{pkg|linux}} kernel will automatically trigger a UKI rebuild. But you may want to review other [[pacman hooks]] in the {{ic|/etc/pacman.d/hooks/}} directory, such as the one for the [[NVIDIA#pacman hook|NVIDIA driver]]. | ||
}} | |||
==== Signing the UKIs for Secure Boot ==== | ==== Signing the UKIs for Secure Boot ==== | ||
By using a [ | By using a [[mkinitcpio#Post hooks|mkinitcpio post hook]], the generated unified kernel images can be signed for [[Secure Boot]]. [[Create]] the following file and make it [[executable]]: | ||
{{hc|/etc/initcpio/post/uki-sbsign|2= | {{hc|/etc/initcpio/post/uki-sbsign|2= | ||
Line 143: | Line 123: | ||
=== kernel-install === | === kernel-install === | ||
For [[kernel-install]] to generate UKIs, install {{Pkg|systemd-ukify}} and set the {{ic|kernel-install}} ''layout'' to {{ic|uki}}: | |||
{{hc|/etc/kernel/install.conf| | |||
2=layout=uki}} | |||
{{Note|[[mkinitcpio]] will create the initrd and [[#ukify]] will thereafter generate the UKI.}} | |||
Any configuration for [[#ukify]] must be done in {{ic|/etc/kernel/uki.conf}} in order to be used by [[kernel-install]], e.g. | |||
{{hc|/etc/kernel/uki.conf| | |||
2=[UKI] | |||
Splash=/usr/share/systemd/bootctl/splash-arch.bmp | |||
}} | |||
{{ | {{Note|Do not set the kernel command line in this file, it will be ignored. Use [[Kernel-install#Kernel command line]].}} | ||
Alternatively, for mkinitcpio to generate the UKI, set it as the default {{ic|uki_generator}}: | |||
{{hc|/etc/kernel/install.conf| | |||
2=layout=uki | |||
uki_generator=mkinitcpio}} | |||
In that case, {{Pkg|systemd-ukify}} is not necessary. You can also set a different {{ic|initrd_generator}}, see {{Man|8|kernel-install}}. | |||
Reinstall the kernel packages that you use in order for the change to take effect. | |||
=== dracut === | === dracut === | ||
See [[dracut#Unified kernel image]] and | See [[dracut#Unified kernel image]] and [[dracut#Generate a new initramfs on kernel upgrade]]. | ||
=== sbctl === | === sbctl === | ||
Line 174: | Line 163: | ||
=== ukify === | === ukify === | ||
[[Install]] the {{Pkg|systemd-ukify}} package. Since ''ukify'' cannot generate an initramfs on its own, if required, it must be generated using [[dracut]], [[mkinitcpio]] or [[booster]]. | [[Install]] the {{Pkg|systemd-ukify}} package. To use the automatic signing functions, additionally install {{Pkg|sbsigntools}}. Since ''ukify'' cannot generate an initramfs on its own, if required, it must be generated using [[dracut]], [[mkinitcpio]] or [[booster]]. | ||
A minimal working example can look something like this: | A minimal working example can look something like this: | ||
# / | # ukify build --linux=''/boot/vmlinuz-linux'' \ | ||
--initrd=''/boot/initramfs-linux.img'' \ | |||
--cmdline="''quiet rw''" | |||
{{Note|If [[Microcode#Microcode in a separate initramfs file|external microcode initramfs images]] are used, {{ic|/boot/amd-ucode.img}} or {{ic|/boot/intel-ucode.img}} must always be placed '''first''', before the main initramfs image. E.g. {{ic|1=--initrd=/boot/intel-ucode.img --initrd=/boot/initramfs-linux.img}}.}} | |||
Then, copy the resulting file to the EFI | Then, copy the resulting file to the EFI system partition: | ||
# cp ''filename''.efi ''esp''/EFI/Linux/ | # cp ''filename''.efi ''esp''/EFI/Linux/ | ||
Line 192: | Line 185: | ||
{{hc|/etc/ukify.conf|2= | {{hc|/etc/ukify.conf|2= | ||
[UKI] | |||
Linux=/boot/vmlinuz-linux | |||
Initrd=/boot/intel-ucode.img /boot/initramfs-linux.img | |||
Cmdline=@/etc/kernel/cmdline | |||
OSRelease=@/etc/os-release | |||
Splash=/usr/share/systemd/bootctl/splash-arch.bmp | |||
}} | }} | ||
{{Note|If the initramfs generator already bundles CPU microcode by default, then only specify the initramfs image in {{ic|1=Initrd=/boot/initramfs-linux.img}}.}} | |||
{{Accuracy|section=Automatic update of ukify-generated images via systemd path units is unreliable|Automatic update of ukify-generated images via systemd path units is unreliable}} | |||
{{hc|/etc/systemd/system/run_ukify.service|2= | {{hc|/etc/systemd/system/run_ukify.service|2= | ||
Line 207: | Line 202: | ||
[Service] | [Service] | ||
Type=oneshot | Type=oneshot | ||
ExecStart=/usr/bin/ | ExecStart=/usr/bin/ukify build --config=/etc/ukify.conf --output ''esp''/EFI/Linux/archlinux-linux.efi | ||
}} | }} | ||
Line 232: | Line 227: | ||
When building the unified kernel image, pass in {{ic|/tmp/combined_initrd.img}} as the initrd. This file can be removed afterwards. | When building the unified kernel image, pass in {{ic|/tmp/combined_initrd.img}} as the initrd. This file can be removed afterwards. | ||
{{Note|For [[Unified Extensible Firmware Interface#UEFI firmware bitness|IA32 UEFI]], replace {{ic|/usr/lib/systemd/boot/efi/linuxx64.efi.stub}} with {{ic|/usr/lib/systemd/boot/efi/linuxia32.efi.stub}} in the following commands.}} | |||
{{bc|1= | {{bc|1= | ||
$ osrel_offs=$(objdump -h "/usr/lib/systemd/boot/efi/linuxx64.efi.stub" {{!}} awk 'NF==7 {size=strtonum("0x"$3); offset=strtonum("0x"$4)} END {print size + offset}') | $ align="$(objdump -p /usr/lib/systemd/boot/efi/linuxx64.efi.stub {{!}} awk '{ if ($1 == "SectionAlignment"){print $2} }')" | ||
$ align=$((16#$align)) | |||
$ osrel_offs="$(objdump -h "/usr/lib/systemd/boot/efi/linuxx64.efi.stub" {{!}} awk 'NF==7 {size=strtonum("0x"$3); offset=strtonum("0x"$4)} END {print size + offset}')" | |||
$ osrel_offs=$((osrel_offs + "$align" - osrel_offs % "$align")) | |||
$ cmdline_offs=$((osrel_offs + $(stat -Lc%s "/usr/lib/os-release"))) | $ cmdline_offs=$((osrel_offs + $(stat -Lc%s "/usr/lib/os-release"))) | ||
$ cmdline_offs=$((cmdline_offs + "$align" - cmdline_offs % "$align")) | |||
$ splash_offs=$((cmdline_offs + $(stat -Lc%s "/etc/kernel/cmdline"))) | $ splash_offs=$((cmdline_offs + $(stat -Lc%s "/etc/kernel/cmdline"))) | ||
$ | $ splash_offs=$((splash_offs + "$align" - splash_offs % "$align")) | ||
$ initrd_offs=$((linux_offs + $(stat -Lc%s "'' | $ initrd_offs=$((splash_offs + $(stat -Lc%s "/usr/share/systemd/bootctl/splash-arch.bmp"))) | ||
$ initrd_offs=$((initrd_offs + "$align" - initrd_offs % "$align")) | |||
$ linux_offs=$((initrd_offs + $(stat -Lc%s "''initrd-file''"))) | |||
$ linux_offs=$((linux_offs + "$align" - linux_offs % "$align")) | |||
$ objcopy \ | $ objcopy \ | ||
--add-section .osrel="/usr/lib/os-release" --change-section-vma .osrel=$(printf 0x%x $osrel_offs) \ | --add-section .osrel="/usr/lib/os-release" --change-section-vma .osrel=$(printf 0x%x $osrel_offs) \ | ||
Line 245: | Line 250: | ||
--add-section .splash="/usr/share/systemd/bootctl/splash-arch.bmp" \ | --add-section .splash="/usr/share/systemd/bootctl/splash-arch.bmp" \ | ||
--change-section-vma .splash=$(printf 0x%x $splash_offs) \ | --change-section-vma .splash=$(printf 0x%x $splash_offs) \ | ||
--add-section .initrd="''initrd-file''" \ | |||
--change-section-vma .initrd=$(printf 0x%x $initrd_offs) \ | |||
--add-section .linux="''vmlinuz-file''" \ | --add-section .linux="''vmlinuz-file''" \ | ||
--change-section-vma .linux=$(printf 0x%x $linux_offs) \ | --change-section-vma .linux=$(printf 0x%x $linux_offs) \ | ||
"/usr/lib/systemd/boot/efi/linuxx64.efi.stub" "''linux''.efi" | "/usr/lib/systemd/boot/efi/linuxx64.efi.stub" "''linux''.efi" | ||
}} | }} | ||
The offsets are | A few things to note: | ||
* The offsets are dynamically calculated so no sections overlap, as recommended in [https://github.com/systemd/systemd/commit/0fa2cac4f0cdefaf1addd7f1fe0fd8113db9360b#commitcomment-76747223]. | |||
* The sections are aligned to what the {{ic|SectionAlignment}} field of the PE stub indicates (usually 0x1000). | |||
* The kernel image must be in the last section, to prevent in-place decompression from overwriting the sections that follow, as stated in [https://github.com/systemd/systemd/commit/0fa2cac4f0cdefaf1addd7f1fe0fd8113db9360b#commitcomment-84868898]. | |||
After creating the image, copy it to the EFI system partition: | After creating the image, copy it to the EFI system partition: | ||
Line 259: | Line 268: | ||
== Booting == | == Booting == | ||
{{Note|When [[Secure Boot]] is active, unified kernel images with an embedded {{ic|.cmdline}} ignore all command line options passed to them (either using a boot entry or interactively). When Secure Boot is not active, the options passed via the command line override the embedded {{ic|.cmdline}}.}} | |||
=== systemd-boot === | === systemd-boot === | ||
[[systemd-boot#Unified kernel images|systemd-boot]] searches in {{ic|''esp''/EFI/Linux/}} for unified kernel images, and there is no further configuration needed. See {{man|7|sd-boot|FILES}} | [[systemd-boot#Unified kernel images|systemd-boot]] searches in {{ic|''esp''/EFI/Linux/}} for unified kernel images, and there is no further configuration needed. See {{man|7|sd-boot|FILES}} | ||
=== rEFInd === | === rEFInd === | ||
Line 277: | Line 288: | ||
Recall that no kernel parameters from {{ic|''esp''/EFI/refind_linux.conf}} will be passed when booting this way. If the UKI was generated without a {{ic|.cmdline}} section, specify the kernel parameters in the menu entry with an {{ic|options}} line. | Recall that no kernel parameters from {{ic|''esp''/EFI/refind_linux.conf}} will be passed when booting this way. If the UKI was generated without a {{ic|.cmdline}} section, specify the kernel parameters in the menu entry with an {{ic|options}} line. | ||
=== GRUB === | |||
Similar to rEFInd, [[GRUB]] can chainload EFI UKIs as described in [[GRUB#Chainloading a unified kernel image]]. | |||
=== Directly from UEFI === | === Directly from UEFI === | ||
Line 282: | Line 297: | ||
[[efibootmgr]] can be used to create a UEFI boot entry for the ''.efi'' file: | [[efibootmgr]] can be used to create a UEFI boot entry for the ''.efi'' file: | ||
# efibootmgr --create --disk /dev/ | # efibootmgr --create --disk /dev/sd''X'' --part ''partition_number'' --label "Arch Linux" --loader '\EFI\Linux\arch-linux.efi' --unicode | ||
See {{man|8|efibootmgr}} for an explanation of the options. | See {{man|8|efibootmgr}} for an explanation of the options. | ||
{{Note| | {{Note|UEFI specification uses backward slash {{ic|\}} as path separator but ''efibootmgr'' can automatically convert UNIX-style {{ic|/}} path separators.}} | ||
== See also == | == See also == | ||
* [https://www.youtube.com/watch?v=7UhwK3g99_0 All Systems Go! talk on UKIs] | |||
* [https://uapi-group.org/specifications/specs/unified_kernel_image/ Unified kernel image specification] | * [https://uapi-group.org/specifications/specs/unified_kernel_image/ Unified kernel image specification] | ||
* [https://linderud.dev/blog/mkinitcpio-v31-and-uefi-stubs/ mkinitcpio v31 and UEFI stubs] | * [https://linderud.dev/blog/mkinitcpio-v31-and-uefi-stubs/ mkinitcpio v31 and UEFI stubs] |
Latest revision as of 14:01, 19 April 2024
A unified kernel image (UKI) is a single executable which can be booted directly from UEFI firmware, or automatically sourced by boot loaders with little or no configuration. It is the combination of a UEFI boot stub program like systemd-stub(7), a Linux kernel image, an initrd, and further resources in a single UEFI PE file.
This file, and therefore all these elements can then easily be signed for use with Secure Boot.
esp
denotes the mountpoint of the EFI system partition.Preparing a unified kernel image
There are several ways to generate a UKI image and install it to the proper place (the esp/Linux directory). Currently several tools compete for doing this functionality, so choose one of the following based on your needs and your likings.
mkinitcpio
Kernel command line
mkinitcpio supports reading kernel parameters from command line files in the /etc/cmdline.d
directory. Mkinitcpio will concatenate the contents of all files with a .conf
extension in this directory and use them to generate the kernel command line. Any lines in the command line file that start with a # character are treated as comments and ignored by mkinitcpio. Take care to remove entries pointing to microcode and initramfs.
For example:
/etc/cmdline.d/root.conf
root=UUID=0a3407de-014b-458b-b5c1-848e92a327a3 rw
- If your root file system is on a non-default Btrfs subvolume, make sure to set necessary mount flags in
rootflags
. For example, if your system subvolume ID is256
, you should addrootflags=subvolid=256
to the kernel command line. See Btrfs#Mounting subvolume as root. - It is not necessary to copy all flags in
/etc/fstab
sincerootflags
is only used during boot. Systemd will read fstab, remount and apply flags listed there automatically after boot.
/etc/cmdline.d/security.conf
# enable apparmor lsm=landlock,lockdown,yama,integrity,apparmor,bpf audit=1 audit_backlog_limit=256
Alternatively, /etc/kernel/cmdline
can be used to configure the kernel command line.
For example:
/etc/kernel/cmdline
root=UUID=0a3407de-014b-458b-b5c1-848e92a327a3 rw quiet bgrt_disable
- The
root=
parameter may be omitted if the root partition is automounted by systemd. - The
bgrt_disable
parameter tells Linux to not display the OEM logo after loading the ACPI tables.
.preset file
Next, 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:
- Un-comment (i.e. remove
#
) thePRESET_uki=
parameter for each item inPRESETS=
, - Optionally, comment out
PRESET_image=
to avoid storing a redundantinitramfs-*.img
file, - Optionally, add or un-comment the
--splash
parameter to eachPRESET_options=
line for which you want to add a splash image.
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" PRESETS=('default' 'fallback') #default_config="/etc/mkinitcpio.conf" #default_image="/boot/initramfs-linux.img" default_uki="esp/EFI/Linux/arch-linux.efi" default_options="--splash=/usr/share/systemd/bootctl/splash-arch.bmp" #fallback_config="/etc/mkinitcpio.conf" #fallback_image="/boot/initramfs-linux-fallback.img" fallback_uki="esp/EFI/Linux/arch-linux-fallback.efi" fallback_options="-S autodetect"
- If all you want to do is boot from the unified kernel images, you can mount the ESP to
/efi
and only those need to reside on the ESP partition. - You can append
--cmdline /etc/kernel/fallback_cmdline
tofallback_options
to use a different cmdline than above for the fallback image (e.g. withoutquiet
). - To omit embedding the kernel command line, add
--no-cmdline
toPRESET_options=
. Kernel parameters will need to be passed via the boot loader.
PRESET_uki
options were previously known as PRESET_efi_image
, changed November 2022 (see archlinux/mkinitcpio/mkinitcpio#134), with older option deprecated but working for now.pacman hook
Updates to systemd-stub (part of systemd), microcode (both intel-ucode and amd-ucode), and linux kernel will automatically trigger a UKI rebuild. But you may want to review other pacman hooks in the /etc/pacman.d/hooks/
directory, such as the one for the NVIDIA driver.
Signing the UKIs for Secure Boot
By using a mkinitcpio post hook, the generated unified kernel images can be signed for Secure Boot. Create the following file and make it executable:
/etc/initcpio/post/uki-sbsign
#!/usr/bin/env bash uki="$3" [[ -n "$uki" ]] || exit 0 keypairs=(/path/to/db.key /path/to/db.crt) for (( i=0; i<${#keypairs[@]}; i+=2 )); do key="${keypairs[$i]}" cert="${keypairs[(( i + 1 ))]}" if ! sbverify --cert "$cert" "$uki" &>/dev/null; then sbsign --key "$key" --cert "$cert" --output "$uki" "$uki" fi done
Replace /path/to/db.key
and /path/to/db.crt
with the paths to the key pair you want to use for signing the image.
Building the UKIs
Finally, make sure that the directory for the UKIs exists and regenerate the initramfs. For example, for the linux preset:
# mkdir -p esp/EFI/Linux # mkinitcpio -p linux
Optionally, remove any leftover initramfs-*.img
from /boot
or /efi
.
kernel-install
For kernel-install to generate UKIs, install systemd-ukify and set the kernel-install
layout to uki
:
/etc/kernel/install.conf
layout=uki
Any configuration for #ukify must be done in /etc/kernel/uki.conf
in order to be used by kernel-install, e.g.
/etc/kernel/uki.conf
[UKI] Splash=/usr/share/systemd/bootctl/splash-arch.bmp
Alternatively, for mkinitcpio to generate the UKI, set it as the default uki_generator
:
/etc/kernel/install.conf
layout=uki uki_generator=mkinitcpio
In that case, systemd-ukify is not necessary. You can also set a different initrd_generator
, see kernel-install(8).
Reinstall the kernel packages that you use in order for the change to take effect.
dracut
See dracut#Unified kernel image and dracut#Generate a new initramfs on kernel upgrade.
sbctl
Install the sbctl package. Store the kernel command line in /etc/kernel/cmdline
. Use the sbctl bundle
command with the --save
parameter to create a bundle and have it be regenerated by a Pacman hook at appropriate times:
# sbctl bundle --save esp/EFI/Linux/arch-linux.efi
To create more EFI binaries for other kernels and initramfs images, repeat the above command with parameters --kernel-img
and --initramfs
, see sbctl(8) § EFI BINARY COMMANDS. The EFI binaries can be regenerated at any time with sbctl generate-bundles
.
ukify
Install the systemd-ukify package. To use the automatic signing functions, additionally install sbsigntools. Since ukify cannot generate an initramfs on its own, if required, it must be generated using dracut, mkinitcpio or booster.
A minimal working example can look something like this:
# ukify build --linux=/boot/vmlinuz-linux \ --initrd=/boot/initramfs-linux.img \ --cmdline="quiet rw"
/boot/amd-ucode.img
or /boot/intel-ucode.img
must always be placed first, before the main initramfs image. E.g. --initrd=/boot/intel-ucode.img --initrd=/boot/initramfs-linux.img
.Then, copy the resulting file to the EFI system partition:
# cp filename.efi esp/EFI/Linux/
- To skip having copy over the resulting EFI executable to the EFI System Partition, use the
--output=esp/EFI/Linux/filename.efi
command line option to ukify. - When specifying the
--cmdline
option, one can specify a file name to read the kernel parameters from (e.g./etc/kernel/cmdline
by adding the@
symbol before the file name, like--cmdline=@/path/to/cmdline
.
An example for automatic UKI building with a systemd service for normal kernel image with intel ucode and /efi mounted ESP:
/etc/ukify.conf
[UKI] Linux=/boot/vmlinuz-linux Initrd=/boot/intel-ucode.img /boot/initramfs-linux.img Cmdline=@/etc/kernel/cmdline OSRelease=@/etc/os-release Splash=/usr/share/systemd/bootctl/splash-arch.bmp
Initrd=/boot/initramfs-linux.img
./etc/systemd/system/run_ukify.service
[Unit] Description=Run systemd ukify [Service] Type=oneshot ExecStart=/usr/bin/ukify build --config=/etc/ukify.conf --output esp/EFI/Linux/archlinux-linux.efi
/etc/systemd/system/run_ukify.path
[Unit] Description=Run systemd ukify [Path] PathChanged=/boot/initramfs-linux.img PathChanged=/boot/intel-ucode.img Unit=run_ukify.service [Install] WantedBy=multi-user.target
Then enable run_ukify.path
.
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 esp/cpu_manufacturer-ucode.img esp/initramfs-linux.img > /tmp/combined_initrd.img
When building the unified kernel image, pass in /tmp/combined_initrd.img
as the initrd. This file can be removed afterwards.
/usr/lib/systemd/boot/efi/linuxx64.efi.stub
with /usr/lib/systemd/boot/efi/linuxia32.efi.stub
in the following commands.$ align="$(objdump -p /usr/lib/systemd/boot/efi/linuxx64.efi.stub | awk '{ if ($1 == "SectionAlignment"){print $2} }')" $ align=$((16#$align)) $ osrel_offs="$(objdump -h "/usr/lib/systemd/boot/efi/linuxx64.efi.stub" | awk 'NF==7 {size=strtonum("0x"$3); offset=strtonum("0x"$4)} END {print size + offset}')" $ osrel_offs=$((osrel_offs + "$align" - osrel_offs % "$align")) $ cmdline_offs=$((osrel_offs + $(stat -Lc%s "/usr/lib/os-release"))) $ cmdline_offs=$((cmdline_offs + "$align" - cmdline_offs % "$align")) $ splash_offs=$((cmdline_offs + $(stat -Lc%s "/etc/kernel/cmdline"))) $ splash_offs=$((splash_offs + "$align" - splash_offs % "$align")) $ initrd_offs=$((splash_offs + $(stat -Lc%s "/usr/share/systemd/bootctl/splash-arch.bmp"))) $ initrd_offs=$((initrd_offs + "$align" - initrd_offs % "$align")) $ linux_offs=$((initrd_offs + $(stat -Lc%s "initrd-file"))) $ linux_offs=$((linux_offs + "$align" - linux_offs % "$align")) $ objcopy \ --add-section .osrel="/usr/lib/os-release" --change-section-vma .osrel=$(printf 0x%x $osrel_offs) \ --add-section .cmdline="/etc/kernel/cmdline" \ --change-section-vma .cmdline=$(printf 0x%x $cmdline_offs) \ --add-section .splash="/usr/share/systemd/bootctl/splash-arch.bmp" \ --change-section-vma .splash=$(printf 0x%x $splash_offs) \ --add-section .initrd="initrd-file" \ --change-section-vma .initrd=$(printf 0x%x $initrd_offs) \ --add-section .linux="vmlinuz-file" \ --change-section-vma .linux=$(printf 0x%x $linux_offs) \ "/usr/lib/systemd/boot/efi/linuxx64.efi.stub" "linux.efi"
A few things to note:
- The offsets are dynamically calculated so no sections overlap, as recommended in [1].
- The sections are aligned to what the
SectionAlignment
field of the PE stub indicates (usually 0x1000). - The kernel image must be in the last section, to prevent in-place decompression from overwriting the sections that follow, as stated in [2].
After creating the image, copy it to the EFI system partition:
# cp linux.efi esp/EFI/Linux/
Booting
.cmdline
ignore all command line options passed to them (either using a boot entry or interactively). When Secure Boot is not active, the options passed via the command line override the embedded .cmdline
.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
rEFInd
rEFInd will autodetect unified kernel images on your EFI system partition, and is capable of loading them. They can also be manually specified in refind.conf
, by default located at:
esp/EFI/refind/refind.conf
menuentry "Arch Linux" { icon \EFI\refind\icons\os_arch.png ostype Linux loader \EFI\Linux\arch-linux.efi }
Recall that no kernel parameters from esp/EFI/refind_linux.conf
will be passed when booting this way. If the UKI was generated without a .cmdline
section, specify the kernel parameters in the menu entry with an options
line.
GRUB
Similar to rEFInd, GRUB can chainload EFI UKIs as described in GRUB#Chainloading a unified kernel image.
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 "Arch Linux" --loader '\EFI\Linux\arch-linux.efi' --unicode
See efibootmgr(8) for an explanation of the options.
\
as path separator but efibootmgr can automatically convert UNIX-style /
path separators.