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/.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/docs/boot-paths.md b/docs/boot-paths.md new file mode 100644 index 0000000..9cb1d20 --- /dev/null +++ b/docs/boot-paths.md @@ -0,0 +1,171 @@ +# 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 "${dev}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 `replace_fum_efivar.efi` you have to + +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 + ``` + +## 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. diff --git a/docs/images/boot-paths.png b/docs/images/boot-paths.png new file mode 100644 index 0000000..12cdc6b Binary files /dev/null and b/docs/images/boot-paths.png differ diff --git a/docs/images/boot-paths.puml b/docs/images/boot-paths.puml new file mode 100644 index 0000000..8c1902e --- /dev/null +++ b/docs/images/boot-paths.puml @@ -0,0 +1,38 @@ +@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); + note left + Yes, it's shim + endnote + 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 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: | diff --git a/meta-dts-distro/classes-recipe/uki.bbclass b/meta-dts-distro/classes-recipe/uki.bbclass new file mode 100644 index 0000000..edf6b7f --- /dev/null +++ b/meta-dts-distro/classes-recipe/uki.bbclass @@ -0,0 +1,196 @@ +# 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 \ + binutils-cross-${TARGET_ARCH} \ + virtual/kernel \ + python3-pefile-native \ +" + +inherit image-artifact-names + +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 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") +} + +# 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 diff --git a/meta-dts-distro/conf/distro/dts-distro.conf b/meta-dts-distro/conf/distro/dts-distro.conf index 3b0d7cc..5391482 100644 --- a/meta-dts-distro/conf/distro/dts-distro.conf +++ b/meta-dts-distro/conf/distro/dts-distro.conf @@ -31,8 +31,11 @@ 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/BOOT/grub${EFI_ARCH}.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..077de03 --- /dev/null +++ b/meta-dts-distro/recipes-bsp/grub/grub-efi/grub.cfg @@ -0,0 +1,7 @@ +serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1 +default=DTS +timeout=0 + +menuentry 'DTS' { + chainloader /EFI/DTS/dtsx64.efi +} 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 ad2a194..e48641f 100644 --- a/meta-dts-distro/recipes-bsp/grub/grub-efi_%.bbappend +++ b/meta-dts-distro/recipes-bsp/grub/grub-efi_%.bbappend @@ -1 +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 \ + file://sbat.csv \ +" + +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" 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..8480212 --- /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}BOOT${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 598cc9f..5c216e6 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,33 @@ 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_ARCH}.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 \ + shim${EFI_ARCH}.efi;EFI/DTS/grub${EFI_ARCH}.efi \ +" + +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 \ +" + +do_image_wic[depends] += "shim:do_deploy" + +addtask ipxe_uki after do_image_complete before do_build 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 diff --git a/scripts/generate-ipxe-menu.sh b/scripts/generate-ipxe-menu.sh index d917383..fd18e05 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 <