How UEFI Drivers Register Protocols in DXE

This article explains how UEFI drivers publish and register protocols during the Driver Execution Environment (DXE) phase. In UEFI architecture, protocols act as standardized interfaces enabling inter-module communication. Drivers register these interfaces by attaching them to handles via DXE Core Boot Services, allowing other drivers, system applications, and the firmware core to discover, bind, and execute protocol-defined functionality.

The Role of Protocols and Handles

In the DXE environment, communication is fundamentally modular. A protocol is a C structure containing function pointers and data structures, uniquely identified by a 128-bit Globally Unique Identifier (EFI_GUID). Protocols do not exist in isolation; they are attached to an EFI_HANDLE. A handle is an opaque pointer maintained by the DXE Core that serves as a container for one or more protocols representing a device, a controller, or an abstract system service.

Core Registration APIs

To register a protocol, a DXE driver uses the UEFI Boot Services table (EFI_BOOT_SERVICES, commonly accessible via the global pointer gBS). The two primary functions used for registration are:

  • gBS->InstallProtocolInterface(): Installs a single protocol interface onto an existing handle or creates a new handle if the handle pointer is initialized to NULL.
  • gBS->InstallMultipleProtocolInterfaces(): A variable-argument function that can install multiple protocols onto a single handle atomically. This is generally preferred for modern drivers because it reduces overhead and avoids race conditions.

The Registration Process

  1. Protocol Definition: The driver defines the protocol structure containing pointers to its internal functions and defines the unique EFI_GUID corresponding to that protocol.

  2. Handle Allocation and Binding: Within the driver's entry point (e.g., UefiMain or InitializeDriver), the driver prepares the interface instance. If the protocol represents a new service or virtual device, the driver initializes an EFI_HANDLE variable to NULL. If the driver is augmenting an existing hardware device, it uses the device's existing handle.

  3. Invoking Boot Services: The driver calls InstallMultipleProtocolInterfaces(), passing:

    • The address of the target EFI_HANDLE.
    • The protocol's EFI_GUID.
    • The pointer to the protocol's interface structure.
    • A terminating NULL parameter.
EFI_STATUS Status;
EFI_HANDLE DriverHandle = NULL;

Status = gBS->InstallMultipleProtocolInterfaces (
                &DriverHandle,
                &gMyCustomProtocolGuid,
                &mMyCustomProtocolInstance,
                NULL
                );
  1. Handle Database Update: Upon receiving the call, the DXE Core creates a handle entry (if NULL was passed) and links the protocol GUID and interface pointer to that handle in the global DXE handle database.

Notification and Consumption by Other Modules

Once a protocol is registered, the DXE Core signals any protocol notification events registered via gBS->RegisterProtocolNotify(). This mechanism allows dependent drivers to stay dormant until their prerequisite protocols are installed.

Other DXE modules can then locate and consume the registered protocol using one of several methods:

  • gBS->LocateProtocol(): Finds the first available instance of a protocol in the system.
  • gBS->OpenProtocol(): Opens a protocol on a specific handle with defined attributes, ensuring proper tracking of driver-to-device bindings.
  • gBS->LocateHandleBuffer(): Retrieves all handles that support a specific protocol GUID, enabling drivers to iterate over multiple instances of an interface across the platform.