mirror of
https://github.com/edera-dev/sprout.git
synced 2025-12-19 18:40:18 +00:00
add more documentation to some actions and configurations
This commit is contained in:
@@ -9,24 +9,37 @@ use std::rc::Rc;
|
||||
use uefi::CString16;
|
||||
use uefi::proto::loaded_image::LoadedImage;
|
||||
|
||||
/// The configuration of the chainload action.
|
||||
#[derive(Serialize, Deserialize, Default, Clone)]
|
||||
pub struct ChainloadConfiguration {
|
||||
/// The path to the image to chainload.
|
||||
/// This can be a Linux EFI stub (vmlinuz usually) or a standard EFI executable.
|
||||
pub path: String,
|
||||
/// The options to pass to the image.
|
||||
/// The options are concatenated by a space and then passed to the EFI application.
|
||||
#[serde(default)]
|
||||
pub options: Vec<String>,
|
||||
/// An optional path to a Linux initrd.
|
||||
/// This uses the [LINUX_EFI_INITRD_MEDIA_GUID] mechanism to load the initrd into the EFI stack.
|
||||
/// For Linux, you can also use initrd=\path\to\initrd as an option, but this option is
|
||||
/// generally better and safer as it can support additional load options in the future.
|
||||
#[serde(default, rename = "linux-initrd")]
|
||||
pub linux_initrd: Option<String>,
|
||||
}
|
||||
|
||||
/// Executes the chainload action using the specified `configuration` inside the provided `context`.
|
||||
pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfiguration) -> Result<()> {
|
||||
// Retrieve the current image handle of sprout.
|
||||
let sprout_image = uefi::boot::image_handle();
|
||||
|
||||
// Resolve the path to the image to chainload.
|
||||
let resolved = utils::resolve_path(
|
||||
context.root().loaded_image_path()?,
|
||||
&context.stamp(&configuration.path),
|
||||
)
|
||||
.context("unable to resolve chainload path")?;
|
||||
|
||||
// Load the image to chainload.
|
||||
let image = uefi::boot::load_image(
|
||||
sprout_image,
|
||||
uefi::boot::LoadImageSource::FromDevicePath {
|
||||
@@ -36,9 +49,11 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
|
||||
)
|
||||
.context("unable to load image")?;
|
||||
|
||||
// Open the LoadedImage protocol of the image to chainload.
|
||||
let mut loaded_image_protocol = uefi::boot::open_protocol_exclusive::<LoadedImage>(image)
|
||||
.context("unable to open loaded image protocol")?;
|
||||
|
||||
// Stamp and concatenate the options to pass to the image.
|
||||
let options = configuration
|
||||
.options
|
||||
.iter()
|
||||
@@ -46,6 +61,10 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
|
||||
// Pass the options to the image, if any are provided.
|
||||
// The holder must drop at the end of this function to ensure the options are not leaked,
|
||||
// and the holder here ensures it outlives the if block here, as a pointer has to be
|
||||
// passed to the image. This has been hand-validated to be safe.
|
||||
let mut options_holder: Option<Box<CString16>> = None;
|
||||
if !options.is_empty() {
|
||||
let options = Box::new(
|
||||
@@ -80,15 +99,28 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
|
||||
initrd_handle = Some(handle);
|
||||
}
|
||||
|
||||
// Retrieve the base and size of the loaded image to display.
|
||||
let (base, size) = loaded_image_protocol.info();
|
||||
info!("loaded image: base={:#x} size={:#x}", base.addr(), size);
|
||||
|
||||
// Start the loaded image.
|
||||
// This call might return, or it may pass full control to another image that will never return.
|
||||
// Capture the result to ensure we can return an error if the image fails to start, but only
|
||||
// after the optional initrd has been unregistered.
|
||||
let result = uefi::boot::start_image(image).context("unable to start image");
|
||||
|
||||
// Unregister the initrd if it was registered.
|
||||
if let Some(initrd_handle) = initrd_handle
|
||||
&& let Err(error) = initrd_handle.unregister()
|
||||
{
|
||||
error!("unable to unregister linux initrd: {}", error);
|
||||
}
|
||||
|
||||
// Assert there was no error starting the image.
|
||||
result.context("unable to start image")?;
|
||||
// Explicitly drop the option holder to clarify the lifetime.
|
||||
drop(options_holder);
|
||||
|
||||
// Return control to sprout.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3,12 +3,15 @@ use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::rc::Rc;
|
||||
|
||||
/// The configuration of the print action.
|
||||
#[derive(Serialize, Deserialize, Default, Clone)]
|
||||
pub struct PrintConfiguration {
|
||||
/// The text to print to the console.
|
||||
#[serde(default)]
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
/// Executes the print action with the specified `configuration` inside the provided `context`.
|
||||
pub fn print(context: Rc<SproutContext>, configuration: &PrintConfiguration) -> Result<()> {
|
||||
println!("{}", context.stamp(&configuration.text));
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user