mirror of
https://github.com/edera-dev/sprout.git
synced 2026-11-04 23:52:22 +00:00
Add linux-initrd-chain to the chainload action and initrd-chain to the edera action. Each file in the list is read in order and concatenated into a single initrd. The chain can't be combined with the single initrd option on the same action. BLS entries with multiple initrds, either as repeated initrd lines or as multiple paths on one line, previously only loaded the last one. Parse all of them and set them in the initrd-0 through initrd-7 slots, which the autoconfigured BLS action now chains. Unused slots stamp to the filesystem root and are skipped. Entries with more than 8 initrds are skipped with a warning.
110 lines
4.1 KiB
Rust
110 lines
4.1 KiB
Rust
use crate::generators::bls::BLS_INITRD_SLOTS;
|
|
use alloc::string::ToString;
|
|
use alloc::{format, vec};
|
|
use anyhow::{Context, Result};
|
|
use edera_sprout_config::RootConfiguration;
|
|
use edera_sprout_config::actions::ActionDeclaration;
|
|
use edera_sprout_config::actions::chainload::ChainloadConfiguration;
|
|
use edera_sprout_config::entries::EntryDeclaration;
|
|
use edera_sprout_config::generators::GeneratorDeclaration;
|
|
use edera_sprout_config::generators::bls::BlsConfiguration;
|
|
use edera_sprout_parsing::unique_hash;
|
|
use uefi::cstr16;
|
|
use uefi::fs::{FileSystem, Path};
|
|
use uefi::proto::device_path::DevicePath;
|
|
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
|
|
|
|
/// The name prefix of the BLS chainload action that will be used
|
|
/// by the BLS generator to chainload entries.
|
|
const BLS_CHAINLOAD_ACTION_PREFIX: &str = "bls-chainload-";
|
|
|
|
/// Scan the specified `filesystem` for BLS configurations.
|
|
pub fn scan(
|
|
filesystem: &mut FileSystem,
|
|
root: &DevicePath,
|
|
config: &mut RootConfiguration,
|
|
) -> Result<bool> {
|
|
// BLS has a loader.conf file that can specify its own auto-entries mechanism.
|
|
let bls_loader_conf_path = Path::new(cstr16!("\\loader\\loader.conf"));
|
|
// BLS also has an entries directory that can specify explicit entries.
|
|
let bls_entries_path = Path::new(cstr16!("\\loader\\entries"));
|
|
|
|
// Convert the device path root to a string we can use in the configuration.
|
|
let mut root = root
|
|
.to_string16(DisplayOnly(false), AllowShortcuts(false))
|
|
.context("unable to convert device root to string")?
|
|
.to_string();
|
|
// Add a trailing forward-slash to the root to ensure the device root is completed.
|
|
root.push('/');
|
|
|
|
// Generate a unique hash of the root path.
|
|
let root_unique_hash = unique_hash(&root);
|
|
|
|
// Whether we have a loader.conf file.
|
|
let has_loader_conf = filesystem
|
|
.try_exists(bls_loader_conf_path)
|
|
.context("unable to check for BLS loader.conf file")?;
|
|
|
|
// Whether we have an entries directory.
|
|
// We actually iterate the entries to see if there are any.
|
|
let has_entries_dir = filesystem
|
|
.read_dir(bls_entries_path)
|
|
.ok()
|
|
.and_then(|mut iterator| iterator.next())
|
|
.map(|entry| entry.is_ok())
|
|
.unwrap_or(false);
|
|
|
|
// Detect if a BLS supported configuration is on this filesystem.
|
|
// We check both loader.conf and entries directory as only one of them is required.
|
|
if !(has_loader_conf || has_entries_dir) {
|
|
return Ok(false);
|
|
}
|
|
|
|
// Generate a unique name for the BLS chainload action.
|
|
let chainload_action_name = format!("{}{}", BLS_CHAINLOAD_ACTION_PREFIX, root_unique_hash,);
|
|
|
|
// BLS is now detected, generate a configuration for it.
|
|
let generator = BlsConfiguration {
|
|
entry: EntryDeclaration {
|
|
title: "$title".to_string(),
|
|
actions: vec![chainload_action_name.clone()],
|
|
..Default::default()
|
|
},
|
|
path: format!("{}\\loader", root),
|
|
};
|
|
|
|
// Generate a unique name for the BLS generator and insert the generator into the configuration.
|
|
config.generators.insert(
|
|
format!("auto-bls-{}", root_unique_hash),
|
|
GeneratorDeclaration {
|
|
bls: Some(generator),
|
|
..Default::default()
|
|
},
|
|
);
|
|
|
|
// Generate a chainload configuration for BLS.
|
|
// BLS will provide these values to us.
|
|
// Every initrd slot is chained in order. Unused slots stamp to the root of the
|
|
// filesystem, which the chainload action skips.
|
|
let chainload = ChainloadConfiguration {
|
|
path: format!("{}\\$chainload", root),
|
|
options: vec!["$options".to_string()],
|
|
linux_initrd: None,
|
|
linux_initrd_chain: (0..BLS_INITRD_SLOTS)
|
|
.map(|slot| format!("{}\\$initrd-{}", root, slot))
|
|
.collect(),
|
|
};
|
|
|
|
// Insert the chainload action into the configuration.
|
|
config.actions.insert(
|
|
chainload_action_name,
|
|
ActionDeclaration {
|
|
chainload: Some(chainload),
|
|
..Default::default()
|
|
},
|
|
);
|
|
|
|
// We had a BLS supported configuration, so return true.
|
|
Ok(true)
|
|
}
|