feat: Add firmware installation and module dependency resolution
- Add Alpine firmware package installation support - Implement recursive module dependency resolution using modinfo - Add config/firmware.conf for NIC firmware selection - Enhanced initramfs_setup_modules with dependency tracking - Firmware installation integrated into main build process Features: - Automatic dependency resolution for kernel modules - Alpine's separate firmware APK packages for optimal size - Stage1/Stage2 module loading with complete dependencies - No duplicate modules between stages
This commit is contained in:
23
config/firmware.conf
Normal file
23
config/firmware.conf
Normal file
@@ -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
|
||||||
@@ -35,6 +35,7 @@ PACKAGES_LIST="${CONFIG_DIR}/packages.list"
|
|||||||
SOURCES_CONF="${CONFIG_DIR}/sources.conf"
|
SOURCES_CONF="${CONFIG_DIR}/sources.conf"
|
||||||
MODULES_CONF="${CONFIG_DIR}/modules.conf"
|
MODULES_CONF="${CONFIG_DIR}/modules.conf"
|
||||||
KERNEL_CONFIG="${CONFIG_DIR}/kernel.config"
|
KERNEL_CONFIG="${CONFIG_DIR}/kernel.config"
|
||||||
|
FIRMWARE_CONF="${CONFIG_DIR}/firmware.conf"
|
||||||
ZINIT_CONFIG_DIR="${CONFIG_DIR}/zinit"
|
ZINIT_CONFIG_DIR="${CONFIG_DIR}/zinit"
|
||||||
|
|
||||||
# Build options
|
# Build options
|
||||||
@@ -147,6 +148,7 @@ function verify_configuration_files() {
|
|||||||
"$SOURCES_CONF"
|
"$SOURCES_CONF"
|
||||||
"$MODULES_CONF"
|
"$MODULES_CONF"
|
||||||
"$KERNEL_CONFIG"
|
"$KERNEL_CONFIG"
|
||||||
|
"$FIRMWARE_CONF"
|
||||||
)
|
)
|
||||||
|
|
||||||
local missing_configs=()
|
local missing_configs=()
|
||||||
@@ -193,6 +195,9 @@ function main_build_process() {
|
|||||||
# Phase 3: Install Alpine packages (NO OpenRC)
|
# Phase 3: Install Alpine packages (NO OpenRC)
|
||||||
alpine_install_packages "$INSTALL_DIR" "$PACKAGES_LIST"
|
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
|
# Phase 4: Build and install ThreeFold components
|
||||||
components_parse_sources_conf "$SOURCES_CONF" "$COMPONENTS_DIR"
|
components_parse_sources_conf "$SOURCES_CONF" "$COMPONENTS_DIR"
|
||||||
|
|
||||||
|
|||||||
@@ -348,7 +348,73 @@ EOF
|
|||||||
log_info "Alpine system configuration complete"
|
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 functions
|
||||||
export -f alpine_extract_miniroot alpine_setup_chroot alpine_cleanup_chroot
|
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
|
export -f alpine_configure_repos alpine_configure_system
|
||||||
@@ -67,13 +67,13 @@ function initramfs_setup_zinit() {
|
|||||||
log_info "zinit setup complete - OpenRC completely replaced"
|
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() {
|
function initramfs_setup_modules() {
|
||||||
local initramfs_dir="$1"
|
local initramfs_dir="$1"
|
||||||
local modules_conf="$2"
|
local modules_conf="$2"
|
||||||
local kernel_version="${3:-$(uname -r)}"
|
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
|
if [[ ! -f "$modules_conf" ]]; then
|
||||||
log_error "Modules configuration file not found: ${modules_conf}"
|
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}"
|
local modules_dir="${initramfs_dir}/lib/modules/${kernel_version}"
|
||||||
safe_mkdir "$modules_dir"
|
safe_mkdir "$modules_dir"
|
||||||
|
|
||||||
# Create stage1 module list (critical boot modules)
|
# Create stage1 module list with dependencies
|
||||||
log_info "Creating stage1 module list (critical boot modules)"
|
log_info "Resolving stage1 module dependencies (critical boot modules)"
|
||||||
grep "^stage1:" "$modules_conf" | cut -d: -f2 > "${modules_dir}/stage1.list"
|
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)
|
local stage1_with_deps=()
|
||||||
log_info "Creating stage2 module list (extended hardware support)"
|
if [[ ${#stage1_modules[@]} -gt 0 ]]; then
|
||||||
grep "^stage2:" "$modules_conf" | cut -d: -f2 > "${modules_dir}/stage2.list"
|
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
|
# Create module loading scripts
|
||||||
initramfs_create_module_scripts "$initramfs_dir" "$kernel_version"
|
initramfs_create_module_scripts "$initramfs_dir" "$kernel_version"
|
||||||
|
|
||||||
# Count modules
|
# Report final counts
|
||||||
local stage1_count=$(wc -l < "${modules_dir}/stage1.list" 2>/dev/null || echo 0)
|
local stage1_count=${#stage1_with_deps[@]}
|
||||||
local stage2_count=$(wc -l < "${modules_dir}/stage2.list" 2>/dev/null || echo 0)
|
local stage2_count=${#stage2_with_deps[@]}
|
||||||
|
|
||||||
log_info "Module configuration complete:"
|
log_info "Module configuration complete:"
|
||||||
log_info " Stage1 (critical): ${stage1_count} modules"
|
log_info " Stage1 (critical + deps): ${stage1_count} modules"
|
||||||
log_info " Stage2 (extended): ${stage2_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
|
# Create module loading scripts for zinit
|
||||||
function initramfs_create_module_scripts() {
|
function initramfs_create_module_scripts() {
|
||||||
local initramfs_dir="$1"
|
local initramfs_dir="$1"
|
||||||
@@ -437,4 +543,72 @@ function initramfs_test_archive() {
|
|||||||
# Export functions
|
# Export functions
|
||||||
export -f initramfs_setup_zinit initramfs_setup_modules initramfs_create_module_scripts
|
export -f initramfs_setup_zinit initramfs_setup_modules initramfs_create_module_scripts
|
||||||
export -f initramfs_strip_and_upx initramfs_create_cpio
|
export -f initramfs_strip_and_upx initramfs_create_cpio
|
||||||
export -f initramfs_validate initramfs_test_archive
|
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[@]}"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user