From 1c732a1c4318d1ee161bab84c912f0c884c2529b Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Sat, 1 Nov 2025 18:04:06 -0400 Subject: [PATCH] feat(bootloader-interface): add support for LoaderEntryDefault and LoaderEntryOneShot --- src/entries.rs | 5 +++ src/integrations/bootloader_interface.rs | 30 ++++++++++++++++ src/main.rs | 44 +++++++++++++++++++----- 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/src/entries.rs b/src/entries.rs index eed0ece..757a45f 100644 --- a/src/entries.rs +++ b/src/entries.rs @@ -94,6 +94,11 @@ impl BootableEntry { self.default = true; } + // Unmark this entry as the default entry. + pub fn unmark_default(&mut self) { + self.default = false; + } + /// Mark this entry as being pinned, which prevents prefixing. pub fn mark_pin_name(&mut self) { self.pin_name = true; diff --git a/src/integrations/bootloader_interface.rs b/src/integrations/bootloader_interface.rs index 42db6f1..4b3798e 100644 --- a/src/integrations/bootloader_interface.rs +++ b/src/integrations/bootloader_interface.rs @@ -45,6 +45,8 @@ impl BootloaderInterface { | LoaderFeatures::ConfigTimeout | LoaderFeatures::ConfigTimeoutOneShot | LoaderFeatures::MenuDisable + | LoaderFeatures::EntryDefault + | LoaderFeatures::EntryOneShot } /// Tell the system that Sprout was initialized at the current time. @@ -275,4 +277,32 @@ impl BootloaderInterface { // We provide the unspecified value instead. Ok(BootloaderInterfaceTimeout::Unspecified) } + + /// Get the default entry set by the bootloader interface. + pub fn get_default_entry() -> Result> { + Self::VENDOR + .get_cstr16("LoaderEntryDefault") + .context("unable to get default entry from bootloader interface") + } + + /// Get the oneshot entry set by the bootloader interface. + /// This should be the entry we boot. + pub fn get_oneshot_entry() -> Result> { + // Acquire the value of the LoaderEntryOneShot variable. + // If it is not set, return None. + let Some(value) = Self::VENDOR + .get_cstr16("LoaderEntryOneShot") + .context("unable to get oneshot entry from bootloader interface")? + else { + return Ok(None); + }; + + // Remove the oneshot entry from the bootloader interface. + Self::VENDOR + .remove("LoaderEntryOneShot") + .context("unable to remove oneshot entry")?; + + // Return the oneshot value. + Ok(Some(value)) + } } diff --git a/src/main.rs b/src/main.rs index 476305e..7233357 100644 --- a/src/main.rs +++ b/src/main.rs @@ -262,13 +262,6 @@ fn run() -> Result<()> { } } - // If no entries were the default, pick the first entry as the default entry. - if entries.iter().all(|entry| !entry.is_default()) - && let Some(entry) = entries.first_mut() - { - entry.mark_default(); - } - // Tell the bootloader interface what entries are available. BootloaderInterface::set_entries(entries.iter().map(|entry| entry.name())) .context("unable to set entries in bootloader interface")?; @@ -280,8 +273,16 @@ fn run() -> Result<()> { let bootloader_interface_timeout = BootloaderInterface::get_timeout().context("unable to get bootloader interface timeout")?; + // Acquire the default entry from the bootloader interface. + let bootloader_interface_default_entry = BootloaderInterface::get_default_entry() + .context("unable to get bootloader interface default entry")?; + + // Acquire the oneshot entry from the bootloader interface. + let bootloader_interface_oneshot_entry = BootloaderInterface::get_oneshot_entry() + .context("unable to get bootloader interface oneshot entry")?; + // If --boot is specified, boot that entry immediately. - let force_boot_entry = context.root().options().boot.as_ref(); + let mut force_boot_entry = context.root().options().boot.clone(); // If --force-menu is specified, show the boot menu regardless of the value of --boot. let mut force_boot_menu = context.root().options().force_menu; @@ -320,6 +321,33 @@ fn run() -> Result<()> { } } + // Apply bootloader interface default entry settings. + if let Some(ref bootloader_interface_default_entry) = bootloader_interface_default_entry { + // Iterate over all the entries and mark the default entry as the one specified. + for entry in &mut entries { + // Mark the entry as the default entry if it matches the specified entry. + // If the entry does not match the specified entry, unmark it as the default entry. + if entry.is_match(bootloader_interface_default_entry) { + entry.mark_default(); + } else { + entry.unmark_default(); + } + } + } + + // Apply bootloader interface oneshot entry settings. + // If set, we will force booting the oneshot entry. + if let Some(ref bootloader_interface_oneshot_entry) = bootloader_interface_oneshot_entry { + force_boot_entry = Some(bootloader_interface_oneshot_entry.clone()); + } + + // If no entries were the default, pick the first entry as the default entry. + if entries.iter().all(|entry| !entry.is_default()) + && let Some(entry) = entries.first_mut() + { + entry.mark_default(); + } + // Convert the menu timeout to a duration. let menu_timeout = Duration::from_secs(menu_timeout);