diff --git a/uefi-test-runner/src/boot/misc.rs b/uefi-test-runner/src/boot/misc.rs index 2f8c06fc6..7fab703f5 100644 --- a/uefi-test-runner/src/boot/misc.rs +++ b/uefi-test-runner/src/boot/misc.rs @@ -25,6 +25,7 @@ pub fn test(st: &SystemTable) { test_watchdog(bt); info!("Testing protocol handler services..."); test_register_protocol_notify(bt); + test_register_protocol_notify_freestanding(); test_protocol_interface_management(); test_install_protocol_interface(bt); test_reinstall_protocol_interface(bt); @@ -156,6 +157,20 @@ fn test_register_protocol_notify(bt: &BootServices) { .expect("Failed to register protocol notify fn"); } +fn test_register_protocol_notify_freestanding() { + unsafe extern "efiapi" fn callback(_event: Event, _context: Option>) { + info!("in callback for test_register_protocol_notify_freestanding") + } + + let protocol = &TestProtocol::GUID; + let event = unsafe { + boot::create_event(EventType::NOTIFY_SIGNAL, Tpl::NOTIFY, Some(callback), None).unwrap() + }; + + boot::register_protocol_notify(protocol, &event) + .expect("Failed to register protocol notify fn"); +} + fn test_protocol_interface_management() { let mut interface = TestProtocol { data: 123 }; let interface_ptr: *mut _ = &mut interface; diff --git a/uefi/src/boot.rs b/uefi/src/boot.rs index 818ccc491..0f903ef54 100644 --- a/uefi/src/boot.rs +++ b/uefi/src/boot.rs @@ -28,7 +28,7 @@ use crate::proto::device_path::LoadedImageDevicePath; pub use uefi::table::boot::{ AllocateType, EventNotifyFn, LoadImageSource, OpenProtocolAttributes, OpenProtocolParams, - SearchType, TimerTrigger, + ProtocolSearchKey, SearchType, TimerTrigger, }; pub use uefi_raw::table::boot::{EventType, MemoryAttribute, MemoryDescriptor, MemoryType, Tpl}; @@ -374,7 +374,7 @@ pub fn check_event(event: Event) -> Result { /// Removes `event` from any event group to which it belongs and closes it. /// -/// If `event` was registered with `register_protocol_notify`, then the +/// If `event` was registered with [`register_protocol_notify`], then the /// corresponding registration will be removed. Calling this function within the /// corresponding notify function is allowed. /// @@ -615,6 +615,34 @@ pub unsafe fn uninstall_protocol_interface( (bt.uninstall_protocol_interface)(handle.as_ptr(), protocol, interface).to_result() } +/// Registers `event` to be signaled whenever a protocol interface is registered for +/// `protocol` by [`install_protocol_interface`] or [`reinstall_protocol_interface`]. +/// +/// If successful, a [`SearchType::ByRegisterNotify`] is returned. This can be +/// used with [`locate_handle`] or [`locate_handle_buffer`] to identify the +/// newly (re)installed handles that support `protocol`. +/// +/// Events can be unregistered from protocol interface notification by calling [`close_event`]. +/// +/// # Errors +/// +/// * [`Status::OUT_OF_RESOURCES`]: the event could not be allocated. +pub fn register_protocol_notify( + protocol: &'static Guid, + event: &Event, +) -> Result> { + let bt = boot_services_raw_panicking(); + let bt = unsafe { bt.as_ref() }; + + let mut key = ptr::null(); + unsafe { (bt.register_protocol_notify)(protocol, event.as_ptr(), &mut key) }.to_result_with_val( + || { + // OK to unwrap: key is non-null for Status::SUCCESS. + SearchType::ByRegisterNotify(ProtocolSearchKey(NonNull::new(key.cast_mut()).unwrap())) + }, + ) +} + /// Get the list of protocol interface [`Guids`][Guid] that are installed /// on a [`Handle`]. ///