diff --git a/uefi-test-runner/src/proto/device_path.rs b/uefi-test-runner/src/proto/device_path.rs index 942837241..311b51847 100644 --- a/uefi-test-runner/src/proto/device_path.rs +++ b/uefi-test-runner/src/proto/device_path.rs @@ -1,9 +1,11 @@ use alloc::string::ToString; use alloc::vec::Vec; +use uefi::boot; use uefi::prelude::*; use uefi::proto::device_path::text::*; use uefi::proto::device_path::{DevicePath, LoadedImageDevicePath}; use uefi::proto::loaded_image::LoadedImage; +use uefi::proto::media::disk::DiskIo; pub fn test(bt: &BootServices) { info!("Running device path protocol test"); @@ -64,6 +66,10 @@ pub fn test(bt: &BootServices) { { assert_eq!(n1, n2); } + + // Test `locate_device_path`. + let mut dp = &*device_path; + boot::locate_device_path::(&mut dp).unwrap(); } // test 2/2: test high-level to-string api diff --git a/uefi/src/boot.rs b/uefi/src/boot.rs index 2cff6dd4f..6cb56c3ef 100644 --- a/uefi/src/boot.rs +++ b/uefi/src/boot.rs @@ -557,6 +557,40 @@ pub fn protocols_per_handle(handle: Handle) -> Result { }) } +/// Locates the handle of a device on the device path that supports the specified protocol. +/// +/// The `device_path` is updated to point at the remaining part of the [`DevicePath`] after +/// the part that matched the protocol. For example, it can be used with a device path +/// that contains a file path to strip off the file system portion of the device path, +/// leaving the file path and handle to the file system driver needed to access the file. +/// +/// If the first node of `device_path` matches the protocol, the `device_path` +/// is advanced to the device path terminator node. If `device_path` is a +/// multi-instance device path, the function will operate on the first instance. +/// +/// # Errors +/// +/// * [`Status::NOT_FOUND`]: no matching handles. +pub fn locate_device_path( + device_path: &mut &DevicePath, +) -> Result { + let bt = boot_services_raw_panicking(); + let bt = unsafe { bt.as_ref() }; + + let mut handle = ptr::null_mut(); + let mut device_path_ptr: *const uefi_raw::protocol::device_path::DevicePathProtocol = + device_path.as_ffi_ptr().cast(); + unsafe { + (bt.locate_device_path)(&P::GUID, &mut device_path_ptr, &mut handle).to_result_with_val( + || { + *device_path = DevicePath::from_ffi_ptr(device_path_ptr.cast()); + // OK to unwrap: handle is non-null for Status::SUCCESS. + Handle::from_ptr(handle).unwrap() + }, + ) + } +} + /// Returns an array of handles that support the requested protocol in a /// pool-allocated buffer. ///