From 2fba2bd4cd0f8bc3a9275ef753802ee4181821a0 Mon Sep 17 00:00:00 2001 From: Jan De Landtsheer Date: Sat, 20 Sep 2025 16:11:44 +0200 Subject: [PATCH] initramfs+kernel: path anchors, helper, and init debug hook initramfs: anchor relative paths to PROJECT_ROOT in [bash.initramfs_validate()](scripts/lib/initramfs.sh:799) and [bash.initramfs_create_cpio()](scripts/lib/initramfs.sh:688) to avoid CWD drift. Add diagnostics logs. kernel: anchor kernel output path to PROJECT_ROOT in [bash.kernel_build_with_initramfs()](scripts/lib/kernel.sh:174) to ensure dist/vmlinuz.efi is under PROJECT_ROOT/dist. helper: add [scripts/rebuild-after-zinit.sh](scripts/rebuild-after-zinit.sh) to incrementally rebuild after zinit/modules.conf/init changes. Default: initramfs-only (recreates cpio). Flags: --with-kernel, --refresh-container-mods, --run-tests. Uses --rebuild-from=initramfs_create when rebuilding kernel. init: add early debug shell on kernel param initdebug=true; prefer /init-debug when present else spawn /bin/sh -l. See [config/init](config/init:1). modules(stage1): add USB keyboard support (HID + host controllers) in [config/modules.conf](config/modules.conf:1): usbhid, hid_generic, hid, xhci/ehci/ohci/uhci. --- config/init | 29 +++++++-- config/modules.conf | 17 +++++ scripts/lib/initramfs.sh | 18 +++++ scripts/lib/kernel.sh | 22 +++++-- scripts/rebuild-after-zinit.sh | 116 +++++++++++++++++++++++++++++++++ 5 files changed, 194 insertions(+), 8 deletions(-) create mode 100755 scripts/rebuild-after-zinit.sh diff --git a/config/init b/config/init index dc41479..c2ac727 100755 --- a/config/init +++ b/config/init @@ -24,6 +24,12 @@ mount -t devtmpfs devtmpfs /dev mkdir -p /dev/pts mount -t devpts devpts /dev/pts +# Early debug shell if kernel parameter initdebug=true is present +if grep -qw "initdebug=true" /proc/cmdline; then + echo "[+] initdebug=true detected; starting emergency shell. Type 'exit' to continue boot." + /bin/sh -l +fi + echo "[+] building ram filesystem" @@ -100,19 +106,34 @@ modprobe virtio_net 2>/dev/null || true modprobe e1000 2>/dev/null || true modprobe e1000e 2>/dev/null || true +echo "[+] loading USB keyboard support" +modprobe usbcore +modprobe ehci-hcd +modprobe xhci-hcd +modprobe usbhid +modprobe evdev + # Unmount init filesystems umount /proc 2>/dev/null || true umount /sys 2>/dev/null || true -echo "[+] checking for debug files" -if [ -e /init-debug ]; then - echo " executing debug script..." +echo "[+] debug hook: initdebug=true or /init-debug" +if grep -qw "initdebug=true" /proc/cmdline; then + if [ -x /init-debug ]; then + echo " initdebug=true: executing /init-debug ..." + sh /init-debug + else + echo " initdebug=true: starting interactive shell (no /init-debug). Type 'exit' to continue." + /bin/sh -l + fi +elif [ -x /init-debug ]; then + echo " executing /init-debug ..." sh /init-debug fi echo "[+] switching root" mkdir /root/home echo " exec switch_root /mnt/root /sbin/zinit init" -exec switch_root /mnt/root /sbin/zinit init +exec switch_root /mnt/root /sbin/zinit -d init ## diff --git a/config/modules.conf b/config/modules.conf index ce6fbed..8cfb874 100644 --- a/config/modules.conf +++ b/config/modules.conf @@ -38,3 +38,20 @@ stage1:tun:none # TUN/TAP for networking stage1:overlay:none # OverlayFS for containers stage1:fuse:none # OverlayFS for containers +# Stage 1: USB keyboard support (host controllers + HID) +stage1:xhci_pci:none +stage1:xhci_hcd:none +stage1:ehci_pci:none +stage1:ehci_hcd:none +stage1:ohci_pci:none +stage1:ohci_hcd:none +stage1:uhci_hcd:none +stage1:usbhid:none +stage1:hid_generic:none +stage1:hid:none +stage1:atkbd:none +stage1:libps2:none +stage1:i2c_smbus:none +stage1:serio:none +stage1:i8042i:none + diff --git a/scripts/lib/initramfs.sh b/scripts/lib/initramfs.sh index 08e9516..19e8403 100644 --- a/scripts/lib/initramfs.sh +++ b/scripts/lib/initramfs.sh @@ -691,6 +691,24 @@ function initramfs_create_cpio() { local compression="${3:-$INITRAMFS_COMPRESSION}" section_header "Creating initramfs.cpio.${compression}" + + # Diagnostics and path normalization (anchor relative to PROJECT_ROOT) + log_info "Create CPIO debug: input='${initramfs_dir}' PWD=$(pwd) PROJECT_ROOT=${PROJECT_ROOT:-unset}" + local _initramfs_dir_resolved + if is_absolute_path "${initramfs_dir}"; then + _initramfs_dir_resolved="${initramfs_dir}" + log_debug "Create CPIO path strategy: absolute input honored" + else + if [[ -n "${PROJECT_ROOT:-}" ]]; then + _initramfs_dir_resolved="${PROJECT_ROOT}/${initramfs_dir#./}" + log_debug "Create CPIO path strategy: relative input anchored to PROJECT_ROOT" + else + _initramfs_dir_resolved="$(pwd)/${initramfs_dir}" + log_warn "PROJECT_ROOT unset; falling back to PWD anchoring" + fi + fi + log_info "Create CPIO debug: resolved initramfs_dir='${_initramfs_dir_resolved}'" + initramfs_dir="${_initramfs_dir_resolved}" if [[ ! -d "$initramfs_dir" ]]; then log_error "Initramfs directory not found: ${initramfs_dir}" diff --git a/scripts/lib/kernel.sh b/scripts/lib/kernel.sh index f2a9e63..9d03101 100644 --- a/scripts/lib/kernel.sh +++ b/scripts/lib/kernel.sh @@ -206,15 +206,29 @@ function kernel_build_with_initramfs() { return 1 fi + # Resolve output path to absolute BEFORE cd side-effects influence relative paths + local output_abs="$output_file" + if [[ "$output_abs" != /* ]]; then + if [[ -n "${PROJECT_ROOT:-}" ]]; then + output_abs="${PROJECT_ROOT}/${output_abs#./}" + log_debug "kernel_build_with_initramfs: output path anchored to PROJECT_ROOT: ${output_abs}" + else + output_abs="$(pwd)/${output_abs}" + log_warn "kernel_build_with_initramfs: PROJECT_ROOT unset; output anchored to PWD: ${output_abs}" + fi + fi + # Copy to output location - local output_dir=$(dirname "$output_file") + local output_dir + output_dir=$(dirname "$output_abs") safe_mkdir "$output_dir" - safe_copy "$kernel_image" "$output_file" + safe_copy "$kernel_image" "$output_abs" # Verify final kernel - local kernel_size=$(get_file_size "$output_file") + local kernel_size + kernel_size=$(get_file_size "$output_abs") log_info "Kernel build complete:" - log_info " Output file: ${output_file}" + log_info " Output file: ${output_abs}" log_info " Kernel size: ${kernel_size}" # Verify initramfs is embedded diff --git a/scripts/rebuild-after-zinit.sh b/scripts/rebuild-after-zinit.sh new file mode 100755 index 0000000..4defdb9 --- /dev/null +++ b/scripts/rebuild-after-zinit.sh @@ -0,0 +1,116 @@ +#!/bin/bash +# Rebuild kernel (and required prior stages) after zinit config or init scripts change +# Usage: +# scripts/rebuild-after-zinit.sh # minimal rebuild of initramfs only (skip boot tests; no kernel rebuild) +# scripts/rebuild-after-zinit.sh --run-tests # include boot tests (still no kernel rebuild by default) +# scripts/rebuild-after-zinit.sh --with-kernel # also rebuild kernel (re-embed updated initramfs) +# scripts/rebuild-after-zinit.sh --refresh-container-mods # rebuild container /lib/modules if missing (kernel modules stage) +# scripts/rebuild-after-zinit.sh -- ... # pass extra args to build.sh + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +STAGES_DIR="${PROJECT_ROOT}/.build-stages" + +log() { echo "[rebuild-zinit] $*"; } + +run_tests=0 +extra_args=() +rebuild_kernel=0 +refresh_container_mods=0 + +# Parse flags; pass through any remaining args to build.sh after -- +while [[ $# -gt 0 ]]; do + case "$1" in + --run-tests) + run_tests=1 + shift + ;; + --with-kernel) + rebuild_kernel=1 + shift + ;; + --refresh-container-mods) + refresh_container_mods=1 + shift + ;; + --) + shift + extra_args=("$@") + break + ;; + *) + # Pass unknown args through to build.sh + extra_args+=("$1") + shift + ;; + esac +done + +log "PROJECT_ROOT=${PROJECT_ROOT}" +log "STAGES_DIR=${STAGES_DIR}" + +# Minimal set of stages to clear when zinit changes: +# - zinit_setup: recopy zinit YAML and init scripts into initramfs +# - validation: re-check initramfs contents +# - initramfs_create: recreate archive including updated zinit files +# - initramfs_test: re-test archive +# - kernel_build: re-embed updated initramfs into kernel +# - boot_tests: optional, depends on --run-tests +stages_to_clear=( + # Ensure new/changed module selections in [config/modules.conf](config/modules.conf) + # are re-resolved and copied into the initramfs: + "modules_setup" + "modules_copy" + + # Re-copy /init into the initramfs root from [config/init](config/init) + "init_script" + + # Ensure zinit YAML/init script changes are reapplied: + "zinit_setup" + + # Re-validate and recreate archive (no kernel rebuild by default): + "validation" + "initramfs_create" + "initramfs_test" +) + +# Optionally rebuild container modules if requested (fresh container scenario) +if [[ "$refresh_container_mods" -eq 1 ]]; then + stages_to_clear=("kernel_modules" "${stages_to_clear[@]}") +fi + +# Optionally rebuild kernel (re-embed updated initramfs) +if [[ "$rebuild_kernel" -eq 1 ]]; then + stages_to_clear+=("kernel_build") +fi + +# Remove completion markers to force incremental rebuild of those stages +for s in "${stages_to_clear[@]}"; do + marker="${STAGES_DIR}/${s}.done" + if [[ -f "$marker" ]]; then + log "Removing stage marker: ${marker}" + rm -f "$marker" + else + log "Marker not present (already pending): ${s}" + fi +done + +# Build +log "Starting incremental rebuild (zinit changes)" +# If we plan to rebuild the kernel, force the pipeline to run from initramfs_create +# so the cpio archive is recreated before kernel_build (ignoring prior .done markers). +build_from_args=() +if [[ "$rebuild_kernel" -eq 1 ]]; then + build_from_args=(--rebuild-from=initramfs_create) + log "Rebuild-from: initramfs_create (guarantee cpio is recreated before kernel_build)" +fi + +if [[ "$run_tests" -eq 1 ]]; then + log "Including boot tests" + DEBUG=1 "${PROJECT_ROOT}/scripts/build.sh" "${build_from_args[@]}" "${extra_args[@]}" +else + log "Skipping boot tests (use --run-tests to include)" + DEBUG=1 "${PROJECT_ROOT}/scripts/build.sh" --skip-tests "${build_from_args[@]}" "${extra_args[@]}" +fi \ No newline at end of file