diff --git a/src/config.rs b/src/config.rs index 6759b38..9d22e4f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,5 @@ use crate::actions::ActionDeclaration; +use crate::drivers::DriverDeclaration; use crate::generators::GeneratorDeclaration; use crate::utils; use anyhow::Context; @@ -13,6 +14,8 @@ pub struct RootConfiguration { #[serde(default)] pub values: BTreeMap, #[serde(default)] + pub drivers: BTreeMap, + #[serde(default)] pub actions: BTreeMap, #[serde(default)] pub entries: BTreeMap, diff --git a/src/drivers.rs b/src/drivers.rs new file mode 100644 index 0000000..a9665d2 --- /dev/null +++ b/src/drivers.rs @@ -0,0 +1,72 @@ +use crate::context::SproutContext; +use crate::utils; +use anyhow::{Context, Result}; +use log::info; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; +use std::rc::Rc; +use uefi::boot::SearchType; +use uefi::proto::device_path::LoadedImageDevicePath; + +#[derive(Serialize, Deserialize, Default, Clone)] +pub struct DriverDeclaration { + pub path: String, +} + +fn load_driver(context: Rc, driver: &DriverDeclaration) -> Result<()> { + let sprout_image = uefi::boot::image_handle(); + let image_device_path_protocol = + uefi::boot::open_protocol_exclusive::(sprout_image) + .context("unable to open loaded image device path protocol")?; + + let mut full_path = utils::device_path_root(&image_device_path_protocol)?; + + full_path.push_str(&context.stamp(&driver.path)); + + info!("driver path: {}", full_path); + + let device_path = utils::text_to_device_path(&full_path)?; + + let image = uefi::boot::load_image( + sprout_image, + uefi::boot::LoadImageSource::FromDevicePath { + device_path: &device_path, + boot_policy: uefi::proto::BootPolicy::ExactMatch, + }, + ) + .context("failed to load image")?; + + uefi::boot::start_image(image).context("failed to start driver image")?; + + Ok(()) +} + +fn reconnect() -> Result<()> { + let handles = uefi::boot::locate_handle_buffer(SearchType::AllHandles) + .context("failed to locate handles buffer")?; + + for handle in handles.iter() { + // ignore result as there is nothing we can do if it doesn't work. + let _ = uefi::boot::connect_controller(*handle, None, None, true); + } + + Ok(()) +} + +pub fn load( + context: Rc, + drivers: &BTreeMap, +) -> Result<()> { + if drivers.is_empty() { + return Ok(()); + } + + info!("loading drivers"); + for (name, driver) in drivers { + load_driver(context.clone(), driver).context(format!("failed to load driver: {}", name))?; + } + + reconnect().context("failed to reconnect drivers")?; + info!("loaded drivers"); + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 86b4154..6f71d8a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use std::rc::Rc; pub mod actions; pub mod config; pub mod context; +pub mod drivers; pub mod generators; pub mod setup; pub mod utils; @@ -43,6 +44,8 @@ fn main() -> Result<()> { context.insert(&config.values); let context = context.freeze(); + drivers::load(context.clone(), &config.drivers).context("failed to load drivers")?; + phase(context.clone(), &config.phases.startup)?; let mut all_entries = Vec::new();