Skip to content

Commit c491669

Browse files
committed
add support for prebuilt UKIs
Some distributions (like Fedora) ship their own prebuilt Unified Kernel Images (UKIs). In some use cases, it's helpful to use mkosi to build images that consume these distro-shipped UKIs rather than building a UKI from scratch. This commit allows mkosi to natively consume prebuilt UKIs, eliminating the need for any additional scripts. Fixes #4174
1 parent d4f44d2 commit c491669

7 files changed

Lines changed: 74 additions & 12 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# SPDX-License-Identifier: LGPL-2.1-or-later
2+
3+
[Match]
4+
Architecture=arm64
5+
Bootloader=uki-signed
6+
7+
[Content]
8+
# kernel-uki-virt ships a pre-built UKI for virtual machines, needed to test
9+
# Bootloader=uki-signed. Not available on all Fedora architectures (e.g. ppc64le),
10+
# so kept in arch-specific configs and gated on Bootloader=uki-signed.
11+
Packages=
12+
kernel-uki-virt
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# SPDX-License-Identifier: LGPL-2.1-or-later
2+
3+
[Match]
4+
Architecture=x86-64
5+
Bootloader=uki-signed
6+
7+
[Content]
8+
# kernel-uki-virt ships a pre-built UKI for virtual machines, needed to test
9+
# Bootloader=uki-signed. Not available on all Fedora architectures (e.g. ppc64le),
10+
# so kept in arch-specific configs and gated on Bootloader=uki-signed.
11+
Packages=
12+
kernel-uki-virt

β€Žmkosi/__init__.pyβ€Ž

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
summary,
8484
systemd_tool_version,
8585
want_kernel,
86+
want_prebuilt_uki,
8687
want_selinux_relabel,
8788
yes_no,
8889
)
@@ -2144,10 +2145,7 @@ def install_uki(
21442145
with umask(~0o700):
21452146
boot_binary.parent.mkdir(parents=True, exist_ok=True)
21462147

2147-
if (
2148-
context.config.bootloader.is_signed()
2149-
and context.config.unified_kernel_images == UnifiedKernelImage.auto
2150-
) or context.config.unified_kernel_images == UnifiedKernelImage.signed:
2148+
if want_prebuilt_uki(context.config):
21512149
for p in (context.root / "usr/lib/modules" / kver).glob("*.efi"):
21522150
log_step(f"Installing prebuilt UKI at {p} to {boot_binary}")
21532151
copyfile2(p, boot_binary)

β€Žmkosi/bootloader.pyβ€Ž

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
SecureBootSignTool,
2626
ShimBootloader,
2727
systemd_tool_version,
28+
want_prebuilt_uki,
2829
)
2930
from mkosi.context import Context
3031
from mkosi.distribution import Distribution
@@ -680,15 +681,21 @@ def gen_kernel_images(context: Context) -> Iterator[tuple[str, Path]]:
680681
# scripts in the kernel source tree sometimes do weird stuff. But let's make sure we're not returning
681682
# UKIs as the UKI on Fedora is named vmlinuz-virt.efi. Also look for uncompressed images (vmlinux) as
682683
# some architectures ship those. Prefer vmlinuz if both are present.
683-
for kimg in kver.glob("vmlinuz*"):
684-
if KernelType.identify(context.config, kimg) != KernelType.uki:
685-
yield kver.name, kimg
686-
break
684+
if want_prebuilt_uki(context.config):
685+
for kimg in kver.glob("vmlinuz*.efi"):
686+
if KernelType.identify(context.config, kimg) == KernelType.uki:
687+
yield kver.name, kimg
688+
break
687689
else:
688-
for kimg in kver.glob("vmlinux*"):
690+
for kimg in kver.glob("vmlinuz*"):
689691
if KernelType.identify(context.config, kimg) != KernelType.uki:
690692
yield kver.name, kimg
691693
break
694+
else:
695+
for kimg in kver.glob("vmlinux*"):
696+
if KernelType.identify(context.config, kimg) != KernelType.uki:
697+
yield kver.name, kimg
698+
break
692699

693700

694701
def install_systemd_boot(context: Context) -> None:

β€Žmkosi/config.pyβ€Ž

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3299,6 +3299,7 @@ def parse_kernel_module_filter_regexp(p: str) -> str:
32993299
dest="bootloader",
33003300
section="Content",
33013301
parse=config_make_enum_parser(Bootloader),
3302+
match=config_make_enum_matcher(Bootloader),
33023303
choices=Bootloader.choices(),
33033304
default=Bootloader.systemd_boot,
33043305
help="Specify which UEFI bootloader to use",
@@ -5445,6 +5446,15 @@ def want_default_initrd(config: Config) -> bool:
54455446
return Path("default") in config.initrds
54465447

54475448

5449+
def want_prebuilt_uki(config: Config) -> bool:
5450+
# Returns True when mkosi should use a distro-pre-built signed UKI rather than building one itself.
5451+
# This happens when a signed bootloader is selected (implying distro UKIs) or when
5452+
# UnifiedKernelImages=signed is set explicitly.
5453+
return (
5454+
config.bootloader.is_signed() and config.unified_kernel_images == UnifiedKernelImage.auto
5455+
) or config.unified_kernel_images == UnifiedKernelImage.signed
5456+
5457+
54485458
def finalize_historydir(args: Args, output_dir: Optional[Path] = None) -> Path:
54495459
# When an output directory is given, the build history is also stored there so that builds into
54505460
# distinct output directories don't read each other's history. Otherwise it lives in the config dir.

β€Žmkosi/qemu.pyβ€Ž

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from mkosi.bootloader import KernelType
3131
from mkosi.config import (
3232
Args,
33+
Bootloader,
3334
Config,
3435
ConfigFeature,
3536
ConsoleMode,
@@ -1314,9 +1315,16 @@ def add_virtiofs_mount(
13141315
if kernel and (kerneltype != KernelType.uki or not config.architecture.supports_smbios(firmware)):
13151316
cmdline += ["-append", " ".join(config.kernel_command_line + kcl)]
13161317
elif config.architecture.supports_smbios(firmware):
1318+
# With Bootloader=uki-signed, a UKI built by the distro is used, and we cannot embed
1319+
# config.kernel_command_line in the UKI. Instead, pass those options through SMBIOS type#11. We
1320+
# know that this will work because all UEFI systems support SMBIOS and UKIs by construction use
1321+
# systemd-stub, which reads SMBIOS type#11.
1322+
stub_kcl = (
1323+
config.kernel_command_line if config.bootloader == Bootloader.uki_signed else []
1324+
) + kcl
13171325
cmdline += [
13181326
"-smbios",
1319-
f"type=11,value=io.systemd.stub.kernel-cmdline-extra={' '.join(kcl).replace(',', ',,')}",
1327+
f"type=11,value=io.systemd.stub.kernel-cmdline-extra={' '.join(stub_kcl).replace(',', ',,')}", # noqa: E501
13201328
"-smbios",
13211329
f"type=11,value=io.systemd.boot.kernel-cmdline-extra={' '.join(kcl).replace(',', ',,')}",
13221330
]

β€Žtests/test_boot.pyβ€Ž

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import pytest
77

8-
from mkosi.config import Bootloader, Firmware, OutputFormat
8+
from mkosi.config import Architecture, Bootloader, Firmware, OutputFormat
99
from mkosi.distribution import Distribution
1010
from mkosi.run import find_binary, run
1111
from mkosi.versioncomp import GenericVersion
@@ -59,7 +59,22 @@ def test_format(config: ImageConfig, format: OutputFormat) -> None:
5959

6060
@pytest.mark.parametrize("bootloader", Bootloader)
6161
def test_bootloader(config: ImageConfig, bootloader: Bootloader) -> None:
62-
if config.distribution == Distribution.rhel_ubi or bootloader.is_signed():
62+
if config.distribution == Distribution.rhel_ubi or (
63+
bootloader.is_signed() and bootloader != Bootloader.uki_signed
64+
):
65+
return
66+
67+
# TODO: want_prebuilt_uki() also fires for UnifiedKernelImage=signed with a non-signed bootloader,
68+
# but there is no integration test for that path yet.
69+
# uki-signed test matrix:
70+
# x86-64 Fedora β†’ supports_smbios(uefi)=True, kernel-uki-virt available β†’ runs
71+
# arm64 Fedora β†’ supports_smbios(uefi)=True, kernel-uki-virt available β†’ runs
72+
# ppc64le Fedora β†’ supports_smbios(uefi)=False β†’ skipped
73+
# non-Fedora β†’ no kernel-uki-virt equivalent β†’ skipped
74+
if bootloader == Bootloader.uki_signed and (
75+
config.distribution != Distribution.fedora
76+
or not Architecture.native().supports_smbios(Firmware.uefi)
77+
):
6378
return
6479

6580
firmware = Firmware.linux if bootloader == Bootloader.none else Firmware.auto

0 commit comments

Comments
Β (0)