Skip to content

Commit 50b5141

Browse files
authored
Merge pull request #1298 from nicholasbishop/bishop-more-event-funcs
Add freestanding set_timer and wait_for_event
2 parents e251d03 + 2aa5bd3 commit 50b5141

File tree

2 files changed

+82
-1
lines changed

2 files changed

+82
-1
lines changed

uefi-test-runner/src/boot/misc.rs

+9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub fn test(st: &SystemTable<Boot>) {
1818
test_timer(bt);
1919
info!("Testing events...");
2020
test_check_event_freestanding();
21+
test_timer_freestanding();
2122
test_event_callback(bt);
2223
test_callback_with_ctx(bt);
2324
info!("Testing watchdog...");
@@ -48,6 +49,14 @@ fn test_check_event_freestanding() {
4849
assert!(!is_signaled);
4950
}
5051

52+
fn test_timer_freestanding() {
53+
let timer_event =
54+
unsafe { boot::create_event(EventType::TIMER, Tpl::CALLBACK, None, None) }.unwrap();
55+
let mut events = unsafe { [timer_event.unsafe_clone()] };
56+
boot::set_timer(&timer_event, TimerTrigger::Relative(5_0 /*00 ns */)).unwrap();
57+
assert_eq!(boot::wait_for_event(&mut events).unwrap(), 0);
58+
}
59+
5160
fn test_timer(bt: &BootServices) {
5261
let timer_event = unsafe { bt.create_event(EventType::TIMER, Tpl::APPLICATION, None, None) }
5362
.expect("Failed to create TIMER event");

uefi/src/boot.rs

+73-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use {
2121

2222
pub use uefi::table::boot::{
2323
AllocateType, EventNotifyFn, LoadImageSource, OpenProtocolAttributes, OpenProtocolParams,
24-
SearchType,
24+
SearchType, TimerTrigger,
2525
};
2626
pub use uefi_raw::table::boot::{EventType, MemoryType, Tpl};
2727

@@ -233,6 +233,78 @@ pub fn check_event(event: Event) -> Result<bool> {
233233
}
234234
}
235235

236+
/// Sets the trigger for an event of type [`TIMER`].
237+
///
238+
/// # Errors
239+
///
240+
/// * [`Status::INVALID_PARAMETER`]: `event` is not valid.
241+
///
242+
/// [`TIMER`]: EventType::TIMER
243+
pub fn set_timer(event: &Event, trigger_time: TimerTrigger) -> Result {
244+
let bt = boot_services_raw_panicking();
245+
let bt = unsafe { bt.as_ref() };
246+
247+
let (ty, time) = match trigger_time {
248+
TimerTrigger::Cancel => (0, 0),
249+
TimerTrigger::Periodic(hundreds_ns) => (1, hundreds_ns),
250+
TimerTrigger::Relative(hundreds_ns) => (2, hundreds_ns),
251+
};
252+
unsafe { (bt.set_timer)(event.as_ptr(), ty, time) }.to_result()
253+
}
254+
255+
/// Stops execution until an event is signaled.
256+
///
257+
/// This function must be called at priority level [`Tpl::APPLICATION`].
258+
///
259+
/// The input [`Event`] slice is repeatedly iterated from first to last until
260+
/// an event is signaled or an error is detected. The following checks are
261+
/// performed on each event:
262+
///
263+
/// * If an event is of type [`NOTIFY_SIGNAL`], then a
264+
/// [`Status::INVALID_PARAMETER`] error is returned with the index of the
265+
/// event that caused the failure.
266+
/// * If an event is in the signaled state, the signaled state is cleared
267+
/// and the index of the event that was signaled is returned.
268+
/// * If an event is not in the signaled state but does have a notification
269+
/// function, the notification function is queued at the event's
270+
/// notification task priority level. If the execution of the event's
271+
/// notification function causes the event to be signaled, then the
272+
/// signaled state is cleared and the index of the event that was signaled
273+
/// is returned.
274+
///
275+
/// To wait for a specified time, a timer event must be included in `events`.
276+
///
277+
/// To check if an event is signaled without waiting, an already signaled
278+
/// event can be used as the last event in the slice being checked, or the
279+
/// [`check_event`] interface may be used.
280+
///
281+
/// # Errors
282+
///
283+
/// * [`Status::INVALID_PARAMETER`]: `events` is empty, or one of the events of
284+
/// of type [`NOTIFY_SIGNAL`].
285+
/// * [`Status::UNSUPPORTED`]: the current TPL is not [`Tpl::APPLICATION`].
286+
///
287+
/// [`NOTIFY_SIGNAL`]: EventType::NOTIFY_SIGNAL
288+
pub fn wait_for_event(events: &mut [Event]) -> Result<usize, Option<usize>> {
289+
let bt = boot_services_raw_panicking();
290+
let bt = unsafe { bt.as_ref() };
291+
292+
let number_of_events = events.len();
293+
let events: *mut uefi_raw::Event = events.as_mut_ptr().cast();
294+
295+
let mut index = 0;
296+
unsafe { (bt.wait_for_event)(number_of_events, events, &mut index) }.to_result_with(
297+
|| index,
298+
|s| {
299+
if s == Status::INVALID_PARAMETER {
300+
Some(index)
301+
} else {
302+
None
303+
}
304+
},
305+
)
306+
}
307+
236308
/// Connect one or more drivers to a controller.
237309
///
238310
/// Usually one disconnects and then reconnects certain drivers

0 commit comments

Comments
 (0)