USB Peripheral Enumeration in UEFI PEI and DXE

During the UEFI boot process, USB peripheral enumeration is handled across two distinct stages: the Pre-EFI Initialization (PEI) phase and the Driver Execution Environment (DXE) phase. In PEI, enumeration is a lightweight, synchronous operation designed strictly for system recovery and firmware updates, driven by minimal PEI Modules (PEIMs) operating in constrained memory environments. In contrast, the DXE phase implements the full UEFI Driver Model, executing comprehensive tree-based bus discovery to configure controllers, hubs, and end devices to support broad user input and boot media selection prior to operating system handoff.

USB Enumeration in the PEI Phase

The primary purpose of USB management in PEI is to provide recovery mechanisms, such as loading a firmware capsule from a USB flash drive, before main memory is fully stabilized or when DXE fails to execute.

  1. Host Controller Initialization: A USB Host Controller PEIM (such as an XHCI or EHCI PEIM) configures the physical hardware registers into a basic operational state. This module installs the EFI_PEI_USB_CONTROLLER_PPI (PEIM-to-PEIM Interface).
  2. Minimal Stack Binding: The USB Bus PEIM consumes this controller PPI. Instead of full bus infrastructure, PEI utilizes a simplified, polled transaction model that avoids interrupts and complex asynchronous transfers.
  3. Targeted Detection: The Bus PEIM polls the root hub ports for connection changes. When a device is detected, it applies a reset signaling sequence, determines the device speed (Low, Full, High, or SuperSpeed), and reads the first 8 bytes of the Device Descriptor using the default control endpoint (Endpoint 0, Address 0).
  4. Addressing and Configuration: The PEIM assigns a unique device address using the SET_ADDRESS standard request, retrieves the remaining device and configuration descriptors, and sends a SET_CONFIGURATION request.
  5. Class-Specific Handlers: PEI typically does not bind generic drivers. Instead, a targeted PEIM (such as a USB Mass Storage PEIM) binds directly to the configured device using a minimal protocol wrapper to read boot blocks or update capsules.

USB Enumeration in the DXE Phase

Once the system transitions to DXE, physical memory is fully mapped, and the comprehensive UEFI Driver Model takes over. The DXE USB stack consists of Host Controller Drivers (XhciDxe, EhciDxe, UhciDxe), the core USB Bus Driver (UsbBusDxe), and peripheral class drivers (UsbKbDxe, UsbMassStorageDxe).

1. Controller Protocol Installation

The PCI Bus Driver discovers the USB host controller on the PCI root bridge and starts the matching host controller DXE driver via the EFI_DRIVER_BINDING_PROTOCOL. The host controller driver initializes the hardware, builds transfer rings or scheduling lists in system RAM, and produces the EFI_USB2_HC_PROTOCOL on the controller's handle.

2. Root Hub Discovery

UsbBusDxe attaches to any handle exposing EFI_USB2_HC_PROTOCOL. It queries the controller via GetRootHubPortStatus to determine the number of physical ports and their current connection states.

3. Standard Enumeration Sequence

For every port reporting a connected peripheral, UsbBusDxe executes standard USB specification enumeration:

  • Port Reset and Debounce: The bus driver resets the port, verifies signal stability, and reads the negotiated speed from the host controller.
  • Initial Descriptor Query: It issues a GET_DESCRIPTOR request for the Device Descriptor to Address 0 to determine the maximum packet size (MaxPacketSize0) of Endpoint 0.
  • Address Assignment: It issues a SET_ADDRESS request, assigning the device a unique bus address.
  • Full Descriptor Retrieval: Using the new address, the bus driver reads the full Device Descriptor, followed by the Configuration Descriptor tree (including Interface, Endpoint, and class-specific HID or Companion descriptors).
  • Configuration Selection: The driver evaluates device power requirements and issues a SET_CONFIGURATION request, transitioning the device into the configured state.

4. Hub Handling and Recursion

If a device's class code identifies it as an external USB hub, the UsbBusDxe driver binds a virtual hub manager to that node. It powers up the downstream ports, monitors status change endpoints via periodic interrupt transfers, and recursively repeats the reset-address-configure sequence for any nested devices discovered down the tree.

5. Interface Abstraction and Driver Binding

For non-hub end devices, UsbBusDxe creates a new child handle for each interface defined in the active configuration. On each child handle, it installs:

  • EFI_DEVICE_PATH_PROTOCOL (representing the physical path through controllers and hubs)
  • EFI_USB_IO_PROTOCOL (providing uniform access to interrupt, bulk, and control transfers)

Finally, the DXE core invokes ConnectController on these child handles. Peripheral drivers match the class, subclass, and protocol codes in the interface descriptors:

  • USB Keyboards and Mice: UsbKbDxe and UsbMouseDxe bind to the EFI_USB_IO_PROTOCOL and produce EFI_SIMPLE_TEXT_INPUT_PROTOCOL or EFI_ABSOLUTE_POINTER_PROTOCOL.
  • Storage Devices: UsbMassStorageDxe binds and produces EFI_BLOCK_IO_PROTOCOL and EFI_DISK_INFO_PROTOCOL, exposing the drive as an accessible boot target to the UEFI Boot Manager.