From ff78bd663b4254b4c24bf7405c9f6918b7494387 Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Thu, 2 Apr 2026 15:21:41 -0700 Subject: [PATCH 1/4] build-dtb-image: recurse into vendor subdirs when copying DTBs The FIT image build path used a flat glob to collect DTBs from the resolved source directory: cp -rap "${DTB_SRC}"/*.dtb* "${DTB_STAGE}/" This assumes all DTB files reside directly in DTB_SRC. In practice, DTBs are always installed one level deeper under a vendor subdirectory: lib/firmware//device-tree/qcom/*.dtb When --kernel-deb is used, DTB_SRC resolves to the device-tree directory (a symlink to usr/lib/linux-image-/). The glob expands to nothing because the DTBs are in qcom/, not at the top level, causing the build to fail: cp: cannot stat '.../device-tree/*.dtb*': No such file or directory Replace the flat glob with find -L, which follows symlinks and recurses into all vendor subdirectories, copying every *.dtb and *.dtbo file flat into the mkimage staging directory (arch/arm64/boot/dts/qcom/) as the ITS file expects. Also add a post-copy count check and a sorted DTB listing so that an empty or misconfigured DTB source is caught early with a clear diagnostic rather than a cryptic mkimage FATAL ERROR. Signed-off-by: Bjordis Collaku --- kernel/scripts/build-dtb-image.sh | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/kernel/scripts/build-dtb-image.sh b/kernel/scripts/build-dtb-image.sh index 54615be..ef87586 100755 --- a/kernel/scripts/build-dtb-image.sh +++ b/kernel/scripts/build-dtb-image.sh @@ -504,9 +504,27 @@ else DTB_STAGE="${FIT_STAGE}/arch/arm64/boot/dts/qcom" mkdir -p "${DTB_STAGE}" - # Copy DTBs from the resolved DTB source directory + # Copy DTBs from the resolved DTB source directory. + # DTBs may be nested under vendor subdirectories (e.g. qcom/), so use + # find -L (follow symlinks) rather than a flat glob to collect them all + # into the staging dir flat — the ITS file references them by basename + # under arch/arm64/boot/dts/qcom/. echo "[INFO] Copying DTBs from ${DTB_SRC} ..." - cp -rap "${DTB_SRC}"/*.dtb* "${DTB_STAGE}/" + dtb_count=0 + while IFS= read -r dtb; do + cp -p "${dtb}" "${DTB_STAGE}/" + (( dtb_count++ )) || true + done < <(find -L "${DTB_SRC}" \( -name '*.dtb' -o -name '*.dtbo' \) -type f) + + if (( dtb_count == 0 )); then + echo "[ERROR] No DTB files found under ${DTB_SRC}" >&2 + echo " Verify the kernel package was built with DTB support" >&2 + echo " and that lib/firmware/*/device-tree resolves correctly." >&2 + exit 1 + fi + echo "[INFO] Staged ${dtb_count} DTB file(s) to ${DTB_STAGE}" + echo "[INFO] Staged DTBs:" + ls "${DTB_STAGE}"/*.dtb 2>/dev/null | xargs -n1 basename | sort | sed 's/^/ /' # ----------------------------------------------------------------------- # Step 4. Compile qcom-metadata.dts → qcom-metadata.dtb From 76c01b397d819d54b1a3eafe9914534748993091 Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Thu, 2 Apr 2026 19:16:57 -0700 Subject: [PATCH 2/4] rootfs: fix grub.cfg generation when using pkg-linux-qcom kernel package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The /etc/kernel/postinst.d/zz-update-grub hook (grub-common) guards its update-grub call with a systemd check: if [ -d /run/systemd/system ]; then update-grub || true; fi In a chroot environment systemd is not running, so /run/systemd/system does not exist and update-grub is silently skipped. This left /boot/grub/grub.cfg absent, causing the subsequent sed-based GRUB cleanup to fail with: sed: can't read /boot/grub/grub.cfg: No such file or directory The build-kernel-deb.sh-generated package calls update-grub directly in its postinst (unconditionally), so it was unaffected. The pkg-linux-qcom package follows the Debian standard of delegating to postinst.d hooks, which exposed this chroot-specific gap. Fix: call update-grub explicitly in the chroot immediately after kernel installation, bypassing the systemd guard. No changes to the kernel package postinst — grub.cfg generation is the build script's responsibility in a chroot context. Signed-off-by: Bjordis Collaku --- rootfs/scripts/build-rootfs.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rootfs/scripts/build-rootfs.sh b/rootfs/scripts/build-rootfs.sh index 8a7d10d..ddbb59f 100755 --- a/rootfs/scripts/build-rootfs.sh +++ b/rootfs/scripts/build-rootfs.sh @@ -551,6 +551,10 @@ echo '[CHROOT] Installing custom firmware and kernel...' $CMD_FW_INSTALL yes \"\" | dpkg -i /$(basename "$KERNEL_DEB") +# Run update-grub explicitly: the zz-update-grub hook skips it in a chroot +# because systemd is not running (/run/systemd/system absent). +update-grub + adduser --disabled-password --gecos '' qcom echo 'qcom:qcom' | chpasswd usermod -aG sudo qcom From 3386dd05f3be774410390734a2536b5815de76e6 Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Fri, 3 Apr 2026 14:48:39 -0700 Subject: [PATCH 3/4] build-dtb-image: probe usr/lib/firmware/ first for usrmerge .deb layout pkg-linux-qcom now installs the device-tree compat symlink under usr/lib/firmware//device-tree (usrmerge layout). Update the --kernel-deb DTB discovery to check usr/lib/firmware/ first and fall back to lib/firmware/ for legacy packages, so both layouts are handled transparently. Signed-off-by: Bjordis Collaku --- kernel/scripts/build-dtb-image.sh | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/kernel/scripts/build-dtb-image.sh b/kernel/scripts/build-dtb-image.sh index ef87586..5d8655c 100755 --- a/kernel/scripts/build-dtb-image.sh +++ b/kernel/scripts/build-dtb-image.sh @@ -19,10 +19,11 @@ # - Provide a Debian kernel package (.deb) as input. # - The script extracts the .deb via `dpkg-deb -R` into a temp directory. # - DTBs are expected to be present under: -# $DEB_DIR/lib/firmware/$BASE_KERNEL_VERSION/device-tree +# $DEB_DIR/usr/lib/firmware/$BASE_KERNEL_VERSION/device-tree (usrmerge layout) +# $DEB_DIR/lib/firmware/$BASE_KERNEL_VERSION/device-tree (legacy layout) # where $BASE_KERNEL_VERSION can be anything. -# - The script assumes there is exactly ONE: -# $DEB_DIR/lib/firmware/*/device-tree +# - The script assumes there is exactly ONE device-tree directory across +# both search paths. # # (B) DTB source directory mode (dev/kernel-tree mode) # - Provide the DTB source directory directly (e.g. a kernel build tree): @@ -171,7 +172,9 @@ usage() { Usage: $0 (--kernel-deb | --dtb-src ) --manifest [--size ] [--out ] --kernel-deb, -kernel-deb Path to Debian kernel package (.deb). DTBs read from: - /lib/firmware/*/device-tree (must be exactly one) + /usr/lib/firmware/*/device-tree (usrmerge layout) + /lib/firmware/*/device-tree (legacy layout) + Exactly one device-tree directory must be found. --dtb-src, -dtb-src Path to DTB source directory (e.g. arch/arm64/boot/dts/qcom) @@ -361,13 +364,21 @@ if [[ -n "${KERNEL_DEB}" ]]; then echo "[INFO] Extracting kernel .deb to: ${DEB_DIR}" dpkg-deb -R "${KERNEL_DEB}" "${DEB_DIR}" - # Locate exactly one device-tree directory under lib/firmware/*/device-tree + # Locate exactly one device-tree directory. + # Modern packages (usrmerge / pkg-linux-qcom) install the compat symlink under + # usr/lib/firmware//device-tree; legacy packages used lib/firmware/. + # Check usr/lib/firmware/ first; fall back to lib/firmware/. shopt -s nullglob - dt_dirs=( "${DEB_DIR}/lib/firmware"/*/device-tree ) + dt_dirs=( "${DEB_DIR}/usr/lib/firmware"/*/device-tree ) + if (( ${#dt_dirs[@]} == 0 )); then + dt_dirs=( "${DEB_DIR}/lib/firmware"/*/device-tree ) + fi shopt -u nullglob if (( ${#dt_dirs[@]} == 0 )); then - echo "[ERROR] No DTB directory found at '${DEB_DIR}/lib/firmware/*/device-tree'." >&2 + echo "[ERROR] No DTB directory found under:" >&2 + echo " '${DEB_DIR}/usr/lib/firmware/*/device-tree'" >&2 + echo " '${DEB_DIR}/lib/firmware/*/device-tree'" >&2 exit 1 fi if (( ${#dt_dirs[@]} > 1 )); then @@ -519,7 +530,7 @@ else if (( dtb_count == 0 )); then echo "[ERROR] No DTB files found under ${DTB_SRC}" >&2 echo " Verify the kernel package was built with DTB support" >&2 - echo " and that lib/firmware/*/device-tree resolves correctly." >&2 + echo " and that usr/lib/firmware/*/device-tree resolves correctly." >&2 exit 1 fi echo "[INFO] Staged ${dtb_count} DTB file(s) to ${DTB_STAGE}" From e5b64c713bb80bbf43f57444a1a4f2562bef1f28 Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Thu, 9 Apr 2026 15:53:35 -0700 Subject: [PATCH 4/4] build-dtb-image: probe Debian standard DTB path first in --kernel-deb mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When extracting DTBs from a kernel .deb, probe paths in order: 1. usr/lib/linux-image-*/ (Debian standard — direct, no symlink) 2. usr/lib/firmware/*/device-tree (Ubuntu compat, usrmerge layout) 3. lib/firmware/*/device-tree (Ubuntu compat, legacy layout) Probing the Debian standard path first avoids any dependency on the Ubuntu compat symlink and works correctly on pure Debian systems that never install it, as well as on Ubuntu regardless of usrmerge layout. The fallback chain is fully backward compatible: legacy packages (built by build-kernel-deb.sh) only populate lib/firmware/, so the script falls through steps 1 and 2 and resolves via step 3 as before. Signed-off-by: Bjordis Collaku --- kernel/scripts/build-dtb-image.sh | 42 +++++++++++++++++++------------ 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/kernel/scripts/build-dtb-image.sh b/kernel/scripts/build-dtb-image.sh index 5d8655c..9062f9a 100755 --- a/kernel/scripts/build-dtb-image.sh +++ b/kernel/scripts/build-dtb-image.sh @@ -18,12 +18,13 @@ # (A) Kernel .deb mode (recommended / upstream-friendly) # - Provide a Debian kernel package (.deb) as input. # - The script extracts the .deb via `dpkg-deb -R` into a temp directory. -# - DTBs are expected to be present under: -# $DEB_DIR/usr/lib/firmware/$BASE_KERNEL_VERSION/device-tree (usrmerge layout) -# $DEB_DIR/lib/firmware/$BASE_KERNEL_VERSION/device-tree (legacy layout) -# where $BASE_KERNEL_VERSION can be anything. -# - The script assumes there is exactly ONE device-tree directory across -# both search paths. +# - DTBs are located by probing the following paths in order: +# 1. $DEB_DIR/usr/lib/linux-image-*/ (Debian standard — direct, no symlink) +# 2. $DEB_DIR/usr/lib/firmware/*/device-tree (Ubuntu compat, usrmerge layout) +# 3. $DEB_DIR/lib/firmware/*/device-tree (Ubuntu compat, legacy layout) +# Probing the Debian standard path first ensures correct operation on +# both Debian and Ubuntu regardless of whether the compat symlink exists. +# - The script assumes there is exactly ONE matching directory. # # (B) DTB source directory mode (dev/kernel-tree mode) # - Provide the DTB source directory directly (e.g. a kernel build tree): @@ -171,10 +172,11 @@ usage() { cat < | --dtb-src ) --manifest [--size ] [--out ] - --kernel-deb, -kernel-deb Path to Debian kernel package (.deb). DTBs read from: - /usr/lib/firmware/*/device-tree (usrmerge layout) - /lib/firmware/*/device-tree (legacy layout) - Exactly one device-tree directory must be found. + --kernel-deb, -kernel-deb Path to Debian kernel package (.deb). DTBs located by probing: + 1. /usr/lib/linux-image-*/ (Debian standard) + 2. /usr/lib/firmware/*/device-tree (Ubuntu, usrmerge) + 3. /lib/firmware/*/device-tree (Ubuntu, legacy) + Exactly one directory must be found across all search paths. --dtb-src, -dtb-src Path to DTB source directory (e.g. arch/arm64/boot/dts/qcom) @@ -364,12 +366,19 @@ if [[ -n "${KERNEL_DEB}" ]]; then echo "[INFO] Extracting kernel .deb to: ${DEB_DIR}" dpkg-deb -R "${KERNEL_DEB}" "${DEB_DIR}" - # Locate exactly one device-tree directory. - # Modern packages (usrmerge / pkg-linux-qcom) install the compat symlink under - # usr/lib/firmware//device-tree; legacy packages used lib/firmware/. - # Check usr/lib/firmware/ first; fall back to lib/firmware/. + # Locate the DTB directory from the extracted .deb. + # Probe in order (most to least preferred): + # 1. usr/lib/linux-image-*/ — Debian standard install location (direct, no symlink). + # Works on both Debian and Ubuntu regardless of usrmerge. + # 2. usr/lib/firmware/*/device-tree — Ubuntu compat symlink (usrmerge layout). + # 3. lib/firmware/*/device-tree — Ubuntu compat symlink (legacy layout). + # Searching the Debian standard path first avoids any dependency on the Ubuntu + # compat symlink and is correct on pure Debian systems that never install it. shopt -s nullglob - dt_dirs=( "${DEB_DIR}/usr/lib/firmware"/*/device-tree ) + dt_dirs=( "${DEB_DIR}/usr/lib/linux-image-"*/ ) + if (( ${#dt_dirs[@]} == 0 )); then + dt_dirs=( "${DEB_DIR}/usr/lib/firmware"/*/device-tree ) + fi if (( ${#dt_dirs[@]} == 0 )); then dt_dirs=( "${DEB_DIR}/lib/firmware"/*/device-tree ) fi @@ -377,6 +386,7 @@ if [[ -n "${KERNEL_DEB}" ]]; then if (( ${#dt_dirs[@]} == 0 )); then echo "[ERROR] No DTB directory found under:" >&2 + echo " '${DEB_DIR}/usr/lib/linux-image-*/'" >&2 echo " '${DEB_DIR}/usr/lib/firmware/*/device-tree'" >&2 echo " '${DEB_DIR}/lib/firmware/*/device-tree'" >&2 exit 1 @@ -530,7 +540,7 @@ else if (( dtb_count == 0 )); then echo "[ERROR] No DTB files found under ${DTB_SRC}" >&2 echo " Verify the kernel package was built with DTB support" >&2 - echo " and that usr/lib/firmware/*/device-tree resolves correctly." >&2 + echo " and that usr/lib/linux-image-*/ is present in the package." >&2 exit 1 fi echo "[INFO] Staged ${dtb_count} DTB file(s) to ${DTB_STAGE}"