2025-10-01 16:45:04 -07:00
|
|
|
#![feature(uefi_std)]
|
2025-10-04 23:12:01 -07:00
|
|
|
|
2025-10-11 14:35:29 -07:00
|
|
|
use crate::context::{RootContext, SproutContext};
|
2025-10-14 12:47:33 -07:00
|
|
|
use crate::phases::phase;
|
2025-10-11 14:35:29 -07:00
|
|
|
use anyhow::{Context, Result, bail};
|
2025-10-05 00:09:53 -07:00
|
|
|
use log::info;
|
2025-10-13 00:55:11 -07:00
|
|
|
use std::collections::BTreeMap;
|
|
|
|
|
use std::ops::Deref;
|
|
|
|
|
use uefi::proto::device_path::LoadedImageDevicePath;
|
|
|
|
|
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
|
2025-10-04 23:12:01 -07:00
|
|
|
|
|
|
|
|
pub mod actions;
|
2025-10-01 18:25:49 -07:00
|
|
|
pub mod config;
|
2025-10-04 23:12:01 -07:00
|
|
|
pub mod context;
|
2025-10-12 22:39:56 -07:00
|
|
|
pub mod drivers;
|
2025-10-14 12:47:33 -07:00
|
|
|
pub mod entries;
|
2025-10-13 00:55:11 -07:00
|
|
|
pub mod extractors;
|
2025-10-04 23:12:01 -07:00
|
|
|
pub mod generators;
|
2025-10-14 12:47:33 -07:00
|
|
|
pub mod phases;
|
2025-10-01 16:45:04 -07:00
|
|
|
pub mod setup;
|
2025-10-01 21:30:43 -07:00
|
|
|
pub mod utils;
|
2025-10-01 16:45:04 -07:00
|
|
|
|
2025-10-11 14:35:29 -07:00
|
|
|
fn main() -> Result<()> {
|
|
|
|
|
setup::init()?;
|
2025-10-01 18:25:49 -07:00
|
|
|
|
2025-10-11 14:35:29 -07:00
|
|
|
let config = config::load()?;
|
2025-10-05 00:09:53 -07:00
|
|
|
|
2025-10-11 14:35:29 -07:00
|
|
|
if config.version != config::latest_version() {
|
|
|
|
|
bail!("unsupported configuration version: {}", config.version);
|
2025-10-05 00:09:53 -07:00
|
|
|
}
|
|
|
|
|
|
2025-10-13 00:55:11 -07:00
|
|
|
let mut root = {
|
|
|
|
|
let current_image_device_path_protocol = uefi::boot::open_protocol_exclusive::<
|
|
|
|
|
LoadedImageDevicePath,
|
|
|
|
|
>(uefi::boot::image_handle())
|
2025-10-14 12:47:33 -07:00
|
|
|
.context("unable to get loaded image device path")?;
|
2025-10-13 00:55:11 -07:00
|
|
|
let loaded_image_path = current_image_device_path_protocol.deref().to_boxed();
|
|
|
|
|
info!(
|
|
|
|
|
"loaded image path: {}",
|
|
|
|
|
loaded_image_path.to_string(DisplayOnly(false), AllowShortcuts(false))?
|
|
|
|
|
);
|
|
|
|
|
RootContext::new(loaded_image_path)
|
|
|
|
|
};
|
|
|
|
|
|
2025-10-04 23:12:01 -07:00
|
|
|
root.actions_mut().extend(config.actions.clone());
|
|
|
|
|
|
2025-10-11 14:35:29 -07:00
|
|
|
let mut context = SproutContext::new(root);
|
2025-10-04 23:12:01 -07:00
|
|
|
context.insert(&config.values);
|
|
|
|
|
let context = context.freeze();
|
|
|
|
|
|
2025-10-14 12:47:33 -07:00
|
|
|
phase(context.clone(), &config.phases.early).context("unable to execute early phase")?;
|
2025-10-13 16:23:08 -07:00
|
|
|
|
2025-10-14 12:47:33 -07:00
|
|
|
drivers::load(context.clone(), &config.drivers).context("unable to load drivers")?;
|
2025-10-12 22:39:56 -07:00
|
|
|
|
2025-10-13 00:55:11 -07:00
|
|
|
let mut extracted = BTreeMap::new();
|
|
|
|
|
for (name, extractor) in &config.extractors {
|
|
|
|
|
let value = extractors::extract(context.clone(), extractor)
|
2025-10-14 12:47:33 -07:00
|
|
|
.context(format!("unable to extract value {}", name))?;
|
2025-10-13 00:55:11 -07:00
|
|
|
info!("extracted value {}: {}", name, value);
|
|
|
|
|
extracted.insert(name.clone(), value);
|
|
|
|
|
}
|
|
|
|
|
let mut context = context.fork();
|
|
|
|
|
context.insert(&extracted);
|
|
|
|
|
let context = context.freeze();
|
|
|
|
|
|
2025-10-14 12:47:33 -07:00
|
|
|
phase(context.clone(), &config.phases.startup).context("unable to execute startup phase")?;
|
2025-10-04 23:12:01 -07:00
|
|
|
|
|
|
|
|
let mut all_entries = Vec::new();
|
|
|
|
|
|
|
|
|
|
for (_name, entry) in config.entries {
|
|
|
|
|
all_entries.push((context.clone(), entry));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (_name, generator) in config.generators {
|
|
|
|
|
let context = context.fork().freeze();
|
|
|
|
|
|
2025-10-11 14:35:29 -07:00
|
|
|
for entry in generators::generate(context.clone(), &generator)? {
|
2025-10-04 23:12:01 -07:00
|
|
|
all_entries.push(entry);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-04 23:33:23 -07:00
|
|
|
let mut final_entries = Vec::new();
|
|
|
|
|
for (context, entry) in all_entries {
|
2025-10-04 23:12:01 -07:00
|
|
|
let mut context = context.fork();
|
|
|
|
|
context.insert(&entry.values);
|
|
|
|
|
let context = context.finalize().freeze();
|
|
|
|
|
|
2025-10-04 23:33:23 -07:00
|
|
|
final_entries.push((context, entry));
|
2025-10-04 23:12:01 -07:00
|
|
|
}
|
|
|
|
|
|
2025-10-05 00:09:53 -07:00
|
|
|
info!("entries:");
|
2025-10-04 23:33:23 -07:00
|
|
|
for (index, (context, entry)) in final_entries.iter().enumerate() {
|
|
|
|
|
let title = context.stamp(&entry.title);
|
2025-10-05 00:09:53 -07:00
|
|
|
info!(" entry {}: {}", index + 1, title);
|
2025-10-04 23:33:23 -07:00
|
|
|
}
|
|
|
|
|
|
2025-10-14 12:47:33 -07:00
|
|
|
phase(context.clone(), &config.phases.late).context("unable to execute late phase")?;
|
2025-10-13 16:23:08 -07:00
|
|
|
|
2025-10-19 02:25:55 -07:00
|
|
|
let Some((context, entry)) = final_entries.first() else {
|
|
|
|
|
bail!("no entries found");
|
|
|
|
|
};
|
2025-10-04 23:33:23 -07:00
|
|
|
|
|
|
|
|
for action in &entry.actions {
|
2025-10-05 00:09:53 -07:00
|
|
|
let action = context.stamp(action);
|
2025-10-11 14:35:29 -07:00
|
|
|
actions::execute(context.clone(), &action)
|
2025-10-14 12:47:33 -07:00
|
|
|
.context(format!("unable to execute action '{}'", action))?;
|
2025-10-01 21:30:43 -07:00
|
|
|
}
|
2025-10-11 14:35:29 -07:00
|
|
|
Ok(())
|
2025-10-01 16:45:04 -07:00
|
|
|
}
|