From 6138bbe2e868e1896ed640ad6d6dde1868311a54 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Wed, 31 Jul 2024 21:53:05 -0400 Subject: [PATCH 1/2] boot: Add freestanding connect_controller and disconnect_controller --- uefi/src/boot.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/uefi/src/boot.rs b/uefi/src/boot.rs index 8bc961a63..98e7ef5a8 100644 --- a/uefi/src/boot.rs +++ b/uefi/src/boot.rs @@ -3,6 +3,7 @@ //! These functions will panic if called after exiting boot services. use crate::data_types::PhysicalAddress; +use crate::proto::device_path::DevicePath; use crate::proto::{Protocol, ProtocolPointer}; use core::ffi::c_void; use core::ops::{Deref, DerefMut}; @@ -137,6 +138,72 @@ pub unsafe fn free_pool(ptr: NonNull) -> Result { unsafe { (bt.free_pool)(ptr.as_ptr()) }.to_result() } +/// Connect one or more drivers to a controller. +/// +/// Usually one disconnects and then reconnects certain drivers +/// to make them rescan some state that changed, e.g. reconnecting +/// a block handle after your app modified disk partitions. +/// +/// # Errors +/// +/// * [`Status::NOT_FOUND`]: there are no driver-binding protocol instances +/// present in the system, or no drivers are connected to `controller`. +/// * [`Status::SECURITY_VIOLATION`]: the caller does not have permission to +/// start drivers associated with `controller`. +pub fn connect_controller( + controller: Handle, + driver_image: Option, + remaining_device_path: Option<&DevicePath>, + recursive: bool, +) -> Result { + let bt = boot_services_raw_panicking(); + let bt = unsafe { bt.as_ref() }; + + unsafe { + (bt.connect_controller)( + controller.as_ptr(), + Handle::opt_to_ptr(driver_image), + remaining_device_path + .map(|dp| dp.as_ffi_ptr()) + .unwrap_or(ptr::null()) + .cast(), + recursive, + ) + } + .to_result_with_err(|_| ()) +} + +/// Disconnect one or more drivers from a controller. +/// +/// See also [`connect_controller`]. +/// +/// # Errors +/// +/// * [`Status::INVALID_PARAMETER`]: `driver_image` is set but does not manage +/// `controller`, or does not support the driver binding protocol, or one of +/// the handles is invalid. +/// * [`Status::OUT_OF_RESOURCES`]: not enough resources available to disconnect +/// drivers. +/// * [`Status::DEVICE_ERROR`]: the controller could not be disconnected due to +/// a device error. +pub fn disconnect_controller( + controller: Handle, + driver_image: Option, + child: Option, +) -> Result { + let bt = boot_services_raw_panicking(); + let bt = unsafe { bt.as_ref() }; + + unsafe { + (bt.disconnect_controller)( + controller.as_ptr(), + Handle::opt_to_ptr(driver_image), + Handle::opt_to_ptr(child), + ) + } + .to_result_with_err(|_| ()) +} + /// Returns an array of handles that support the requested protocol in a /// pool-allocated buffer. /// From ff48052213ba548ddb6b5306680984b4e8f46453 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Wed, 31 Jul 2024 22:06:41 -0400 Subject: [PATCH 2/2] test-runner: Update reconnect_serial_to_console Use boot::connect_controller. The BootServices param is no longer needed. --- uefi-test-runner/src/main.rs | 7 +++---- uefi-test-runner/src/proto/console/serial.rs | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/uefi-test-runner/src/main.rs b/uefi-test-runner/src/main.rs index 64a06f317..a45e944ea 100644 --- a/uefi-test-runner/src/main.rs +++ b/uefi-test-runner/src/main.rs @@ -143,7 +143,7 @@ fn send_request_helper(serial: &mut Serial, request: HostRequest) -> Result { /// This must be called after opening the serial protocol in exclusive mode, as /// that breaks the connection to the console, which in turn prevents logs from /// getting to the host. -fn reconnect_serial_to_console(boot_services: &BootServices, serial_handle: Handle) { +fn reconnect_serial_to_console(serial_handle: Handle) { let mut storage = Vec::new(); // Create a device path that specifies the terminal type. let terminal_guid = if cfg!(target_arch = "aarch64") { @@ -160,8 +160,7 @@ fn reconnect_serial_to_console(boot_services: &BootServices, serial_handle: Hand .finalize() .unwrap(); - boot_services - .connect_controller(serial_handle, None, Some(terminal_device_path), true) + uefi::boot::connect_controller(serial_handle, None, Some(terminal_device_path), true) .expect("failed to reconnect serial to console"); } @@ -198,7 +197,7 @@ fn send_request_to_host(bt: &BootServices, request: HostRequest) { // device, which was broken when we opened the protocol in exclusive // mode above. drop(serial); - reconnect_serial_to_console(bt, serial_handle); + reconnect_serial_to_console(serial_handle); if let Err(err) = res { panic!("request failed: \"{request:?}\": {:?}", err.status()); diff --git a/uefi-test-runner/src/proto/console/serial.rs b/uefi-test-runner/src/proto/console/serial.rs index a39d448ef..6c20f6568 100644 --- a/uefi-test-runner/src/proto/console/serial.rs +++ b/uefi-test-runner/src/proto/console/serial.rs @@ -67,7 +67,7 @@ pub unsafe fn test(bt: &BootServices) { // device, which was broken when we opened the protocol in exclusive // mode above. drop(serial); - reconnect_serial_to_console(bt, handle); + reconnect_serial_to_console(handle); if let Err(err) = res { panic!("serial test failed: {:?}", err.status());