diff --git a/crates/boot/src/actions/chainload.rs b/crates/boot/src/actions/chainload.rs index fdebfc0..385349f 100644 --- a/crates/boot/src/actions/chainload.rs +++ b/crates/boot/src/actions/chainload.rs @@ -1,4 +1,5 @@ use crate::context::SproutContext; +use crate::phases::before_handoff; use crate::utils; use alloc::boxed::Box; use alloc::rc::Rc; @@ -88,6 +89,10 @@ pub fn chainload(context: Rc, 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 diff --git a/crates/boot/src/options.rs b/crates/boot/src/options.rs index 0bf1748..512eb9e 100644 --- a/crates/boot/src/options.rs +++ b/crates/boot/src/options.rs @@ -24,6 +24,8 @@ pub struct SproutOptions { pub force_menu: bool, /// The timeout for the boot menu in seconds. pub menu_timeout: Option, + /// Retains the boot console before boot. + pub retain_boot_console: bool, } /// The default Sprout options. @@ -35,6 +37,7 @@ impl Default for SproutOptions { boot: None, force_menu: false, menu_timeout: None, + retain_boot_console: false, } } } @@ -42,7 +45,7 @@ impl Default for SproutOptions { /// 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 { enum ArgID { Help, @@ -51,6 +54,7 @@ impl SproutOptions { Boot, ForceMenu, MenuTimeout, + RetainBootConsole, } // All the options for the Sprout executable. @@ -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. @@ -99,6 +105,10 @@ impl SproutOptions { // The timeout for the boot menu in seconds. result.menu_timeout = Some(value.parse::()?); } + ArgID::RetainBootConsole => { + // Retain the boot console before booting. + result.retain_boot_console = true; + } ArgID::Help => { let ctx = HelpWriterContext { options: &OPTIONS, diff --git a/crates/boot/src/phases.rs b/crates/boot/src/phases.rs index 3a6b14c..30e55c6 100644 --- a/crates/boot/src/phases.rs +++ b/crates/boot/src/phases.rs @@ -24,3 +24,13 @@ pub fn phase(context: Rc, 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(()) +}