diff --git a/src/entries.rs b/src/entries.rs index d624c77..eed0ece 100644 --- a/src/entries.rs +++ b/src/entries.rs @@ -28,6 +28,7 @@ pub struct BootableEntry { context: Rc, declaration: EntryDeclaration, default: bool, + pin_name: bool, } impl BootableEntry { @@ -44,6 +45,7 @@ impl BootableEntry { context, declaration, default: false, + pin_name: false, } } @@ -72,6 +74,11 @@ impl BootableEntry { self.default } + /// Fetch whether the entry is pinned, which prevents prefixing. + pub fn is_pin_name(&self) -> bool { + self.pin_name + } + /// Swap out the context of the entry. pub fn swap_context(&mut self, context: Rc) { self.context = context; @@ -87,6 +94,11 @@ impl BootableEntry { self.default = true; } + /// Mark this entry as being pinned, which prevents prefixing. + pub fn mark_pin_name(&mut self) { + self.pin_name = true; + } + /// Prepend the name of the entry with `prefix`. pub fn prepend_name_prefix(&mut self, prefix: &str) { self.name.insert_str(0, prefix); diff --git a/src/generators/bls.rs b/src/generators/bls.rs index 9dc8d7d..4133427 100644 --- a/src/generators/bls.rs +++ b/src/generators/bls.rs @@ -83,13 +83,16 @@ pub fn generate(context: Rc, bls: &BlsConfiguration) -> Result, bls: &BlsConfiguration) -> Result Result<()> { // TODO(azenla): Implement support for LoaderTimeInitUSec here. @@ -18,26 +22,54 @@ impl BootloaderInterface { } /// Tell the system what the partition GUID of the ESP Sprout was booted from is. - pub fn set_partition_guid(_guid: &Guid) -> Result<()> { - // TODO(azenla): Implement support for LoaderDevicePartUUID here. - Ok(()) + pub fn set_partition_guid(guid: &Guid) -> Result<()> { + Self::set_cstr16("LoaderDevicePartUUID", &guid.to_string()) } /// Tell the system what boot entries are available. - pub fn set_entries>(_entries: impl Iterator) -> Result<()> { - // TODO(azenla): Implement support for LoaderEntries here. - Ok(()) + pub fn set_entries>(entries: impl Iterator) -> Result<()> { + // Entries are stored as a null-terminated list of CString16 strings back to back. + // 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")?; + // Write the bytes (including the null terminator) into the data buffer. + data.extend_from_slice(entry.as_bytes()); + } + Self::set("LoaderEntries", &data) } /// Tell the system what the default boot entry is. - pub fn set_default_entry(_entry: String) -> Result<()> { - // TODO(azenla): Implement support for LoaderEntryDefault here. - Ok(()) + pub fn set_default_entry(entry: String) -> Result<()> { + Self::set_cstr16("LoaderEntryDefault", &entry) } /// Tell the system what the selected boot entry is. - pub fn set_selected_entry(_entry: String) -> Result<()> { - // TODO(azenla): Implement support for LoaderEntrySelected here. + pub fn set_selected_entry(entry: String) -> Result<()> { + Self::set_cstr16("LoaderEntrySelected", &entry) + } + + /// The [VariableAttributes] for bootloader interface variables. + fn attributes() -> VariableAttributes { + VariableAttributes::BOOTSERVICE_ACCESS | VariableAttributes::RUNTIME_ACCESS + } + + /// Set a bootloader interface variable specified by `key` to `value`. + fn set(key: &str, value: &[u8]) -> Result<()> { + let name = + CString16::try_from(key).context("unable to convert variable name to CString16")?; + uefi::runtime::set_variable(&name, &Self::VENDOR, Self::attributes(), value) + .with_context(|| format!("unable to set efi variable {}", key))?; Ok(()) } + + /// 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()) + } } diff --git a/src/main.rs b/src/main.rs index bbe8f8d..f936654 100644 --- a/src/main.rs +++ b/src/main.rs @@ -182,13 +182,17 @@ fn run() -> Result<()> { for (name, generator) in config.generators { let context = context.fork().freeze(); - // We will prefix all entries with [name]-. + // We will prefix all entries with [name]-, provided the name is not pinned. let prefix = format!("{}-", name); // Add all the entries generated by the generator to the entry list. // The generator specifies the context associated with the entry. for mut entry in generators::generate(context.clone(), &generator)? { - entry.prepend_name_prefix(&prefix); + // If the entry name is not pinned, prepend the name prefix. + if !entry.is_pin_name() { + entry.prepend_name_prefix(&prefix); + } + entries.push(entry); } }