mirror of
https://github.com/edera-dev/sprout.git
synced 2025-12-19 10:10:17 +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.stamp(&configuration.path),
|
||||
)
|
||||
.context("failed to resolve chainload path")?;
|
||||
.context("unable to resolve chainload path")?;
|
||||
|
||||
let image = uefi::boot::load_image(
|
||||
sprout_image,
|
||||
@@ -37,7 +37,7 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
|
||||
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)
|
||||
.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 {
|
||||
let initrd_path = context.stamp(linux_initrd);
|
||||
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(
|
||||
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();
|
||||
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 {
|
||||
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);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -25,9 +25,9 @@ pub fn default_splash_time() -> u32 {
|
||||
|
||||
fn setup_graphics() -> Result<ScopedProtocol<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)
|
||||
.context("failed to open graphics output")
|
||||
.context("unable to open graphics output")
|
||||
}
|
||||
|
||||
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 = ImageReader::with_format(Cursor::new(image), ImageFormat::Png)
|
||||
.decode()
|
||||
.context("failed to decode splash image")?;
|
||||
.context("unable to decode splash image")?;
|
||||
draw(image)?;
|
||||
std::thread::sleep(Duration::from_secs(configuration.time as u64));
|
||||
Ok(())
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use crate::actions::ActionDeclaration;
|
||||
use crate::drivers::DriverDeclaration;
|
||||
use crate::entries::EntryDeclaration;
|
||||
use crate::extractors::ExtractorDeclaration;
|
||||
use crate::generators::GeneratorDeclaration;
|
||||
use crate::phases::PhasesConfiguration;
|
||||
use crate::utils;
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
@@ -30,37 +32,14 @@ pub struct RootConfiguration {
|
||||
pub phases: PhasesConfiguration,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Clone)]
|
||||
pub struct EntryDeclaration {
|
||||
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 latest_version() -> u32 {
|
||||
1
|
||||
}
|
||||
|
||||
pub fn load() -> Result<RootConfiguration> {
|
||||
let current_image_device_path_protocol =
|
||||
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 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")?;
|
||||
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,
|
||||
},
|
||||
)
|
||||
.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(())
|
||||
}
|
||||
|
||||
fn reconnect() -> Result<()> {
|
||||
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() {
|
||||
// ignore result as there is nothing we can do if it doesn't work.
|
||||
@@ -63,10 +63,10 @@ pub fn load(
|
||||
|
||||
info!("loading 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");
|
||||
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,
|
||||
) -> Result<String> {
|
||||
let handles = uefi::boot::find_handles::<SimpleFileSystem>()
|
||||
.context("failed to find filesystem handles")?;
|
||||
.context("unable to find filesystem handles")?;
|
||||
for handle in handles {
|
||||
let mut has_match = false;
|
||||
|
||||
@@ -55,7 +55,7 @@ pub fn extract(
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Err(error).context("failed to open filesystem partition info")?;
|
||||
Err(error).context("unable to open filesystem partition info")?;
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ pub fn extract(
|
||||
&& let Some(ref has_partition_uuid) = extractor.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 {
|
||||
continue;
|
||||
}
|
||||
@@ -77,7 +77,7 @@ pub fn extract(
|
||||
&& let Some(ref has_partition_type_uuid) = extractor.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 {
|
||||
continue;
|
||||
}
|
||||
@@ -85,17 +85,17 @@ pub fn extract(
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
.open_volume()
|
||||
.context("failed to open filesystem volume")?;
|
||||
.context("unable to open filesystem volume")?;
|
||||
let label = root
|
||||
.get_boxed_info::<FileSystemVolumeLabel>()
|
||||
.context("failed to get filesystem volume label")?;
|
||||
.context("unable to get filesystem volume label")?;
|
||||
|
||||
if label.volume_label() != want_label {
|
||||
continue;
|
||||
@@ -105,7 +105,7 @@ pub fn extract(
|
||||
|
||||
if let Some(ref item) = extractor.has_item {
|
||||
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 metadata = filesystem.metadata(Path::new(&want_item));
|
||||
|
||||
@@ -125,9 +125,9 @@ pub fn extract(
|
||||
}
|
||||
|
||||
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();
|
||||
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 {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::config::EntryDeclaration;
|
||||
use crate::context::SproutContext;
|
||||
use crate::entries::EntryDeclaration;
|
||||
use crate::generators::bls::BlsConfiguration;
|
||||
use crate::generators::matrix::MatrixConfiguration;
|
||||
use anyhow::Result;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
mod entry;
|
||||
|
||||
use crate::config::EntryDeclaration;
|
||||
use crate::context::SproutContext;
|
||||
use crate::entries::EntryDeclaration;
|
||||
use crate::generators::bls::entry::BlsEntry;
|
||||
use crate::utils;
|
||||
use anyhow::{Context, Result};
|
||||
@@ -13,6 +11,8 @@ use uefi::fs::{FileSystem, Path};
|
||||
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
|
||||
use uefi::proto::media::fs::SimpleFileSystem;
|
||||
|
||||
mod entry;
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Clone)]
|
||||
pub struct BlsConfiguration {
|
||||
pub entry: EntryDeclaration,
|
||||
@@ -32,19 +32,19 @@ pub fn generate(
|
||||
|
||||
let path = context.stamp(&bls.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)
|
||||
.context("failed to open bls filesystem")?;
|
||||
.context("unable to open bls filesystem")?;
|
||||
let mut fs = FileSystem::new(fs);
|
||||
let sub_text_path = resolved
|
||||
.sub_path
|
||||
.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_iter = fs
|
||||
.read_dir(entries_path)
|
||||
.context("failed to read bls entries")?;
|
||||
.context("unable to read bls entries")?;
|
||||
|
||||
for entry in entries_iter {
|
||||
let entry = entry?;
|
||||
@@ -57,13 +57,13 @@ pub fn generate(
|
||||
}
|
||||
|
||||
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 content = fs
|
||||
.read(full_entry_path)
|
||||
.context("failed to read bls file")?;
|
||||
let content = String::from_utf8(content).context("failed to read bls entry as utf8")?;
|
||||
let entry = BlsEntry::from_str(&content).context("failed to parse bls entry")?;
|
||||
.context("unable to read bls file")?;
|
||||
let content = String::from_utf8(content).context("unable to read bls entry as utf8")?;
|
||||
let entry = BlsEntry::from_str(&content).context("unable to parse bls entry")?;
|
||||
|
||||
if !entry.is_valid() {
|
||||
continue;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::config::EntryDeclaration;
|
||||
use crate::context::SproutContext;
|
||||
use crate::entries::EntryDeclaration;
|
||||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
33
src/main.rs
33
src/main.rs
@@ -1,12 +1,11 @@
|
||||
#![feature(uefi_std)]
|
||||
|
||||
use crate::config::PhaseConfiguration;
|
||||
use crate::context::{RootContext, SproutContext};
|
||||
use crate::phases::phase;
|
||||
use anyhow::{Context, Result, bail};
|
||||
use log::info;
|
||||
use std::collections::BTreeMap;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use uefi::proto::device_path::LoadedImageDevicePath;
|
||||
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
|
||||
|
||||
@@ -14,25 +13,13 @@ pub mod actions;
|
||||
pub mod config;
|
||||
pub mod context;
|
||||
pub mod drivers;
|
||||
pub mod entries;
|
||||
pub mod extractors;
|
||||
pub mod generators;
|
||||
pub mod phases;
|
||||
pub mod setup;
|
||||
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<()> {
|
||||
setup::init()?;
|
||||
|
||||
@@ -46,7 +33,7 @@ fn main() -> Result<()> {
|
||||
let current_image_device_path_protocol = 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 loaded_image_path = current_image_device_path_protocol.deref().to_boxed();
|
||||
info!(
|
||||
"loaded image path: {}",
|
||||
@@ -61,14 +48,14 @@ fn main() -> Result<()> {
|
||||
context.insert(&config.values);
|
||||
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();
|
||||
for (name, extractor) in &config.extractors {
|
||||
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);
|
||||
extracted.insert(name.clone(), value);
|
||||
}
|
||||
@@ -76,7 +63,7 @@ fn main() -> Result<()> {
|
||||
context.insert(&extracted);
|
||||
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();
|
||||
|
||||
@@ -107,7 +94,7 @@ fn main() -> Result<()> {
|
||||
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;
|
||||
|
||||
@@ -116,7 +103,7 @@ fn main() -> Result<()> {
|
||||
for action in &entry.actions {
|
||||
let action = context.stamp(action);
|
||||
actions::execute(context.clone(), &action)
|
||||
.context(format!("failed to execute action '{}'", action))?;
|
||||
.context(format!("unable to execute action '{}'", action))?;
|
||||
}
|
||||
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 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<()> {
|
||||
let system_table = uefi_std::env::system_table();
|
||||
let image_handle = uefi_std::env::image_handle();
|
||||
@@ -15,6 +19,6 @@ pub fn init() -> Result<()> {
|
||||
uefi::boot::set_image_handle(handle);
|
||||
}
|
||||
|
||||
uefi::helpers::init().context("failed to initialize uefi")?;
|
||||
uefi::helpers::init().context("unable to initialize uefi")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
41
src/utils.rs
41
src/utils.rs
@@ -9,6 +9,8 @@ use uefi::{CString16, Handle};
|
||||
pub mod framebuffer;
|
||||
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> {
|
||||
let path = CString16::try_from(path).context("unable to convert path to CString16")?;
|
||||
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")
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
let mut path = path
|
||||
.node_iter()
|
||||
@@ -44,6 +49,9 @@ pub fn device_path_root(path: &DevicePath) -> Result<String> {
|
||||
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> {
|
||||
let path = path
|
||||
.node_iter()
|
||||
@@ -65,15 +73,27 @@ pub fn device_path_subpath(path: &DevicePath) -> Result<String> {
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
/// Represents the components of a resolved path.
|
||||
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>,
|
||||
/// The subpath of the resolved path. This is the path to the file.
|
||||
/// For example, "\EFI\BOOT\BOOTX64.efi"
|
||||
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>,
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
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
|
||||
.node_iter()
|
||||
.next()
|
||||
@@ -91,21 +111,21 @@ pub fn resolve_path(default_root_path: &DevicePath, input: &str) -> Result<Resol
|
||||
input.insert_str(
|
||||
0,
|
||||
device_path_root(default_root_path)
|
||||
.context("failed to get loaded image device root")?
|
||||
.context("unable to get loaded image device root")?
|
||||
.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 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())
|
||||
.context("failed to convert root to path")?
|
||||
.context("unable to convert root to path")?
|
||||
.to_boxed();
|
||||
let mut root_path = root_path.as_ref();
|
||||
let handle = uefi::boot::locate_device_path::<SimpleFileSystem>(&mut root_path)
|
||||
.context("failed to locate filesystem device path")?;
|
||||
let subpath = device_path_subpath(path.deref()).context("failed to get device subpath")?;
|
||||
.context("unable to locate filesystem device path")?;
|
||||
let subpath = device_path_subpath(path.deref()).context("unable to get device subpath")?;
|
||||
Ok(ResolvedPath {
|
||||
root_path: root_path.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>> {
|
||||
let resolved = resolve_path(default_root_path, input)?;
|
||||
let fs = uefi::boot::open_protocol_exclusive::<SimpleFileSystem>(resolved.filesystem_handle)
|
||||
|
||||
@@ -27,7 +27,7 @@ impl Framebuffer {
|
||||
dest: (0, 0),
|
||||
dims: (self.width, self.height),
|
||||
})
|
||||
.context("failed to blit framebuffer")?;
|
||||
.context("unable to blit framebuffer")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,9 @@ fn already_registered() -> Result<bool> {
|
||||
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> {
|
||||
let path = LinuxMediaInitrdProtocol::device_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<()> {
|
||||
if !already_registered()? {
|
||||
return Ok(());
|
||||
|
||||
Reference in New Issue
Block a user