mirror of
https://github.com/rust-osdev/uefi-rs
synced 2026-06-08 17:17:36 +00:00
uefi: make TimerTrigger more pleasant to use
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
## Added
|
||||
|
||||
## Changed
|
||||
|
||||
- **Breaking:** The variants of `TimerTrigger` now hold a `Duration`
|
||||
|
||||
# uefi - v0.37.0 (2026-03-22)
|
||||
|
||||
|
||||
+58
-11
@@ -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<c_void>);
|
||||
|
||||
#[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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user