diff --git a/uefi-test-runner/src/bin/shell_launcher.rs b/uefi-test-runner/src/bin/shell_launcher.rs index 123307bd6..5146bac46 100644 --- a/uefi-test-runner/src/bin/shell_launcher.rs +++ b/uefi-test-runner/src/bin/shell_launcher.rs @@ -13,6 +13,7 @@ extern crate alloc; use alloc::vec::Vec; use log::info; +use uefi::boot; use uefi::prelude::*; use uefi::proto::device_path::build::{self, DevicePathBuilder}; use uefi::proto::device_path::{DevicePath, DeviceSubType, DeviceType, LoadedImageDevicePath}; @@ -21,13 +22,10 @@ use uefi::table::boot::LoadImageSource; /// Get the device path of the shell app. This is the same as the /// currently-loaded image's device path, but with the file path part changed. -fn get_shell_app_device_path<'a>( - boot_services: &BootServices, - storage: &'a mut Vec, -) -> &'a DevicePath { - let loaded_image_device_path = boot_services - .open_protocol_exclusive::(boot_services.image_handle()) - .expect("failed to open LoadedImageDevicePath protocol"); +fn get_shell_app_device_path(storage: &mut Vec) -> &DevicePath { + let loaded_image_device_path = + boot::open_protocol_exclusive::(boot::image_handle()) + .expect("failed to open LoadedImageDevicePath protocol"); let mut builder = DevicePathBuilder::with_vec(storage); for node in loaded_image_device_path.node_iter() { @@ -50,7 +48,7 @@ fn efi_main(image: Handle, st: SystemTable) -> Status { let boot_services = st.boot_services(); let mut storage = Vec::new(); - let shell_image_path = get_shell_app_device_path(boot_services, &mut storage); + let shell_image_path = get_shell_app_device_path(&mut storage); // Load the shell app. let shell_image_handle = boot_services @@ -65,8 +63,7 @@ fn efi_main(image: Handle, st: SystemTable) -> Status { // Set the command line passed to the shell app so that it will run the // test-runner app. This automatically turns off the five-second delay. - let mut shell_loaded_image = boot_services - .open_protocol_exclusive::(shell_image_handle) + let mut shell_loaded_image = boot::open_protocol_exclusive::(shell_image_handle) .expect("failed to open LoadedImage protocol"); let load_options = cstr16!(r"shell.efi test_runner.efi arg1 arg2"); unsafe { diff --git a/uefi/src/boot.rs b/uefi/src/boot.rs index 5f05c7e46..d8a3b4917 100644 --- a/uefi/src/boot.rs +++ b/uefi/src/boot.rs @@ -38,7 +38,7 @@ pub fn image_handle() -> Handle { /// /// This function should only be called as described above, and the /// `image_handle` must be a valid image [`Handle`]. The safety guarantees of -/// `open_protocol_exclusive` rely on the global image handle being correct. +/// [`open_protocol_exclusive`] rely on the global image handle being correct. pub unsafe fn set_image_handle(image_handle: Handle) { IMAGE_HANDLE.store(image_handle.as_ptr(), Ordering::Release); } @@ -162,7 +162,7 @@ pub fn locate_handle_buffer(search_ty: SearchType) -> Result { /// Opens a protocol interface for a handle. /// -/// See also `open_protocol_exclusive`, which provides a safe subset of this +/// See also [`open_protocol_exclusive`], which provides a safe subset of this /// functionality. /// /// This function attempts to get the protocol implementation of a handle, based @@ -214,6 +214,34 @@ pub unsafe fn open_protocol( }) } +/// Opens a protocol interface for a handle in exclusive mode. +/// +/// If successful, a [`ScopedProtocol`] is returned that will automatically +/// close the protocol interface when dropped. +/// +/// # Errors +/// +/// * [`Status::UNSUPPORTED`]: the handle does not support the protocol. +/// * [`Status::ACCESS_DENIED`]: the protocol is already open in a way that is +/// incompatible with the new request. +pub fn open_protocol_exclusive( + handle: Handle, +) -> Result> { + // Safety: opening in exclusive mode with the correct agent + // handle set ensures that the protocol cannot be modified or + // removed while it is open, so this usage is safe. + unsafe { + open_protocol::

( + OpenProtocolParams { + handle, + agent: image_handle(), + controller: None, + }, + OpenProtocolAttributes::Exclusive, + ) + } +} + /// A buffer returned by [`locate_handle_buffer`] that contains an array of /// [`Handle`]s that support the requested protocol. #[derive(Debug, Eq, PartialEq)]