From 0147de25e492d6426a79fdb7e75691c98733bf1c Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Wed, 4 Feb 2026 16:50:04 -0800 Subject: [PATCH 1/9] build-rootfs: Replace manual GRUB config with standard update-grub workflow This commit replaces the static, manual generation of /boot/grub.cfg with the standard Debian update-grub mechanism. This change ensures that the bootloader configuration is automatically synchronized with installed kernels and adheres to standard distribution practices. Key Changes: * Standard Implementation: Replaced the manual file write of /boot/grub.cfg with the generation of /etc/default/grub followed by execution of update-grub. * Dependency Management: Added grub-common and grub2-common to the debootstrap package list to provide the necessary tools (grub-mkconfig, grub-probe) inside the chroot. * Correct Recovery Mode: Configured critical hardware arguments (console, root label, EFI) in GRUB_CMDLINE_LINUX. Unlike the previous single-entry manual config, this ensures that auto-generated "Recovery Mode" entries retain necessary drivers and serial console output. * Filesystem Addressing: Set GRUB_DISABLE_LINUX_UUID=true to force root=LABEL=system, maintaining portability for the generic rootfs image. Signed-off-by: Bjordis Collaku --- rootfs/scripts/build-rootfs.sh | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/rootfs/scripts/build-rootfs.sh b/rootfs/scripts/build-rootfs.sh index e49f2fac..6bd10aac 100755 --- a/rootfs/scripts/build-rootfs.sh +++ b/rootfs/scripts/build-rootfs.sh @@ -206,6 +206,8 @@ _seed_to_debootstrap_include() { passwd systemd-sysv apt + grub-common + grub2-commong ) for p in "${required_pkgs[@]}"; do @@ -510,16 +512,26 @@ kernel_ver=$(basename "$KERNEL_DEB" \ | sed 's|^linux-kernel-\(.*\)-arm64\.deb$|\1|' \ | sed 's|-[0-9][0-9]*-[0-9][0-9]*$||') -echo '[CHROOT] Writing GRUB configuration for single DTB-agnostic entry...' -tee /boot/grub.cfg > /dev/null < /etc/default/grub +GRUB_DEFAULT=0 +GRUB_TIMEOUT=5 +GRUB_DISTRIBUTOR=\`lsb_release -i -s 2> /dev/null || echo Debian\` -menuentry \"\${DISTRO} \${CODENAME}\" { - search --no-floppy --label system --set=root - linux /boot/vmlinuz-\$kernel_ver earlycon console=ttyMSM0,115200n8 root=LABEL=system cma=128M rw clk_ignore_unused pd_ignore_unused efi=noruntime rootwait ignore_loglevel - initrd /boot/initrd.img-\$kernel_ver -} -GRUBCFG +# 1. CRITICAL HARDWARE SETTINGS (Applies to Normal AND Recovery) +# These are required for the board to physically boot and show output. +GRUB_CMDLINE_LINUX="earlycon console=ttyMSM0,115200n8 root=LABEL=system cma=128M rw clk_ignore_unused pd_ignore_unused efi=noruntime rootwait ignore_loglevel" + +# 2. OPTIONAL UX SETTINGS (Applies to Normal only) +# Leave empty so Recovery Mode gives you full verbose logs without extra noise. +GRUB_CMDLINE_LINUX_DEFAULT="" + +# 3. Use LABEL=system instead of UUID (Required for generic images) +GRUB_DISABLE_LINUX_UUID=true +EOF + +echo '[CHROOT] Generating grub.cfg via update-grub...' +update-grub " # ============================================================================== From f0e40b99eaeae6b5a5cc9b0c50790ea1c44edaf0 Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Wed, 4 Feb 2026 17:02:59 -0800 Subject: [PATCH 2/9] Fix typo in package name from 'grub2-commong' to 'grub2-common' Signed-off-by: Bjordis Collaku --- rootfs/scripts/build-rootfs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootfs/scripts/build-rootfs.sh b/rootfs/scripts/build-rootfs.sh index 6bd10aac..4f4336e0 100755 --- a/rootfs/scripts/build-rootfs.sh +++ b/rootfs/scripts/build-rootfs.sh @@ -207,7 +207,7 @@ _seed_to_debootstrap_include() { systemd-sysv apt grub-common - grub2-commong + grub2-common ) for p in "${required_pkgs[@]}"; do From 34dc75ff9bbfe15ce252b92746aaf1abd18781c2 Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Wed, 4 Feb 2026 17:36:47 -0800 Subject: [PATCH 3/9] build-rootfs: Move GRUB config generation to host to fix nesting issues This commit refactors the GRUB configuration logic by moving the generation of /etc/default/grub from the chroot environment to the host context. Generating the configuration file inside the nested chroot command string caused shell quoting conflicts and prevented the reliable writing of the config file (specifically affecting heredoc termination and variable escaping). Key Changes: * Host-Side Generation: Extracted the config writing logic to a new pre-chroot step (Step 7.5). It now uses a quoted heredoc (cat <<'EOF') to write the file directly into the mounted rootfs. * Stability: This ensures that variables and backticks (e.g., for `lsb_release`) are written literally to the file and not interpreted by the host shell. * Clean Execution: The chroot step (Step 8) is now simplified to strictly run `update-grub`, relying on the correctly pre-seeded configuration file. Signed-off-by: Bjordis Collaku --- rootfs/scripts/build-rootfs.sh | 41 +++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/rootfs/scripts/build-rootfs.sh b/rootfs/scripts/build-rootfs.sh index 4f4336e0..eff4d053 100755 --- a/rootfs/scripts/build-rootfs.sh +++ b/rootfs/scripts/build-rootfs.sh @@ -433,6 +433,26 @@ mount -o bind /sys "$ROOTFS_DIR/sys" mount -o bind /dev "$ROOTFS_DIR/dev" mount --bind /dev/pts "$ROOTFS_DIR/dev/pts" +# ============================================================================== +# Step 7.5: Configure GRUB defaults +# ============================================================================== +echo "[INFO] configuring /etc/default/grub..." + +cat < "$ROOTFS_DIR/etc/default/grub" +GRUB_DEFAULT=0 +GRUB_TIMEOUT=5 +GRUB_DISTRIBUTOR=\`lsb_release -i -s 2> /dev/null || echo Debian\` + +# Critical hardware settings (Applies to Normal and Recovery modes) +GRUB_CMDLINE_LINUX="earlycon console=ttyMSM0,115200n8 root=LABEL=system cma=128M rw clk_ignore_unused pd_ignore_unused efi=noruntime rootwait ignore_loglevel" + +# Optional UX settings (Applies to Normal mode only) +GRUB_CMDLINE_LINUX_DEFAULT="" + +# Force filesystem label usage for generic image portability +GRUB_DISABLE_LINUX_UUID=true +EOF + # ============================================================================== # Step 8: Enter chroot to Install Packages and Configure GRUB # ============================================================================== @@ -512,26 +532,11 @@ kernel_ver=$(basename "$KERNEL_DEB" \ | sed 's|^linux-kernel-\(.*\)-arm64\.deb$|\1|' \ | sed 's|-[0-9][0-9]*-[0-9][0-9]*$||') -echo '[CHROOT] Configuring /etc/default/grub...' -cat < /etc/default/grub -GRUB_DEFAULT=0 -GRUB_TIMEOUT=5 -GRUB_DISTRIBUTOR=\`lsb_release -i -s 2> /dev/null || echo Debian\` - -# 1. CRITICAL HARDWARE SETTINGS (Applies to Normal AND Recovery) -# These are required for the board to physically boot and show output. -GRUB_CMDLINE_LINUX="earlycon console=ttyMSM0,115200n8 root=LABEL=system cma=128M rw clk_ignore_unused pd_ignore_unused efi=noruntime rootwait ignore_loglevel" - -# 2. OPTIONAL UX SETTINGS (Applies to Normal only) -# Leave empty so Recovery Mode gives you full verbose logs without extra noise. -GRUB_CMDLINE_LINUX_DEFAULT="" - -# 3. Use LABEL=system instead of UUID (Required for generic images) -GRUB_DISABLE_LINUX_UUID=true -EOF - echo '[CHROOT] Generating grub.cfg via update-grub...' update-grub + +# Ensure compatibility with bootloaders expecting the legacy path +ln -sf /boot/grub/grub.cfg /boot/grub.cfg " # ============================================================================== From b1d0c096b102bb6320af07b11c7c28df9ccb6f00 Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Wed, 4 Feb 2026 23:23:49 -0800 Subject: [PATCH 4/9] build-rootfs: Fix missing /boot/grub directory causing update-grub failure This commit resolves a build failure where `grub-mkconfig` (invoked by `update-grub`) exited with "Directory nonexistent". The error occurred because the `/boot/grub` directory structure was not present in the rootfs prior to the execution of `update-grub`. The transition to host-side configuration requires explicitly creating these artifact directories, as they are not guaranteed to be populated by `debootstrap` at this stage. Key Changes: * Explicitly added `mkdir -p` for `/boot/grub` and `/etc/default` in Step 7.5. * Ensures the destination directory exists before the host writes the configuration file or the chroot attempts to generate the boot menu. --- rootfs/scripts/build-rootfs.sh | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/rootfs/scripts/build-rootfs.sh b/rootfs/scripts/build-rootfs.sh index eff4d053..42730bcd 100755 --- a/rootfs/scripts/build-rootfs.sh +++ b/rootfs/scripts/build-rootfs.sh @@ -436,20 +436,27 @@ mount --bind /dev/pts "$ROOTFS_DIR/dev/pts" # ============================================================================== # Step 7.5: Configure GRUB defaults # ============================================================================== -echo "[INFO] configuring /etc/default/grub..." +echo "[INFO] Configuring /etc/default/grub..." -cat < "$ROOTFS_DIR/etc/default/grub" +# Ensure target directories exist before writing configuration +mkdir -p "$ROOTFS_DIR/boot/grub" +mkdir -p "$ROOTFS_DIR/etc/default" + +# Write GRUB defaults using quoted heredoc to prevent host-side expansion +cat <<'EOF' > "$ROOTFS_DIR/etc/default/grub" GRUB_DEFAULT=0 GRUB_TIMEOUT=5 -GRUB_DISTRIBUTOR=\`lsb_release -i -s 2> /dev/null || echo Debian\` +GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian` -# Critical hardware settings (Applies to Normal and Recovery modes) +# Kernel parameters applied to BOTH Normal and Recovery boot modes +# (Critical hardware settings: console, rootfs, clocks, EFI) GRUB_CMDLINE_LINUX="earlycon console=ttyMSM0,115200n8 root=LABEL=system cma=128M rw clk_ignore_unused pd_ignore_unused efi=noruntime rootwait ignore_loglevel" -# Optional UX settings (Applies to Normal mode only) +# Kernel parameters applied ONLY to Normal boot mode +# (UX settings: quiet, splash, etc. - Left empty for verbose output) GRUB_CMDLINE_LINUX_DEFAULT="" -# Force filesystem label usage for generic image portability +# Disable UUIDs to support generic filesystem images GRUB_DISABLE_LINUX_UUID=true EOF From 6cc7faf57fe1ce7044fc20684b26a82771251f07 Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Thu, 5 Feb 2026 09:41:08 -0800 Subject: [PATCH 5/9] build-rootfs: Sanitize generated GRUB config for generic portability This commit implements a post-processing stage for the GRUB configuration to resolve "host contamination" issues. When `update-grub` runs inside the chroot, it probes the build host's hardware, incorrectly baking the host's filesystem UUIDs and block device paths (e.g., `/dev/nvme0n1p1`) into the target image. This patch scrubs these host-specific artifacts to ensure the generated rootfs is generic and portable. Key Changes: - Enforce Label-Based Search: Replaces the standard `search --fs-uuid` command with `search --label system` via sed. This ensures the bootloader can locate the kernel partition regardless of the underlying storage UUID. - Sanitize Kernel Command Line: Strips the host-detected `root=/dev/xxx` parameter. This prevents conflicts with the intended `root=LABEL=system` argument defined in `/etc/default/grub`. - Relative Compatibility Symlink: Updates the legacy `/boot/grub.cfg` symlink to use a relative path (`grub/grub.cfg`) instead of an absolute one, ensuring correct resolution on both the target and the build host. Signed-off-by: Bjordis Collaku --- rootfs/scripts/build-rootfs.sh | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/rootfs/scripts/build-rootfs.sh b/rootfs/scripts/build-rootfs.sh index 42730bcd..b3a8da24 100755 --- a/rootfs/scripts/build-rootfs.sh +++ b/rootfs/scripts/build-rootfs.sh @@ -542,8 +542,23 @@ kernel_ver=$(basename "$KERNEL_DEB" \ echo '[CHROOT] Generating grub.cfg via update-grub...' update-grub -# Ensure compatibility with bootloaders expecting the legacy path -ln -sf /boot/grub/grub.cfg /boot/grub.cfg +# ============================================================================== +# POST-PROCESSING: GRUB Configuration Cleanup & Standardization +# ============================================================================== + +# 1. Enforce Generic Partition Search +# Replace host-detected UUIDs with stable Label searching to ensure +# the image boots on any storage medium. +sed -i 's/search --no-floppy --fs-uuid --set=root .*/search --no-floppy --label system --set=root/g' /boot/grub/grub.cfg + +# 2. Clean Kernel Command Line +# Remove the host-detected root device (e.g., root=/dev/nvme0n1p1) to prevent +# conflicts with our 'root=LABEL=system' argument. +sed -i 's/root=\/dev\/[^ ]* //g' /boot/grub/grub.cfg + +# 3. Legacy Compatibility +# Create a relative symlink for bootloaders expecting the old path. +ln -sf grub/grub.cfg /boot/grub.cfg " # ============================================================================== From db20d11a11e48a67b0aa3bcaed9f2a5de58450c1 Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Thu, 5 Feb 2026 09:47:35 -0800 Subject: [PATCH 6/9] build-rootfs: Remove unused kernel version detection logic Remove the manual kernel version extraction logic (kernel_ver calculation) from Step 8. This variable was previously required for manually constructing grub.cfg menu entries. With the transition to the standard `update-grub` workflow, the kernel version is automatically detected by scanning /boot, making this explicit parsing redundant and unused. Signed-off-by: Bjordis Collaku --- rootfs/scripts/build-rootfs.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rootfs/scripts/build-rootfs.sh b/rootfs/scripts/build-rootfs.sh index b3a8da24..cac8c4d5 100755 --- a/rootfs/scripts/build-rootfs.sh +++ b/rootfs/scripts/build-rootfs.sh @@ -533,12 +533,6 @@ rm -f /tmp/\${CODENAME}_post.manifest /tmp/sorted_base.manifest /tmp/sorted_post echo '[CHROOT] Base package list preserved as /tmp/\${CODENAME}_base.manifest' echo '[CHROOT] Custom installed packages saved to /tmp/packages_\${DATE}.manifest' -echo '[CHROOT] Detecting installed kernel version...' - -kernel_ver=$(basename "$KERNEL_DEB" \ - | sed 's|^linux-kernel-\(.*\)-arm64\.deb$|\1|' \ - | sed 's|-[0-9][0-9]*-[0-9][0-9]*$||') - echo '[CHROOT] Generating grub.cfg via update-grub...' update-grub From 14ae106a7f654cf90ef52110f1c2cfdf301ed350 Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Thu, 5 Feb 2026 10:01:12 -0800 Subject: [PATCH 7/9] build-rootfs: Remove redundant update-grub invocation This commit removes the explicit `update-grub` call from the build sequence, delegating bootloader configuration entirely to the kernel package's installation hooks. The generation of `grub.cfg` is guaranteed by the kernel package's `postinst` script, which executes `update-grub` immediately following `update-initramfs`. Eliminating the secondary invocation in the build script reduces redundancy while maintaining reliance on standard package management lifecycle events to populate the bootloader configuration prior to image finalization. Signed-off-by: Bjordis Collaku --- rootfs/scripts/build-rootfs.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/rootfs/scripts/build-rootfs.sh b/rootfs/scripts/build-rootfs.sh index cac8c4d5..a2a79f4d 100755 --- a/rootfs/scripts/build-rootfs.sh +++ b/rootfs/scripts/build-rootfs.sh @@ -533,11 +533,8 @@ rm -f /tmp/\${CODENAME}_post.manifest /tmp/sorted_base.manifest /tmp/sorted_post echo '[CHROOT] Base package list preserved as /tmp/\${CODENAME}_base.manifest' echo '[CHROOT] Custom installed packages saved to /tmp/packages_\${DATE}.manifest' -echo '[CHROOT] Generating grub.cfg via update-grub...' -update-grub - # ============================================================================== -# POST-PROCESSING: GRUB Configuration Cleanup & Standardization +# GRUB Configuration Cleanup & Standardization # ============================================================================== # 1. Enforce Generic Partition Search From 677c9b3803b4f2c54df61c1d37ecf0fbce9a4118 Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Thu, 5 Feb 2026 11:25:43 -0800 Subject: [PATCH 8/9] build-rootfs: Enable dual-output GRUB menu (Serial + Console) This commit configures the GRUB bootloader to simultaneously output its menu to both the serial port and the attached display. By default, `update-grub` prioritizes graphical terminals (gfxterm) or auto-detects a single output, often rendering the menu invisible on headless serial connections or embedded displays without full driver support. This change explicitly sets `GRUB_TERMINAL="serial console"`, ensuring the menu is accessible via the serial debug port (115200 baud) and the native text-mode console on HDMI/DP. Signed-off-by: Bjordis Collaku --- rootfs/scripts/build-rootfs.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rootfs/scripts/build-rootfs.sh b/rootfs/scripts/build-rootfs.sh index a2a79f4d..d8e8c7df 100755 --- a/rootfs/scripts/build-rootfs.sh +++ b/rootfs/scripts/build-rootfs.sh @@ -448,6 +448,12 @@ GRUB_DEFAULT=0 GRUB_TIMEOUT=5 GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian` +# --- DUAL OUTPUT CONFIGURATION --- +# "serial" -> Outputs menu to the serial port +# "console" -> Outputs menu to the attached display (HDMI/DP) in text mode +GRUB_TERMINAL="serial console" +GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1" + # Kernel parameters applied to BOTH Normal and Recovery boot modes # (Critical hardware settings: console, rootfs, clocks, EFI) GRUB_CMDLINE_LINUX="earlycon console=ttyMSM0,115200n8 root=LABEL=system cma=128M rw clk_ignore_unused pd_ignore_unused efi=noruntime rootwait ignore_loglevel" From 4a44f23a415d1d60db4d0a156515d1f1b62ee671 Mon Sep 17 00:00:00 2001 From: Bjordis Collaku Date: Wed, 11 Feb 2026 13:44:40 -0800 Subject: [PATCH 9/9] build-rootfs: Implement post-processing Device Tree injection for Debian This commit introduces a platform-specific bootloader configuration stage for ARM64 Debian targets. Since the standard GRUB generation logic in the target environment does not natively support automated DTB loading via variables, this change implements a surgical post-processing step at the end of the chroot phase: 1. Dynamic Resolution: Uses a multi-path search (/usr/lib and /lib/firmware) to locate the 'glymur-crd.dtb' platform description. 2. Visibility: Establishes a stable '/boot/dtb' symlink to ensure the bootloader can access hardware descriptions within its filesystem scope. 3. Injection: Directly patches the generated 'grub.cfg' to include the 'devicetree' directive following the 'initrd' load sequence. This approach ensures hardware-specific initialization is successful on first boot while maintaining compatibility with the host's existing distribution-specific GRUB scripts. Signed-off-by: Bjordis Collaku --- rootfs/scripts/build-rootfs.sh | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/rootfs/scripts/build-rootfs.sh b/rootfs/scripts/build-rootfs.sh index ccdf6b0d..71bae5b9 100755 --- a/rootfs/scripts/build-rootfs.sh +++ b/rootfs/scripts/build-rootfs.sh @@ -568,6 +568,32 @@ sed -i 's/root=\/dev\/[^ ]* //g' /boot/grub/grub.cfg # 3. Legacy Compatibility # Create a relative symlink for bootloaders expecting the old path. ln -sf grub/grub.cfg /boot/grub.cfg + +# ============================================================================== +# Device Tree Configuration for Debian platforms +# ============================================================================== + +if [ \"\${distro_lc}\" = \"debian\" ]; then + echo '[INFO][CHROOT] Debian target detected. Configuring platform Device Tree...' + + # Locate the platform Device Tree Blob (DTB) in standard library or firmware paths + DTB_PATH=\$(find /usr/lib /lib/firmware -name \"glymur-crd.dtb\" -print -quit) + + if [ -n \"\$DTB_PATH\" ]; then + echo \"[INFO][CHROOT] Platform DTB resolved: \$DTB_PATH\" + + # Ensure DTB is accessible in the bootloader's filesystem scope + ln -sf \"\$DTB_PATH\" /boot/dtb + + # Inject the devicetree directive into the generated GRUB configuration. + # This appends the command immediately following the 'initrd' load. + sed -i \"/^[[:space:]]*initrd/a \ devicetree /boot/dtb\" /boot/grub/grub.cfg + + echo '[SUCCESS][CHROOT] Device Tree directive injected into /boot/grub/grub.cfg' + else + echo '[WARN][CHROOT] Target DTB (glymur-crd.dtb) not found. Skipping injection.' + fi +fi " # ==============================================================================