How Option ROMs Register Interrupts in UEFI
Third-party Option ROMs (OpROMs) operating in a Unified Extensible Firmware Interface (UEFI) environment handle interrupts differently than traditional legacy BIOS implementations. This article examines the architectural mechanisms UEFI provides for interrupt management, detailing how native UEFI drivers register hardware interrupt handlers, use event-driven timer callbacks as non-preemptive alternatives, replace legacy software interrupts with protocols, and manage legacy OpROM execution via the Compatibility Support Module (CSM).
The Architectural Shift from Legacy BIOS to UEFI
In legacy BIOS systems, an Option ROM loaded from a PCI expansion
card hooked directly into the real-mode Interrupt Vector Table (IVT)
located at memory address 0x0000:0x0000 or modified the
protected-mode Interrupt Descriptor Table (IDT). A legacy OpROM provided
hardware and software services by intercepting real-mode interrupt calls
such as INT 10h for video or INT 13h for
storage.
Native UEFI eliminates raw interrupt hooking for boot-time device drivers. UEFI runs in protected or long mode with a flat memory model and operates predominantly as a single-threaded, polling-based, cooperative multitasking environment. Consequently, native UEFI Option ROMs are structured as standard UEFI drivers (PE32+ binaries) rather than raw machine code blobs.
Registering Hardware Interrupts via Protocols
When a hardware device requires servicing via a physical interrupt line (such as PCI INTx or MSI/MSI-X) during the pre-boot phase, the UEFI driver cannot manipulate the CPU's IDT directly. Instead, it must rely on architectural protocols provided by the DXE (Driver Execution Environment) core.
To register a hardware interrupt service routine, a driver uses the
EFI_HARDWARE_INTERRUPT_PROTOCOL (or platform-specific
variations such as EFI_HARDWARE_INTERRUPT2_PROTOCOL). The
process proceeds through the following steps:
Locate the Protocol: The third-party driver calls the Boot Service
gBS->LocateProtocol()to obtain a pointer to the platform's activeEFI_HARDWARE_INTERRUPT_PROTOCOLinterface.Define the Handler: The driver defines an interrupt handler function adhering to the
EFI_CPU_INTERRUPT_HANDLERprototype:typedef VOID (EFIAPI *EFI_CPU_INTERRUPT_HANDLER)( IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_SYSTEM_CONTEXT SystemContext );Register the Routine: The driver invokes the
RegisterInterruptHandlermember function of the protocol, passing the target interrupt vector source assigned to the PCI device along with the pointer to the handler function.Enable the Vector: Once registered, the driver calls
EnableInterruptSourceto unmask the interrupt vector in the platform's interrupt controller (e.g., APIC).
Because UEFI core services are generally not re-entrant, code running within a hardware interrupt handler must be minimal, avoiding calls to most UEFI Boot Services to prevent deadlocks or state corruption.
Event-Driven Asynchronous Polling as the Standard Approach
Due to the constraints and platform dependencies of hardware interrupts in pre-boot environments, the standard UEFI design pattern discourages raw hardware ISRs for third-party Option ROMs. Instead, UEFI provides an asynchronous event model that abstracts interrupt-like behavior without preemptive context switching:
- Creating a Timer Event: The driver uses
gBS->CreateEvent()with the typeEVT_TIMER | EVT_NOTIFY_SIGNALand assigns a notification callback function. - Arming the Timer: The driver calls
gBS->SetTimer(), setting the timer toTimerPeriodicwith a trigger interval (often ranging from 10 to 100 milliseconds). - Execution at TPL: The UEFI core's scheduler calls
the driver’s callback function whenever the timer expires, executing at
a specific Task Priority Level (TPL), typically
TPL_CALLBACKorTPL_NOTIFY.
Inside this callback, the driver queries its hardware status registers to determine if an operation has finished or if an error has occurred, mimicking an interrupt-driven state machine safely within the UEFI cooperative model.
Replacing Software Interrupts with Protocols
In legacy environments, third-party Option ROMs registered themselves as software interrupt handlers so operating system loaders or other utilities could invoke their services. In UEFI, software interrupts are entirely replaced by the UEFI Protocol model:
- Protocol Implementation: The OpROM implements a
defined interface, such as
EFI_BLOCK_IO_PROTOCOLfor mass storage controllers orEFI_GRAPHICS_OUTPUT_PROTOCOL(GOP) for display adapters. - Publishing the Interface: The driver calls
gBS->InstallMultipleProtocolInterfaces()to bind its function pointers and device path to the handle representing the underlying hardware controller. - Consumer Discovery: Other drivers and the OS boot manager locate and call these services directly through function pointers, bypassing the need for software interrupt dispatching.
Legacy Option ROMs and the Compatibility Support Module (CSM)
If a third-party Option ROM is compiled strictly as a legacy binary rather than a native UEFI driver, it cannot natively interact with the UEFI driver model. In systems where legacy boot support is enabled:
- The UEFI firmware loads the Compatibility Support Module (CSM), which provides a partial real-mode BIOS execution environment.
- The CSM driver (
EFI_LEGACY_BIOS_PROTOCOL) copies the legacy OpROM into the Compatibility16 execution space (typically theC0000h–EFFFFhregion). - The CSM transitions the processor to real or virtual-8086 mode and executes the OpROM's entry point.
- The legacy OpROM then directly writes to the 16-bit Interrupt Vector
Table (IVT) in the first kilobyte of physical RAM, registering
traditional software and hardware interrupt handlers (such as
INT 13hor hardware IRQs routed through the legacy 8259 PIC) exactly as it would on native BIOS firmware.