diff --git a/uefi-test-runner/src/boot/misc.rs b/uefi-test-runner/src/boot/misc.rs index 228af5bf..40b61bb0 100644 --- a/uefi-test-runner/src/boot/misc.rs +++ b/uefi-test-runner/src/boot/misc.rs @@ -2,7 +2,7 @@ use core::ffi::c_void; use core::ptr::{self, NonNull}; - +use core::time::Duration; use uefi::boot::{ EventType, OpenProtocolAttributes, OpenProtocolParams, SearchType, TimerTrigger, Tpl, }; @@ -55,7 +55,11 @@ fn test_timer() { let timer_event = unsafe { boot::create_event_ex(EventType::TIMER, Tpl::CALLBACK, None, None, None) } .unwrap(); - boot::set_timer(&timer_event, TimerTrigger::Relative(5_0 /*00 ns */)).unwrap(); + boot::set_timer( + &timer_event, + TimerTrigger::Relative(Duration::from_nanos(5_000)), + ) + .unwrap(); let mut events = [unsafe { timer_event.unsafe_clone() }]; assert_eq!(boot::wait_for_event(&mut events).unwrap(), 0); diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index 5df212f8..b0b1f63d 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -3,7 +3,7 @@ ## Added ## Changed - +- **Breaking:** The variants of `TimerTrigger` now hold a `Duration` # uefi - v0.37.0 (2026-03-22) diff --git a/uefi/src/boot.rs b/uefi/src/boot.rs index 5f9a44f3..c73f5fc1 100644 --- a/uefi/src/boot.rs +++ b/uefi/src/boot.rs @@ -593,10 +593,11 @@ 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 => (TimerDelay::CANCEL, 0), - TimerTrigger::Periodic(period) => (TimerDelay::PERIODIC, period), - TimerTrigger::Relative(delay) => (TimerDelay::RELATIVE, delay), + let time = trigger_time.to_100ns_steps(); + let ty = match trigger_time { + TimerTrigger::Cancel => TimerDelay::CANCEL, + TimerTrigger::Periodic(_) => TimerDelay::PERIODIC, + TimerTrigger::Relative(_) => TimerDelay::RELATIVE, }; unsafe { (bt.set_timer)(event.as_ptr(), ty, time) }.to_result() } @@ -1937,28 +1938,74 @@ pub type EventNotifyFn = unsafe extern "efiapi" fn(event: Event, context: Option /// See [`set_timer`]. /// /// [`TIMER`]: EventType::TIMER -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] pub enum TimerTrigger { /// Remove the event's timer setting. Cancel, /// Trigger the event periodically. Periodic( - /// Duration between event signaling in units of 100ns. If set to zero, - /// the event will be signaled on every timer tick. - u64, + /// Duration to wait before the next event is fired. + /// + /// If set to zero, the event will be signaled on every timer tick. + Duration, ), /// Trigger the event one time. Relative( - /// Duration to wait before signaling the event in units of 100ns. If - /// set to zero, the event will be signaled on the next timer tick. - u64, + /// Duration to wait before the next event is fired. + /// + /// If set to zero, the event will be signaled on every timer tick. + Duration, ), } +impl TimerTrigger { + /// Transforms the underlying value to 100ns steps, a format widely used + /// in EFI APIs. + #[must_use] + pub fn to_100ns_steps(self) -> u64 { + const NANOS_PER_STEP: u128 = 100; + match self { + Self::Cancel => 0, + Self::Periodic(dur) => { + let ns100_steps = dur.as_nanos().div_ceil(NANOS_PER_STEP); + u64::try_from(ns100_steps).expect("should be representable as u64") + } + Self::Relative(dur) => { + let ns100_steps = dur.as_nanos().div_ceil(NANOS_PER_STEP); + u64::try_from(ns100_steps).expect("should be representable as u64") + } + } + } +} + /// Opaque pointer returned by [`register_protocol_notify`] to be used /// with [`locate_handle`] via [`SearchType::ByRegisterNotify`]. #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct ProtocolSearchKey(pub(crate) NonNull); + +#[cfg(test)] +mod tests { + use core::time::Duration; + use uefi::boot::TimerTrigger; + + #[test] + fn test_timer_trigger_100ns_steps() { + let trigger = TimerTrigger::Periodic(Duration::from_nanos(0)); + assert_eq!(trigger.to_100ns_steps(), 0); + let trigger = TimerTrigger::Relative(Duration::from_nanos(0)); + assert_eq!(trigger.to_100ns_steps(), 0); + + let trigger = TimerTrigger::Periodic(Duration::from_nanos(12_300)); + assert_eq!(trigger.to_100ns_steps(), 123); + let trigger = TimerTrigger::Relative(Duration::from_nanos(12_300)); + assert_eq!(trigger.to_100ns_steps(), 123); + + let trigger = TimerTrigger::Periodic(Duration::from_secs(42)); + assert_eq!(trigger.to_100ns_steps(), 420000000); + let trigger = TimerTrigger::Relative(Duration::from_secs(42)); + assert_eq!(trigger.to_100ns_steps(), 420000000); + } +}