diff --git a/uefi-test-runner/src/boot/misc.rs b/uefi-test-runner/src/boot/misc.rs index 11f41bdae..04b14ccd1 100644 --- a/uefi-test-runner/src/boot/misc.rs +++ b/uefi-test-runner/src/boot/misc.rs @@ -17,6 +17,7 @@ pub fn test() { info!("Testing events..."); test_check_event(); test_callback_with_ctx(); + test_signal_event(); info!("Testing watchdog..."); test_watchdog(); info!("Testing protocol handler services..."); @@ -92,6 +93,38 @@ fn test_callback_with_ctx() { assert_eq!(data, 456); } +fn test_signal_event() { + let mut data = 123u32; + + extern "efiapi" fn callback(_event: Event, ctx: Option>) { + info!("Inside the signal event callback"); + // Safety: this callback is run within the parent function's + // scope, so the context pointer is still valid. + unsafe { + let ctx = ctx.unwrap().as_ptr().cast::(); + *ctx = 456; + } + } + + let ctx: *mut u32 = &mut data; + let ctx = NonNull::new(ctx.cast::()).unwrap(); + + let event = unsafe { + boot::create_event( + EventType::NOTIFY_SIGNAL, + Tpl::CALLBACK, + Some(callback), + Some(ctx), + ) + .expect("Failed to create event with context") + }; + + boot::signal_event(&event).expect("Failed to signal event"); + + // Check that `data` was updated inside the event callback. + assert_eq!(data, 456); +} + fn test_watchdog() { // There's no way to check the watchdog timer value, so just test setting it. diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index 952bad60c..562fa77ce 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -1,5 +1,8 @@ # uefi - [Unreleased] +## Added +- Added `boot::signal_event`. + ## Changed - **Breaking:** Removed `BootPolicyError` as `BootPolicy` construction is no longer fallible. `BootPolicy` now tightly integrates the new `Boolean` type diff --git a/uefi/src/boot.rs b/uefi/src/boot.rs index 21c956700..2c3978165 100644 --- a/uefi/src/boot.rs +++ b/uefi/src/boot.rs @@ -467,6 +467,31 @@ pub fn check_event(event: Event) -> Result { } } +/// Places the supplied `event` in the signaled state. If `event` is already in +/// the signaled state, the function returns successfully. If `event` is of type +/// [`NOTIFY_SIGNAL`], the event's notification function is scheduled to be +/// invoked at the event's notification task priority level. +/// +/// This function may be invoked from any task priority level. +/// +/// If `event` is part of an event group, then all of the events in the event +/// group are also signaled and their notification functions are scheduled. +/// +/// When signaling an event group, it is possible to create an event in the +/// group, signal it and then close the event to remove it from the group. +/// +/// # Errors +/// +/// The specification does not list any errors. +/// +/// [`NOTIFY_SIGNAL`]: EventType::NOTIFY_SIGNAL +pub fn signal_event(event: &Event) -> Result { + let bt = boot_services_raw_panicking(); + let bt = unsafe { bt.as_ref() }; + + unsafe { (bt.signal_event)(event.as_ptr()) }.to_result() +} + /// Removes `event` from any event group to which it belongs and closes it. /// /// If `event` was registered with [`register_protocol_notify`], then the