How UEFI Drivers Manage DMA Bus Mastering Safely
Direct Memory Access (DMA) allows peripherals to transfer data
directly to and from system memory without continuous CPU intervention,
but doing so during the pre-boot phase poses severe risks to system
stability and security. UEFI drivers manage DMA bus mastering safely by
abstracting hardware operations through standardized protocols—primarily
the EFI_PCI_IO_PROTOCOL—which manage buffer allocation,
translate host addresses to bus addresses, handle cache coherency, and
enforce hardware-based memory protection mechanisms such as IOMMUs.
The Abstraction of Device Addresses
UEFI drivers never pass raw host physical memory addresses directly to hardware for bus-mastering transactions. The physical memory layout perceived by the CPU may differ significantly from the address space visible to a PCI device due to host bridges, I/O virtualization, or addressing limitations (e.g., a 32-bit device operating on a 64-bit platform).
To bridge this gap safely, the UEFI specification delegates DMA
transactions to the EFI_PCI_IO_PROTOCOL. This protocol
abstracts the underlying architecture, ensuring that drivers obtain
safe, hardware-compatible addresses for any data exchange.
The DMA Lifecycle: Allocation, Mapping, and Unmapping
Safe bus-master transactions in UEFI follow a strict three-phase lifecycle:
1. Buffer Allocation
When a driver requires memory for bidirectional communication or
persistent control structures (such as ring buffers), it calls
EFI_PCI_IO_PROTOCOL.AllocateBuffer().
- Drivers specify the memory type (typically
EfiBootServicesDataorEfiRuntimeServicesData). - This method ensures the allocated memory meets the addressing capabilities of the device (such as restricting allocation below 4 GB for legacy 32-bit controllers).
2. Device Mapping
Before hardware initiates a read or write, the driver must register
the buffer using EFI_PCI_IO_PROTOCOL.Map(). The driver
specifies the operation type:
EfiPciIoOperationBusMasterRead: Used when the device reads system memory.EfiPciIoOperationBusMasterWrite: Used when the device writes to system memory.EfiPciIoOperationBusMasterCommonBuffer: Used for memory that will be accessed simultaneously by both the CPU and the device.
The Map() function provides a DeviceAddress
that the driver programs into the peripheral's registers, as well as a
tracking token (Mapping). If the device cannot access the
original buffer directly—either due to physical address limits or page
isolation—the UEFI firmware transparently provides an internal "bounce
buffer" located in an accessible region.
3. Unmapping and Finalization
Once the transaction concludes, the driver calls
EFI_PCI_IO_PROTOCOL.Unmap(). This step is critical:
- If a bounce buffer was used during a write operation,
Unmap()copies the modified data from the bounce buffer back into the caller's target memory. - It frees any temporary resources allocated for the translation.
- It invalidates the hardware mapping token to prevent dangling access.
Cache Coherency Management
CPUs rely heavily on high-speed caches, which can lead to stale data if a bus-mastering device updates system RAM directly. Conversely, data written by the CPU might reside in cache lines rather than main memory when a device attempts to read it.
UEFI drivers prevent cache incoherency through the Map()
and Unmap() sequences:
- Calling
Map()for a read operation flushes dirty CPU cache lines down to physical RAM so the device sees the most recent data. - Calling
Unmap()after a write operation invalidates the CPU cache lines associated with that memory range, forcing the processor to reload updated data directly from system RAM. - Memory allocated for common buffers is assigned cache attributes (typically uncached or write-combining) that ensure immediate coherency without explicit flushing.
Hardware-Enforced Protection (IOMMU)
Modern UEFI platforms enforce security against malicious or errant DMA (such as attacks via external Thunderbolt or PCIe ports) using an Input-Output Memory Management Unit (IOMMU), such as Intel VT-d or AMD-Vi.
UEFI firmware integrates the EDKII_IOMMU_PROTOCOL. Under
this model:
- DMA is disabled by default for all devices until explicitly enabled by firmware.
- When
Map()is called, the platform programs the IOMMU page tables to permit access only to the specific physical pages registered for that transaction. - Unauthorized memory access attempts trigger a hardware fault, isolating the operating system and platform firmware from pre-boot DMA attacks.