Timeline
Timeline
2025-10-30
init
This article introduces the architecture principles and programming interfaces of ARM SMMUv3 and its controller MMU-600, discussing the role of SMMU/IOMMU in addressing device DMA access security and performance issues in bare-metal and virtualization scenarios. It summarizes in detail the internal composition of MMU-600, the two-stage address translation mechanism, the page table walk and configuration process based on StreamID and SubstreamID, and briefly mentions the composition and core functions of the Linux IOMMU driver framework.
Reference Documents:
Technical Manual:
- System Memory Management Unit Architecture Specification, SMMU architecture version 3
- MMU-600 System Memory Management Unit, Technical Reference Manual
What is SMMU/IOMMU
- SMMU is ARM’s implementation of IOMMU (Input/Output Memory Management Unit), which translates virtual addresses accessed by devices into physical addresses
- AMD IOMMU
- Intel VD-T

Bare-metal OS Scenario

DMA access by IO devices may have issues:
- IO devices receive physical addresses and can access all memory addresses. Therefore, DMA can corrupt other devices or system memory, such as malicious IO devices.
- There is also no protection for device drivers, such as malicious drivers
- Information leakage between IO devices is easy: Side channel attack
Virtualization Scenario

Disadvantage:
Each DMA operation requires trapping into the VMM to allocate physical memory for IO devices, resulting in a performance loss (about 20-30%).
Solution: SMMU

Each IO device has its own page table
Scatter-gather means that IO devices can use a contiguous range of virtual addresses, but the final translated physical addresses do not necessarily need to be contiguous.
History of SMMU development

Usage of SMMU

The CPU accesses devices using the MMU, while device access to memory must go through the SMMU
MMU-600 controller
- SMMUv3 is a specification, and MMU-600 is a controller implemented based on the SMMUv3.1 specification.
- MMU-600 translates device IOVA to PA, supporting 2-stage address translation or Bypass mode.
- Stage 1: Translate IOVA->PA or IOVA->IPA
- Stage2:IPA->PA
- Both: IOVA->IPA->PA
- Bypass mode (skipping SMMU)
- Features
- Compatible with SMMUv3.1
- Supports ARMv8 AArch32 and AArch64 page table formats
- Supports 4KB, 16KB, and 64KB pages
- Supports PCIe, ATS, and PASIDs
- Supports RPI (Page Request Interface)
- Supports ACE5-Lite atomic operations
- Supports translation faults; software can implement demand paging
- Supports GICv3 integration and message-based interrupts
MMU-600 block diagram

MMU-600 internal composition
- TBU (Translation Buffer Unit)
- Includes TLB to cache translation results
- Each connected master has at least one TBU
- If the TBU does not find a TLB entry, it sends a request to the TCU.
- TCU(Translation Control Unit)
- Hardware unit for address translation.
- The MMU-600 has only one TCU.
- Manage memory requests.
- Traverse page tables.
- Execute configuration page tables.
- Implements backup caching structures
- SMMU programming interface.
- DTI
- Used to connect TBU to TCU.
- Uses the AXI Stream protocol.

StreamID
- A DMA transfer includes: target address, size, read/write attributes, security attributes, shareability attributes, cache attributes, and StreamID.
- StreamID is used to associate a device (function).
- StreamID is used to index the Stream Table, which contains per-SMMU related page table information.
- For PCIe devices, StreamID[15:0] == RequesterID[15:0] equals BDF.
- Bits[15:8] Bus number
- Bits[7:3] Device number
- Bits[2:0] Function number
- For non-PCIe devices, the StreamID is obtained through DTS (thus the StreamID is fixed).

Traverse the Stream Table
- Each Stream Table Entry (STE) in the Stream Table contains:
- The page table base address for Stage 2 translation
- Points to a Context Descriptor, which contains the page table base address for Stage 1 translation
- Use StreamID to index the Stream Table
- The Stream Table needs to be created and populated by OS software
- If the number of STEs (Stream Table Entries) exceeds 64, a two-level table must be used
- streamID[n:x] indexes the first-level table, streamID[x-1:0] indexes the second-level table
- N represents the most significant bit of streamID, typically 15
- X is the split point, STRTAB_BASE_CFG.SPLIT
- For example: n=15, x=8, then StreamID[15:8] indexes the first-level table, StreamID[7:0] indexes the second-level table

Two-level table example

Assume StreamID is only 10 bits, i.e., StreamID[9:0], and assume x is 8, then use StreamID[9:8] to index the first-level table, and StreamID[7:0] to index the second-level table
The first-level table has 4 entries, and each second-level table has 256 entries.
The StreamID is 10 bits in total, 2^10 equals 1024, meaning it can index up to 0~1023 STEs.
Context Descriptors table
The CD contains the stage 1 page table base address, ASID, page table attributes, etc.
The S1ContextPtr in the STE points to the CD.
The stage 2 page table base address is in the STE.
Software management:
- Virtualization: The Hypervisor manages the Stream Table and stage 2 page tables, while the Guest OS manages the CD and stage 1 page tables.
- The bare-metal OS manages the Stream Table and CD.

Context Descriptors table SubstreamID

SubstreamID The S1ContextPtr in the STE points to a CD (Context Descriptor) table, and the SubstreamID is used to index this table.
Each CD contains the page table base address to be used in stage 1.
A device may be used by multiple processes; the SMMU distinguishes them via the substream ID, and each process can have its own substream ID.
For PCIe devices, PASID is used as the SubstreamID.
Summary

Command and Event queues
- The command queue is used for input, and the event queue is used for output. Each queue has a producer and a consumer.
- The output queue contains data generated by the SMMU, which is then consumed by software. The input queue is where software generates data, which is then consumed by the SMMU.


For detailed descriptions of each command, see Chapter 4 of the SMMUv3 manual.
Linux IOMMU Driver Framework
Two main functions of the IOMMU driver:
- Provide DMA interfaces and functions for IO devices.
- Provide SVA (Shared Virtual Addressing) functionality for IO devices, sharing the virtual address space between the IO device and a process.
IOMMU includes:
- IOMMU framework
- IOMMU controller driver
- IOMMU dma-mapping
- Interfaces provided by IOMMU to IO devices

- The IOMMU Domain is mainly used to provide the ability to access the IOMMU controller.
- The iommu_group is the smallest resource isolation unit.
- Generally, one device occupies one iommu_group. Multiple devices that are based on a certain hardware topology and are trusted, or point-to-point protected transport devices, can be added to one iommu_group.
- A server system may consist of multiple IOMMU controllers



The bridge between IOMMU domain and SMMU controller - iommu_ops

SMMU driver: DMA

Writing an IOMMU IO device driver
Manual setup
- Allocate an IOMMU domain
1 | domain = iommu_domain_alloc() |
- Add device dev to the IOMMU domain
1 | iommu_attach_device(domain, dev) |
- Establish mapping
1 | iommu_map() |

Automatic setup
- For PCI devices or platform devices, automatically detect and initialize IOMMU through bus scanning
driver_probe_device()->
dev->bus->dma_configure(dev)->
platform_dma_configure()/pci_dma_configure()->
of_dma_configure()
- Automatically set struct dma_map_ops *dma_ops for IOMMU
For PCI and platform devices, DMA API interfaces can be used, such as dma_map_page()
of_dma_configure()->
arch_setup_dma_ops()->
dev->dma_ops = &iommu_dma_ops;
- arch/arm64/mm/dma-mapping.c

IO Device SMMU Initialization Process

Summary

SVA(Shared Virtual Addressing)
Sharing Process Address Space Between Processes and Devices
(Based on Linux 5.15 Kernel)
Why SVA
Traditional DMA Mode

SVA Mode

In DMA mode, it is difficult to share some complex data structures between CPU and GPU/FPGA/accelerator cards

Linux SVA Framework

From the driver perspective, what new API interfaces are added

Summary

IO page fault
- Page fault on the CPU side, handled via the CPU’s page fault handler_mm_fault
- Page fault on the device side:
- PCIe device: PRI extension (Page Request Interface)
- Platform device: using SMMU’s stall mode
- Stall mode: When an IO device triggers an exception, the transaction is paused and the event is recorded in the event queue. The OS software needs to handle it and then send a CMD_RESUME command to resume the transaction.

Question: Why does the IO device side page fault handling call the CPU side’s handle_mm_fault() to establish VA->PA page table entries, what about the IO device’s page table? Who establishes it?
SVA, sharing the same set of page tables
Invalid TLB operation

- When the CPU side modifies the mm or releases memory
- Call flush_tlb() to invalidate the TLB on the CPU side
- Use the callback function registered via mmu_notifier to invalidate the corresponding IOTLB on the IO device side and the IOTLB of the PCIe ATC

- Is it possible for an IO device to actively modify the VA->PA mapping relationship?
- In non-SVA cases, via iommu_map and iommu_umap interface to allocate and release DMA buffers. iommu_unmap()->iotlb_sync()
- In SVA cases, the virtual address allocated on the CPU side can be used as IOVA. When an IO device triggers a page fault, it directly goes through the IO page fault handling process.
PCIe’s newly added ATS (Address Translation Services)

- ATS mechanism in PCIe: The device caches the PA corresponding to the VA, so when the device uses the PA for memory access, it does not need to go through IOMMU page table translation
- The ATC (Address Translation Cache) of a PCIe device has its own TLB
- Before the device performs DMA, it checks whether the ATC has an entry corresponding to the VA
- If yes: directly use the PA to access memory
- If no: send an ATS request to the SMMU, and after the SMMU finds the PA, it replies with an ATS completion
- The PCIe ATS specification defines the format of ATS request and completion message packets.
- Address Translation Services Revision 1.1
- SMMU driver:
- Enable ATS
- ATS invalidation operation. When the SMMU changes VA->PA, the SMMU needs to send an ATS invalidation request to the PCIe ATC.
- SMMU provides CMD_ATC_INV command

PRI (Page Request Interface) support
- The advantage of the PRI mechanism is that when preparing to initiate a DMA operation, it is not necessary to prepare (pin) the DMA buffer in advance.
- Use case: high-speed network card; in burst scenarios, the host does not need to reserve and occupy a large amount of buffer in advance.
- PRI mechanism:
- When the ATC encounters a TLB miss, it sends a Page Request Message.
- The RC sends the message to the SMMU.
- The SMMU writes the page fault request to the PRI queue, triggering a PRI interrupt.
- OS software allocates physical memory.
- OS software replies with CMD_PRI_RESP command

