From f9dd56c8e7b3b99bcc3c4168ca79ecc01dd26680 Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Sat, 1 Nov 2025 03:24:14 -0400 Subject: [PATCH] feat(bootloader-interface): add support for LoaderFeatures --- Cargo.lock | 1 + Cargo.toml | 1 + src/integrations/bootloader_interface.rs | 34 +++++++++++--- .../bootloader_interface/bitflags.rs | 46 +++++++++++++++++++ src/utils/variables.rs | 6 +++ 5 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 src/integrations/bootloader_interface/bitflags.rs diff --git a/Cargo.lock b/Cargo.lock index 3c119dc..7a09a30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -119,6 +119,7 @@ name = "edera-sprout" version = "0.0.16" dependencies = [ "anyhow", + "bitflags", "image", "log", "serde", diff --git a/Cargo.toml b/Cargo.toml index 9b7b028..bc633c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ edition = "2024" [dependencies] anyhow = "1.0.100" +bitflags = "2.10.0" toml = "0.9.8" log = "0.4.28" diff --git a/src/integrations/bootloader_interface.rs b/src/integrations/bootloader_interface.rs index f0095b2..b303209 100644 --- a/src/integrations/bootloader_interface.rs +++ b/src/integrations/bootloader_interface.rs @@ -1,3 +1,4 @@ +use crate::integrations::bootloader_interface::bitflags::LoaderFeatures; use crate::platform::timer::PlatformTimer; use crate::utils::device_path_subpath; use crate::utils::variables::{VariableClass, VariableController}; @@ -6,6 +7,9 @@ use uefi::proto::device_path::DevicePath; use uefi::{Guid, guid}; use uefi_raw::table::runtime::VariableVendor; +/// bitflags: LoaderFeatures bitflags. +mod bitflags; + /// The name of the bootloader to tell the system. const LOADER_NAME: &str = "Sprout"; @@ -18,6 +22,11 @@ impl BootloaderInterface { "4a67b082-0a4c-41cf-b6c7-440b29bb8c4f" ))); + /// The feature we support in Sprout. + fn features() -> LoaderFeatures { + LoaderFeatures::LoadDriver | LoaderFeatures::Tpm2ActivePcrBanks | LoaderFeatures::RetainShim + } + /// Tell the system that Sprout was initialized at the current time. pub fn mark_init(timer: &PlatformTimer) -> Result<()> { Self::mark_time("LoaderTimeInitUSec", timer) @@ -45,13 +54,26 @@ impl BootloaderInterface { ) } - /// Tell the system what loader is being used. + /// Tell the system what loader is being used and our features. pub fn set_loader_info() -> Result<()> { - Self::VENDOR.set_cstr16( - "LoaderInfo", - LOADER_NAME, - VariableClass::BootAndRuntimeTemporary, - ) + // Set the LoaderInfo variable with the name of the loader. + Self::VENDOR + .set_cstr16( + "LoaderInfo", + LOADER_NAME, + VariableClass::BootAndRuntimeTemporary, + ) + .context("unable to set loader info variable")?; + + // Set the LoaderFeatures variable with the features we support. + Self::VENDOR + .set_u64le( + "LoaderFeatures", + Self::features().bits(), + VariableClass::BootAndRuntimeTemporary, + ) + .context("unable to set loader features variable")?; + Ok(()) } /// Tell the system the relative path to the partition root of the current bootloader. diff --git a/src/integrations/bootloader_interface/bitflags.rs b/src/integrations/bootloader_interface/bitflags.rs new file mode 100644 index 0000000..7040a1f --- /dev/null +++ b/src/integrations/bootloader_interface/bitflags.rs @@ -0,0 +1,46 @@ +use bitflags::bitflags; + +bitflags! { + /// Feature bitflags for the bootloader interface. + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct LoaderFeatures: u64 { + /// Bootloader supports LoaderConfigTimeout. + const ConfigTimeout = 1 << 0; + /// Bootloader supports LoaderConfigTimeoutOneShot. + const ConfigTimeoutOneShot = 1 << 1; + /// Bootloader supports LoaderEntryDefault. + const EntryDefault = 1 << 2; + /// Bootloader supports LoaderEntryOneShot. + const EntryOneShot = 1 << 3; + /// Bootloader supports boot counting. + const BootCounting = 1 << 4; + /// Bootloader supports detection from XBOOTLDR partitions. + const Xbootldr = 1 << 5; + /// Bootloader supports handling of random seeds. + const RandomSeed = 1 << 6; + /// Bootloader supports loading drivers. + const LoadDriver = 1 << 7; + /// Bootloader supports sort keys. + const SortKey = 1 << 8; + /// Bootloader supports saved entries. + const SavedEntry = 1 << 9; + /// Bootloader supports device trees. + const DeviceTree = 1 << 10; + /// Bootloader supports secure boot enroll. + const SecureBootEnroll = 1 << 11; + /// Bootloader retains the shim. + const RetainShim = 1 << 12; + /// Bootloader supports disabling the menu via menu timeout variable. + const MenuDisable = 1 << 13; + /// Bootloader supports multi-profile UKI. + const MultiProfileUki = 1 << 14; + /// Bootloader reports URLs. + const ReportUrl = 1 << 15; + /// Bootloader supports type-1 UKIs. + const Type1Uki = 1 << 16; + /// Bootloader supports type-1 UKI urls. + const Type1UkiUrl = 1 << 17; + /// Bootloader indicates TPM2 active PCR banks. + const Tpm2ActivePcrBanks = 1 << 18; + } +} diff --git a/src/utils/variables.rs b/src/utils/variables.rs index 490c95d..3f48955 100644 --- a/src/utils/variables.rs +++ b/src/utils/variables.rs @@ -98,4 +98,10 @@ impl VariableController { pub fn set_bool(&self, key: &str, value: bool, class: VariableClass) -> Result<()> { self.set(key, &[value as u8], class) } + + /// Set the u64 little-endian variable specified by `key` to `value`. + /// The variable `class` controls the attributes for the variable. + pub fn set_u64le(&self, key: &str, value: u64, class: VariableClass) -> Result<()> { + self.set(key, &value.to_le_bytes(), class) + } }