From bd96541fc3c0bf5570759dfd3dbae09ad290f4cc Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 11 Aug 2024 16:26:30 -0400 Subject: [PATCH 1/2] boot: Add freestanding get_handle_for_protocol --- uefi/src/boot.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/uefi/src/boot.rs b/uefi/src/boot.rs index 2cff6dd4f..f978ba440 100644 --- a/uefi/src/boot.rs +++ b/uefi/src/boot.rs @@ -588,6 +588,44 @@ pub fn locate_handle_buffer(search_ty: SearchType) -> Result { }) } +/// 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 { todo!() } +/// # fn test() -> Result { +/// # let image_handle: Handle = get_fake_val(); +/// let handle = boot::get_handle_for_protocol::()?; +/// let device_path_to_text = boot::open_protocol_exclusive::(handle)?; +/// # Ok(()) +/// # } +/// ``` +/// +/// # Errors +/// +/// * [`Status::NOT_FOUND`]: no matching handle. +/// * [`Status::OUT_OF_RESOURCES`]: out of memory. +pub fn get_handle_for_protocol() -> Result { + 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 From a8e77f38e5ed2e26bd191f199034db3ab3bc0312 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 11 Aug 2024 16:27:59 -0400 Subject: [PATCH 2/2] test-runner: Test boot::get_handle_for_protocol Modify send_request_to_host to use freestanding boot functions instead of BootServices. There are plenty of other places that still test BootServices::get_handle_for_protocol. --- uefi-test-runner/src/main.rs | 12 +++++------- uefi-test-runner/src/proto/console/gop.rs | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/uefi-test-runner/src/main.rs b/uefi-test-runner/src/main.rs index a45e944ea..2f0b4a0ac 100644 --- a/uefi-test-runner/src/main.rs +++ b/uefi-test-runner/src/main.rs @@ -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::() - .expect("Failed to get serial handle"); +fn send_request_to_host(request: HostRequest) { + let serial_handle = + uefi::boot::get_handle_for_protocol::().expect("Failed to get serial handle"); // Open the serial protocol in exclusive mode. // @@ -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_handle) + let mut serial = uefi::boot::open_protocol_exclusive::(serial_handle) .expect("Could not open serial protocol"); // Send the request, but don't check the result yet so that first @@ -211,7 +209,7 @@ fn shutdown(mut st: SystemTable) -> ! { // 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 diff --git a/uefi-test-runner/src/proto/console/gop.rs b/uefi-test-runner/src/proto/console/gop.rs index 94bcbda40..7afb163fd 100644 --- a/uefi-test-runner/src/proto/console/gop.rs +++ b/uefi-test-runner/src/proto/console/gop.rs @@ -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")); } }