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.
- 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). - 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.
- 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).
- Addressing and Configuration: The PEIM assigns a
unique device address using the
SET_ADDRESSstandard request, retrieves the remaining device and configuration descriptors, and sends aSET_CONFIGURATIONrequest. - 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_DESCRIPTORrequest for the Device Descriptor to Address 0 to determine the maximum packet size (MaxPacketSize0) of Endpoint 0. - Address Assignment: It issues a
SET_ADDRESSrequest, 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_CONFIGURATIONrequest, 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:
UsbKbDxeandUsbMouseDxebind to theEFI_USB_IO_PROTOCOLand produceEFI_SIMPLE_TEXT_INPUT_PROTOCOLorEFI_ABSOLUTE_POINTER_PROTOCOL. - Storage Devices:
UsbMassStorageDxebinds and producesEFI_BLOCK_IO_PROTOCOLandEFI_DISK_INFO_PROTOCOL, exposing the drive as an accessible boot target to the UEFI Boot Manager.