#!/bin/bash # ============================================================================ # DarkForge Linux — Kernel Build Script # ============================================================================ # Downloads, configures, and compiles the Linux kernel for DarkForge. # # Prerequisites (Arch Linux): # sudo pacman -S base-devel bc flex bison libelf perl openssl # # Usage: # cd /path/to/project-root # bash kernel/build-kernel.sh # # Output: # kernel/vmlinuz — Compressed kernel (bzImage) # kernel/vmlinuz.efi — Copy with .efi extension for EFISTUB # kernel/System.map — Symbol map # kernel/modules/ — Kernel modules (if any) # build/linux-/ — Full kernel source tree (for module builds) # # Notes: # - Runs as regular user (no sudo needed for compile) # - Uses the config at kernel/config # - Applies 'make olddefconfig' to fill in defaults for unspecified options # - Builds with -j32 (16C/32T) # ============================================================================ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" # --- Configuration ----------------------------------------------------------- KERNEL_VERSION="6.19.9" KERNEL_MAJOR="6.19" KERNEL_URL="https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${KERNEL_VERSION}.tar.xz" KERNEL_SIGN_URL="${KERNEL_URL}.sign" BUILD_DIR="${PROJECT_ROOT}/build" KERNEL_SRC="${BUILD_DIR}/linux-${KERNEL_VERSION}" CONFIG_FILE="${SCRIPT_DIR}/config" JOBS=32 RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' info() { echo -e "${CYAN}>>> $1${NC}"; } ok() { echo -e "${GREEN}>>> $1${NC}"; } warn() { echo -e "${YELLOW}!!! $1${NC}"; } die() { echo -e "${RED}!!! $1${NC}"; exit 1; } # --- Preflight --------------------------------------------------------------- info "DarkForge Kernel Builder — Linux ${KERNEL_VERSION}" echo "" # Check required tools for tool in gcc make flex bison bc perl; do command -v "$tool" >/dev/null 2>&1 || die "Missing: $tool — install with pacman" done # Check for libelf headers (needed for CONFIG_BPF_SYSCALL, etc.) if ! pkg-config --exists libelf 2>/dev/null; then warn "libelf not found — install with: sudo pacman -S libelf" warn "Continuing anyway (may fail if CONFIG_BPF_SYSCALL=y)" fi # Check for openssl headers (needed for module signing) if ! pkg-config --exists openssl 2>/dev/null && ! [ -f /usr/include/openssl/opensslv.h ]; then warn "OpenSSL headers not found — install with: sudo pacman -S openssl" fi # --- Download kernel source -------------------------------------------------- mkdir -p "${BUILD_DIR}" TARBALL="${BUILD_DIR}/linux-${KERNEL_VERSION}.tar.xz" if [ -f "$TARBALL" ]; then info "Kernel tarball already downloaded: ${TARBALL}" else info "Downloading Linux ${KERNEL_VERSION}..." # Try cdn.kernel.org first, then mirrors for url in \ "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${KERNEL_VERSION}.tar.xz" \ "https://mirrors.edge.kernel.org/pub/linux/kernel/v6.x/linux-${KERNEL_VERSION}.tar.xz" \ "https://mirror.aarnet.edu.au/pub/ftp.kernel.org/linux/kernel/v6.x/linux-${KERNEL_VERSION}.tar.xz"; do if curl --connect-timeout 15 -fL# -o "$TARBALL" "$url" 2>&1; then ok "Downloaded from ${url}" break else warn "Failed: ${url}" rm -f "$TARBALL" fi done fi [ -f "$TARBALL" ] || die "Failed to download kernel tarball" # Verify tarball is valid if ! xz -t "$TARBALL" 2>/dev/null; then die "Kernel tarball is corrupt — delete ${TARBALL} and re-run" fi # --- Extract kernel source --------------------------------------------------- if [ -d "$KERNEL_SRC" ] && [ -f "$KERNEL_SRC/Makefile" ]; then info "Kernel source already extracted: ${KERNEL_SRC}" else info "Extracting Linux ${KERNEL_VERSION}..." tar -xf "$TARBALL" -C "${BUILD_DIR}" [ -d "$KERNEL_SRC" ] || die "Expected directory ${KERNEL_SRC} not found after extraction" ok "Extracted to ${KERNEL_SRC}" fi # --- Apply DarkForge config -------------------------------------------------- info "Applying DarkForge kernel config..." # Copy our config cp "$CONFIG_FILE" "${KERNEL_SRC}/.config" # Update version target in config header comment (informational only) # The actual version comes from the kernel source, not the config # Run olddefconfig to fill in all unspecified options with defaults # This is critical — our config only specifies ~176 options out of thousands cd "$KERNEL_SRC" make olddefconfig ok "Config applied — $(grep -c '=y\|=m' .config) options enabled" # Verify critical options survived olddefconfig CRITICAL_OPTS=( "CONFIG_EFI_STUB=y" "CONFIG_BLK_DEV_NVME=y" "CONFIG_EXT4_FS=y" "CONFIG_PREEMPT=y" "CONFIG_MODULES=y" "CONFIG_DRM=y" "CONFIG_R8169=y" "CONFIG_EFI=y" ) FAIL=0 for opt in "${CRITICAL_OPTS[@]}"; do key="${opt%%=*}" if ! grep -q "^${opt}$" .config; then warn "CRITICAL: ${opt} not set in final config!" FAIL=1 fi done if [ "$FAIL" -eq 1 ]; then die "Critical config options missing after olddefconfig — review .config" fi ok "All critical config options verified" # --- Compile ----------------------------------------------------------------- info "Compiling Linux ${KERNEL_VERSION} with -j${JOBS}..." info "This will take a few minutes on 16C/32T..." echo "" # Set DarkForge compiler flags for kernel build # Note: kernel has its own CFLAGS handling; -march is passed via KCFLAGS # The kernel's CONFIG_MZEN4 handles most CPU-specific codegen KCFLAGS="-march=znver4 -pipe" # znver4 because znver5 may not be fully supported by all kernel assembly # TODO: test znver5 when compiler+kernel support is confirmed START_TIME=$(date +%s) make -j${JOBS} KCFLAGS="$KCFLAGS" bzImage 2>&1 | tail -20 END_TIME=$(date +%s) ELAPSED=$((END_TIME - START_TIME)) if [ -f "arch/x86/boot/bzImage" ]; then ok "Kernel compiled in ${ELAPSED}s" else die "Kernel compilation failed — check output above" fi # Build modules (for any =m options) info "Building kernel modules..." make -j${JOBS} modules 2>&1 | tail -5 ok "Modules built" # --- Install outputs --------------------------------------------------------- info "Installing kernel outputs..." # Copy bzImage cp arch/x86/boot/bzImage "${SCRIPT_DIR}/vmlinuz" cp arch/x86/boot/bzImage "${SCRIPT_DIR}/vmlinuz.efi" ok "Kernel: ${SCRIPT_DIR}/vmlinuz ($(du -h "${SCRIPT_DIR}/vmlinuz" | cut -f1))" # Copy System.map cp System.map "${SCRIPT_DIR}/System.map" # Install modules to a staging directory MODULES_DIR="${SCRIPT_DIR}/modules" rm -rf "$MODULES_DIR" make INSTALL_MOD_PATH="$MODULES_DIR" modules_install 2>&1 | tail -3 ok "Modules installed to ${MODULES_DIR}" # Verify the kernel is a valid EFI application if file "${SCRIPT_DIR}/vmlinuz" | grep -q "bzImage"; then ok "Kernel is a valid bzImage" elif file "${SCRIPT_DIR}/vmlinuz" | grep -q "EFI\|PE32"; then ok "Kernel is a valid EFI binary" else warn "Kernel type: $(file "${SCRIPT_DIR}/vmlinuz")" warn "May not boot via EFISTUB — verify manually" fi # --- Summary ----------------------------------------------------------------- echo "" echo "============================================================================" echo -e "${GREEN} DarkForge Kernel Build Complete${NC}" echo "============================================================================" echo "" echo " Version: Linux ${KERNEL_VERSION}-darkforge" echo " Kernel: ${SCRIPT_DIR}/vmlinuz" echo " Kernel EFI: ${SCRIPT_DIR}/vmlinuz.efi" echo " System.map: ${SCRIPT_DIR}/System.map" echo " Modules: ${MODULES_DIR}/" echo " Source: ${KERNEL_SRC}/" echo "" echo " Compile time: ${ELAPSED}s" echo " Kernel size: $(du -h "${SCRIPT_DIR}/vmlinuz" | cut -f1)" echo "" echo " Next steps:" echo " 1. Rebuild ISO: sudo bash src/iso/build-iso-arch.sh" echo " 2. Test in QEMU: see tests/run-tests.sh" echo " 3. For real hardware: copy vmlinuz.efi to ESP as /EFI/Linux/vmlinuz.efi" echo "" echo "============================================================================"