From d684b135e3105026528dffa03ab5f1a1834493b4 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Wed, 7 Aug 2024 00:44:04 -0400 Subject: [PATCH 1/3] boot: Add freestanding set_timer --- uefi/src/boot.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/uefi/src/boot.rs b/uefi/src/boot.rs index a7be3d2b5..13076d53e 100644 --- a/uefi/src/boot.rs +++ b/uefi/src/boot.rs @@ -21,7 +21,7 @@ use { pub use uefi::table::boot::{ AllocateType, EventNotifyFn, LoadImageSource, OpenProtocolAttributes, OpenProtocolParams, - SearchType, + SearchType, TimerTrigger, }; pub use uefi_raw::table::boot::{EventType, MemoryType, Tpl}; @@ -233,6 +233,25 @@ pub fn check_event(event: Event) -> Result { } } +/// Sets the trigger for an event of type [`TIMER`]. +/// +/// # Errors +/// +/// * [`Status::INVALID_PARAMETER`]: `event` is not valid. +/// +/// [`TIMER`]: EventType::TIMER +pub fn set_timer(event: &Event, trigger_time: TimerTrigger) -> Result { + let bt = boot_services_raw_panicking(); + let bt = unsafe { bt.as_ref() }; + + let (ty, time) = match trigger_time { + TimerTrigger::Cancel => (0, 0), + TimerTrigger::Periodic(hundreds_ns) => (1, hundreds_ns), + TimerTrigger::Relative(hundreds_ns) => (2, hundreds_ns), + }; + unsafe { (bt.set_timer)(event.as_ptr(), ty, time) }.to_result() +} + /// Connect one or more drivers to a controller. /// /// Usually one disconnects and then reconnects certain drivers From cc27f2fba730ecad64abd8c3cb835f26578cdec1 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Wed, 7 Aug 2024 13:47:04 -0400 Subject: [PATCH 2/3] boot: Add freestanding wait_for_event --- uefi/src/boot.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/uefi/src/boot.rs b/uefi/src/boot.rs index 13076d53e..57196fb57 100644 --- a/uefi/src/boot.rs +++ b/uefi/src/boot.rs @@ -252,6 +252,59 @@ pub fn set_timer(event: &Event, trigger_time: TimerTrigger) -> Result { unsafe { (bt.set_timer)(event.as_ptr(), ty, time) }.to_result() } +/// Stops execution until an event is signaled. +/// +/// This function must be called at priority level [`Tpl::APPLICATION`]. +/// +/// The input [`Event`] slice is repeatedly iterated from first to last until +/// an event is signaled or an error is detected. The following checks are +/// performed on each event: +/// +/// * If an event is of type [`NOTIFY_SIGNAL`], then a +/// [`Status::INVALID_PARAMETER`] error is returned with the index of the +/// event that caused the failure. +/// * If an event is in the signaled state, the signaled state is cleared +/// and the index of the event that was signaled is returned. +/// * If an event is not in the signaled state but does have a notification +/// function, the notification function is queued at the event's +/// notification task priority level. If the execution of the event's +/// notification function causes the event to be signaled, then the +/// signaled state is cleared and the index of the event that was signaled +/// is returned. +/// +/// To wait for a specified time, a timer event must be included in `events`. +/// +/// To check if an event is signaled without waiting, an already signaled +/// event can be used as the last event in the slice being checked, or the +/// [`check_event`] interface may be used. +/// +/// # Errors +/// +/// * [`Status::INVALID_PARAMETER`]: `events` is empty, or one of the events of +/// of type [`NOTIFY_SIGNAL`]. +/// * [`Status::UNSUPPORTED`]: the current TPL is not [`Tpl::APPLICATION`]. +/// +/// [`NOTIFY_SIGNAL`]: EventType::NOTIFY_SIGNAL +pub fn wait_for_event(events: &mut [Event]) -> Result> { + let bt = boot_services_raw_panicking(); + let bt = unsafe { bt.as_ref() }; + + let number_of_events = events.len(); + let events: *mut uefi_raw::Event = events.as_mut_ptr().cast(); + + let mut index = 0; + unsafe { (bt.wait_for_event)(number_of_events, events, &mut index) }.to_result_with( + || index, + |s| { + if s == Status::INVALID_PARAMETER { + Some(index) + } else { + None + } + }, + ) +} + /// Connect one or more drivers to a controller. /// /// Usually one disconnects and then reconnects certain drivers From 2aa5bd34aef0a750fc3dd8a2b9a0928ad3e539e8 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Wed, 7 Aug 2024 14:21:00 -0400 Subject: [PATCH 3/3] test-runner: Add test_timer_freestanding --- uefi-test-runner/src/boot/misc.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/uefi-test-runner/src/boot/misc.rs b/uefi-test-runner/src/boot/misc.rs index 5768320e4..c91830aef 100644 --- a/uefi-test-runner/src/boot/misc.rs +++ b/uefi-test-runner/src/boot/misc.rs @@ -18,6 +18,7 @@ pub fn test(st: &SystemTable) { test_timer(bt); info!("Testing events..."); test_check_event_freestanding(); + test_timer_freestanding(); test_event_callback(bt); test_callback_with_ctx(bt); info!("Testing watchdog..."); @@ -48,6 +49,14 @@ fn test_check_event_freestanding() { assert!(!is_signaled); } +fn test_timer_freestanding() { + let timer_event = + unsafe { boot::create_event(EventType::TIMER, Tpl::CALLBACK, None, None) }.unwrap(); + let mut events = unsafe { [timer_event.unsafe_clone()] }; + boot::set_timer(&timer_event, TimerTrigger::Relative(5_0 /*00 ns */)).unwrap(); + assert_eq!(boot::wait_for_event(&mut events).unwrap(), 0); +} + fn test_timer(bt: &BootServices) { let timer_event = unsafe { bt.create_event(EventType::TIMER, Tpl::APPLICATION, None, None) } .expect("Failed to create TIMER event");