Skip to content

boot: Add freestanding get_handle_for_protocol #1314

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions uefi-test-runner/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,9 @@ fn reconnect_serial_to_console(serial_handle: Handle) {
/// Send the `request` string to the host via the `serial` device, then
/// wait up to 10 seconds to receive a reply. Returns an error if the
/// reply is not `"OK\n"`.
fn send_request_to_host(bt: &BootServices, request: HostRequest) {
let serial_handle = bt
.get_handle_for_protocol::<Serial>()
.expect("Failed to get serial handle");
fn send_request_to_host(request: HostRequest) {
let serial_handle =
uefi::boot::get_handle_for_protocol::<Serial>().expect("Failed to get serial handle");

// Open the serial protocol in exclusive mode.
//
Expand All @@ -183,8 +182,7 @@ fn send_request_to_host(bt: &BootServices, request: HostRequest) {
// end with `connect_controller`.
//
// [console splitter driver]: https://github.com/tianocore/edk2/blob/HEAD/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c
let mut serial = bt
.open_protocol_exclusive::<Serial>(serial_handle)
let mut serial = uefi::boot::open_protocol_exclusive::<Serial>(serial_handle)
.expect("Could not open serial protocol");

// Send the request, but don't check the result yet so that first
Expand All @@ -211,7 +209,7 @@ fn shutdown(mut st: SystemTable<Boot>) -> ! {
// Tell the host that tests are done. We are about to exit boot
// services, so we can't easily communicate with the host any later
// than this.
send_request_to_host(st.boot_services(), HostRequest::TestsComplete);
send_request_to_host(HostRequest::TestsComplete);

// Send a special log to the host so that we can verify that logging works
// up until exiting boot services. See `reconnect_serial_to_console` for the
Expand Down
2 changes: 1 addition & 1 deletion uefi-test-runner/src/proto/console/gop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub unsafe fn test(bt: &BootServices) {

// `draw_fb` is skipped on aarch64, so the screenshot doesn't match.
if cfg!(not(target_arch = "aarch64")) {
send_request_to_host(bt, HostRequest::Screenshot("gop_test"));
send_request_to_host(HostRequest::Screenshot("gop_test"));
}
}

Expand Down
38 changes: 38 additions & 0 deletions uefi/src/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,44 @@ pub fn locate_handle_buffer(search_ty: SearchType) -> Result<HandleBuffer> {
})
}

/// Find an arbitrary handle that supports a particular [`Protocol`]. Returns
/// [`NOT_FOUND`] if no handles support the protocol.
///
/// This method is a convenient wrapper around [`locate_handle_buffer`] for
/// getting just one handle. This is useful when you don't care which handle the
/// protocol is opened on. For example, [`DevicePathToText`] isn't tied to a
/// particular device, so only a single handle is expected to exist.
///
/// [`NOT_FOUND`]: Status::NOT_FOUND
/// [`DevicePathToText`]: uefi::proto::device_path::text::DevicePathToText
///
/// # Example
///
/// ```
/// use uefi::proto::device_path::text::DevicePathToText;
/// use uefi::{boot, Handle};
/// # use uefi::Result;
///
/// # fn get_fake_val<T>() -> T { todo!() }
/// # fn test() -> Result {
/// # let image_handle: Handle = get_fake_val();
/// let handle = boot::get_handle_for_protocol::<DevicePathToText>()?;
/// let device_path_to_text = boot::open_protocol_exclusive::<DevicePathToText>(handle)?;
/// # Ok(())
/// # }
/// ```
///
/// # Errors
///
/// * [`Status::NOT_FOUND`]: no matching handle.
/// * [`Status::OUT_OF_RESOURCES`]: out of memory.
pub fn get_handle_for_protocol<P: ProtocolPointer + ?Sized>() -> Result<Handle> {
locate_handle_buffer(SearchType::ByProtocol(&P::GUID))?
.first()
.cloned()
.ok_or_else(|| Status::NOT_FOUND.into())
}

/// Opens a protocol interface for a handle.
///
/// See also [`open_protocol_exclusive`], which provides a safe subset of this
Expand Down