From cff55322fc59863fe7ccc54af34d4a7e285a1d0a Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Thu, 30 Oct 2025 12:44:07 -0400 Subject: [PATCH] feat(bootloader-interface): implement support for LoaderImageIdentifier --- src/integrations/bootloader_interface.rs | 28 ++++++++++++++++++------ src/main.rs | 4 ++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/integrations/bootloader_interface.rs b/src/integrations/bootloader_interface.rs index 18f71af..82351cb 100644 --- a/src/integrations/bootloader_interface.rs +++ b/src/integrations/bootloader_interface.rs @@ -1,5 +1,7 @@ use crate::platform::timer::PlatformTimer; +use crate::utils::device_path_subpath; use anyhow::{Context, Result}; +use uefi::proto::device_path::DevicePath; use uefi::{CString16, Guid, guid}; use uefi_raw::table::runtime::{VariableAttributes, VariableVendor}; @@ -28,6 +30,12 @@ impl BootloaderInterface { Self::set_cstr16(key, &elapsed.as_micros().to_string()) } + /// Tell the system the relative path to the partition root of the current bootloader. + pub fn set_loader_path(path: &DevicePath) -> Result<()> { + let subpath = device_path_subpath(path).context("unable to get loader path subpath")?; + Self::set_cstr16("LoaderImageIdentifier", &subpath) + } + /// Tell the system what the partition GUID of the ESP Sprout was booted from is. pub fn set_partition_guid(guid: &Guid) -> Result<()> { Self::set_cstr16("LoaderDevicePartUUID", &guid.to_string()) @@ -39,11 +47,14 @@ impl BootloaderInterface { // Iterate over the entries and convert them to CString16 placing them into data. let mut data = Vec::new(); for entry in entries { - // Convert the entry to a CString16. - let entry = CString16::try_from(entry.as_ref()) - .context("unable to convert entry to CString16")?; + // Convert the entry to CString16 little endian. + let encoded = entry + .as_ref() + .encode_utf16() + .flat_map(|c| c.to_le_bytes()) + .collect::>(); // Write the bytes (including the null terminator) into the data buffer. - data.extend_from_slice(entry.as_bytes()); + data.extend_from_slice(&encoded); } Self::set("LoaderEntries", &data) } @@ -91,8 +102,11 @@ impl BootloaderInterface { /// Set a bootloader interface variable specified by `key` to `value`, converting the value to /// a [CString16]. fn set_cstr16(key: &str, value: &str) -> Result<()> { - let value = - CString16::try_from(value).context("unable to convert variable value to CString16")?; - Self::set(key, value.as_bytes()) + // Encode the value as a CString16 little endian. + let encoded = value + .encode_utf16() + .flat_map(|c| c.to_le_bytes()) + .collect::>(); + Self::set(key, &encoded) } } diff --git a/src/main.rs b/src/main.rs index fb9616a..7a657f2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -112,6 +112,10 @@ fn run() -> Result<()> { .context("unable to set partition guid in bootloader interface")?; } + // Tell the bootloader interface what the loaded image path is. + BootloaderInterface::set_loader_path(&loaded_image_path) + .context("unable to set loader path in bootloader interface")?; + // Create the root context. let mut root = RootContext::new(loaded_image_path, timer, options);