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:
2025-08-31 12:43:10 +02:00
parent 860b9aa161
commit 041ad29a70
4 changed files with 283 additions and 15 deletions

View File

@@ -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
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[@]}"
}