Skip to content

Commit

Permalink
uefi: helpers: Introduce OwnedDevicePath
Browse files Browse the repository at this point in the history
This PR is split off from rust-lang#135368 to reduce noise.

No real functionality changes, just some quality of life improvements.

Introduce `device_path_to_text_raw` which creates a Box<[u16]> (UTF-16
string) from path instead of creating OsString. The UTF-16 returned by
`EFI_DEVICE_PATH_TO_TEXT` protocol is owned by the caller, so we are
just moving the memory management to box instead of freeing it in the
function itself.

OsString internally is stored as WTF-8, which means converting OsString
to Box<[u16]> requires allocation. This is not ideal for std::fs APIs
where we need to perform Device Path Protocol matching while opening a
volume, and create a UEFI UTF-16 string from the remaining path (which
represents file path inside a volume). This remaining path is never used
on the Rust side, and thus does not need to be converted to WTF-8 to be
used. By introducing direct conversion to Box<[u16]>, we shorten the
conversions from `EFI_DEVICE_PATH_PROTOCOL` -> WTF-8 -> UTF-16 to
`EFI_DEVICE_PATH_PROTOCOL` -> UTF-16 which is required in every file
open operation. That is, we remove 2 intermediate allocation and 1
UTF-16 validation.

Also implement Debug for OwnedDevicePath for some quality of life
improvements.

Signed-off-by: Ayush Singh <ayush@beagleboard.org>
  • Loading branch information
Ayush1325 committed Jan 12, 2025
1 parent 12445e0 commit 2ea801a
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 7 deletions.
20 changes: 14 additions & 6 deletions library/std/src/sys/pal/uefi/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use r_efi::protocols::{device_path, device_path_to_text, shell};

use crate::ffi::{OsStr, OsString};
use crate::io::{self, const_error};
use crate::iter::Iterator;
use crate::mem::{MaybeUninit, size_of};
use crate::os::uefi::env::boot_services;
use crate::os::uefi::ffi::{OsStrExt, OsStringExt};
Expand Down Expand Up @@ -222,14 +223,14 @@ pub(crate) fn runtime_services() -> Option<NonNull<r_efi::efi::RuntimeServices>>
NonNull::new(runtime_services)
}

pub(crate) struct DevicePath(NonNull<r_efi::protocols::device_path::Protocol>);
pub(crate) struct OwnedDevicePath(pub(crate) NonNull<r_efi::protocols::device_path::Protocol>);

impl DevicePath {
impl OwnedDevicePath {
pub(crate) fn from_text(p: &OsStr) -> io::Result<Self> {
fn inner(
p: &OsStr,
protocol: NonNull<r_efi::protocols::device_path_from_text::Protocol>,
) -> io::Result<DevicePath> {
) -> io::Result<OwnedDevicePath> {
let path_vec = p.encode_wide().chain(Some(0)).collect::<Vec<u16>>();
if path_vec[..path_vec.len() - 1].contains(&0) {
return Err(const_error!(
Expand All @@ -242,7 +243,7 @@ impl DevicePath {
unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) };

NonNull::new(path)
.map(DevicePath)
.map(OwnedDevicePath)
.ok_or_else(|| const_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path"))
}

Expand Down Expand Up @@ -275,12 +276,12 @@ impl DevicePath {
))
}

pub(crate) fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol {
pub(crate) const fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol {
self.0.as_ptr()
}
}

impl Drop for DevicePath {
impl Drop for OwnedDevicePath {
fn drop(&mut self) {
if let Some(bt) = boot_services() {
let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
Expand All @@ -291,6 +292,13 @@ impl Drop for DevicePath {
}
}

impl crate::fmt::Debug for OwnedDevicePath {
fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
let p = device_path_to_text(self.0).unwrap();
p.fmt(f)
}
}

pub(crate) struct OwnedProtocol<T> {
guid: r_efi::efi::Guid,
handle: NonNull<crate::ffi::c_void>,
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/pal/uefi/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ mod uefi_command_internal {

impl Image {
pub fn load_image(p: &OsStr) -> io::Result<Self> {
let path = helpers::DevicePath::from_text(p)?;
let path = helpers::OwnedDevicePath::from_text(p)?;
let boot_services: NonNull<r_efi::efi::BootServices> = boot_services()
.ok_or_else(|| const_error!(io::ErrorKind::NotFound, "Boot Services not found"))?
.cast();
Expand Down

0 comments on commit 2ea801a

Please sign in to comment.