Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crates/boot/src/actions/chainload.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::context::SproutContext;
use crate::phases::before_handoff;
use crate::utils;
use alloc::boxed::Box;
use alloc::rc::Rc;
Expand Down Expand Up @@ -88,6 +89,10 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
BootloaderInterface::mark_exec(context.root().timer())
.context("unable to mark execution of boot entry in bootloader interface")?;

// Since we are about to hand off control to another image, we need to execute the handoff hook.
// This will perform operations like clearing the screen.
before_handoff(&context).context("unable to execute before handoff hook")?;

// 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
Expand Down
12 changes: 11 additions & 1 deletion crates/boot/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub struct SproutOptions {
pub force_menu: bool,
/// The timeout for the boot menu in seconds.
pub menu_timeout: Option<u64>,
/// Retains the boot console before boot.
pub retain_boot_console: bool,
}

/// The default Sprout options.
Expand All @@ -35,14 +37,15 @@ impl Default for SproutOptions {
boot: None,
force_menu: false,
menu_timeout: None,
retain_boot_console: false,
}
}
}

/// The options parser mechanism for Sprout.
impl SproutOptions {
/// Produces [SproutOptions] from the arguments provided by the UEFI core.
/// Internally we utilize the `jaarg` argument parser which has excellent no_std support.
/// Internally, we use the `jaarg` argument parser which has excellent no_std support.
pub fn parse() -> Result<Self> {
enum ArgID {
Help,
Expand All @@ -51,6 +54,7 @@ impl SproutOptions {
Boot,
ForceMenu,
MenuTimeout,
RetainBootConsole,
}

// All the options for the Sprout executable.
Expand All @@ -65,6 +69,8 @@ impl SproutOptions {
Opt::flag(ArgID::ForceMenu, &["--force-menu"]).help_text("Force showing the boot menu"),
Opt::value(ArgID::MenuTimeout, &["--menu-timeout"], "TIMEOUT")
.help_text("Boot menu timeout, in seconds"),
Opt::flag(ArgID::RetainBootConsole, &["--retain-boot-console"])
.help_text("Retain boot console before boot"),
]);

// Acquire the arguments as determined by the UEFI core.
Expand Down Expand Up @@ -99,6 +105,10 @@ impl SproutOptions {
// The timeout for the boot menu in seconds.
result.menu_timeout = Some(value.parse::<u64>()?);
}
ArgID::RetainBootConsole => {
// Retain the boot console before booting.
result.retain_boot_console = true;
}
ArgID::Help => {
let ctx = HelpWriterContext {
options: &OPTIONS,
Expand Down
10 changes: 10 additions & 0 deletions crates/boot/src/phases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,13 @@ pub fn phase(context: Rc<SproutContext>, phase: &[PhaseConfiguration]) -> Result
}
Ok(())
}

/// Manual hook called by code in the bootloader that hands off to another image.
/// This is used to perform actions like clearing the screen.
pub fn before_handoff(context: &SproutContext) -> Result<()> {
// If we have not been asked to retain the boot console, then we should clear the screen.
if !context.root().options().retain_boot_console {
uefi::system::with_stdout(|stdout| stdout.reset(true)).context("unable to clear screen")?;
}
Ok(())
}
Loading