mirror of
https://github.com/edera-dev/sprout.git
synced 2025-12-19 13:50:16 +00:00
begin documenting some functions and align error messages
This commit is contained in:
@@ -28,7 +28,7 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
|
|||||||
context.root().loaded_image_path()?,
|
context.root().loaded_image_path()?,
|
||||||
&context.stamp(&configuration.path),
|
&context.stamp(&configuration.path),
|
||||||
)
|
)
|
||||||
.context("failed to resolve chainload path")?;
|
.context("unable to resolve chainload path")?;
|
||||||
|
|
||||||
let image = uefi::boot::load_image(
|
let image = uefi::boot::load_image(
|
||||||
sprout_image,
|
sprout_image,
|
||||||
@@ -37,7 +37,7 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
|
|||||||
boot_policy: uefi::proto::BootPolicy::ExactMatch,
|
boot_policy: uefi::proto::BootPolicy::ExactMatch,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.context("failed to load image")?;
|
.context("unable to load image")?;
|
||||||
|
|
||||||
let mut loaded_image_protocol = uefi::boot::open_protocol_exclusive::<LoadedImage>(image)
|
let mut loaded_image_protocol = uefi::boot::open_protocol_exclusive::<LoadedImage>(image)
|
||||||
.context("unable to open loaded image protocol")?;
|
.context("unable to open loaded image protocol")?;
|
||||||
@@ -76,20 +76,20 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
|
|||||||
if let Some(ref linux_initrd) = configuration.linux_initrd {
|
if let Some(ref linux_initrd) = configuration.linux_initrd {
|
||||||
let initrd_path = context.stamp(linux_initrd);
|
let initrd_path = context.stamp(linux_initrd);
|
||||||
let content = utils::read_file_contents(context.root().loaded_image_path()?, &initrd_path)
|
let content = utils::read_file_contents(context.root().loaded_image_path()?, &initrd_path)
|
||||||
.context("failed to read linux initrd")?;
|
.context("unable to read linux initrd")?;
|
||||||
initrd_handle = Some(
|
initrd_handle = Some(
|
||||||
register_linux_initrd(content.into_boxed_slice())
|
register_linux_initrd(content.into_boxed_slice())
|
||||||
.context("failed to register linux initrd")?,
|
.context("unable to register linux initrd")?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (base, size) = loaded_image_protocol.info();
|
let (base, size) = loaded_image_protocol.info();
|
||||||
info!("loaded image: base={:#x} size={:#x}", base.addr(), size);
|
info!("loaded image: base={:#x} size={:#x}", base.addr(), size);
|
||||||
let result = uefi::boot::start_image(image).context("failed to start image");
|
let result = uefi::boot::start_image(image).context("unable to start image");
|
||||||
if let Some(initrd_handle) = initrd_handle {
|
if let Some(initrd_handle) = initrd_handle {
|
||||||
unregister_linux_initrd(initrd_handle).context("failed to unregister linux initrd")?;
|
unregister_linux_initrd(initrd_handle).context("unable to unregister linux initrd")?;
|
||||||
}
|
}
|
||||||
result.context("failed to start image")?;
|
result.context("unable to start image")?;
|
||||||
drop(options_holder);
|
drop(options_holder);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ pub fn default_splash_time() -> u32 {
|
|||||||
|
|
||||||
fn setup_graphics() -> Result<ScopedProtocol<GraphicsOutput>> {
|
fn setup_graphics() -> Result<ScopedProtocol<GraphicsOutput>> {
|
||||||
let gop_handle = uefi::boot::get_handle_for_protocol::<GraphicsOutput>()
|
let gop_handle = uefi::boot::get_handle_for_protocol::<GraphicsOutput>()
|
||||||
.context("failed to get graphics output")?;
|
.context("unable to get graphics output")?;
|
||||||
uefi::boot::open_protocol_exclusive::<GraphicsOutput>(gop_handle)
|
uefi::boot::open_protocol_exclusive::<GraphicsOutput>(gop_handle)
|
||||||
.context("failed to open graphics output")
|
.context("unable to open graphics output")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fit_to_frame(image: &DynamicImage, frame: Rect) -> Rect {
|
fn fit_to_frame(image: &DynamicImage, frame: Rect) -> Rect {
|
||||||
@@ -99,7 +99,7 @@ pub fn splash(context: Rc<SproutContext>, configuration: &SplashConfiguration) -
|
|||||||
let image = read_file_contents(context.root().loaded_image_path()?, &image)?;
|
let image = read_file_contents(context.root().loaded_image_path()?, &image)?;
|
||||||
let image = ImageReader::with_format(Cursor::new(image), ImageFormat::Png)
|
let image = ImageReader::with_format(Cursor::new(image), ImageFormat::Png)
|
||||||
.decode()
|
.decode()
|
||||||
.context("failed to decode splash image")?;
|
.context("unable to decode splash image")?;
|
||||||
draw(image)?;
|
draw(image)?;
|
||||||
std::thread::sleep(Duration::from_secs(configuration.time as u64));
|
std::thread::sleep(Duration::from_secs(configuration.time as u64));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use crate::actions::ActionDeclaration;
|
use crate::actions::ActionDeclaration;
|
||||||
use crate::drivers::DriverDeclaration;
|
use crate::drivers::DriverDeclaration;
|
||||||
|
use crate::entries::EntryDeclaration;
|
||||||
use crate::extractors::ExtractorDeclaration;
|
use crate::extractors::ExtractorDeclaration;
|
||||||
use crate::generators::GeneratorDeclaration;
|
use crate::generators::GeneratorDeclaration;
|
||||||
|
use crate::phases::PhasesConfiguration;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@@ -30,37 +32,14 @@ pub struct RootConfiguration {
|
|||||||
pub phases: PhasesConfiguration,
|
pub phases: PhasesConfiguration,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, Clone)]
|
pub fn latest_version() -> u32 {
|
||||||
pub struct EntryDeclaration {
|
1
|
||||||
pub title: String,
|
|
||||||
#[serde(default)]
|
|
||||||
pub actions: Vec<String>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub values: BTreeMap<String, String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, Clone)]
|
|
||||||
pub struct PhasesConfiguration {
|
|
||||||
#[serde(default)]
|
|
||||||
pub early: Vec<PhaseConfiguration>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub startup: Vec<PhaseConfiguration>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub late: Vec<PhaseConfiguration>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, Clone)]
|
|
||||||
pub struct PhaseConfiguration {
|
|
||||||
#[serde(default)]
|
|
||||||
pub actions: Vec<String>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub values: BTreeMap<String, String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load() -> Result<RootConfiguration> {
|
pub fn load() -> Result<RootConfiguration> {
|
||||||
let current_image_device_path_protocol =
|
let current_image_device_path_protocol =
|
||||||
uefi::boot::open_protocol_exclusive::<LoadedImageDevicePath>(uefi::boot::image_handle())
|
uefi::boot::open_protocol_exclusive::<LoadedImageDevicePath>(uefi::boot::image_handle())
|
||||||
.context("failed to get loaded image device path")?;
|
.context("unable to get loaded image device path")?;
|
||||||
let path = current_image_device_path_protocol.deref().to_boxed();
|
let path = current_image_device_path_protocol.deref().to_boxed();
|
||||||
|
|
||||||
let content = utils::read_file_contents(&path, "sprout.toml")
|
let content = utils::read_file_contents(&path, "sprout.toml")
|
||||||
@@ -69,7 +48,3 @@ pub fn load() -> Result<RootConfiguration> {
|
|||||||
toml::from_slice(&content).context("unable to parse sprout.toml file")?;
|
toml::from_slice(&content).context("unable to parse sprout.toml file")?;
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn latest_version() -> u32 {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -34,16 +34,16 @@ fn load_driver(context: Rc<SproutContext>, driver: &DriverDeclaration) -> Result
|
|||||||
boot_policy: uefi::proto::BootPolicy::ExactMatch,
|
boot_policy: uefi::proto::BootPolicy::ExactMatch,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.context("failed to load image")?;
|
.context("unable to load image")?;
|
||||||
|
|
||||||
uefi::boot::start_image(image).context("failed to start driver image")?;
|
uefi::boot::start_image(image).context("unable to start driver image")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconnect() -> Result<()> {
|
fn reconnect() -> Result<()> {
|
||||||
let handles = uefi::boot::locate_handle_buffer(SearchType::AllHandles)
|
let handles = uefi::boot::locate_handle_buffer(SearchType::AllHandles)
|
||||||
.context("failed to locate handles buffer")?;
|
.context("unable to locate handles buffer")?;
|
||||||
|
|
||||||
for handle in handles.iter() {
|
for handle in handles.iter() {
|
||||||
// ignore result as there is nothing we can do if it doesn't work.
|
// ignore result as there is nothing we can do if it doesn't work.
|
||||||
@@ -63,10 +63,10 @@ pub fn load(
|
|||||||
|
|
||||||
info!("loading drivers");
|
info!("loading drivers");
|
||||||
for (name, driver) in drivers {
|
for (name, driver) in drivers {
|
||||||
load_driver(context.clone(), driver).context(format!("failed to load driver: {}", name))?;
|
load_driver(context.clone(), driver).context(format!("unable to load driver: {}", name))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
reconnect().context("failed to reconnect drivers")?;
|
reconnect().context("unable to reconnect drivers")?;
|
||||||
info!("loaded drivers");
|
info!("loaded drivers");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/entries.rs
Normal file
11
src/entries.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default, Clone)]
|
||||||
|
pub struct EntryDeclaration {
|
||||||
|
pub title: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub actions: Vec<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub values: BTreeMap<String, String>,
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ pub fn extract(
|
|||||||
extractor: &FilesystemDeviceMatchExtractor,
|
extractor: &FilesystemDeviceMatchExtractor,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
let handles = uefi::boot::find_handles::<SimpleFileSystem>()
|
let handles = uefi::boot::find_handles::<SimpleFileSystem>()
|
||||||
.context("failed to find filesystem handles")?;
|
.context("unable to find filesystem handles")?;
|
||||||
for handle in handles {
|
for handle in handles {
|
||||||
let mut has_match = false;
|
let mut has_match = false;
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ pub fn extract(
|
|||||||
{
|
{
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Err(error).context("failed to open filesystem partition info")?;
|
Err(error).context("unable to open filesystem partition info")?;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ pub fn extract(
|
|||||||
&& let Some(ref has_partition_uuid) = extractor.has_partition_uuid
|
&& let Some(ref has_partition_uuid) = extractor.has_partition_uuid
|
||||||
{
|
{
|
||||||
let parsed_uuid = Guid::from_str(has_partition_uuid)
|
let parsed_uuid = Guid::from_str(has_partition_uuid)
|
||||||
.map_err(|e| anyhow!("failed to parse has-partition-uuid: {}", e))?;
|
.map_err(|e| anyhow!("unable to parse has-partition-uuid: {}", e))?;
|
||||||
if partition_uuid != parsed_uuid {
|
if partition_uuid != parsed_uuid {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ pub fn extract(
|
|||||||
&& let Some(ref has_partition_type_uuid) = extractor.has_partition_type_uuid
|
&& let Some(ref has_partition_type_uuid) = extractor.has_partition_type_uuid
|
||||||
{
|
{
|
||||||
let parsed_uuid = Guid::from_str(has_partition_type_uuid)
|
let parsed_uuid = Guid::from_str(has_partition_type_uuid)
|
||||||
.map_err(|e| anyhow!("failed to parse has-partition-type-uuid: {}", e))?;
|
.map_err(|e| anyhow!("unable to parse has-partition-type-uuid: {}", e))?;
|
||||||
if partition_type_guid != parsed_uuid {
|
if partition_type_guid != parsed_uuid {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -85,17 +85,17 @@ pub fn extract(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut filesystem = uefi::boot::open_protocol_exclusive::<SimpleFileSystem>(handle)
|
let mut filesystem = uefi::boot::open_protocol_exclusive::<SimpleFileSystem>(handle)
|
||||||
.context("failed to open filesystem protocol")?;
|
.context("unable to open filesystem protocol")?;
|
||||||
|
|
||||||
if let Some(ref label) = extractor.has_label {
|
if let Some(ref label) = extractor.has_label {
|
||||||
let want_label = CString16::try_from(context.stamp(label).as_str())
|
let want_label = CString16::try_from(context.stamp(label).as_str())
|
||||||
.context("failed to convert label to CString16")?;
|
.context("unable to convert label to CString16")?;
|
||||||
let mut root = filesystem
|
let mut root = filesystem
|
||||||
.open_volume()
|
.open_volume()
|
||||||
.context("failed to open filesystem volume")?;
|
.context("unable to open filesystem volume")?;
|
||||||
let label = root
|
let label = root
|
||||||
.get_boxed_info::<FileSystemVolumeLabel>()
|
.get_boxed_info::<FileSystemVolumeLabel>()
|
||||||
.context("failed to get filesystem volume label")?;
|
.context("unable to get filesystem volume label")?;
|
||||||
|
|
||||||
if label.volume_label() != want_label {
|
if label.volume_label() != want_label {
|
||||||
continue;
|
continue;
|
||||||
@@ -105,7 +105,7 @@ pub fn extract(
|
|||||||
|
|
||||||
if let Some(ref item) = extractor.has_item {
|
if let Some(ref item) = extractor.has_item {
|
||||||
let want_item = CString16::try_from(context.stamp(item).as_str())
|
let want_item = CString16::try_from(context.stamp(item).as_str())
|
||||||
.context("failed to convert item to CString16")?;
|
.context("unable to convert item to CString16")?;
|
||||||
let mut filesystem = FileSystem::new(filesystem);
|
let mut filesystem = FileSystem::new(filesystem);
|
||||||
let metadata = filesystem.metadata(Path::new(&want_item));
|
let metadata = filesystem.metadata(Path::new(&want_item));
|
||||||
|
|
||||||
@@ -125,9 +125,9 @@ pub fn extract(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let path = uefi::boot::open_protocol_exclusive::<DevicePath>(handle)
|
let path = uefi::boot::open_protocol_exclusive::<DevicePath>(handle)
|
||||||
.context("failed to open filesystem device path")?;
|
.context("unable to open filesystem device path")?;
|
||||||
let path = path.deref();
|
let path = path.deref();
|
||||||
return utils::device_path_root(path).context("failed to get device path root");
|
return utils::device_path_root(path).context("unable to get device path root");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(fallback) = &extractor.fallback {
|
if let Some(fallback) = &extractor.fallback {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::config::EntryDeclaration;
|
|
||||||
use crate::context::SproutContext;
|
use crate::context::SproutContext;
|
||||||
|
use crate::entries::EntryDeclaration;
|
||||||
use crate::generators::bls::BlsConfiguration;
|
use crate::generators::bls::BlsConfiguration;
|
||||||
use crate::generators::matrix::MatrixConfiguration;
|
use crate::generators::matrix::MatrixConfiguration;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
mod entry;
|
|
||||||
|
|
||||||
use crate::config::EntryDeclaration;
|
|
||||||
use crate::context::SproutContext;
|
use crate::context::SproutContext;
|
||||||
|
use crate::entries::EntryDeclaration;
|
||||||
use crate::generators::bls::entry::BlsEntry;
|
use crate::generators::bls::entry::BlsEntry;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
@@ -13,6 +11,8 @@ use uefi::fs::{FileSystem, Path};
|
|||||||
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
|
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
|
||||||
use uefi::proto::media::fs::SimpleFileSystem;
|
use uefi::proto::media::fs::SimpleFileSystem;
|
||||||
|
|
||||||
|
mod entry;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, Clone)]
|
#[derive(Serialize, Deserialize, Default, Clone)]
|
||||||
pub struct BlsConfiguration {
|
pub struct BlsConfiguration {
|
||||||
pub entry: EntryDeclaration,
|
pub entry: EntryDeclaration,
|
||||||
@@ -32,19 +32,19 @@ pub fn generate(
|
|||||||
|
|
||||||
let path = context.stamp(&bls.path);
|
let path = context.stamp(&bls.path);
|
||||||
let resolved = utils::resolve_path(context.root().loaded_image_path()?, &path)
|
let resolved = utils::resolve_path(context.root().loaded_image_path()?, &path)
|
||||||
.context("failed to resolve bls path")?;
|
.context("unable to resolve bls path")?;
|
||||||
let fs = uefi::boot::open_protocol_exclusive::<SimpleFileSystem>(resolved.filesystem_handle)
|
let fs = uefi::boot::open_protocol_exclusive::<SimpleFileSystem>(resolved.filesystem_handle)
|
||||||
.context("failed to open bls filesystem")?;
|
.context("unable to open bls filesystem")?;
|
||||||
let mut fs = FileSystem::new(fs);
|
let mut fs = FileSystem::new(fs);
|
||||||
let sub_text_path = resolved
|
let sub_text_path = resolved
|
||||||
.sub_path
|
.sub_path
|
||||||
.to_string(DisplayOnly(false), AllowShortcuts(false))
|
.to_string(DisplayOnly(false), AllowShortcuts(false))
|
||||||
.context("failed to convert subpath to string")?;
|
.context("unable to convert subpath to string")?;
|
||||||
let entries_path = Path::new(&sub_text_path);
|
let entries_path = Path::new(&sub_text_path);
|
||||||
|
|
||||||
let entries_iter = fs
|
let entries_iter = fs
|
||||||
.read_dir(entries_path)
|
.read_dir(entries_path)
|
||||||
.context("failed to read bls entries")?;
|
.context("unable to read bls entries")?;
|
||||||
|
|
||||||
for entry in entries_iter {
|
for entry in entries_iter {
|
||||||
let entry = entry?;
|
let entry = entry?;
|
||||||
@@ -57,13 +57,13 @@ pub fn generate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let full_entry_path = CString16::try_from(format!("{}\\{}", sub_text_path, name).as_str())
|
let full_entry_path = CString16::try_from(format!("{}\\{}", sub_text_path, name).as_str())
|
||||||
.context("failed to construct full entry path")?;
|
.context("unable to construct full entry path")?;
|
||||||
let full_entry_path = Path::new(&full_entry_path);
|
let full_entry_path = Path::new(&full_entry_path);
|
||||||
let content = fs
|
let content = fs
|
||||||
.read(full_entry_path)
|
.read(full_entry_path)
|
||||||
.context("failed to read bls file")?;
|
.context("unable to read bls file")?;
|
||||||
let content = String::from_utf8(content).context("failed to read bls entry as utf8")?;
|
let content = String::from_utf8(content).context("unable to read bls entry as utf8")?;
|
||||||
let entry = BlsEntry::from_str(&content).context("failed to parse bls entry")?;
|
let entry = BlsEntry::from_str(&content).context("unable to parse bls entry")?;
|
||||||
|
|
||||||
if !entry.is_valid() {
|
if !entry.is_valid() {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::config::EntryDeclaration;
|
|
||||||
use crate::context::SproutContext;
|
use crate::context::SproutContext;
|
||||||
|
use crate::entries::EntryDeclaration;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|||||||
33
src/main.rs
33
src/main.rs
@@ -1,12 +1,11 @@
|
|||||||
#![feature(uefi_std)]
|
#![feature(uefi_std)]
|
||||||
|
|
||||||
use crate::config::PhaseConfiguration;
|
|
||||||
use crate::context::{RootContext, SproutContext};
|
use crate::context::{RootContext, SproutContext};
|
||||||
|
use crate::phases::phase;
|
||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{Context, Result, bail};
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
|
||||||
use uefi::proto::device_path::LoadedImageDevicePath;
|
use uefi::proto::device_path::LoadedImageDevicePath;
|
||||||
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
|
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
|
||||||
|
|
||||||
@@ -14,25 +13,13 @@ pub mod actions;
|
|||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod drivers;
|
pub mod drivers;
|
||||||
|
pub mod entries;
|
||||||
pub mod extractors;
|
pub mod extractors;
|
||||||
pub mod generators;
|
pub mod generators;
|
||||||
|
pub mod phases;
|
||||||
pub mod setup;
|
pub mod setup;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
fn phase(context: Rc<SproutContext>, phase: &[PhaseConfiguration]) -> Result<()> {
|
|
||||||
for item in phase {
|
|
||||||
let mut context = context.fork();
|
|
||||||
context.insert(&item.values);
|
|
||||||
let context = context.freeze();
|
|
||||||
|
|
||||||
for action in item.actions.iter() {
|
|
||||||
actions::execute(context.clone(), action)
|
|
||||||
.context(format!("failed to execute action '{}'", action))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
setup::init()?;
|
setup::init()?;
|
||||||
|
|
||||||
@@ -46,7 +33,7 @@ fn main() -> Result<()> {
|
|||||||
let current_image_device_path_protocol = uefi::boot::open_protocol_exclusive::<
|
let current_image_device_path_protocol = uefi::boot::open_protocol_exclusive::<
|
||||||
LoadedImageDevicePath,
|
LoadedImageDevicePath,
|
||||||
>(uefi::boot::image_handle())
|
>(uefi::boot::image_handle())
|
||||||
.context("failed to get loaded image device path")?;
|
.context("unable to get loaded image device path")?;
|
||||||
let loaded_image_path = current_image_device_path_protocol.deref().to_boxed();
|
let loaded_image_path = current_image_device_path_protocol.deref().to_boxed();
|
||||||
info!(
|
info!(
|
||||||
"loaded image path: {}",
|
"loaded image path: {}",
|
||||||
@@ -61,14 +48,14 @@ fn main() -> Result<()> {
|
|||||||
context.insert(&config.values);
|
context.insert(&config.values);
|
||||||
let context = context.freeze();
|
let context = context.freeze();
|
||||||
|
|
||||||
phase(context.clone(), &config.phases.early).context("failed to execute early phase")?;
|
phase(context.clone(), &config.phases.early).context("unable to execute early phase")?;
|
||||||
|
|
||||||
drivers::load(context.clone(), &config.drivers).context("failed to load drivers")?;
|
drivers::load(context.clone(), &config.drivers).context("unable to load drivers")?;
|
||||||
|
|
||||||
let mut extracted = BTreeMap::new();
|
let mut extracted = BTreeMap::new();
|
||||||
for (name, extractor) in &config.extractors {
|
for (name, extractor) in &config.extractors {
|
||||||
let value = extractors::extract(context.clone(), extractor)
|
let value = extractors::extract(context.clone(), extractor)
|
||||||
.context(format!("failed to extract value {}", name))?;
|
.context(format!("unable to extract value {}", name))?;
|
||||||
info!("extracted value {}: {}", name, value);
|
info!("extracted value {}: {}", name, value);
|
||||||
extracted.insert(name.clone(), value);
|
extracted.insert(name.clone(), value);
|
||||||
}
|
}
|
||||||
@@ -76,7 +63,7 @@ fn main() -> Result<()> {
|
|||||||
context.insert(&extracted);
|
context.insert(&extracted);
|
||||||
let context = context.freeze();
|
let context = context.freeze();
|
||||||
|
|
||||||
phase(context.clone(), &config.phases.startup).context("failed to execute startup phase")?;
|
phase(context.clone(), &config.phases.startup).context("unable to execute startup phase")?;
|
||||||
|
|
||||||
let mut all_entries = Vec::new();
|
let mut all_entries = Vec::new();
|
||||||
|
|
||||||
@@ -107,7 +94,7 @@ fn main() -> Result<()> {
|
|||||||
info!(" entry {}: {}", index + 1, title);
|
info!(" entry {}: {}", index + 1, title);
|
||||||
}
|
}
|
||||||
|
|
||||||
phase(context.clone(), &config.phases.late).context("failed to execute late phase")?;
|
phase(context.clone(), &config.phases.late).context("unable to execute late phase")?;
|
||||||
|
|
||||||
let index = 1;
|
let index = 1;
|
||||||
|
|
||||||
@@ -116,7 +103,7 @@ fn main() -> Result<()> {
|
|||||||
for action in &entry.actions {
|
for action in &entry.actions {
|
||||||
let action = context.stamp(action);
|
let action = context.stamp(action);
|
||||||
actions::execute(context.clone(), &action)
|
actions::execute(context.clone(), &action)
|
||||||
.context(format!("failed to execute action '{}'", action))?;
|
.context(format!("unable to execute action '{}'", action))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/phases.rs
Normal file
38
src/phases.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
use crate::actions;
|
||||||
|
use crate::context::SproutContext;
|
||||||
|
use anyhow::Context;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default, Clone)]
|
||||||
|
pub struct PhasesConfiguration {
|
||||||
|
#[serde(default)]
|
||||||
|
pub early: Vec<PhaseConfiguration>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub startup: Vec<PhaseConfiguration>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub late: Vec<PhaseConfiguration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default, Clone)]
|
||||||
|
pub struct PhaseConfiguration {
|
||||||
|
#[serde(default)]
|
||||||
|
pub actions: Vec<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub values: BTreeMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn phase(context: Rc<SproutContext>, phase: &[PhaseConfiguration]) -> anyhow::Result<()> {
|
||||||
|
for item in phase {
|
||||||
|
let mut context = context.fork();
|
||||||
|
context.insert(&item.values);
|
||||||
|
let context = context.freeze();
|
||||||
|
|
||||||
|
for action in item.actions.iter() {
|
||||||
|
actions::execute(context.clone(), action)
|
||||||
|
.context(format!("unable to execute action '{}'", action))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use std::os::uefi as uefi_std;
|
use std::os::uefi as uefi_std;
|
||||||
|
|
||||||
|
/// Initializes the UEFI environment.
|
||||||
|
///
|
||||||
|
/// This fetches the system table and current image handle from uefi_std and injects
|
||||||
|
/// them into the uefi crate.
|
||||||
pub fn init() -> Result<()> {
|
pub fn init() -> Result<()> {
|
||||||
let system_table = uefi_std::env::system_table();
|
let system_table = uefi_std::env::system_table();
|
||||||
let image_handle = uefi_std::env::image_handle();
|
let image_handle = uefi_std::env::image_handle();
|
||||||
@@ -15,6 +19,6 @@ pub fn init() -> Result<()> {
|
|||||||
uefi::boot::set_image_handle(handle);
|
uefi::boot::set_image_handle(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
uefi::helpers::init().context("failed to initialize uefi")?;
|
uefi::helpers::init().context("unable to initialize uefi")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/utils.rs
41
src/utils.rs
@@ -9,6 +9,8 @@ use uefi::{CString16, Handle};
|
|||||||
pub mod framebuffer;
|
pub mod framebuffer;
|
||||||
pub mod linux_media_initrd;
|
pub mod linux_media_initrd;
|
||||||
|
|
||||||
|
/// Parses the input [path] as a [DevicePath].
|
||||||
|
/// Uses the [DevicePathFromText] protocol exclusively, and will fail if it cannot acquire the protocol.
|
||||||
pub fn text_to_device_path(path: &str) -> Result<PoolDevicePath> {
|
pub fn text_to_device_path(path: &str) -> Result<PoolDevicePath> {
|
||||||
let path = CString16::try_from(path).context("unable to convert path to CString16")?;
|
let path = CString16::try_from(path).context("unable to convert path to CString16")?;
|
||||||
let device_path_from_text = uefi::boot::open_protocol_exclusive::<DevicePathFromText>(
|
let device_path_from_text = uefi::boot::open_protocol_exclusive::<DevicePathFromText>(
|
||||||
@@ -22,6 +24,9 @@ pub fn text_to_device_path(path: &str) -> Result<PoolDevicePath> {
|
|||||||
.context("unable to convert text to device path")
|
.context("unable to convert text to device path")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Grabs the root part of the [path].
|
||||||
|
/// For example, given "PciRoot(0x0)/Pci(0x4,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/\EFI\BOOT\BOOTX64.efi"
|
||||||
|
/// it will give "PciRoot(0x0)/Pci(0x4,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)"
|
||||||
pub fn device_path_root(path: &DevicePath) -> Result<String> {
|
pub fn device_path_root(path: &DevicePath) -> Result<String> {
|
||||||
let mut path = path
|
let mut path = path
|
||||||
.node_iter()
|
.node_iter()
|
||||||
@@ -44,6 +49,9 @@ pub fn device_path_root(path: &DevicePath) -> Result<String> {
|
|||||||
Ok(path)
|
Ok(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Grabs the part of the [path] after the root.
|
||||||
|
/// For example, given "PciRoot(0x0)/Pci(0x4,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/\EFI\BOOT\BOOTX64.efi"
|
||||||
|
/// it will give "\EFI\BOOT\BOOTX64.efi"
|
||||||
pub fn device_path_subpath(path: &DevicePath) -> Result<String> {
|
pub fn device_path_subpath(path: &DevicePath) -> Result<String> {
|
||||||
let path = path
|
let path = path
|
||||||
.node_iter()
|
.node_iter()
|
||||||
@@ -65,15 +73,27 @@ pub fn device_path_subpath(path: &DevicePath) -> Result<String> {
|
|||||||
Ok(path)
|
Ok(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the components of a resolved path.
|
||||||
pub struct ResolvedPath {
|
pub struct ResolvedPath {
|
||||||
|
/// The root path of the resolved path. This is the device itself.
|
||||||
|
/// For example, "PciRoot(0x0)/Pci(0x4,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/"
|
||||||
pub root_path: Box<DevicePath>,
|
pub root_path: Box<DevicePath>,
|
||||||
|
/// The subpath of the resolved path. This is the path to the file.
|
||||||
|
/// For example, "\EFI\BOOT\BOOTX64.efi"
|
||||||
pub sub_path: Box<DevicePath>,
|
pub sub_path: Box<DevicePath>,
|
||||||
|
/// The full path of the resolved path. This is the safest path to use.
|
||||||
|
/// For example, "PciRoot(0x0)/Pci(0x4,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/\EFI\BOOT\BOOTX64.efi"
|
||||||
pub full_path: Box<DevicePath>,
|
pub full_path: Box<DevicePath>,
|
||||||
|
/// The handle of the filesystem containing the path.
|
||||||
|
/// This can be used to acquire a [SimpleFileSystem] protocol to read the file.
|
||||||
pub filesystem_handle: Handle,
|
pub filesystem_handle: Handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolve a path specified by [input] to its various components.
|
||||||
|
/// Uses [default_root_path] as the base root if one is not specified in the path.
|
||||||
|
/// Returns [ResolvedPath] which contains the resolved components.
|
||||||
pub fn resolve_path(default_root_path: &DevicePath, input: &str) -> Result<ResolvedPath> {
|
pub fn resolve_path(default_root_path: &DevicePath, input: &str) -> Result<ResolvedPath> {
|
||||||
let mut path = text_to_device_path(input).context("failed to convert text to path")?;
|
let mut path = text_to_device_path(input).context("unable to convert text to path")?;
|
||||||
let path_has_device = path
|
let path_has_device = path
|
||||||
.node_iter()
|
.node_iter()
|
||||||
.next()
|
.next()
|
||||||
@@ -91,21 +111,21 @@ pub fn resolve_path(default_root_path: &DevicePath, input: &str) -> Result<Resol
|
|||||||
input.insert_str(
|
input.insert_str(
|
||||||
0,
|
0,
|
||||||
device_path_root(default_root_path)
|
device_path_root(default_root_path)
|
||||||
.context("failed to get loaded image device root")?
|
.context("unable to get loaded image device root")?
|
||||||
.as_str(),
|
.as_str(),
|
||||||
);
|
);
|
||||||
path = text_to_device_path(input.as_str()).context("failed to convert text to path")?;
|
path = text_to_device_path(input.as_str()).context("unable to convert text to path")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = path.to_boxed();
|
let path = path.to_boxed();
|
||||||
let root = device_path_root(path.as_ref()).context("failed to convert root to path")?;
|
let root = device_path_root(path.as_ref()).context("unable to convert root to path")?;
|
||||||
let root_path = text_to_device_path(root.as_str())
|
let root_path = text_to_device_path(root.as_str())
|
||||||
.context("failed to convert root to path")?
|
.context("unable to convert root to path")?
|
||||||
.to_boxed();
|
.to_boxed();
|
||||||
let mut root_path = root_path.as_ref();
|
let mut root_path = root_path.as_ref();
|
||||||
let handle = uefi::boot::locate_device_path::<SimpleFileSystem>(&mut root_path)
|
let handle = uefi::boot::locate_device_path::<SimpleFileSystem>(&mut root_path)
|
||||||
.context("failed to locate filesystem device path")?;
|
.context("unable to locate filesystem device path")?;
|
||||||
let subpath = device_path_subpath(path.deref()).context("failed to get device subpath")?;
|
let subpath = device_path_subpath(path.deref()).context("unable to get device subpath")?;
|
||||||
Ok(ResolvedPath {
|
Ok(ResolvedPath {
|
||||||
root_path: root_path.to_boxed(),
|
root_path: root_path.to_boxed(),
|
||||||
sub_path: text_to_device_path(subpath.as_str())?.to_boxed(),
|
sub_path: text_to_device_path(subpath.as_str())?.to_boxed(),
|
||||||
@@ -114,6 +134,13 @@ pub fn resolve_path(default_root_path: &DevicePath, input: &str) -> Result<Resol
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read the contents of a file at the location specified with the [input] path.
|
||||||
|
/// Internally, this uses [resolve_path] to resolve the path to its various components.
|
||||||
|
/// [resolve_path] is passed the [default_root_path] which should specify a base root.
|
||||||
|
///
|
||||||
|
/// This acquires exclusive protocol access to the [SimpleFileSystem] protocol of the resolved
|
||||||
|
/// filesystem handle, so care must be taken to call this function outside a scope with
|
||||||
|
/// the filesystem handle protocol acquired.
|
||||||
pub fn read_file_contents(default_root_path: &DevicePath, input: &str) -> Result<Vec<u8>> {
|
pub fn read_file_contents(default_root_path: &DevicePath, input: &str) -> Result<Vec<u8>> {
|
||||||
let resolved = resolve_path(default_root_path, input)?;
|
let resolved = resolve_path(default_root_path, input)?;
|
||||||
let fs = uefi::boot::open_protocol_exclusive::<SimpleFileSystem>(resolved.filesystem_handle)
|
let fs = uefi::boot::open_protocol_exclusive::<SimpleFileSystem>(resolved.filesystem_handle)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ impl Framebuffer {
|
|||||||
dest: (0, 0),
|
dest: (0, 0),
|
||||||
dims: (self.width, self.height),
|
dims: (self.width, self.height),
|
||||||
})
|
})
|
||||||
.context("failed to blit framebuffer")?;
|
.context("unable to blit framebuffer")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,9 @@ fn already_registered() -> Result<bool> {
|
|||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Registers the provided [data] with the UEFI stack as a Linux initrd.
|
||||||
|
/// This uses a special device path that Linux EFI stub will look at
|
||||||
|
/// to load the initrd from.
|
||||||
pub fn register_linux_initrd(data: Box<[u8]>) -> Result<LinuxMediaInitrdHandle> {
|
pub fn register_linux_initrd(data: Box<[u8]>) -> Result<LinuxMediaInitrdHandle> {
|
||||||
let path = LinuxMediaInitrdProtocol::device_path();
|
let path = LinuxMediaInitrdProtocol::device_path();
|
||||||
let path = Box::leak(path);
|
let path = Box::leak(path);
|
||||||
@@ -149,6 +152,8 @@ pub fn register_linux_initrd(data: Box<[u8]>) -> Result<LinuxMediaInitrdHandle>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unregisters a Linux initrd from the UEFI stack.
|
||||||
|
/// This will free the memory allocated by the initrd.
|
||||||
pub fn unregister_linux_initrd(handle: LinuxMediaInitrdHandle) -> Result<()> {
|
pub fn unregister_linux_initrd(handle: LinuxMediaInitrdHandle) -> Result<()> {
|
||||||
if !already_registered()? {
|
if !already_registered()? {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|||||||
Reference in New Issue
Block a user