feat(boot): clear screen before boot handoff, if --retain-boot-console is not specified on the command-line (#51)

This commit is contained in:
2025-12-20 21:45:35 -08:00
committed by GitHub
parent fafabe234e
commit 2da457ee7c
3 changed files with 26 additions and 1 deletions

View File

@@ -1,4 +1,5 @@
use crate::context::SproutContext; use crate::context::SproutContext;
use crate::phases::before_handoff;
use crate::utils; use crate::utils;
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::rc::Rc; use alloc::rc::Rc;
@@ -88,6 +89,10 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
BootloaderInterface::mark_exec(context.root().timer()) BootloaderInterface::mark_exec(context.root().timer())
.context("unable to mark execution of boot entry in bootloader interface")?; .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. // Start the loaded image.
// This call might return, or it may pass full control to another image that will never return. // 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 // Capture the result to ensure we can return an error if the image fails to start, but only

View File

@@ -24,6 +24,8 @@ pub struct SproutOptions {
pub force_menu: bool, pub force_menu: bool,
/// The timeout for the boot menu in seconds. /// The timeout for the boot menu in seconds.
pub menu_timeout: Option<u64>, pub menu_timeout: Option<u64>,
/// Retains the boot console before boot.
pub retain_boot_console: bool,
} }
/// The default Sprout options. /// The default Sprout options.
@@ -35,6 +37,7 @@ impl Default for SproutOptions {
boot: None, boot: None,
force_menu: false, force_menu: false,
menu_timeout: None, menu_timeout: None,
retain_boot_console: false,
} }
} }
} }
@@ -42,7 +45,7 @@ impl Default for SproutOptions {
/// The options parser mechanism for Sprout. /// The options parser mechanism for Sprout.
impl SproutOptions { impl SproutOptions {
/// Produces [SproutOptions] from the arguments provided by the UEFI core. /// 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> { pub fn parse() -> Result<Self> {
enum ArgID { enum ArgID {
Help, Help,
@@ -51,6 +54,7 @@ impl SproutOptions {
Boot, Boot,
ForceMenu, ForceMenu,
MenuTimeout, MenuTimeout,
RetainBootConsole,
} }
// All the options for the Sprout executable. // 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::flag(ArgID::ForceMenu, &["--force-menu"]).help_text("Force showing the boot menu"),
Opt::value(ArgID::MenuTimeout, &["--menu-timeout"], "TIMEOUT") Opt::value(ArgID::MenuTimeout, &["--menu-timeout"], "TIMEOUT")
.help_text("Boot menu timeout, in seconds"), .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. // Acquire the arguments as determined by the UEFI core.
@@ -99,6 +105,10 @@ impl SproutOptions {
// The timeout for the boot menu in seconds. // The timeout for the boot menu in seconds.
result.menu_timeout = Some(value.parse::<u64>()?); result.menu_timeout = Some(value.parse::<u64>()?);
} }
ArgID::RetainBootConsole => {
// Retain the boot console before booting.
result.retain_boot_console = true;
}
ArgID::Help => { ArgID::Help => {
let ctx = HelpWriterContext { let ctx = HelpWriterContext {
options: &OPTIONS, options: &OPTIONS,

View File

@@ -24,3 +24,13 @@ pub fn phase(context: Rc<SproutContext>, phase: &[PhaseConfiguration]) -> Result
} }
Ok(()) 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(())
}