From c832d46044e0ee77a7a19efcbf43aa2bfc177f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Iwanicki?= Date: Mon, 3 Feb 2025 13:03:47 +0100 Subject: [PATCH 01/15] classes-recipe/uki.bbclass: copy uki bbclass from poky master MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Iwanicki --- meta-dts-distro/classes-recipe/uki.bbclass | 195 +++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 meta-dts-distro/classes-recipe/uki.bbclass diff --git a/meta-dts-distro/classes-recipe/uki.bbclass b/meta-dts-distro/classes-recipe/uki.bbclass new file mode 100644 index 0000000..92f6905 --- /dev/null +++ b/meta-dts-distro/classes-recipe/uki.bbclass @@ -0,0 +1,195 @@ +# Unified kernel image (UKI) class +# +# This bbclass merges kernel, initrd etc as a UKI standard UEFI binary, +# to be loaded with UEFI firmware and systemd-boot on target HW. +# TPM PCR pre-calculation is not supported since systemd-measure tooling +# is meant to run on target, not in cross compile environment. +# +# See: +# https://www.freedesktop.org/software/systemd/man/latest/ukify.html +# https://uapi-group.org/specifications/specs/unified_kernel_image/ +# +# The UKI contains: +# +# - UEFI stub +# The linux kernel can generate a UEFI stub, however the one from systemd-boot can fetch +# the command line from a separate section of the EFI application, avoiding the need to +# rebuild the kernel. +# - kernel +# - initramfs +# - kernel command line +# - uname -r kernel version +# - /etc/os-release to create a boot menu with version details +# - optionally secure boot signature(s) +# - other metadata (e.g. TPM PCR measurements) +# +# Usage instructions: +# +# - requires UEFI compatible firmware on target, e.g. qemuarm64-secureboot u-boot based +# from meta-arm or qemux86 ovmf/edk2 based firmware for x86_64 +# +# - Distro/build config: +# +# INIT_MANAGER = "systemd" +# MACHINE_FEATURES:append = " efi" +# EFI_PROVIDER = "systemd-boot" +# INITRAMFS_IMAGE = "core-image-minimal-initramfs" +# +# - image recipe: +# +# inherit uki +# +# - qemuboot/runqemu changes in image recipe or build config: +# +# # Kernel command line must be inside the signed uki +# QB_KERNEL_ROOT = "" +# # kernel is in the uki image, not loaded separately +# QB_DEFAULT_KERNEL = "none" +# +# - for UEFI secure boot, systemd-boot and uki (including kernel) can +# be signed but require sbsign-tool-native (recipe available from meta-secure-core, +# see also qemuarm64-secureboot from meta-arm). Set variable +# UKI_SB_KEY to path of private key and UKI_SB_CERT for certificate. +# Note that systemd-boot also need to be signed with the same key. +# +# - at runtime, UEFI firmware will load and boot systemd-boot which +# creates a menu from all detected uki binaries. No need to manually +# setup boot menu entries. +# +# - see efi-uki-bootdisk.wks.in how to create ESP partition which hosts systemd-boot, +# config file(s) for systemd-boot and the UKI binaries. +# + +DEPENDS += "\ + os-release \ + systemd-boot \ + systemd-boot-native \ + virtual/cross-binutils \ + virtual/kernel \ +" + +inherit image-artifact-names +require ../conf/image-uefi.conf + +INITRAMFS_IMAGE ?= "core-image-minimal-initramfs" + +INITRD_ARCHIVE ?= "${INITRAMFS_IMAGE}-${MACHINE}.${INITRAMFS_FSTYPES}" + +do_image_complete[depends] += "${INITRAMFS_IMAGE}:do_image_complete" + +UKIFY_CMD ?= "ukify build" +UKI_CONFIG_FILE ?= "${UNPACKDIR}/uki.conf" +UKI_FILENAME ?= "uki.efi" +UKI_KERNEL_FILENAME ?= "${KERNEL_IMAGETYPE}" +UKI_CMDLINE ?= "rootwait root=LABEL=root console=${KERNEL_CONSOLE}" +# secure boot keys and cert, needs sbsign-tools-native (meta-secure-core) +#UKI_SB_KEY ?= "" +#UKI_SB_CERT ?= "" + +IMAGE_EFI_BOOT_FILES ?= "${UKI_FILENAME};EFI/Linux/${UKI_FILENAME}" + +do_uki[depends] += " \ + systemd-boot:do_deploy \ + virtual/kernel:do_deploy \ + " +do_uki[depends] += "${@ '${INITRAMFS_IMAGE}:do_image_complete' if d.getVar('INITRAMFS_IMAGE') else ''}" + +# ensure that the build directory is empty everytime we generate a newly-created uki +do_uki[cleandirs] = "${B}" +# influence the build directory at the start of the builds +do_uki[dirs] = "${B}" + +# we want to allow specifying files in SRC_URI, such as for signing the UKI +python () { + d.delVarFlag("do_fetch","noexec") + d.delVarFlag("do_unpack","noexec") +} + +# main task +python do_uki() { + import glob + import bb.process + + # base ukify command, can be extended if needed + ukify_cmd = d.getVar('UKIFY_CMD') + + deploy_dir_image = d.getVar('DEPLOY_DIR_IMAGE') + + # architecture + target_arch = d.getVar('EFI_ARCH') + if target_arch: + ukify_cmd += " --efi-arch %s" % (target_arch) + + # systemd stubs + stub = "%s/linux%s.efi.stub" % (d.getVar('DEPLOY_DIR_IMAGE'), target_arch) + if not os.path.exists(stub): + bb.fatal(f"ERROR: cannot find {stub}.") + ukify_cmd += " --stub %s" % (stub) + + # initrd + initramfs_image = "%s" % (d.getVar('INITRD_ARCHIVE')) + ukify_cmd += " --initrd=%s" % (os.path.join(deploy_dir_image, initramfs_image)) + + deploy_dir_image = d.getVar('DEPLOY_DIR_IMAGE') + + # kernel + kernel_filename = d.getVar('UKI_KERNEL_FILENAME') or None + if kernel_filename: + kernel = "%s/%s" % (deploy_dir_image, kernel_filename) + if not os.path.exists(kernel): + bb.fatal(f"ERROR: cannot find %s" % (kernel)) + ukify_cmd += " --linux=%s" % (kernel) + # not always needed, ukify can detect version from kernel binary + kernel_version = d.getVar('KERNEL_VERSION') + if kernel_version: + ukify_cmd += "--uname %s" % (kernel_version) + else: + bb.fatal("ERROR - UKI_KERNEL_FILENAME not set") + + # command line + cmdline = d.getVar('UKI_CMDLINE') + if cmdline: + ukify_cmd += " --cmdline='%s'" % (cmdline) + + # dtb + if d.getVar('KERNEL_DEVICETREE'): + for dtb in d.getVar('KERNEL_DEVICETREE').split(): + dtb_path = "%s/%s" % (deploy_dir_image, dtb) + if not os.path.exists(dtb_path): + bb.fatal(f"ERROR: cannot find {dtb_path}.") + ukify_cmd += " --devicetree %s" % (dtb_path) + + # custom config for ukify + if os.path.exists(d.getVar('UKI_CONFIG_FILE')): + ukify_cmd += " --config=%s" % (d.getVar('UKI_CONFIG_FILE')) + + # systemd tools + ukify_cmd += " --tools=%s%s/lib/systemd/tools" % \ + (d.getVar("RECIPE_SYSROOT_NATIVE"), d.getVar("prefix")) + + # version + ukify_cmd += " --os-release=@%s%s/lib/os-release" % \ + (d.getVar("RECIPE_SYSROOT"), d.getVar("prefix")) + + # TODO: tpm2 measure for secure boot, depends on systemd-native and TPM tooling + # needed in systemd > 254 to fulfill ConditionSecurity=measured-uki + # Requires TPM device on build host, thus not supported at build time. + #ukify_cmd += " --measure" + + # securebooot signing, also for kernel + key = d.getVar('UKI_SB_KEY') + if key: + ukify_cmd += " --sign-kernel --secureboot-private-key='%s'" % (key) + cert = d.getVar('UKI_SB_CERT') + if cert: + ukify_cmd += " --secureboot-certificate='%s'" % (cert) + + # custom output UKI filename + output = " --output=%s/%s" % (d.getVar('DEPLOY_DIR_IMAGE'), d.getVar('UKI_FILENAME')) + ukify_cmd += " %s" % (output) + + # Run the ukify command + bb.debug(2, "uki: running command: %s" % (ukify_cmd)) + bb.process.run(ukify_cmd, shell=True) +} +addtask uki after do_rootfs before do_deploy do_image_complete do_image_wic From ff8a4d20568643edb68dfecbc56b28bcfabc355d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Iwanicki?= Date: Mon, 3 Feb 2025 13:10:47 +0100 Subject: [PATCH 02/15] uki: modify uki.bbclass to make image build and inherit it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Iwanicki --- meta-dts-distro/classes-recipe/uki.bbclass | 7 ++++--- meta-dts-distro/recipes-dts/images/dts-base-image.bb | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/meta-dts-distro/classes-recipe/uki.bbclass b/meta-dts-distro/classes-recipe/uki.bbclass index 92f6905..edf6b7f 100644 --- a/meta-dts-distro/classes-recipe/uki.bbclass +++ b/meta-dts-distro/classes-recipe/uki.bbclass @@ -64,12 +64,12 @@ DEPENDS += "\ os-release \ systemd-boot \ systemd-boot-native \ - virtual/cross-binutils \ + binutils-cross-${TARGET_ARCH} \ virtual/kernel \ + python3-pefile-native \ " inherit image-artifact-names -require ../conf/image-uefi.conf INITRAMFS_IMAGE ?= "core-image-minimal-initramfs" @@ -94,12 +94,13 @@ do_uki[depends] += " \ " do_uki[depends] += "${@ '${INITRAMFS_IMAGE}:do_image_complete' if d.getVar('INITRAMFS_IMAGE') else ''}" -# ensure that the build directory is empty everytime we generate a newly-created uki +# ensure that the build directory is empty every time we generate a newly-created uki do_uki[cleandirs] = "${B}" # influence the build directory at the start of the builds do_uki[dirs] = "${B}" # we want to allow specifying files in SRC_URI, such as for signing the UKI +# nooelint: oelint.task.noanonpython python () { d.delVarFlag("do_fetch","noexec") d.delVarFlag("do_unpack","noexec") diff --git a/meta-dts-distro/recipes-dts/images/dts-base-image.bb b/meta-dts-distro/recipes-dts/images/dts-base-image.bb index 598cc9f..c984be0 100644 --- a/meta-dts-distro/recipes-dts/images/dts-base-image.bb +++ b/meta-dts-distro/recipes-dts/images/dts-base-image.bb @@ -1 +1,2 @@ require dts-base-image.inc +inherit uki From 769933344dcddb7d64a91727c4637e38807724ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Iwanicki?= Date: Mon, 3 Feb 2025 13:11:16 +0100 Subject: [PATCH 03/15] GRUB: use UKI file to boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Iwanicki --- meta-dts-distro/conf/distro/dts-distro.conf | 3 +++ meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg | 9 +++++++++ meta-dts-distro/recipes-bsp/grub/grub-efi_%.bbappend | 9 +++++++++ meta-dts-distro/recipes-dts/images/dts-base-image.bb | 7 +++++++ meta-dts-distro/wic/usb-stick-dts.wks.in | 4 ++-- 5 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg diff --git a/meta-dts-distro/conf/distro/dts-distro.conf b/meta-dts-distro/conf/distro/dts-distro.conf index 5fa95e0..8a6e04c 100644 --- a/meta-dts-distro/conf/distro/dts-distro.conf +++ b/meta-dts-distro/conf/distro/dts-distro.conf @@ -36,3 +36,6 @@ IMAGE_EFI_BOOT_FILES += "grub-efi-bootx64.efi;EFI/DTS/grubx64.efi" PREFERRED_VERSION_flashrom = "dasharo-v1.2.2+git%" PREFERRED_VERSION_fwupd = "2.0.1" APPEND += "quiet" + +BOOT_LABEL="dts-boot" +ROOT_LABEL="dts-root" diff --git a/meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg b/meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg new file mode 100644 index 0000000..bf170f9 --- /dev/null +++ b/meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg @@ -0,0 +1,9 @@ +serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1 +default=DTS +timeout=0 + +menuentry 'DTS' { + regexp -s 2:rootfs_drive (.*)(hd[0-9]*)(.*) $cmdpath + probe --part-uuid ($rootfs_drive,msdos2) --set=rootfs + chainloader /EFI/DTS/dts.efi root=PARTUUID=$rootfs rootwait console=ttyS0,115200 +} diff --git a/meta-dts-distro/recipes-bsp/grub/grub-efi_%.bbappend b/meta-dts-distro/recipes-bsp/grub/grub-efi_%.bbappend index ad2a194..3cf426b 100644 --- a/meta-dts-distro/recipes-bsp/grub/grub-efi_%.bbappend +++ b/meta-dts-distro/recipes-bsp/grub/grub-efi_%.bbappend @@ -1 +1,10 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" require ${@bb.utils.contains('DISTRO_FEATURES', 'efi-secure-boot', 'grub-efi-efi-custom.inc', '', d)} + +SRC_URI += "file://grub.cfg" + +do_deploy:append() { + install -m 644 "${WORKDIR}/grub.cfg" ${DEPLOY_DIR_IMAGE}/ +} + +GRUB_BUILDIN:append = " probe regexp chain" diff --git a/meta-dts-distro/recipes-dts/images/dts-base-image.bb b/meta-dts-distro/recipes-dts/images/dts-base-image.bb index c984be0..0bcc571 100644 --- a/meta-dts-distro/recipes-dts/images/dts-base-image.bb +++ b/meta-dts-distro/recipes-dts/images/dts-base-image.bb @@ -1,2 +1,9 @@ require dts-base-image.inc inherit uki + +UKI_CMDLINE = "root=LABEL=${ROOT_LABEL} console=${KERNEL_CONSOLE} rootwait ${APPEND}" +UKI_FILENAME = "dts.efi" +IMAGE_EFI_BOOT_FILES += " \ + ${UKI_FILENAME};EFI/DTS/${UKI_FILENAME} \ + grub.cfg;EFI/BOOT/grub.cfg \ + " diff --git a/meta-dts-distro/wic/usb-stick-dts.wks.in b/meta-dts-distro/wic/usb-stick-dts.wks.in index a0c55dd..ab23847 100644 --- a/meta-dts-distro/wic/usb-stick-dts.wks.in +++ b/meta-dts-distro/wic/usb-stick-dts.wks.in @@ -1,4 +1,4 @@ bootloader --timeout=0 --append=" rootwait console=ttyUSB0" -part /boot --source bootimg-biosplusefi --sourceparams="loader=grub-efi" --ondisk sda --label dts-boot --align 1024 --use-uuid --active --system-id 0xef -part / --source rootfs --fstype=ext4 --ondisk sda --label dts-root --align 1024 --use-uuid --fixed-size 1024 +part /boot --source bootimg-biosplusefi --sourceparams="loader=grub-efi" --ondisk sda --label ${BOOT_LABEL} --align 1024 --use-uuid --active --system-id 0xef +part / --source rootfs --fstype=ext4 --ondisk sda --label ${ROOT_LABEL} --align 1024 --use-uuid --fixed-size 1024 From 04bcb6ba39540c5b0e49be2e5d31378b5e423e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Iwanicki?= Date: Mon, 3 Feb 2025 13:11:41 +0100 Subject: [PATCH 04/15] uki: create UKI containing kernel and rootfs for ipxe boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Iwanicki --- .../recipes-dts/images/dts-base-image.bb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/meta-dts-distro/recipes-dts/images/dts-base-image.bb b/meta-dts-distro/recipes-dts/images/dts-base-image.bb index 0bcc571..4e037a4 100644 --- a/meta-dts-distro/recipes-dts/images/dts-base-image.bb +++ b/meta-dts-distro/recipes-dts/images/dts-base-image.bb @@ -7,3 +7,22 @@ IMAGE_EFI_BOOT_FILES += " \ ${UKI_FILENAME};EFI/DTS/${UKI_FILENAME} \ grub.cfg;EFI/BOOT/grub.cfg \ " + +do_ipxe_uki() { + stub="${DEPLOY_DIR_IMAGE}/linux${EFI_ARCH}.efi.stub" + kernel="${DEPLOY_DIR_IMAGE}/${UKI_KERNEL_FILENAME}" + rootfs="${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.cpio.gz" + ukify build --cmdline "${UKI_CMDLINE}" --stub "${stub}" \ + --linux "${kernel}" --initrd "${rootfs}" \ + --tools "${RECIPE_SYSROOT_NATIVE}/lib/systemd/tools" \ + --os-release "${RECIPE_SYSROOT}/lib/os-release" \ + --output "${DEPLOY_DIR_IMAGE}/ipxe_${UKI_FILENAME}" +} + +do_ipxe_uki[depends] += " \ + systemd-boot:do_deploy \ + virtual/kernel:do_deploy \ + dts-base-image:do_image_complete \ +" + +addtask ipxe_uki after do_image_complete before do_build From 6e3083cafce5283cb5668723e9b871c952a5f763 Mon Sep 17 00:00:00 2001 From: iwanicki92 Date: Mon, 9 Feb 2026 00:55:14 +0100 Subject: [PATCH 05/15] recipes-bsp: add and deploy shim Also fix pre-commit issues Signed-off-by: iwanicki92 --- .oelint-constants.json | 9 +++++ .pre-commit-config.yaml | 2 +- meta-dts-distro/recipes-bsp/shim/shim_16.1.bb | 38 +++++++++++++++++++ .../recipes-dts/images/dts-base-image.bb | 5 ++- 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 .oelint-constants.json create mode 100644 meta-dts-distro/recipes-bsp/shim/shim_16.1.bb diff --git a/.oelint-constants.json b/.oelint-constants.json new file mode 100644 index 0000000..5f4b69a --- /dev/null +++ b/.oelint-constants.json @@ -0,0 +1,9 @@ +{ + "variables": { + "known": [ + "IMAGE_EFI_BOOT_FILES", + "INITRD_ARCHIVE" + ], + "renamed": {} + } +} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6a3a5ff..02d896b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,7 +45,7 @@ repos: rev: 9.0.1 hooks: - id: oelint-adv - args: [--rulefile=.oelint-ruleset.json, --hide=info, --quiet, --fix] + args: [--rulefile=.oelint-ruleset.json, --hide=info, --quiet, --fix, --constantmods=+.oelint-constants.json] name: Advanced oelint description: Based on the OpenEmbedded Styleguide and work done by oe-stylize-tool this module offers a (nearly) complete linter for bitbake-recipes. entry: oelint-adv diff --git a/meta-dts-distro/recipes-bsp/shim/shim_16.1.bb b/meta-dts-distro/recipes-bsp/shim/shim_16.1.bb new file mode 100644 index 0000000..f6645a5 --- /dev/null +++ b/meta-dts-distro/recipes-bsp/shim/shim_16.1.bb @@ -0,0 +1,38 @@ +# nooelint: oelint.file.requirenotfound +require conf/image-uefi.conf +inherit deploy + +SUMMARY = "UEFI shim loader" +HOMEPAGE = "https://github.com/rhboot/shim" +SECTION = "bootloaders" + +LICENSE = "BSD-2-Clause" +LIC_FILES_CHKSUM = "file://COPYRIGHT;md5=b92e63892681ee4e8d27e7a7e87ef2bc" + +SRC_URI = "gitsm://github.com/rhboot/shim.git;protocol=https;branch=main" +SRCREV = "afc49558b34548644c1cd0ad1b6526a9470182ed" + +S = "${WORKDIR}/git" + +BACKSLASHES = "\\\\" + +EXTRA_OEMAKE = "\ + CROSS_COMPILE=${TARGET_PREFIX} \ + LIB_GCC="`${CC} -print-libgcc-file-name`" \ + DEFAULT_LOADER=${BACKSLASHES}EFI${BACKSLASHES}DTS${BACKSLASHES}grub${EFI_ARCH}.efi \ +" + +do_configure() { + oe_runmake clean +} + +do_deploy() { + install -Dm 0755 "${B}/shim${EFI_ARCH}.efi" "${DEPLOYDIR}/shim${EFI_ARCH}.efi" + install -Dm 0755 "${B}/mm${EFI_ARCH}.efi" "${DEPLOYDIR}/mm${EFI_ARCH}.efi" + install -Dm 0755 "${B}/fb${EFI_ARCH}.efi" "${DEPLOYDIR}/fb${EFI_ARCH}.efi" + # Required by build_hddimg and build_iso. + # More information in grub/grub-efi_%.bbappend + install -Dm 0755 "${B}/shim${EFI_ARCH}.efi" "${DEPLOYDIR}/grub-efi-${EFI_BOOT_IMAGE}" +} + +addtask deploy after do_compile diff --git a/meta-dts-distro/recipes-dts/images/dts-base-image.bb b/meta-dts-distro/recipes-dts/images/dts-base-image.bb index 4e037a4..c44789d 100644 --- a/meta-dts-distro/recipes-dts/images/dts-base-image.bb +++ b/meta-dts-distro/recipes-dts/images/dts-base-image.bb @@ -6,7 +6,8 @@ UKI_FILENAME = "dts.efi" IMAGE_EFI_BOOT_FILES += " \ ${UKI_FILENAME};EFI/DTS/${UKI_FILENAME} \ grub.cfg;EFI/BOOT/grub.cfg \ - " + shim${EFI_ARCH}.efi;EFI/BOOT/shim${EFI_ARCH}.efi \ +" do_ipxe_uki() { stub="${DEPLOY_DIR_IMAGE}/linux${EFI_ARCH}.efi.stub" @@ -25,4 +26,6 @@ do_ipxe_uki[depends] += " \ dts-base-image:do_image_complete \ " +do_image_wic[depends] += "shim:do_deploy" + addtask ipxe_uki after do_image_complete before do_build From 4dd5eb56ac163cbda061e2768155ec618d51e7db Mon Sep 17 00:00:00 2001 From: iwanicki92 Date: Mon, 9 Feb 2026 00:57:50 +0100 Subject: [PATCH 06/15] recipe-bsp: add SBAT to GRUB & don't deploy as bootx64.efi Signed-off-by: iwanicki92 --- meta-dts-distro/conf/distro/dts-distro.conf | 2 +- .../recipes-bsp/grub/grub-efi/grub.cfg | 2 +- .../recipes-bsp/grub/grub-efi/sbat.csv | 2 ++ .../recipes-bsp/grub/grub-efi_%.bbappend | 30 +++++++++++++++++-- 4 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 meta-dts-distro/recipes-bsp/grub/grub-efi/sbat.csv diff --git a/meta-dts-distro/conf/distro/dts-distro.conf b/meta-dts-distro/conf/distro/dts-distro.conf index 8a6e04c..0781be1 100644 --- a/meta-dts-distro/conf/distro/dts-distro.conf +++ b/meta-dts-distro/conf/distro/dts-distro.conf @@ -31,7 +31,7 @@ IMAGE_FSTYPES = "cpio.gz wic.gz wic.bmap iso" # installing GRUB in EFI/DTS helps in adding custom label in Boot Menu when # Dasharo firmware is installed -IMAGE_EFI_BOOT_FILES += "grub-efi-bootx64.efi;EFI/DTS/grubx64.efi" +IMAGE_EFI_BOOT_FILES += "grub-efi-grub${EFI_ARCH}.efi;EFI/DTS/grub${EFI_ARCH}.efi" PREFERRED_VERSION_flashrom = "dasharo-v1.2.2+git%" PREFERRED_VERSION_fwupd = "2.0.1" diff --git a/meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg b/meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg index bf170f9..a7e7679 100644 --- a/meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg +++ b/meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg @@ -5,5 +5,5 @@ timeout=0 menuentry 'DTS' { regexp -s 2:rootfs_drive (.*)(hd[0-9]*)(.*) $cmdpath probe --part-uuid ($rootfs_drive,msdos2) --set=rootfs - chainloader /EFI/DTS/dts.efi root=PARTUUID=$rootfs rootwait console=ttyS0,115200 + chainloader /EFI/DTS/dtsx64.efi root=PARTUUID=$rootfs rootwait console=ttyS0,115200 } diff --git a/meta-dts-distro/recipes-bsp/grub/grub-efi/sbat.csv b/meta-dts-distro/recipes-bsp/grub/grub-efi/sbat.csv new file mode 100644 index 0000000..3310109 --- /dev/null +++ b/meta-dts-distro/recipes-bsp/grub/grub-efi/sbat.csv @@ -0,0 +1,2 @@ +sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md +grub,6,Free Software Foundation,grub,2.12,https://www.gnu.org/software/grub/ diff --git a/meta-dts-distro/recipes-bsp/grub/grub-efi_%.bbappend b/meta-dts-distro/recipes-bsp/grub/grub-efi_%.bbappend index 3cf426b..e48641f 100644 --- a/meta-dts-distro/recipes-bsp/grub/grub-efi_%.bbappend +++ b/meta-dts-distro/recipes-bsp/grub/grub-efi_%.bbappend @@ -1,10 +1,34 @@ FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" require ${@bb.utils.contains('DISTRO_FEATURES', 'efi-secure-boot', 'grub-efi-efi-custom.inc', '', d)} -SRC_URI += "file://grub.cfg" +SRC_URI += " \ + file://grub.cfg \ + file://sbat.csv \ +" -do_deploy:append() { - install -m 644 "${WORKDIR}/grub.cfg" ${DEPLOY_DIR_IMAGE}/ +do_mkimage:append() { + rm "./${GRUB_IMAGE_PREFIX}${GRUB_IMAGE}" + grub-mkimage -v -c ../cfg -p ${EFIDIR} -d ./grub-core/ -s "${WORKDIR}/sbat.csv" \ + -O ${GRUB_TARGET}-efi -o ./${GRUB_IMAGE_PREFIX}${GRUB_IMAGE} \ + ${GRUB_MKIMAGE_MODULES} } +do_install:append() { + if [ -n "${D}" ]; then + rm -rf "${D}${EFI_PREFIX}/" + fi +} + +do_deploy:append() { + install -m 644 "${WORKDIR}/grub.cfg" "${DEPLOYDIR}/" +} + +# This recipe creates grub-efi-bootx64.efi by default +# ("${GRUB_EFI_PREFIX}-${EFI_BOOT_IMAGE}") +# which is then copied to EFI/BOOT/BOOTX64.efi by build_hddimg and build_iso +# when building ISO image. This results in current bootx64 (shim) being +# overwritten. This workaround isn't needed if iso isn't added to IMAGE_FSTYPES. +EFI_BOOT_IMAGE = "grub${EFI_ARCH}.efi" GRUB_BUILDIN:append = " probe regexp chain" +# We are using custom grub.cfg +RDEPENDS:${PN}:remove = "virtual-grub-bootconf" From ad763b4cac4615a77aab943fb979fc21d64e9ffb Mon Sep 17 00:00:00 2001 From: iwanicki92 Date: Mon, 9 Feb 2026 00:59:00 +0100 Subject: [PATCH 07/15] dts-base-image: rename dts.efi to dtsx64.efi Also append ttyUSB0 to UKI cmdline Signed-off-by: iwanicki92 --- meta-dts-distro/recipes-dts/images/dts-base-image.bb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meta-dts-distro/recipes-dts/images/dts-base-image.bb b/meta-dts-distro/recipes-dts/images/dts-base-image.bb index c44789d..031de2e 100644 --- a/meta-dts-distro/recipes-dts/images/dts-base-image.bb +++ b/meta-dts-distro/recipes-dts/images/dts-base-image.bb @@ -1,8 +1,9 @@ require dts-base-image.inc inherit uki +KERNEL_CONSOLE = "ttyUSB0" UKI_CMDLINE = "root=LABEL=${ROOT_LABEL} console=${KERNEL_CONSOLE} rootwait ${APPEND}" -UKI_FILENAME = "dts.efi" +UKI_FILENAME = "dts${EFI_ARCH}.efi" IMAGE_EFI_BOOT_FILES += " \ ${UKI_FILENAME};EFI/DTS/${UKI_FILENAME} \ grub.cfg;EFI/BOOT/grub.cfg \ From 3e9d02e5cead741ba0a209872f33bcf99553d0c3 Mon Sep 17 00:00:00 2001 From: iwanicki92 Date: Mon, 9 Feb 2026 21:02:18 +0100 Subject: [PATCH 08/15] dts: replace DTS/grubx64.efi with shim On Dasharo firmware this file is used to boot DTS via standard 'Dasharo Tools Suite' bootmenu entry. Signed-off-by: iwanicki92 --- meta-dts-distro/conf/distro/dts-distro.conf | 2 +- meta-dts-distro/recipes-bsp/shim/shim_16.1.bb | 2 +- meta-dts-distro/recipes-dts/images/dts-base-image.bb | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/meta-dts-distro/conf/distro/dts-distro.conf b/meta-dts-distro/conf/distro/dts-distro.conf index 0781be1..899c892 100644 --- a/meta-dts-distro/conf/distro/dts-distro.conf +++ b/meta-dts-distro/conf/distro/dts-distro.conf @@ -31,7 +31,7 @@ IMAGE_FSTYPES = "cpio.gz wic.gz wic.bmap iso" # installing GRUB in EFI/DTS helps in adding custom label in Boot Menu when # Dasharo firmware is installed -IMAGE_EFI_BOOT_FILES += "grub-efi-grub${EFI_ARCH}.efi;EFI/DTS/grub${EFI_ARCH}.efi" +IMAGE_EFI_BOOT_FILES += "grub-efi-grub${EFI_ARCH}.efi;EFI/BOOT/grub${EFI_ARCH}.efi" PREFERRED_VERSION_flashrom = "dasharo-v1.2.2+git%" PREFERRED_VERSION_fwupd = "2.0.1" diff --git a/meta-dts-distro/recipes-bsp/shim/shim_16.1.bb b/meta-dts-distro/recipes-bsp/shim/shim_16.1.bb index f6645a5..8480212 100644 --- a/meta-dts-distro/recipes-bsp/shim/shim_16.1.bb +++ b/meta-dts-distro/recipes-bsp/shim/shim_16.1.bb @@ -19,7 +19,7 @@ BACKSLASHES = "\\\\" EXTRA_OEMAKE = "\ CROSS_COMPILE=${TARGET_PREFIX} \ LIB_GCC="`${CC} -print-libgcc-file-name`" \ - DEFAULT_LOADER=${BACKSLASHES}EFI${BACKSLASHES}DTS${BACKSLASHES}grub${EFI_ARCH}.efi \ + DEFAULT_LOADER=${BACKSLASHES}EFI${BACKSLASHES}BOOT${BACKSLASHES}grub${EFI_ARCH}.efi \ " do_configure() { diff --git a/meta-dts-distro/recipes-dts/images/dts-base-image.bb b/meta-dts-distro/recipes-dts/images/dts-base-image.bb index 031de2e..5c216e6 100644 --- a/meta-dts-distro/recipes-dts/images/dts-base-image.bb +++ b/meta-dts-distro/recipes-dts/images/dts-base-image.bb @@ -8,6 +8,7 @@ IMAGE_EFI_BOOT_FILES += " \ ${UKI_FILENAME};EFI/DTS/${UKI_FILENAME} \ grub.cfg;EFI/BOOT/grub.cfg \ shim${EFI_ARCH}.efi;EFI/BOOT/shim${EFI_ARCH}.efi \ + shim${EFI_ARCH}.efi;EFI/DTS/grub${EFI_ARCH}.efi \ " do_ipxe_uki() { From bfc9efdf20f4e4351dd4a65d628207b8e4ad3475 Mon Sep 17 00:00:00 2001 From: iwanicki92 Date: Tue, 10 Feb 2026 21:43:46 +0100 Subject: [PATCH 09/15] ipxe: update workflow & ipxe script to use dts.efi Also added imgfree as without freeing previous image iPXE fails to boot DTS image: ``` Error registering initrd: Already started Could not boot: Error 0x7f048294 (https://ipxe.org/7f048294) ``` Signed-off-by: iwanicki92 --- .github/workflows/ci.yml | 4 ++++ .github/workflows/develop.yml | 4 ++++ scripts/generate-ipxe-menu.sh | 16 +++++++++------- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b85bece..103348a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,6 +77,7 @@ jobs: ssh -i ~/.ssh/dts-ci-key builder@10.1.40.2 "mkdir -p boot/dts/${DTS_VER}" cd build/tmp/deploy/images/genericx86-64/ cp bzImage bzImage-${DTS_VER} + cp ipxe_dtsx64.efi ipxe_dtsx64-${DTS_VER}.efi cp dts-base-image-genericx86-64.cpio.gz dts-base-image-${DTS_VER}.cpio.gz cp dts-base-image-genericx86-64.wic.gz dts-base-image-${DTS_VER}.wic.gz cp dts-base-image-genericx86-64.wic.bmap dts-base-image-${DTS_VER}.wic.bmap @@ -84,6 +85,7 @@ jobs: # see: https://github.com/dasharo/dasharo-issues/issues/288 # cp dts-base-image-genericx86-64.iso dts-base-image-${DTS_VER}.iso scp -i ~/.ssh/dts-ci-key bzImage-${DTS_VER} builder@10.1.40.2:boot/dts/${DTS_VER}/ + scp -i ~/.ssh/dts-ci-key ipxe_dtsx64-${DTS_VER}.efi builder@10.1.40.2:boot/dts/${DTS_VER}/ scp -i ~/.ssh/dts-ci-key dts-base-image-${DTS_VER}.cpio.gz builder@10.1.40.2:boot/dts/${DTS_VER}/ scp -i ~/.ssh/dts-ci-key dts-base-image-${DTS_VER}.wic.gz builder@10.1.40.2:boot/dts/${DTS_VER}/ scp -i ~/.ssh/dts-ci-key dts-base-image-${DTS_VER}.wic.bmap builder@10.1.40.2:boot/dts/${DTS_VER}/ @@ -103,6 +105,7 @@ jobs: DTS_VER="${{ env.DTS_VER }}" cd build/tmp/deploy/images/genericx86-64/ sha256sum bzImage-${DTS_VER} > bzImage-${DTS_VER}.sha256 + sha256sum ipxe_dtsx64-${DTS_VER}.efi > ipxe_dtsx64-${DTS_VER}.efi.sha256 sha256sum dts-base-image-${DTS_VER}.cpio.gz > dts-base-image-${DTS_VER}.cpio.gz.sha256 sha256sum dts-base-image-${DTS_VER}.wic.gz > dts-base-image-${DTS_VER}.wic.gz.sha256 sha256sum dts-base-image-${DTS_VER}.wic.bmap > dts-base-image-${DTS_VER}.wic.bmap.sha256 @@ -111,6 +114,7 @@ jobs: # see: https://github.com/dasharo/dasharo-issues/issues/288 # sha256sum dts-base-image-${DTS_VER}.iso > dts-base-image-${DTS_VER}.iso.sha256 scp -i ~/.ssh/dts-ci-key bzImage-${DTS_VER}.sha256 builder@10.1.40.2:boot/dts/${DTS_VER}/ + scp -i ~/.ssh/dts-ci-key ipxe_dtsx64-${DTS_VER}.efi.sha256 builder@10.1.40.2:boot/dts/${DTS_VER}/ scp -i ~/.ssh/dts-ci-key dts-base-image-${DTS_VER}.cpio.gz.sha256 builder@10.1.40.2:boot/dts/${DTS_VER}/ scp -i ~/.ssh/dts-ci-key dts-base-image-${DTS_VER}.wic.gz.sha256 builder@10.1.40.2:boot/dts/${DTS_VER}/ scp -i ~/.ssh/dts-ci-key dts-base-image-${DTS_VER}.wic.bmap.sha256 builder@10.1.40.2:boot/dts/${DTS_VER}/ diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 6eb8863..469ced0 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -76,11 +76,13 @@ jobs: ssh -i ~/.ssh/dts-ci-key builder@10.1.40.2 "mkdir -p boot/dts/${DTS_VER}" cd build/tmp/deploy/images/genericx86-64/ cp bzImage bzImage-${DTS_VER} + cp ipxe_dtsx64.efi ipxe_dtsx64-${DTS_VER}.efi cp dts-base-image-genericx86-64.cpio.gz dts-base-image-${DTS_VER}.cpio.gz cp dts-base-image-genericx86-64.wic.gz dts-base-image-${DTS_VER}.wic.gz cp dts-base-image-genericx86-64.wic.bmap dts-base-image-${DTS_VER}.wic.bmap cp dts-base-image-genericx86-64.iso dts-base-image-${DTS_VER}.iso scp -i ~/.ssh/dts-ci-key bzImage-${DTS_VER} builder@10.1.40.2:boot/dts/${DTS_VER}/ + scp -i ~/.ssh/dts-ci-key ipxe_dtsx64-${DTS_VER}.efi builder@10.1.40.2:boot/dts/${DTS_VER}/ scp -i ~/.ssh/dts-ci-key dts-base-image-${DTS_VER}.cpio.gz builder@10.1.40.2:boot/dts/${DTS_VER}/ scp -i ~/.ssh/dts-ci-key dts-base-image-${DTS_VER}.wic.gz builder@10.1.40.2:boot/dts/${DTS_VER}/ scp -i ~/.ssh/dts-ci-key dts-base-image-${DTS_VER}.wic.bmap builder@10.1.40.2:boot/dts/${DTS_VER}/ @@ -98,12 +100,14 @@ jobs: DTS_VER="${{ env.DTS_VER }}" cd build/tmp/deploy/images/genericx86-64/ sha256sum bzImage-${DTS_VER} > bzImage-${DTS_VER}.sha256 + sha256sum ipxe_dtsx64-${DTS_VER}.efi > ipxe_dtsx64-${DTS_VER}.efi.sha256 sha256sum dts-base-image-${DTS_VER}.cpio.gz > dts-base-image-${DTS_VER}.cpio.gz.sha256 sha256sum dts-base-image-${DTS_VER}.wic.gz > dts-base-image-${DTS_VER}.wic.gz.sha256 sha256sum dts-base-image-${DTS_VER}.wic.bmap > dts-base-image-${DTS_VER}.wic.bmap.sha256 sha256sum dts-base-image-${DTS_VER}.iso > dts-base-image-${DTS_VER}.iso.sha256 sha256sum dts-base-image-${DTS_VER}.manifest > dts-base-image-${DTS_VER}.manifest.sha256 scp -i ~/.ssh/dts-ci-key bzImage-${DTS_VER}.sha256 builder@10.1.40.2:boot/dts/${DTS_VER}/ + scp -i ~/.ssh/dts-ci-key ipxe_dtsx64-${DTS_VER}.efi.sha256 builder@10.1.40.2:boot/dts/${DTS_VER}/ scp -i ~/.ssh/dts-ci-key dts-base-image-${DTS_VER}.cpio.gz.sha256 builder@10.1.40.2:boot/dts/${DTS_VER}/ scp -i ~/.ssh/dts-ci-key dts-base-image-${DTS_VER}.wic.gz.sha256 builder@10.1.40.2:boot/dts/${DTS_VER}/ scp -i ~/.ssh/dts-ci-key dts-base-image-${DTS_VER}.wic.bmap.sha256 builder@10.1.40.2:boot/dts/${DTS_VER}/ diff --git a/scripts/generate-ipxe-menu.sh b/scripts/generate-ipxe-menu.sh index d917383..e073574 100755 --- a/scripts/generate-ipxe-menu.sh +++ b/scripts/generate-ipxe-menu.sh @@ -6,6 +6,9 @@ gen_common_ipxe() { #!ipxe set dts_version ${version} set dts_prefix \${dts_version} +iseq \${platform} efi && goto is_efi || goto not_efi +:not_efi + set path_kernel \${dts_prefix}/bzImage-\${dts_version} set path_initrd \${dts_prefix}/dts-base-image-\${dts_version}.cpio.gz @@ -13,25 +16,24 @@ imgfetch --name file_kernel \${path_kernel} imgfetch --name file_initrd \${path_initrd} kernel file_kernel initrd=file_initrd console=ttyUSB0 +boot + +:is_efi EOF } gen_fum_workaround_ipxe() { gen_common_ipxe "$@" cat < Date: Fri, 13 Feb 2026 19:43:20 +0100 Subject: [PATCH 10/15] kas: use 'commit' instead of refspec and bump format version Signed-off-by: iwanicki92 --- kas.yml | 2 +- kas/cache.yml | 2 +- kas/common.yml | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/kas.yml b/kas.yml index 56aec2c..ca46151 100644 --- a/kas.yml +++ b/kas.yml @@ -1,6 +1,6 @@ --- header: - version: 11 + version: 14 includes: - kas/common.yml - kas/cache.yml diff --git a/kas/cache.yml b/kas/cache.yml index b88cd90..b2e3206 100644 --- a/kas/cache.yml +++ b/kas/cache.yml @@ -1,6 +1,6 @@ --- header: - version: 11 + version: 14 local_conf_header: yocto-cache: | diff --git a/kas/common.yml b/kas/common.yml index 077dba3..787a4d9 100644 --- a/kas/common.yml +++ b/kas/common.yml @@ -1,6 +1,6 @@ --- header: - version: 11 + version: 14 repos: meta-dts: @@ -9,7 +9,7 @@ repos: poky: url: https://git.yoctoproject.org/git/poky - refspec: d71d1c02ff622e00d6fa5ca9ce44a4e567691dce + commit: d71d1c02ff622e00d6fa5ca9ce44a4e567691dce layers: meta: meta-poky: @@ -17,7 +17,7 @@ repos: meta-openembedded: url: https://git.openembedded.org/meta-openembedded - refspec: a72010b414ee3d73888ac9cb4e310e8f05e13aea + commit: a72010b414ee3d73888ac9cb4e310e8f05e13aea layers: meta-oe: meta-networking: @@ -25,17 +25,17 @@ repos: meta-security: url: https://git.yoctoproject.org/git/meta-security - refspec: 11ea91192d43d7c2b0b95a93aa63ca7e73e38034 + commit: 11ea91192d43d7c2b0b95a93aa63ca7e73e38034 layers: meta-tpm: meta-dasharo: url: https://github.com/Dasharo/meta-dasharo - refspec: f548e66a69046f60762de05777090c95708ee4a5 + commit: f548e66a69046f60762de05777090c95708ee4a5 meta-coreboot: url: https://github.com/zarhus/meta-coreboot - refspec: c8254de6ee875ff4d8f7a3c91880c4d1ed9a7c6e + commit: c8254de6ee875ff4d8f7a3c91880c4d1ed9a7c6e bblayers_conf_header: standard: | From 7e2266e03d961d55822099228999a60c72bb5f5d Mon Sep 17 00:00:00 2001 From: iwanicki92 Date: Sat, 14 Feb 2026 00:29:41 +0100 Subject: [PATCH 11/15] docs: Add boot paths & Secure Boot Signed-off-by: iwanicki92 --- docs/boot-paths.md | 139 ++++++++++++++++++++++++++++++++++++ docs/images/boot-paths.png | Bin 0 -> 27017 bytes docs/images/boot-paths.puml | 35 +++++++++ 3 files changed, 174 insertions(+) create mode 100644 docs/boot-paths.md create mode 100644 docs/images/boot-paths.png create mode 100644 docs/images/boot-paths.puml diff --git a/docs/boot-paths.md b/docs/boot-paths.md new file mode 100644 index 0000000..57d34f2 --- /dev/null +++ b/docs/boot-paths.md @@ -0,0 +1,139 @@ +# DTS boot paths + +This document describes how DTS can be booted and which files are used in those +different boot paths. Diagram below shows the most important elements + +![](images/boot-paths.png) + +* iPXE - this assumes that [dts.ipxe](https://boot.dasharo.com/dts/dts.ipxe) + script is used + - on non-UEFI firmware old method is still used, i.e. booting `bzImage` and + `.cpio.gz` archive + - on UEFI firmware we first run a small EFI application that renames + FirmwareUpdateMode variable if it exists (workaround for + [Dasharo/dasharo-issues#1759](https://github.com/Dasharo/dasharo-issues/issues/1759)), + and then we boot `ipxe_dtsx64.efi` ([Unified Kernel + Image](https://uapi-group.org/specifications/specs/unified_kernel_image/)) + which contains both kernel and rootfs. +* USB/disk + - on non-UEFI firmware we first boot GRUB which then boots kernel + (`bzImage`). This GRUB, unlike when booting via UEFI is embedded inside + boot partition itself. You can read more about [MBR boot flow + here](https://neosmart.net/wiki/mbr-boot-process/) + - on UEFI firmware we first boot shim, which then boots GRUB which then + boots DTS. This is fairly standard flow used when booting Linux systems. + +## Dasharo UEFI + +When analyzing UEFI boot flow one can notice that shim is mentioned twice +* `EFI/BOOT/bootx64.efi` +* `EFI/DTS/grubx64.efi` + +The first path is the default file booted by UEFI firmware. The second path is +detected automatically by Dasharo firmware and boot menu entry is created under +`Dasharo Tools Suite` name. This and the fact that shim should be the first +file booted if one wants to use GRUB with Secure Boot is the reason why +`EFI/DTS/grubx64.efi` is actually shim and not GRUB. The real GRUB is under +`EFI/BOOT/grubx64.efi` which is booted by shim. + +## Secure Boot + +### USB + +UEFI boot flow was made specifically so it could be compatible with Secure Boot. +Currently, all files are built unsigned and there are no certificates embedded +inside of shim or GRUB, but it's possible to sign all files by yourself. + +Minimal USB example that allows booting DTS with Secure Boot enabled. + +1. Generate Secure Boot key/certificate that'll be used for signing `.efi` files + + ```sh + openssl req -new -x509 -newkey rsa:2048 -nodes \ + -keyout sb.key -out sb.crt -subj "/C=PL" + openssl x509 -in sb.crt -out sb.cer -outform DER + ``` + +2. Decompress and mount DTS boot partition + + ```sh + bmaptool copy images/dts-base-image-genericx86-64.wic.gz dts.img + dev=$(sudo losetup --show -Pf dts.img) + sudo mount "${loop}p1" /mnt + ``` + +3. Sign all files + + ```sh + sudo sbsign --key sb.key --cert sb.crt /mnt/EFI/BOOT/bootx64.efi --output /mnt/EFI/BOOT/bootx64.efi + sudo sbsign --key sb.key --cert sb.crt /mnt/EFI/BOOT/grubx64.efi --output /mnt/EFI/BOOT/grubx64.efi + sudo sbsign --key sb.key --cert sb.crt /mnt/EFI/DTS/grubx64.efi --output /mnt/EFI/DTS/grubx64.efi + sudo sbsign --key sb.key --cert sb.crt /mnt/EFI/DTS/dtsx64.efi --output /mnt/EFI/DTS/dtsx64.efi + ``` + +4. Copy certificate to boot partition. We will add it to Secure Boot allowed + signatures (DB) later + + ```sh + sudo cp sb.cer /mnt + ``` + +5. Unmount everything. + + ```sh + sudo umount /mnt + sudo losetup -d "${dev}" + ``` + +6. Now you can flash `dts.img` on USB flash drive or run it in e.g. QEMU. +7. Enable SB and enroll `sb.cer` into + [DB](https://docs.dasharo.com/dasharo-menu-docs/device-manager/#enabling-secure-boot) +8. Boot DTS. If you've done everything correctly DTS should boot without any + problems. You can verify Secure Boot state by checking dmesg output in + shell: + + ```sh + bash-5.2# dmesg | grep 'Secure boot' + [ 0.004989] Secure boot enabled + ``` + +### iPXE + +Example below allows booting DTS via iPXE with Secure Boot enabled. + +1. Generate Secure Boot key/certificate (or use previous ones) as described in + [Secure Boot USB](#usb) +2. Sign `ipxe_dtsx64.efi`. You can download it from + or build it yourself (it's in `build/tmp/deploy/images/genericx86-64/`) + + ```sh + sbsign --key sb.key --cert sb.crt ipxe_dtsx64.efi --output ipxe_dtsx64.efi + ``` + +3. Start HTTP server + + ```sh + python -m http.server + ``` + +4. Enable SB and enroll `sb.cer` into + [DB](https://docs.dasharo.com/dasharo-menu-docs/device-manager/#secure-boot-configuration) + on your test firmware e.g. in QEMU. +5. Boot `ipxe_dtsx64.efi` via iPXE. You can follow steps in + [Launching DTS](https://docs.dasharo.com/dasharo-tools-suite/documentation/running/#launching-dts) + section. The only difference is in `chain` command: + + ```text + chain http://localhost:8000/ipxe_dtsx64.efi + ``` + + If you are using iPXE on another platform (not QEMU) you should replace + `localhost` with IP of the host with HTTP server running. + +To also run signed `replace_fum_efivar.efi` you have to modify iPXE commands: + +```text +chain http://localhost:8000/replace_fum_efivar.efi +imgfree +chain http://localhost:8000/ipxe_dtsx64.efi +``` diff --git a/docs/images/boot-paths.png b/docs/images/boot-paths.png new file mode 100644 index 0000000000000000000000000000000000000000..a0bc3c7631e48ea50d0265a2d063072f54486a6c GIT binary patch literal 27017 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 VYjBnwXJBAp@O1TaS?83{1ORvY_?Z9z literal 0 HcmV?d00001 diff --git a/docs/images/boot-paths.puml b/docs/images/boot-paths.puml new file mode 100644 index 0000000..97e5e62 --- /dev/null +++ b/docs/images/boot-paths.puml @@ -0,0 +1,35 @@ +@startuml "boot-paths" + start + if (Choose boot method) then (iPXE) + if (UEFI) then (yes) + :Run //replace_fum_efivar.efi//; + note left + Rename //FirmwareUpdateMode// EFI variable + to //FirmwareUpdateModeRT// if it exists + endnote + :Boot //ipxe_dtsx64.efi//; + note left + Contains both kernel and rootfs + endnote + else (no) + :Boot //bzImage// and + //dts.cpio.gz// archive; + endif + else (USB/disk) + if (UEFI) then (no) + :Boot GRUB; + :Boot //bzImage//; + else (yes) + if (Which menu entry) then (Dasharo Tools Suite) + :Boot //EFI/DTS/grubx64.efi// (shim); + else (Default boot file) + :Boot //EFI/BOOT/bootx64.efi// (shim); + endif + :Boot //EFI/BOOT/grubx64.efi// (GRUB); + :Boot //EFI/DTS/dtsx64.efi// (DTS); + endif + :Mount rootfs; + endif + :We are in DTS; + stop +@enduml From 02479798f81aa94eb8c1bcc159dc560cb3499af3 Mon Sep 17 00:00:00 2001 From: iwanicki92 Date: Sat, 14 Feb 2026 01:03:03 +0100 Subject: [PATCH 12/15] grub: Use cmdline embedded in UKI iPXE: Add missing console=ttyUSB0 argument Signed-off-by: iwanicki92 --- meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg | 4 +--- scripts/generate-ipxe-menu.sh | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg b/meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg index a7e7679..077de03 100644 --- a/meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg +++ b/meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg @@ -3,7 +3,5 @@ default=DTS timeout=0 menuentry 'DTS' { - regexp -s 2:rootfs_drive (.*)(hd[0-9]*)(.*) $cmdpath - probe --part-uuid ($rootfs_drive,msdos2) --set=rootfs - chainloader /EFI/DTS/dtsx64.efi root=PARTUUID=$rootfs rootwait console=ttyS0,115200 + chainloader /EFI/DTS/dtsx64.efi } diff --git a/scripts/generate-ipxe-menu.sh b/scripts/generate-ipxe-menu.sh index e073574..fd18e05 100755 --- a/scripts/generate-ipxe-menu.sh +++ b/scripts/generate-ipxe-menu.sh @@ -33,7 +33,7 @@ EOF gen_without_fum_workaround_ipxe() { gen_common_ipxe "$@" - echo "chain \${dts_prefix}/ipxe_dtsx64-\${dts_version}.efi" + echo "chain \${dts_prefix}/ipxe_dtsx64-\${dts_version}.efi console=ttyUSB0" } VERSION=$1 From 885091e6312f53040d835a27d2e9dd7d16554842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Iwanicki?= Date: Wed, 25 Feb 2026 12:07:00 +0100 Subject: [PATCH 13/15] docs: boot-paths: add note to grubx64.efi (shim) and sign *efivar.efi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Iwanicki --- docs/boot-paths.md | 20 ++++++++++++++------ docs/images/boot-paths.png | Bin 27017 -> 27630 bytes docs/images/boot-paths.puml | 3 +++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/boot-paths.md b/docs/boot-paths.md index 57d34f2..e5caed7 100644 --- a/docs/boot-paths.md +++ b/docs/boot-paths.md @@ -130,10 +130,18 @@ Example below allows booting DTS via iPXE with Secure Boot enabled. If you are using iPXE on another platform (not QEMU) you should replace `localhost` with IP of the host with HTTP server running. -To also run signed `replace_fum_efivar.efi` you have to modify iPXE commands: +To also run `replace_fum_efivar.efi` you have to -```text -chain http://localhost:8000/replace_fum_efivar.efi -imgfree -chain http://localhost:8000/ipxe_dtsx64.efi -``` +1. Sign `replace_fum_efivar.efi` the same way you have signed `ipxe_dtsx64.efi` + + ```sh + sbsign --key sb.key --cert sb.crt replace_fum_efivar.efi --output replace_fum_efivar.efi + ``` + +1. Modify iPXE commands: + + ```text + chain http://localhost:8000/replace_fum_efivar.efi + imgfree + chain http://localhost:8000/ipxe_dtsx64.efi + ``` diff --git a/docs/images/boot-paths.png b/docs/images/boot-paths.png index a0bc3c7631e48ea50d0265a2d063072f54486a6c..12cdc6b342e4c68f32409d080d94b1ce9293fb95 100644 GIT binary patch delta 27530 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 HDWM4fVk7eG delta 26911 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 diff --git a/docs/images/boot-paths.puml b/docs/images/boot-paths.puml index 97e5e62..8c1902e 100644 --- a/docs/images/boot-paths.puml +++ b/docs/images/boot-paths.puml @@ -22,6 +22,9 @@ else (yes) if (Which menu entry) then (Dasharo Tools Suite) :Boot //EFI/DTS/grubx64.efi// (shim); + note left + Yes, it's shim + endnote else (Default boot file) :Boot //EFI/BOOT/bootx64.efi// (shim); endif From 9ec4235020bda9f02ab9dc403a56980c22a3e50f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Iwanicki?= Date: Thu, 26 Feb 2026 12:38:46 +0100 Subject: [PATCH 14/15] docs/boot-paths.md: add 'Live USB image' example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Iwanicki --- docs/boot-paths.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/boot-paths.md b/docs/boot-paths.md index e5caed7..0ccdbb9 100644 --- a/docs/boot-paths.md +++ b/docs/boot-paths.md @@ -145,3 +145,27 @@ To also run `replace_fum_efivar.efi` you have to imgfree chain http://localhost:8000/ipxe_dtsx64.efi ``` + +## Live image + +Instead of booting `ipxe_dtsx64.efi` via iPXE you can instead use it as live +USB image. In short, you just have to boot `ipxe_dtsx64.efi` directly, either by +using [Boot from +file](https://docs.dasharo.com/dasharo-menu-docs/boot-maintenance-mgr/#boot-from-file) +menu, or by creating dedicated flash drive. Below is one such example, that will +create `dts-live.img` that can be used in QEMU or flashed into USB flash drive: + +```sh +dd if=/dev/zero of=dts-live.img bs=1 seek=400M count=0 +printf '%s\n' "n" "p" "1" "" "" "t" "ef" "w" | fdisk dts-live.img +dev=$(sudo losetup --show -Pf dts-live.img) +sudo mkfs.vfat "${dev}p1" -n DTS-LIVE +sudo mount "${dev}p1" /mnt +sudo mkdir -p /mnt/EFI/BOOT +sudo cp ipxe_dtsx64.efi /mnt/EFI/BOOT/bootx64.efi +sudo umount /mnt +sudo losetup -d "${dev}" +sync +``` + +This booting method will only work on UEFI firmware. From 1e4274d6b0229cc2869049b346a1ef17c22529c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Iwanicki?= Date: Tue, 24 Mar 2026 15:28:42 +0100 Subject: [PATCH 15/15] Update docs/boot-paths.md Co-authored-by: Kamil Aronowski --- docs/boot-paths.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/boot-paths.md b/docs/boot-paths.md index 0ccdbb9..9cb1d20 100644 --- a/docs/boot-paths.md +++ b/docs/boot-paths.md @@ -59,7 +59,7 @@ Minimal USB example that allows booting DTS with Secure Boot enabled. ```sh bmaptool copy images/dts-base-image-genericx86-64.wic.gz dts.img dev=$(sudo losetup --show -Pf dts.img) - sudo mount "${loop}p1" /mnt + sudo mount "${dev}p1" /mnt ``` 3. Sign all files