return
directory = context.root / "usr/lib/systemd/boot/efi"
- if not directory.exists() or not any(directory.iterdir()):
+ signed = context.config.shim_bootloader == ShimBootloader.signed
+ if not directory.glob("*.efi.signed" if signed else "*.efi"):
if context.config.bootable == ConfigFeature.enabled:
- die("A EFI bootable image with systemd-boot was requested but systemd-boot was not found at "
- f"{directory.relative_to(context.root)}")
+ die(f"An EFI bootable image with systemd-boot was requested but a {'signed ' if signed else ''}"
+ f"systemd-boot binary was not found at {directory.relative_to(context.root)}")
return
- if context.config.secure_boot:
+ if context.config.secure_boot and not signed:
with complete_step("Signing systemd-boot binaries…"):
for input in itertools.chain(directory.glob('*.efi'), directory.glob('*.EFI')):
output = directory / f"{input}.signed"
if context.config.bootloader != Bootloader.grub:
return False
- have = find_grub_directory(context, target="x86_64-efi") is not None
- if not have and context.config.bootable == ConfigFeature.enabled:
- die("An EFI bootable image with grub was requested but grub for EFI is not installed")
+ if context.config.shim_bootloader != ShimBootloader.signed:
+ have = find_grub_directory(context, target="x86_64-efi") is not None
+ if not have and context.config.bootable == ConfigFeature.enabled:
+ die("An EFI bootable image with grub was requested but grub for EFI is not installed")
return True
f.write("set timeout=0\n")
if want_grub_efi(context):
- # Signed EFI grub shipped by distributions reads its configuration from /EFI/<distribution>/grub.cfg in
- # the ESP so let's put a shim there to redirect to the actual configuration file.
- earlyconfig = context.root / "efi/EFI" / context.config.distribution.name / "grub.cfg"
+ # Signed EFI grub shipped by distributions reads its configuration from /EFI/<distribution>/grub.cfg (except
+ # in OpenSUSE) in the ESP so let's put a shim there to redirect to the actual configuration file.
+ if context.config.distribution == Distribution.opensuse:
+ earlyconfig = context.root / "efi/EFI/BOOT/grub.cfg"
+ else:
+ earlyconfig = context.root / "efi/EFI" / context.config.distribution.name / "grub.cfg"
+
with umask(~0o700):
earlyconfig.parent.mkdir(parents=True, exist_ok=True)
return config
-def grub_mkimage(context: Context, *, target: str, modules: Sequence[str] = (), output: Optional[Path] = None) -> None:
+def grub_mkimage(
+ context: Context,
+ *,
+ target: str,
+ modules: Sequence[str] = (),
+ output: Optional[Path] = None,
+ sbat: Optional[Path] = None,
+) -> None:
mkimage = find_grub_binary("mkimage", root=context.config.tools())
assert mkimage
"--prefix", f"/{context.config.distribution.grub_prefix()}",
"--output", output or (directory / "core.img"),
"--format", target,
+ *(["--sbat", str(sbat)] if sbat else []),
+ *(["--disable-shim-lock"] if context.config.shim_bootloader == ShimBootloader.none else []),
+ "cat",
+ "cmp",
+ "div",
+ "echo",
"fat",
+ "hello",
+ "help",
+ "keylayouts",
+ "linux",
+ "loadenv",
+ "ls",
+ "normal",
"part_gpt",
- "search",
+ "read",
+ "reboot",
"search_fs_file",
- "normal",
- "linux",
+ "search",
+ "sleep",
+ "test",
+ "tr",
+ "true",
*modules,
],
sandbox=context.sandbox(
options=[
"--bind", context.root, context.root,
"--ro-bind", earlyconfig.name, earlyconfig.name,
+ *(["--ro-bind", str(sbat), str(sbat)] if sbat else []),
],
),
)
+def find_signed_grub_image(context: Context) -> Optional[Path]:
+ arch = context.config.architecture.to_efi()
+
+ patterns = [
+ f"usr/lib/grub/*-signed/grub{arch}.efi.signed", # Debian/Ubuntu
+ f"boot/efi/EFI/*/grub{arch}.efi", # Fedora/CentOS
+ "usr/share/efi/*/grub.efi", # OpenSUSE
+ ]
+
+ for p in flatten(context.root.glob(pattern) for pattern in patterns):
+ if p.is_symlink() and p.readlink().is_absolute():
+ logging.warning(f"Ignoring signed grub EFI binary which is an absolute path to {p.readlink()}")
+ continue
+
+ return p
+
+ return None
+
+
def install_grub(context: Context) -> None:
if not want_grub_bios(context) and not want_grub_efi(context):
return
with umask(~0o700):
output.parent.mkdir(parents=True, exist_ok=True)
- grub_mkimage(context, target="x86_64-efi", output=output, modules=("chain",))
- if context.config.secure_boot:
- sign_efi_binary(context, output, output)
+ if context.config.shim_bootloader == ShimBootloader.signed:
+ if not (signed := find_signed_grub_image(context)):
+ if context.config.bootable == ConfigFeature.enabled:
+ die("Couldn't find a signed grub EFI binary installed in the image")
+
+ return
+
+ rel = output.relative_to(context.root)
+ log_step(f"Installing signed grub EFI binary from /{signed.relative_to(context.root)} to /{rel}")
+ shutil.copy2(signed, output)
+ else:
+ if context.config.secure_boot and context.config.shim_bootloader != ShimBootloader.none:
+ if not (signed := find_signed_grub_image(context)):
+ die("Couldn't find a signed grub EFI binary installed in the image to extract SBAT from")
+
+ sbat = extract_pe_section(context, signed, ".sbat", context.workspace / "sbat")
+ else:
+ sbat = None
+
+ grub_mkimage(context, target="x86_64-efi", output=output, modules=("chain",), sbat=sbat)
+ if context.config.secure_boot:
+ sign_efi_binary(context, output, output)
dst = context.root / "efi" / context.config.distribution.grub_prefix() / "fonts"
with umask(~0o700):
return "python3" if config.tools_tree else os.getenv("MKOSI_INTERPRETER", "python3")
-def extract_pe_section(context: Context, binary: Path, section: str, output: Path) -> None:
+def extract_pe_section(context: Context, binary: Path, section: str, output: Path) -> Path:
# When using a tools tree, we want to use the pefile module from the tools tree instead of requiring that
# python-pefile is installed on the host. So we execute python as a subprocess to make sure we load
# pefile from the tools tree if one is used.
sandbox=context.sandbox(options=["--ro-bind", binary, binary])
)
+ return output
+
def want_signed_pcrs(config: Config) -> bool:
return (
if (
want_efi(context.config) and
context.config.secure_boot and
+ context.config.shim_bootloader != ShimBootloader.signed and
KernelType.identify(context.config, kimg) == KernelType.pe
):
kimg = sign_efi_binary(context, kimg, dst / "vmlinuz")
else:
boot_binary = context.root / f"boot/EFI/Linux/{token}-{kver}{boot_count}.efi"
- microcode = build_microcode_initrd(context)
-
- initrds = [microcode] if microcode else []
- initrds += context.config.initrds or [build_default_initrd(context)]
-
- if context.config.kernel_modules_initrd:
- initrds += [build_kernel_modules_initrd(context, kver)]
-
# Make sure the parent directory where we'll be writing the UKI exists.
with umask(~0o700):
boot_binary.parent.mkdir(parents=True, exist_ok=True)
- build_uki(
- context,
- systemd_stub_binary(context),
- kver,
- context.root / kimg,
- initrds,
- finalize_cmdline(context, roothash),
- boot_binary,
- )
+ if context.config.shim_bootloader == ShimBootloader.signed:
+ for p in (context.root / "usr/lib/modules" / kver).glob("*.efi"):
+ log_step(f"Installing prebuilt UKI at {p} to {boot_binary}")
+ shutil.copy2(p, boot_binary)
+ break
+ else:
+ if context.config.bootable == ConfigFeature.enabled:
+ die(f"Couldn't find a signed UKI binary installed at /usr/lib/modules/{kver} in the image")
+
+ return
+ else:
+ microcode = build_microcode_initrd(context)
+
+ initrds = [microcode] if microcode else []
+ initrds += context.config.initrds or [build_default_initrd(context)]
+
+ if context.config.kernel_modules_initrd:
+ initrds += [build_kernel_modules_initrd(context, kver)]
+
+ build_uki(
+ context,
+ systemd_stub_binary(context),
+ kver,
+ context.root / kimg,
+ initrds,
+ finalize_cmdline(context, roothash),
+ boot_binary,
+ )
- print_output_size(boot_binary)
+ print_output_size(boot_binary)
if want_grub_efi(context):
config = prepare_grub_config(context)
import errno
import fcntl
import hashlib
+import json
import logging
import os
import random
import uuid
from collections.abc import Iterator
from pathlib import Path
-from typing import Optional
+from typing import NamedTuple, Optional
from mkosi.config import (
- Architecture,
Args,
Config,
ConfigFeature,
from mkosi.tree import copy_tree, rmtree
from mkosi.types import PathString
from mkosi.user import INVOKING_USER, become_root
-from mkosi.util import StrEnum
+from mkosi.util import StrEnum, flatten
from mkosi.versioncomp import GenericVersion
QEMU_KVM_DEVICE_VERSION = GenericVersion("9.0")
die("Couldn't find QEMU/KVM binary")
-def find_ovmf_firmware(config: Config) -> tuple[Path, bool]:
- FIRMWARE_LOCATIONS = {
- Architecture.x86_64: [
- "usr/share/ovmf/x64/OVMF_CODE.secboot.fd",
- "usr/share/qemu/ovmf-x86_64.smm.bin",
- "usr/share/edk2/x64/OVMF_CODE.secboot.4m.fd",
- "usr/share/edk2/x64/OVMF_CODE.secboot.fd",
- ],
- Architecture.x86: [
- "usr/share/edk2/ovmf-ia32/OVMF_CODE.secboot.fd",
- "usr/share/OVMF/OVMF32_CODE_4M.secboot.fd",
- "usr/share/edk2/ia32/OVMF_CODE.secboot.4m.fd",
- "usr/share/edk2/ia32/OVMF_CODE.secboot.fd",
- ],
- }.get(config.architecture, [])
-
- for firmware in FIRMWARE_LOCATIONS:
- if (config.tools() / firmware).exists():
- return Path("/") / firmware, True
-
- FIRMWARE_LOCATIONS = {
- Architecture.x86_64: [
- "usr/share/ovmf/ovmf_code_x64.bin",
- "usr/share/ovmf/x64/OVMF_CODE.fd",
- "usr/share/qemu/ovmf-x86_64.bin",
- "usr/share/edk2/x64/OVMF_CODE.4m.fd",
- "usr/share/edk2/x64/OVMF_CODE.fd",
- ],
- Architecture.x86: [
- "usr/share/ovmf/ovmf_code_ia32.bin",
- "usr/share/edk2/ovmf-ia32/OVMF_CODE.fd",
- "usr/share/edk2/ia32/OVMF_CODE.4m.fd",
- "usr/share/edk2/ia32/OVMF_CODE.fd",
- ],
- Architecture.arm64: ["usr/share/AAVMF/AAVMF_CODE.fd"],
- Architecture.arm: ["usr/share/AAVMF/AAVMF32_CODE.fd"],
- }.get(config.architecture, [])
-
- for firmware in FIRMWARE_LOCATIONS:
- if (config.tools() / firmware).exists():
- logging.warning("Couldn't find OVMF firmware blob with secure boot support, "
- "falling back to OVMF firmware blobs without secure boot support.")
- return Path("/") / firmware, False
-
- # If we can't find an architecture specific path, fall back to some generic paths that might also work.
-
- FIRMWARE_LOCATIONS = [
- "usr/share/edk2/ovmf/OVMF_CODE.secboot.fd",
- "usr/share/edk2-ovmf/OVMF_CODE.secboot.fd",
- "usr/share/qemu/OVMF_CODE.secboot.fd",
- "usr/share/ovmf/OVMF.secboot.fd",
- "usr/share/OVMF/OVMF_CODE_4M.secboot.fd",
- "usr/share/OVMF/OVMF_CODE.secboot.fd",
- ]
+class OvmfConfig(NamedTuple):
+ description: Path
+ firmware: Path
+ format: str
+ vars: Path
+ vars_format: str
- for firmware in FIRMWARE_LOCATIONS:
- if (config.tools() / firmware).exists():
- return Path("/") / firmware, True
-
- FIRMWARE_LOCATIONS = [
- "usr/share/edk2/ovmf/OVMF_CODE.fd",
- "usr/share/edk2-ovmf/OVMF_CODE.fd",
- "usr/share/qemu/OVMF_CODE.fd",
- "usr/share/ovmf/OVMF.fd",
- "usr/share/OVMF/OVMF_CODE_4M.fd",
- "usr/share/OVMF/OVMF_CODE.fd",
- ]
- for firmware in FIRMWARE_LOCATIONS:
- if (config.tools() / firmware).exists():
- logging.warn("Couldn't find OVMF firmware blob with secure boot support, "
- "falling back to OVMF firmware blobs without secure boot support.")
- return Path("/") / firmware, False
+def find_ovmf_firmware(config: Config, firmware: QemuFirmware) -> Optional[OvmfConfig]:
+ if not firmware.is_uefi():
+ return None
+
+ desc = flatten(
+ p.glob("*")
+ for p in (
+ config.tools() / "etc/qemu/firmware",
+ config.tools() / "usr/share/qemu/firmware",
+ )
+ )
- die("Couldn't find OVMF UEFI firmware blob.")
+ arch = config.architecture.to_qemu()
+ machine = config.architecture.default_qemu_machine()
+ for p in sorted(desc):
+ if p.is_dir():
+ continue
-def find_ovmf_vars(config: Config) -> Path:
- OVMF_VARS_LOCATIONS = []
+ j = json.loads(p.read_text())
- if config.architecture == Architecture.x86_64:
- OVMF_VARS_LOCATIONS += [
- "usr/share/ovmf/x64/OVMF_VARS.fd",
- "usr/share/qemu/ovmf-x86_64-vars.bin",
- "usr/share/edk2/x64/OVMF_VARS.4m.fd",
- "usr/share/edk2/x64/OVMF_VARS.fd",
- ]
- elif config.architecture == Architecture.x86:
- OVMF_VARS_LOCATIONS += [
- "usr/share/edk2/ovmf-ia32/OVMF_VARS.fd",
- "usr/share/OVMF/OVMF32_VARS_4M.fd",
- "usr/share/edk2/ia32/OVMF_VARS.4m.fd",
- "usr/share/edk2/ia32/OVMF_VARS.fd",
- ]
- elif config.architecture == Architecture.arm:
- OVMF_VARS_LOCATIONS += ["usr/share/AAVMF/AAVMF32_VARS.fd"]
- elif config.architecture == Architecture.arm64:
- OVMF_VARS_LOCATIONS += ["usr/share/AAVMF/AAVMF_VARS.fd"]
-
- OVMF_VARS_LOCATIONS += [
- "usr/share/edk2/ovmf/OVMF_VARS.fd",
- "usr/share/edk2-ovmf/OVMF_VARS.fd",
- "usr/share/qemu/OVMF_VARS.fd",
- "usr/share/ovmf/OVMF_VARS.fd",
- "usr/share/OVMF/OVMF_VARS_4M.fd",
- "usr/share/OVMF/OVMF_VARS.fd",
- ]
+ if "uefi" not in j["interface-types"]:
+ logging.debug(f"{p.name} firmware description does not target UEFI, skipping")
+ continue
- for location in OVMF_VARS_LOCATIONS:
- if (config.tools() / location).exists():
- return config.tools() / location
+ for target in j["targets"]:
+ if target["architecture"] != arch:
+ continue
- die("Couldn't find OVMF UEFI variables file.")
+ # We cannot use fnmatch as for example our default machine for x86-64 is q35 and the firmware description
+ # lists "pc-q35-*" so we use a substring check instead.
+ if any(machine in glob for glob in target["machines"]):
+ break
+ else:
+ logging.debug(
+ f"{p.name} firmware description does not target architecture {arch} or machine {machine}, skipping"
+ )
+ continue
+
+ if firmware == QemuFirmware.uefi_secure_boot and "secure-boot" not in j["features"]:
+ logging.debug(f"{p.name} firmware description does not include secure boot, skipping")
+ continue
+
+ if firmware != QemuFirmware.uefi_secure_boot and "secure-boot" in j["features"]:
+ logging.debug(f"{p.name} firmware description includes secure boot, skipping")
+ continue
+
+ if config.qemu_firmware_variables == Path("microsoft") and "enrolled-keys" not in j["features"]:
+ logging.debug(f"{p.name} firmware description does not have enrolled Microsoft keys, skipping")
+ continue
+
+ if config.qemu_firmware_variables != Path("microsoft") and "enrolled-keys" in j["features"]:
+ logging.debug(f"{p.name} firmware description has enrolled Microsoft keys, skipping")
+ continue
+
+ logging.debug(f"Using {p.name} firmware description")
+
+ return OvmfConfig(
+ description=Path("/") / p.relative_to(config.tools()),
+ firmware=Path(j["mapping"]["executable"]["filename"]),
+ format=j["mapping"]["executable"]["format"],
+ vars=Path(j["mapping"]["nvram-template"]["filename"]),
+ vars_format=j["mapping"]["nvram-template"]["format"],
+ )
+
+ die("Couldn't find matching OVMF UEFI firmware description")
@contextlib.contextmanager
if config.qemu_firmware == QemuFirmware.auto:
if kernel:
return (
- QemuFirmware.uefi
+ QemuFirmware.uefi_secure_boot
if KernelType.identify(config, kernel) != KernelType.unknown
else QemuFirmware.linux
)
):
return QemuFirmware.linux
else:
- return QemuFirmware.uefi
+ return QemuFirmware.uefi_secure_boot
else:
return config.qemu_firmware
+def finalize_firmware_variables(config: Config, ovmf: OvmfConfig, stack: contextlib.ExitStack) -> tuple[Path, str]:
+ ovmf_vars = stack.enter_context(tempfile.NamedTemporaryFile(prefix="mkosi-ovmf-vars"))
+ if config.qemu_firmware_variables in (None, Path("custom"), Path("microsoft")):
+ ovmf_vars_format = ovmf.vars_format
+ else:
+ ovmf_vars_format = "raw"
+
+ if config.qemu_firmware_variables == Path("custom"):
+ assert config.secure_boot_certificate
+ run(
+ [
+ "virt-fw-vars",
+ "--input", ovmf.vars,
+ "--output", ovmf_vars.name,
+ "--enroll-cert", config.secure_boot_certificate,
+ "--add-db", "OvmfEnrollDefaultKeys", config.secure_boot_certificate,
+ "--no-microsoft",
+ "--secure-boot",
+ "--loglevel", "WARNING",
+ ],
+ sandbox=config.sandbox(
+ options=[
+ "--bind", ovmf_vars.name, ovmf_vars.name,
+ "--ro-bind", config.secure_boot_certificate, config.secure_boot_certificate,
+ ],
+ ),
+ )
+ else:
+ vars = (
+ config.tools() / ovmf.vars.relative_to("/")
+ if config.qemu_firmware_variables == Path("microsoft") or not config.qemu_firmware_variables
+ else config.qemu_firmware_variables
+ )
+ shutil.copy2(vars, Path(ovmf_vars.name))
+
+ return Path(ovmf_vars.name), ovmf_vars_format
+
+
def run_qemu(args: Args, config: Config) -> None:
if config.output_format not in (
OutputFormat.disk,
if (
config.output_format in (OutputFormat.cpio, OutputFormat.uki, OutputFormat.esp) and
- config.qemu_firmware not in (QemuFirmware.auto, QemuFirmware.linux, QemuFirmware.uefi)
+ config.qemu_firmware not in (QemuFirmware.auto, QemuFirmware.linux) and
+ not config.qemu_firmware.is_uefi()
):
die(f"{config.output_format} images cannot be booted with the '{config.qemu_firmware}' firmware")
if config.qemu_kvm == ConfigFeature.enabled and not config.architecture.is_native():
die(f"KVM acceleration requested but {config.architecture} does not match the native host architecture")
+ if config.qemu_firmware_variables == Path("custom") and not config.secure_boot_certificate:
+ die("SecureBootCertificate= must be configured to use QemuFirmwareVariables=custom")
+
# After we unshare the user namespace to sandbox qemu, we might not have access to /dev/kvm or related device nodes
# anymore as access to these might be gated behind the kvm group and we won't be part of the kvm group anymore
# after unsharing the user namespace. To get around this, open all those device nodes early can pass them as file
config.output_format in (OutputFormat.cpio, OutputFormat.directory, OutputFormat.uki)
)
):
- if firmware == QemuFirmware.uefi:
+ if firmware.is_uefi():
name = config.output if config.output_format == OutputFormat.uki else config.output_split_uki
kernel = config.output_dir_or_cwd() / name
else:
"or provide a -kernel argument to mkosi qemu"
)
- ovmf, ovmf_supports_sb = find_ovmf_firmware(config) if firmware == QemuFirmware.uefi else (None, False)
+ ovmf = find_ovmf_firmware(config, firmware)
# A shared memory backend might increase ram usage so only add one if actually necessary for virtiofsd.
shm = []
shm = ["-object", f"memory-backend-memfd,id=mem,size={config.qemu_mem},share=on"]
machine = f"type={config.architecture.default_qemu_machine()}"
- if firmware == QemuFirmware.uefi and config.architecture.supports_smm():
- machine += f",smm={'on' if ovmf_supports_sb else 'off'}"
+ if firmware.is_uefi() and config.architecture.supports_smm():
+ machine += f",smm={'on' if firmware == QemuFirmware.uefi_secure_boot else 'off'}"
if shm:
machine += ",memory-backend=mem"
]
# QEMU has built-in logic to look for the BIOS firmware so we don't need to do anything special for that.
- if firmware == QemuFirmware.uefi:
- cmdline += ["-drive", f"if=pflash,format=raw,readonly=on,file={ovmf}"]
+ if firmware.is_uefi():
+ assert ovmf
+ cmdline += ["-drive", f"if=pflash,format={ovmf.format},readonly=on,file={ovmf.firmware}"]
notifications: dict[str, str] = {}
with contextlib.ExitStack() as stack:
- if firmware == QemuFirmware.uefi:
- ovmf_vars = stack.enter_context(tempfile.NamedTemporaryFile(prefix="mkosi-ovmf-vars"))
- shutil.copy2(config.qemu_firmware_variables or find_ovmf_vars(config), Path(ovmf_vars.name))
- cmdline += ["-drive", f"file={ovmf_vars.name},if=pflash,format=raw"]
- if ovmf_supports_sb:
+ if firmware.is_uefi():
+ assert ovmf
+ ovmf_vars, ovmf_vars_format = finalize_firmware_variables(config, ovmf, stack)
+
+ cmdline += ["-drive", f"file={ovmf_vars},if=pflash,format={ovmf_vars_format}"]
+ if firmware == QemuFirmware.uefi_secure_boot:
cmdline += [
"-global", "ICH9-LPC.disable_s3=1",
"-global", "driver=cfi.pflash01,property=secure,value=on",
"-device", f"scsi-{'cd' if config.qemu_cdrom else 'hd'},drive=mkosi,bootindex=1"]
if (
- firmware == QemuFirmware.uefi and
+ firmware.is_uefi() and
config.qemu_swtpm != ConfigFeature.disabled and
find_binary("swtpm", root=config.tools()) is not None
):
on UEFI firmware is requested using other options
(`Bootable=`, `Bootloader=`).
+: Note that when this option is enabled, mkosi will only install already
+ signed bootloader binaries, kernel image files and unified kernel
+ images as self-signed binaries would not be accepted by the signed
+ version of shim.
+
`UnifiedKernelImages=`, `--unified-kernel-images=`
: Specifies whether to use unified kernel images or not when
`QemuFirmware=`, `--qemu-firmware=`
: When used with the `qemu` verb, this option specifies which firmware
- to use. Takes one of `uefi`, `bios`, `linux`, or `auto`. Defaults to
- `auto`. When set to `uefi`, the OVMF firmware is used. When set to
+ to use. Takes one of `uefi`, `uefi-secure-boot`, `bios`, `linux`, or
+ `auto`. Defaults to `auto`. When set to `uefi`, the OVMF firmware
+ without secure boot support is used. When set to `uefi-secure-boot`,
+ the OVMF firmware with secure boot support is used. When set to
`bios`, the default SeaBIOS firmware is used. When set to `linux`,
direct kernel boot is used. See the `QemuKernel=` option for more
details on which kernel image is used with direct kernel boot. When
- set to `auto`, `linux` is used if a cpio image is being booted, `uefi`
+ set to `auto`, `uefi-secure-boot` is used if possible and `linux`
otherwise.
`QemuFirmwareVariables=`, `--qemu-firmware-variables=`
: When used with the `qemu` verb, this option specifies the path to the
the firmware variables file to use. Currently, this option is only
- taken into account when the `uefi` firmware is used. If not specified,
- mkosi will search for the default variables file and use that instead.
+ taken into account when the `uefi` or `uefi-secure-boot` firmware is
+ used. If not specified, mkosi will search for the default variables
+ file and use that instead.
+
+: When set to `microsoft`, a firmware variables file with the Microsoft
+ secure boot certificates already enrolled will be used.
+
+: When set to `custom`, the secure boot certificate from
+ `SecureBootCertificate=` will be enrolled into the default firmware
+ variables file.
: `virt-fw-vars` from the
[virt-firmware](https://gitlab.com/kraxel/virt-firmware) project can
be used to customize OVMF variable files.
-: Some distributions also provide variable files which already have
- Microsoft's certificates for secure boot enrolled. For Fedora
- and Debian these are `OVMF_VARS.secboot.fd` and `OVMF_VARS_4M.ms.fd`
- under `/usr/share/OVMF` respectively. You can use `locate` and look
- under `/usr/share/qemu/firmware` for hints on where to find these
- files if your distribution ships them.
-
`QemuKernel=`, `--qemu-kernel=`
: Set the kernel image to use for qemu direct kernel boot. If not
| `ubuntu-keyring` | X | X | X | X | X | |
| `util-linux` | X | X | X | X | X | X |
| `virtiofsd` | X | X | | | X | X |
+ | `virt-firmware` | X | X | | | X | |
| `xfsprogs` | X | X | X | X | X | X |
| `xz` | X | X | X | X | X | X |
| `zstd` | X | X | X | X | X | X |