diff --git a/config/firmware.conf b/config/firmware.conf new file mode 100644 index 0000000..a1b7b8c --- /dev/null +++ b/config/firmware.conf @@ -0,0 +1,23 @@ +# Firmware configuration for Zero OS Alpine Initramfs +# Alpine Linux provides separate firmware packages for hardware support +# Format: FIRMWARE_PACKAGE:DESCRIPTION + +# Essential network firmware packages +linux-firmware-bnx2:Broadcom NetXtreme firmware +linux-firmware-e100:Intel PRO/100 firmware +linux-firmware-intel:Intel network and WiFi firmware (includes e1000e, igb, ixgbe, i40e, ice) +linux-firmware-realtek:Realtek network firmware (r8169, etc.) +linux-firmware-mellanox:Mellanox network firmware +linux-firmware-qlogic:QLogic network firmware + +# Storage firmware (if needed) +linux-firmware-marvell:Marvell storage/network firmware + +# Optional firmware packages (uncomment if needed) +#linux-firmware-amd:AMD GPU and network firmware +#linux-firmware-nvidia:NVIDIA GPU firmware +#linux-firmware-atheros:Atheros wireless firmware +#linux-firmware-broadcom:Broadcom wireless firmware + +# Minimal firmware selection for embedded/container environments +# For full hardware support, uncomment additional packages above \ No newline at end of file diff --git a/scripts/build.sh b/scripts/build.sh index db4c791..341efd7 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -35,6 +35,7 @@ PACKAGES_LIST="${CONFIG_DIR}/packages.list" SOURCES_CONF="${CONFIG_DIR}/sources.conf" MODULES_CONF="${CONFIG_DIR}/modules.conf" KERNEL_CONFIG="${CONFIG_DIR}/kernel.config" +FIRMWARE_CONF="${CONFIG_DIR}/firmware.conf" ZINIT_CONFIG_DIR="${CONFIG_DIR}/zinit" # Build options @@ -147,6 +148,7 @@ function verify_configuration_files() { "$SOURCES_CONF" "$MODULES_CONF" "$KERNEL_CONFIG" + "$FIRMWARE_CONF" ) local missing_configs=() @@ -193,6 +195,9 @@ function main_build_process() { # Phase 3: Install Alpine packages (NO OpenRC) alpine_install_packages "$INSTALL_DIR" "$PACKAGES_LIST" + # Phase 3.5: Install firmware packages for hardware support + alpine_install_firmware "$INSTALL_DIR" "$FIRMWARE_CONF" + # Phase 4: Build and install ThreeFold components components_parse_sources_conf "$SOURCES_CONF" "$COMPONENTS_DIR" diff --git a/scripts/lib/alpine.sh b/scripts/lib/alpine.sh index 28f1647..b4d50e7 100644 --- a/scripts/lib/alpine.sh +++ b/scripts/lib/alpine.sh @@ -348,7 +348,73 @@ EOF log_info "Alpine system configuration complete" } +# Install firmware packages for hardware support +function alpine_install_firmware() { + local initramfs_dir="$1" + local firmware_conf="$2" + + section_header "Installing Alpine Firmware Packages" + + if [[ ! -f "$firmware_conf" ]]; then + log_warn "Firmware configuration not found: ${firmware_conf}" + log_info "Skipping firmware installation" + return 0 + fi + + # Setup chroot environment + alpine_setup_chroot "$initramfs_dir" + + # Read firmware packages from config (excluding comments and empty lines) + local firmware_packages=() + while IFS=: read -r package description; do + # Skip comments and empty lines + if [[ "$package" =~ ^[[:space:]]*# ]] || [[ -z "${package// }" ]]; then + continue + fi + + # Trim whitespace + package=$(echo "$package" | xargs) + description=$(echo "$description" | xargs) + + if [[ -n "$package" ]]; then + firmware_packages+=("$package") + log_info " - ${package}: ${description}" + fi + done < "$firmware_conf" + + if [[ ${#firmware_packages[@]} -eq 0 ]]; then + log_warn "No firmware packages found in ${firmware_conf}" + alpine_cleanup_chroot "$initramfs_dir" + return 0 + fi + + log_info "Installing ${#firmware_packages[@]} firmware packages" + + # Install firmware packages + safe_execute chroot "$initramfs_dir" apk add --no-cache "${firmware_packages[@]}" + + # List installed firmware files + log_info "Checking installed firmware files:" + local firmware_count=0 + if [[ -d "${initramfs_dir}/lib/firmware" ]]; then + firmware_count=$(find "${initramfs_dir}/lib/firmware" -type f | wc -l) + local firmware_size=$(du -sh "${initramfs_dir}/lib/firmware" 2>/dev/null | cut -f1 || echo "0B") + log_info " Firmware files: ${firmware_count} (${firmware_size})" + + # Log some example firmware files for verification + log_debug "Sample firmware files:" + find "${initramfs_dir}/lib/firmware" -type f | head -10 | while read -r fw; do + log_debug " $(basename "$fw")" + done + else + log_warn "No firmware directory found after installation" + fi + + alpine_cleanup_chroot "$initramfs_dir" + log_info "Firmware installation complete: ${firmware_count} files" +} + # Export functions export -f alpine_extract_miniroot alpine_setup_chroot alpine_cleanup_chroot -export -f alpine_install_packages alpine_aggressive_cleanup +export -f alpine_install_packages alpine_install_firmware alpine_aggressive_cleanup export -f alpine_configure_repos alpine_configure_system \ No newline at end of file diff --git a/scripts/lib/initramfs.sh b/scripts/lib/initramfs.sh index 84c07d8..986179a 100644 --- a/scripts/lib/initramfs.sh +++ b/scripts/lib/initramfs.sh @@ -67,13 +67,13 @@ function initramfs_setup_zinit() { log_info "zinit setup complete - OpenRC completely replaced" } -# Setup 2-stage module loading system +# Setup 2-stage module loading system with dependency resolution function initramfs_setup_modules() { local initramfs_dir="$1" local modules_conf="$2" local kernel_version="${3:-$(uname -r)}" - section_header "Setting up 2-stage module loading" + section_header "Setting up 2-stage module loading with dependencies" if [[ ! -f "$modules_conf" ]]; then log_error "Modules configuration file not found: ${modules_conf}" @@ -83,26 +83,132 @@ function initramfs_setup_modules() { local modules_dir="${initramfs_dir}/lib/modules/${kernel_version}" safe_mkdir "$modules_dir" - # Create stage1 module list (critical boot modules) - log_info "Creating stage1 module list (critical boot modules)" - grep "^stage1:" "$modules_conf" | cut -d: -f2 > "${modules_dir}/stage1.list" + # Create stage1 module list with dependencies + log_info "Resolving stage1 module dependencies (critical boot modules)" + local stage1_modules=() + while IFS= read -r module; do + [[ -n "$module" ]] && stage1_modules+=("$module") + done < <(grep "^stage1:" "$modules_conf" | cut -d: -f2) - # Create stage2 module list (extended hardware support) - log_info "Creating stage2 module list (extended hardware support)" - grep "^stage2:" "$modules_conf" | cut -d: -f2 > "${modules_dir}/stage2.list" + local stage1_with_deps=() + if [[ ${#stage1_modules[@]} -gt 0 ]]; then + stage1_with_deps=($(initramfs_resolve_module_dependencies "${stage1_modules[@]}")) + fi + + # Write stage1 list with dependencies + printf '%s\n' "${stage1_with_deps[@]}" > "${modules_dir}/stage1.list" + + # Create stage2 module list with dependencies + log_info "Resolving stage2 module dependencies (extended hardware)" + local stage2_modules=() + while IFS= read -r module; do + [[ -n "$module" ]] && stage2_modules+=("$module") + done < <(grep "^stage2:" "$modules_conf" | cut -d: -f2) + + local stage2_with_deps=() + if [[ ${#stage2_modules[@]} -gt 0 ]]; then + stage2_with_deps=($(initramfs_resolve_module_dependencies "${stage2_modules[@]}")) + + # Remove stage1 modules from stage2 to avoid duplicates + local stage2_unique=() + for mod in "${stage2_with_deps[@]}"; do + if ! printf '%s\n' "${stage1_with_deps[@]}" | grep -q "^${mod}$"; then + stage2_unique+=("$mod") + fi + done + stage2_with_deps=("${stage2_unique[@]}") + fi + + # Write stage2 list with unique dependencies + printf '%s\n' "${stage2_with_deps[@]}" > "${modules_dir}/stage2.list" # Create module loading scripts initramfs_create_module_scripts "$initramfs_dir" "$kernel_version" - # Count modules - local stage1_count=$(wc -l < "${modules_dir}/stage1.list" 2>/dev/null || echo 0) - local stage2_count=$(wc -l < "${modules_dir}/stage2.list" 2>/dev/null || echo 0) + # Report final counts + local stage1_count=${#stage1_with_deps[@]} + local stage2_count=${#stage2_with_deps[@]} log_info "Module configuration complete:" - log_info " Stage1 (critical): ${stage1_count} modules" - log_info " Stage2 (extended): ${stage2_count} modules" + log_info " Stage1 (critical + deps): ${stage1_count} modules" + log_info " Stage2 (extended + deps): ${stage2_count} modules" + log_info " Total unique modules: $((stage1_count + stage2_count))" } +# Resolve module dependencies recursively using modinfo +function initramfs_resolve_module_dependencies() { + local modules=("$@") + local resolved_modules=() + local processed_modules=() + + log_debug "Resolving dependencies for modules: ${modules[*]}" + + # Function to recursively resolve a single module's dependencies + function resolve_single_module() { + local module="$1" + + # Skip if already processed + if printf '%s\n' "${processed_modules[@]}" | grep -q "^${module}$"; then + return 0 + fi + + processed_modules+=("$module") + + # Get module dependencies using modinfo + local deps=() + if command_exists "modinfo"; then + # Try to get dependencies - modinfo may fail for built-in modules + local modinfo_output + if modinfo_output=$(modinfo "$module" 2>/dev/null); then + # Extract depends line and parse comma-separated dependencies + local depends_line=$(echo "$modinfo_output" | grep '^depends:' | head -1 | cut -d: -f2- | tr -d ' ') + if [[ -n "$depends_line" && "$depends_line" != "-" ]]; then + IFS=',' read -ra deps <<< "$depends_line" + fi + else + log_debug "modinfo failed for module: $module (may be built-in)" + fi + else + log_warn "modinfo not available, skipping dependency resolution" + fi + + # Recursively resolve dependencies first + for dep in "${deps[@]}"; do + if [[ -n "$dep" ]]; then + log_debug "Module $module depends on: $dep" + resolve_single_module "$dep" + fi + done + + # Add current module to resolved list (after dependencies) + resolved_modules+=("$module") + } + + # Process all requested modules + for module in "${modules[@]}"; do + resolve_single_module "$module" + done + + # Remove duplicates while preserving order + local unique_modules=() + local seen_modules=() + + for module in "${resolved_modules[@]}"; do + if ! printf '%s\n' "${seen_modules[@]}" | grep -q "^${module}$"; then + unique_modules+=("$module") + seen_modules+=("$module") + fi + done + + log_debug "Resolved ${#unique_modules[@]} unique modules with dependencies" + printf '%s\n' "${unique_modules[@]}" +} + +# Export functions +export -f alpine_extract_miniroot alpine_setup_chroot alpine_cleanup_chroot +export -f alpine_install_packages alpine_install_firmware alpine_aggressive_cleanup +export -f alpine_configure_repos alpine_configure_system + # Create module loading scripts for zinit function initramfs_create_module_scripts() { local initramfs_dir="$1" @@ -437,4 +543,72 @@ function initramfs_test_archive() { # Export functions export -f initramfs_setup_zinit initramfs_setup_modules initramfs_create_module_scripts export -f initramfs_strip_and_upx initramfs_create_cpio -export -f initramfs_validate initramfs_test_archive \ No newline at end of file +export -f initramfs_validate initramfs_test_archive +# Resolve module dependencies recursively using modinfo +function initramfs_resolve_module_dependencies() { + local modules=("$@") + local resolved_modules=() + local processed_modules=() + + log_debug "Resolving dependencies for modules: ${modules[*]}" + + # Function to recursively resolve a single module's dependencies + function resolve_single_module() { + local module="$1" + + # Skip if already processed + if printf '%s\n' "${processed_modules[@]}" | grep -q "^${module}$"; then + return 0 + fi + + processed_modules+=("$module") + + # Get module dependencies using modinfo + local deps=() + if command_exists "modinfo"; then + # Try to get dependencies - modinfo may fail for built-in modules + local modinfo_output + if modinfo_output=$(modinfo "$module" 2>/dev/null); then + # Extract depends line and parse comma-separated dependencies + local depends_line=$(echo "$modinfo_output" | grep '^depends:' | head -1 | cut -d: -f2- | tr -d ' ') + if [[ -n "$depends_line" && "$depends_line" != "-" ]]; then + IFS=',' read -ra deps <<< "$depends_line" + fi + else + log_debug "modinfo failed for module: $module (may be built-in)" + fi + else + log_warn "modinfo not available, skipping dependency resolution" + fi + + # Recursively resolve dependencies first + for dep in "${deps[@]}"; do + if [[ -n "$dep" ]]; then + log_debug "Module $module depends on: $dep" + resolve_single_module "$dep" + fi + done + + # Add current module to resolved list (after dependencies) + resolved_modules+=("$module") + } + + # Process all requested modules + for module in "${modules[@]}"; do + resolve_single_module "$module" + done + + # Remove duplicates while preserving order + local unique_modules=() + local seen_modules=() + + for module in "${resolved_modules[@]}"; do + if ! printf '%s\n' "${seen_modules[@]}" | grep -q "^${module}$"; then + unique_modules+=("$module") + seen_modules+=("$module") + fi + done + + log_debug "Resolved ${#unique_modules[@]} unique modules with dependencies" + printf '%s\n' "${unique_modules[@]}" +} \ No newline at end of file