#!/bin/bash # build-kernel-arm64.sh — Build ARM64 kernel for Raspberry Pi 4/5 # # Uses the official raspberrypi/linux kernel fork with bcm2711_defconfig # as the base, overlaid with container-critical config options. # # Output is cached in $CACHE_DIR/custom-kernel-arm64/ and reused across builds. # # Requirements: # - gcc-aarch64-linux-gnu (cross-compiler) # - Standard kernel build deps (bc, bison, flex, etc.) set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" CACHE_DIR="${CACHE_DIR:-$PROJECT_ROOT/build/cache}" # shellcheck source=../config/versions.env . "$SCRIPT_DIR/../config/versions.env" CUSTOM_KERNEL_DIR="$CACHE_DIR/custom-kernel-arm64" CUSTOM_IMAGE="$CUSTOM_KERNEL_DIR/Image" CUSTOM_MODULES="$CUSTOM_KERNEL_DIR/modules" CUSTOM_DTBS="$CUSTOM_KERNEL_DIR/dtbs" mkdir -p "$CACHE_DIR" "$CUSTOM_KERNEL_DIR" # --- Skip if already built --- if [ -f "$CUSTOM_IMAGE" ] && [ -d "$CUSTOM_MODULES" ]; then echo "==> ARM64 kernel already built (cached)" echo " Image: $CUSTOM_IMAGE ($(du -h "$CUSTOM_IMAGE" | cut -f1))" exit 0 fi # --- Verify cross-compiler --- if ! command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then echo "ERROR: aarch64-linux-gnu-gcc not found" echo "Install: apt-get install gcc-aarch64-linux-gnu" exit 1 fi echo "==> Building ARM64 kernel for Raspberry Pi..." echo " Branch: $RPI_KERNEL_BRANCH" echo " Repo: $RPI_KERNEL_REPO" # --- Download kernel source --- KERNEL_SRC_DIR="$CACHE_DIR/rpi-linux-${RPI_KERNEL_BRANCH}" if [ ! -d "$KERNEL_SRC_DIR" ]; then echo "==> Downloading RPi kernel source (shallow clone)..." git clone --depth 1 --branch "$RPI_KERNEL_BRANCH" \ "$RPI_KERNEL_REPO" "$KERNEL_SRC_DIR" else echo "==> Kernel source already cached" fi # --- Build in /tmp for case-sensitivity --- KERNEL_BUILD_DIR="/tmp/kernel-build-arm64" rm -rf "$KERNEL_BUILD_DIR" cp -a "$KERNEL_SRC_DIR" "$KERNEL_BUILD_DIR" cd "$KERNEL_BUILD_DIR" # --- Apply base config (Pi 4 = bcm2711) --- echo "==> Applying bcm2711_defconfig..." make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig # --- Apply container config overrides --- CONFIG_FRAGMENT="$PROJECT_ROOT/build/config/rpi-kernel-config.fragment" if [ -f "$CONFIG_FRAGMENT" ]; then echo "==> Applying KubeSolo config overrides..." while IFS= read -r line; do # Skip comments and empty lines case "$line" in \#*|"") continue ;; esac key="${line%%=*}" value="${line#*=}" case "$value" in y) ./scripts/config --enable "$key" ;; m) ./scripts/config --module "$key" ;; n) ./scripts/config --disable "${key#CONFIG_}" ;; *) ./scripts/config --set-str "$key" "$value" ;; esac done < "$CONFIG_FRAGMENT" fi # Handle "is not set" comments as disables if [ -f "$CONFIG_FRAGMENT" ]; then while IFS= read -r line; do case "$line" in "# CONFIG_"*" is not set") key=$(echo "$line" | sed -n 's/^# \(CONFIG_[A-Z_]*\) is not set$/\1/p') [ -n "$key" ] && ./scripts/config --disable "${key#CONFIG_}" ;; esac done < "$CONFIG_FRAGMENT" fi # Resolve dependencies make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- olddefconfig # --- Build kernel + modules + DTBs --- NPROC=$(nproc 2>/dev/null || echo 4) echo "" echo "==> Building ARM64 kernel (${NPROC} parallel jobs)..." echo " This may take 20-30 minutes..." make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j"$NPROC" Image modules dtbs 2>&1 echo "==> ARM64 kernel build complete" # --- Install to staging --- echo "==> Installing Image..." cp arch/arm64/boot/Image "$CUSTOM_IMAGE" echo "==> Installing modules (stripped)..." rm -rf "$CUSTOM_MODULES" mkdir -p "$CUSTOM_MODULES" make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \ INSTALL_MOD_STRIP=1 modules_install INSTALL_MOD_PATH="$CUSTOM_MODULES" # Remove build/source symlinks KVER=$(ls "$CUSTOM_MODULES/lib/modules/" | head -1) rm -f "$CUSTOM_MODULES/lib/modules/$KVER/build" rm -f "$CUSTOM_MODULES/lib/modules/$KVER/source" # Run depmod depmod -a -b "$CUSTOM_MODULES" "$KVER" 2>/dev/null || true echo "==> Installing Device Tree Blobs..." rm -rf "$CUSTOM_DTBS" mkdir -p "$CUSTOM_DTBS/overlays" # Pi 4 DTBs cp arch/arm64/boot/dts/broadcom/bcm2711*.dtb "$CUSTOM_DTBS/" 2>/dev/null || true # Pi 5 DTBs cp arch/arm64/boot/dts/broadcom/bcm2712*.dtb "$CUSTOM_DTBS/" 2>/dev/null || true # Overlays we need for overlay in disable-wifi disable-bt; do [ -f "arch/arm64/boot/dts/overlays/${overlay}.dtbo" ] && \ cp "arch/arm64/boot/dts/overlays/${overlay}.dtbo" "$CUSTOM_DTBS/overlays/" done # Save config for reference cp .config "$CUSTOM_KERNEL_DIR/.config" # --- Clean up --- echo "==> Cleaning kernel build directory..." cd / rm -rf "$KERNEL_BUILD_DIR" # --- Summary --- echo "" echo "==> ARM64 kernel build complete:" echo " Image: $CUSTOM_IMAGE ($(du -h "$CUSTOM_IMAGE" | cut -f1))" echo " Kernel ver: $KVER" MOD_COUNT=$(find "$CUSTOM_MODULES/lib/modules/$KVER" -name '*.ko*' 2>/dev/null | wc -l) echo " Modules: $MOD_COUNT" echo " Modules size: $(du -sh "$CUSTOM_MODULES/lib/modules/$KVER" 2>/dev/null | cut -f1)" echo " DTBs: $(ls "$CUSTOM_DTBS"/*.dtb 2>/dev/null | wc -l)" echo ""