Skip to content

Commit 769ca4b

Browse files
boot: Add freestanding version of protocols_per_handle
This comes with its own version of the `ProtocolsPerHandle` struct. This one has no `BootServices` reference and no lifetime param. The GUID references in the slice are assumed to have a static lifetime, see safety comment for details.
1 parent c684367 commit 769ca4b

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

uefi/src/boot.rs

+54
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,28 @@ pub unsafe fn uninstall_protocol_interface(
477477
(bt.uninstall_protocol_interface)(handle.as_ptr(), protocol, interface).to_result()
478478
}
479479

480+
/// Get the list of protocol interface [`Guids`][Guid] that are installed
481+
/// on a [`Handle`].
482+
///
483+
/// # Errors
484+
///
485+
/// * [`Status::INVALID_PARAMETER`]: `handle` is invalid.
486+
/// * [`Status::OUT_OF_RESOURCES`]: out of memory.
487+
pub fn protocols_per_handle(handle: Handle) -> Result<ProtocolsPerHandle> {
488+
let bt = boot_services_raw_panicking();
489+
let bt = unsafe { bt.as_ref() };
490+
491+
let mut protocols = ptr::null_mut();
492+
let mut count = 0;
493+
494+
unsafe { (bt.protocols_per_handle)(handle.as_ptr(), &mut protocols, &mut count) }
495+
.to_result_with_val(|| ProtocolsPerHandle {
496+
count,
497+
protocols: NonNull::new(protocols)
498+
.expect("protocols_per_handle must not return a null pointer"),
499+
})
500+
}
501+
480502
/// Returns an array of handles that support the requested protocol in a
481503
/// pool-allocated buffer.
482504
///
@@ -736,6 +758,38 @@ pub fn stall(microseconds: usize) {
736758
}
737759
}
738760

761+
/// Protocol interface [`Guids`][Guid] that are installed on a [`Handle`] as
762+
/// returned by [`protocols_per_handle`].
763+
#[derive(Debug)]
764+
pub struct ProtocolsPerHandle {
765+
protocols: NonNull<*const Guid>,
766+
count: usize,
767+
}
768+
769+
impl Drop for ProtocolsPerHandle {
770+
fn drop(&mut self) {
771+
let _ = unsafe { free_pool(self.protocols.cast::<u8>()) };
772+
}
773+
}
774+
775+
impl Deref for ProtocolsPerHandle {
776+
type Target = [&'static Guid];
777+
778+
fn deref(&self) -> &Self::Target {
779+
let ptr: *const &'static Guid = self.protocols.as_ptr().cast();
780+
781+
// SAFETY:
782+
//
783+
// * The firmware is assumed to provide a correctly-aligned pointer and
784+
// array length.
785+
// * The firmware is assumed to provide valid GUID pointers.
786+
// * Protocol GUIDs should be constants or statics, so a 'static
787+
// lifetime (of the individual pointers, not the overall slice) can be
788+
// assumed.
789+
unsafe { slice::from_raw_parts(ptr, self.count) }
790+
}
791+
}
792+
739793
/// A buffer returned by [`locate_handle_buffer`] that contains an array of
740794
/// [`Handle`]s that support the requested protocol.
741795
#[derive(Debug, Eq, PartialEq)]

0 commit comments

Comments
 (0)