Skip to content

boot: Add freestanding create_event_ex #1313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion uefi-test-runner/src/boot/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ fn test_check_event_freestanding() {

fn test_timer_freestanding() {
let timer_event =
unsafe { boot::create_event(EventType::TIMER, Tpl::CALLBACK, None, None) }.unwrap();
unsafe { boot::create_event_ex(EventType::TIMER, Tpl::CALLBACK, None, 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);
Expand Down
76 changes: 76 additions & 0 deletions uefi/src/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::data_types::PhysicalAddress;
use crate::mem::memory_map::{MemoryMapBackingMemory, MemoryMapKey, MemoryMapMeta, MemoryMapOwned};
use crate::proto::device_path::DevicePath;
use crate::proto::{Protocol, ProtocolPointer};
use crate::table::Revision;
use crate::util::opt_nonnull_to_ptr;
use core::ffi::c_void;
use core::ops::{Deref, DerefMut};
Expand Down Expand Up @@ -267,6 +268,81 @@ pub unsafe fn create_event(
)
}

/// Creates an event in an event group.
///
/// The event's notification function, context, and task priority are specified
/// by `notify_fn`, `notify_ctx`, and `notify_tpl`, respectively. The event will
/// be added to the group of events identified by `event_group`.
///
/// If no group is specified by `event_group`, this function behaves as if the
/// same parameters had been passed to `create_event()`.
///
/// Event groups are collections of events identified by a shared GUID where,
/// when one member event is signaled, all other events are signaled and their
/// individual notification actions are taken. All events are guaranteed to be
/// signaled before the first notification action is taken. All notification
/// functions will be executed in the order specified by their `Tpl`.
///
/// An event can only be part of a single event group. An event may be removed
/// from an event group by calling [`close_event`].
///
/// The [`EventType`] of an event uses the same values as `create_event()`, except that
/// `EventType::SIGNAL_EXIT_BOOT_SERVICES` and `EventType::SIGNAL_VIRTUAL_ADDRESS_CHANGE`
/// are not valid.
///
/// For events of type `NOTIFY_SIGNAL` or `NOTIFY_WAIT`, `notify_fn` must be
/// `Some` and `notify_tpl` must be a valid task priority level. For other event
/// types these parameters are ignored.
///
/// More than one event of type `EventType::TIMER` may be part of a single event
/// group. However, there is no mechanism for determining which of the timers
/// was signaled.
///
/// This operation is only supported starting with UEFI 2.0; earlier versions
/// will fail with [`Status::UNSUPPORTED`].
///
/// # Safety
///
/// The caller must ensure they are passing a valid `Guid` as `event_group`, if applicable.
///
/// # Errors
///
/// * [`Status::INVALID_PARAMETER`]: an invalid combination of parameters was provided.
/// * [`Status::OUT_OF_RESOURCES`]: the event could not be allocated.
pub unsafe fn create_event_ex(
event_type: EventType,
notify_tpl: Tpl,
notify_fn: Option<EventNotifyFn>,
notify_ctx: Option<NonNull<c_void>>,
event_group: Option<NonNull<Guid>>,
) -> Result<Event> {
let bt = boot_services_raw_panicking();
let bt = unsafe { bt.as_ref() };

if bt.header.revision < Revision::EFI_2_00 {
return Err(Status::UNSUPPORTED.into());
}

let mut event = ptr::null_mut();

// Safety: the argument types of the function pointers are defined
// differently, but are compatible and can be safely transmuted.
let notify_fn: Option<uefi_raw::table::boot::EventNotifyFn> = mem::transmute(notify_fn);

(bt.create_event_ex)(
event_type,
notify_tpl,
notify_fn,
opt_nonnull_to_ptr(notify_ctx),
opt_nonnull_to_ptr(event_group),
&mut event,
)
.to_result_with_val(
// OK to unwrap: event is non-null for Status::SUCCESS.
|| Event::from_ptr(event).unwrap(),
)
}

/// Checks to see if an event is signaled, without blocking execution to wait for it.
///
/// Returns `Ok(true)` if the event is in the signaled state or `Ok(false)`
Expand Down