UEFI Timer Events for Asynchronous Driver Tasks
The Unified Extensible Firmware Interface (UEFI) environment is inherently single-threaded, but drivers frequently require background polling, timeouts, or periodic state checks without stalling the boot process. UEFI addresses this by providing an event-driven cooperative multitasking model managed by Boot Services. By leveraging timer events and Task Priority Levels (TPL), UEFI drivers can register non-blocking callback functions that the firmware invokes at regular intervals. This article explains how UEFI timer events are created, scheduled, and dispatched to execute asynchronous periodic tasks efficiently.
The UEFI Execution Model and Events
Unlike traditional operating systems, UEFI does not feature a
preemptive thread scheduler. Instead, it relies on an event architecture
governed by interrupts and Task Priority Levels
(TPL_APPLICATION, TPL_CALLBACK,
TPL_NOTIFY, and TPL_HIGH_LEVEL).
Asynchronous tasks are represented as EFI_EVENT objects.
Drivers register a notification function (a callback) and a context
pointer with the event. When the event is signaled, the UEFI core
schedules the notification function to run at a specified TPL. Execution
is cooperative: a callback will only interrupt code running at a lower
TPL, and no two tasks at the same TPL can execute concurrently on a
single core.
Creating a Timer Event
To set up an asynchronous task, a driver first initializes an event
using the CreateEvent or CreateEventEx boot
service.
When calling CreateEvent, the driver sets the
Type parameter to include both EVT_TIMER and
EVT_NOTIFY_SIGNAL. The driver also specifies:
- NotifyTpl: Typically
TPL_CALLBACKfor standard driver tasks, ensuring it runs above general application code but below critical hardware notifications. - NotifyFunction: The pointer to the driver routine that handles the periodic work.
- NotifyContext: A pointer to driver-defined private data (such as a device context structure).
EFI_STATUS Status;
EFI_EVENT PeriodicEvent;
Status = gBS->CreateEvent (
EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
DriverPeriodicCallback,
DeviceContext,
&PeriodicEvent
);Scheduling Periodic Execution with SetTimer
Once the event is created, it remains dormant until armed using the
SetTimer boot service. To run tasks repeatedly, the driver
configures the timer with the TimerPeriodic type.
Status = gBS->SetTimer (
PeriodicEvent,
TimerPeriodic,
10000000 // 1 second in 100-nanosecond units
);The trigger time is specified in 100-nanosecond units. Setting the
trigger time to 10,000,000 causes the event to fire once
every second.
How UEFI Dispatches Periodic Tasks
- Hardware Interrupts: The underlying platform
firmware sets up a hardware timer interrupt (such as an APIC timer,
HPET, or platform-specific counter) operating at
TPL_HIGH_LEVEL. - Tick Tracking: Every time the hardware timer
interrupt fires, the firmware updates its internal tick counter and
evaluates all active timer events created with
EVT_TIMER. - Signaling: When an event's trigger threshold is
reached, the core marks the event as signaled. For
TimerPeriodicevents, the firmware automatically adds the interval to the event's next trigger target. - Queueing and Dispatch: The notification function is
placed into the execution queue for its designated TPL. As soon as the
processor returns to or drops below that TPL, the firmware invokes
DriverPeriodicCallback(Event, Context).
Best Practices and Constraints
Because UEFI multitasking is cooperative, periodic callbacks must be lightweight. A callback that takes too long to execute or performs synchronous blocking I/O will starve lower-priority tasks and degrade system responsiveness.
Additionally, drivers must clean up timer resources before exiting or unloading:
- Call
SetTimerwithTimerCancelto disarm the timer. - Call
CloseEventto free the event structure and remove pending notifications from the dispatch queue.