Skip to content

Commit 86608f3

Browse files
authored
Merge pull request #1305 from nicholasbishop/bishop-handle-buf
boot: Add freestanding version of protocols_per_handle
2 parents 804115d + cfb3b20 commit 86608f3

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

uefi-test-runner/src/proto/mod.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use uefi::prelude::*;
22
use uefi::proto::loaded_image::LoadedImage;
3-
use uefi::{proto, Identify};
3+
use uefi::{boot, proto, Identify};
44

55
pub fn test(st: &mut SystemTable<Boot>) {
66
info!("Testing various protocols");
@@ -10,6 +10,7 @@ pub fn test(st: &mut SystemTable<Boot>) {
1010
let bt = st.boot_services();
1111
find_protocol(bt);
1212
test_protocols_per_handle(bt);
13+
test_protocols_per_handle_freestanding();
1314

1415
debug::test(bt);
1516
device_path::test(bt);
@@ -55,6 +56,13 @@ fn test_protocols_per_handle(bt: &BootServices) {
5556
assert!(pph.iter().any(|guid| **guid == LoadedImage::GUID));
5657
}
5758

59+
fn test_protocols_per_handle_freestanding() {
60+
let pph = boot::protocols_per_handle(boot::image_handle()).unwrap();
61+
info!("Image handle has {} protocols", pph.len());
62+
// Check that one of the image's protocols is `LoadedImage`.
63+
assert!(pph.iter().any(|guid| **guid == LoadedImage::GUID));
64+
}
65+
5866
mod console;
5967
mod debug;
6068
mod device_path;

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
///
@@ -762,6 +784,38 @@ pub fn stall(microseconds: usize) {
762784
}
763785
}
764786

787+
/// Protocol interface [`Guids`][Guid] that are installed on a [`Handle`] as
788+
/// returned by [`protocols_per_handle`].
789+
#[derive(Debug)]
790+
pub struct ProtocolsPerHandle {
791+
protocols: NonNull<*const Guid>,
792+
count: usize,
793+
}
794+
795+
impl Drop for ProtocolsPerHandle {
796+
fn drop(&mut self) {
797+
let _ = unsafe { free_pool(self.protocols.cast::<u8>()) };
798+
}
799+
}
800+
801+
impl Deref for ProtocolsPerHandle {
802+
type Target = [&'static Guid];
803+
804+
fn deref(&self) -> &Self::Target {
805+
let ptr: *const &'static Guid = self.protocols.as_ptr().cast();
806+
807+
// SAFETY:
808+
//
809+
// * The firmware is assumed to provide a correctly-aligned pointer and
810+
// array length.
811+
// * The firmware is assumed to provide valid GUID pointers.
812+
// * Protocol GUIDs should be constants or statics, so a 'static
813+
// lifetime (of the individual pointers, not the overall slice) can be
814+
// assumed.
815+
unsafe { slice::from_raw_parts(ptr, self.count) }
816+
}
817+
}
818+
765819
/// A buffer returned by [`locate_handle_buffer`] that contains an array of
766820
/// [`Handle`]s that support the requested protocol.
767821
#[derive(Debug, Eq, PartialEq)]

0 commit comments

Comments
 (0)