IOMMU
An IOMMU (Input/Output Memory Management Unit) is a hardware component — part of the CPU or chipset — that provides memory address translation and access protection for I/O devices. It is analogous to the MMU, which translates virtual addresses to physical addresses for CPU-initiated memory accesses, but the IOMMU performs address translation for device-initiated memory accesses via DMA.
Without an IOMMU, any PCIe device (GPU, NIC, storage controller) that performs DMA can read or write any physical memory address on the system, including memory belonging to other processes or the kernel. The IOMMU closes this gap by restricting each device to only the memory regions explicitly mapped for it.
Why IOMMU exists
IOMMU serves two primary purposes:
Security — preventing DMA attacks
A malicious or buggy PCIe device can exploit unrestricted DMA to read or write arbitrary host memory. This class of vulnerability is called a DMA attack. Common attack vectors include:
- A compromised firmware on a NIC reading encryption keys from kernel memory.
- A rogue Thunderbolt peripheral dumping the contents of RAM.
- A malicious PCIe card injecting code into a running process.
With IOMMU enabled, each device is confined to its own set of I/O page table mappings. Any attempt to access memory outside those mappings triggers a fault, and the IOMMU blocks the access.
Virtualization — enabling device passthrough
When a physical device (such as a GPU) is passed through to a VM, the guest OS programs the device with guest physical addresses (GPAs). Without an IOMMU, these addresses are meaningless on the host — the device would DMA into the wrong memory or into memory belonging to another VM or the host kernel.
The IOMMU translates guest physical addresses to host physical addresses (HPAs), making device passthrough safe and functional. This is the mechanism behind GPU passthrough in Proxmox VE and other hypervisors that use Hardware Assisted Virtualization.
How IOMMU works
The IOMMU sits between PCIe devices and the system memory controller. Its operation mirrors how the CPU’s MMU translates virtual addresses using page tables, but for device-initiated DMA instead of CPU-initiated accesses.
DMA translation flow
- A PCIe device issues a DMA request containing an I/O Virtual Address (IOVA) — the address the device believes it is accessing.
- The IOMMU intercepts the request and looks up the IOVA in its I/O page tables (a hierarchical structure similar to CPU page tables, with multiple levels of indirection).
- If a valid mapping exists, the IOMMU translates the IOVA to the corresponding host physical address (HPA) and forwards the DMA request to the memory controller.
- If no valid mapping exists (the device is trying to access memory it has not been granted), the IOMMU raises a DMA remapping fault and blocks the access. The OS kernel logs the fault.
CPU ──────────────────────────── System Memory
^
| (translated HPA)
|
PCIe Device ── DMA request ──── IOMMU ── looks up I/O page table
(IOVA) |
├── valid mapping: translate & allow
└── no mapping: fault & block
Who manages the I/O page tables
The OS kernel (or hypervisor) is responsible for creating, populating, and tearing down I/O page table entries. When a driver maps a DMA buffer for a device, the kernel’s IOMMU driver inserts a mapping from the IOVA range to the physical pages backing that buffer. When the buffer is unmapped, the entry is removed. This gives the kernel complete control over which memory each device can reach.
IOTLB — caching translations
Just as the CPU uses a Translation Lookaside Buffer (TLB) to cache page table translations, the IOMMU maintains an IOTLB (I/O Translation Lookaside Buffer) that caches recently used IOVA-to-HPA mappings. This avoids walking the full I/O page table hierarchy on every DMA request. When the OS modifies I/O page table entries, it must issue an IOTLB invalidation to flush stale cached mappings.
IOMMU groups
An IOMMU group is the smallest set of devices that the IOMMU hardware can isolate from the rest of the system. It is the atomic unit of device isolation — you can pass through all devices in a group to a VM, or none.
Why groups exist
PCIe topology determines IOMMU groups. Devices behind the same PCIe root port or bridge may be able to communicate with each other without going through the IOMMU (via peer-to-peer PCIe transactions). Because the IOMMU cannot intercept those transactions, it cannot isolate the devices from each other. The kernel therefore places them in the same IOMMU group.
Ideal vs. real-world grouping
- Ideal: Each PCIe device is in its own IOMMU group, allowing individual device passthrough.
- Common reality: Consumer motherboards often have poor IOMMU grouping. For example, a discrete GPU and the onboard HD Audio controller may share a group because they sit behind the same root port. In that case, you must pass through both devices to the VM, or neither.
ACS override patch
ACS (Access Control Services) is a PCIe capability that tells the IOMMU whether a bridge or switch can prevent peer-to-peer transactions between its downstream devices. If ACS is supported and enabled, the kernel can split devices into finer-grained IOMMU groups.
Many consumer PCIe root ports lack ACS support. The ACS override patch is an unofficial kernel patch that forces the kernel to treat every device as if ACS were present, splitting devices into individual IOMMU groups. This enables per-device passthrough on hardware that would otherwise have coarse grouping. The trade-off is that it weakens isolation — peer-to-peer DMA between devices that were previously in the same group is no longer blocked by the IOMMU.
Vendor implementations
Intel VT-d
VT-d stands for Virtualization Technology for Directed I/O. It is Intel’s IOMMU implementation, specified in the “Intel Virtualization Technology for Directed I/O Architecture Specification.” VT-d has been available on most Intel CPUs since Sandy Bridge (2nd generation Core, 2011), but it must be explicitly enabled in the BIOS/UEFI firmware — it is often disabled by default.
The Linux kernel driver for Intel VT-d is intel_iommu. The corresponding kernel boot parameter is intel_iommu=on.
Important
VT-d (IOMMU for I/O) is separate from VT-x (CPU virtualization extensions). See the “IOMMU vs VT-x / AMD-V” section below.
AMD-Vi
AMD-Vi (AMD Virtualization — I/O), also referred to as AMD IOMMU, is AMD’s IOMMU implementation. It has been available on AMD CPUs since the Phenom II (2009) and is present on all modern Ryzen and EPYC processors. Like Intel VT-d, it must be enabled in the BIOS/UEFI firmware.
The Linux kernel driver for AMD-Vi is amd_iommu. The corresponding kernel boot parameter is amd_iommu=on.
Both Intel VT-d and AMD-Vi provide the same conceptual functionality (I/O page tables, DMA remapping, interrupt remapping, IOMMU groups). The kernel’s IOMMU subsystem abstracts vendor-specific differences behind a common DMA mapping API.
IOMMU vs VT-x / AMD-V
These are related but distinct hardware features, and confusing them is a common mistake.
| Feature | Intel name | AMD name | Purpose |
|---|---|---|---|
| CPU virtualization extensions | VT-x | AMD-V | Run VM guest code directly on the CPU. Required by KVM. |
| IOMMU (I/O virtualization) | VT-d | AMD-Vi | Translate and isolate device DMA. Required for PCI passthrough. |
Key distinctions:
- You can run VMs without IOMMU. VT-x / AMD-V alone is sufficient for KVM to create and run virtual machines. Guest disk and network I/O are handled by emulated or paravirtual devices (Virtio), not by passing through physical hardware.
- You cannot pass through a physical device (GPU, NIC) without IOMMU. The IOMMU is what makes it safe for a device to DMA into a VM’s memory.
- VT-x / AMD-V operates at the CPU instruction level (trapping privileged guest instructions, managing nested page tables for memory virtualization).
- VT-d / AMD-Vi operates at the I/O bus level (translating device DMA addresses, isolating devices from each other and from host memory).
Checking IOMMU support and status
Check CPU support
- Intel: Look for “VT-d” on the CPU’s specification page at ark.intel.com. On Linux,
grep -c 'vmx' /proc/cpuinfoconfirms VT-x (CPU virtualization) is present, but VT-d requires checking the spec sheet or BIOS — there is no/proc/cpuinfoflag for it. - AMD: Look for “AMD-Vi” in the CPU specification. On Linux,
grep -c 'svm' /proc/cpuinfoconfirms AMD-V (CPU virtualization) is present. AMD-Vi is almost always available if SVM is.
Check if IOMMU is enabled (Linux)
# Check kernel messages for IOMMU initialization
dmesg | grep -i iommu
# Intel -- look for lines like:
# DMAR: IOMMU enabled
# AMD -- look for lines like:
# AMD-Vi: Found IOMMU at ...
# Check that IOMMU groups exist
find /sys/kernel/iommu_groups/ -type l
# List devices in each IOMMU group
for g in /sys/kernel/iommu_groups/*/devices/*; do
echo "IOMMU Group $(basename $(dirname $(dirname $g))): $(lspci -nns $(basename $g))"
doneEnable IOMMU if not active
- Enter BIOS/UEFI setup (typically Del or F2 at boot).
- Find and enable the relevant setting:
- Intel: “Intel VT-d” or “Intel Virtualization Technology for Directed I/O”
- AMD: “IOMMU” or “AMD-Vi” or “SVM Mode” (SVM enables AMD-V; AMD-Vi is often a separate toggle or enabled automatically when SVM is on)
- Add the kernel boot parameter in the GRUB configuration (
/etc/default/grub):- Intel:
intel_iommu=on - AMD:
amd_iommu=on
- Intel:
- Regenerate GRUB config:
update-grub(Debian/Ubuntu) orgrub2-mkconfig -o /boot/grub2/grub.cfg(RHEL/Fedora). - Reboot and verify with
dmesg | grep -i iommu.