4. SMMU 页表结构:Stage-1、Stage-2 与混合转换
SMMU 的页表结构是 IOMMU 地址转换的核心,它直接决定了系统如何将设备发起的 I/O 虚拟地址(IOVA)转换为最终的物理地址(PA)。ARM SMMUv3 支持两种独立的转换阶段:Stage-1 和 Stage-2,以及它们的组合——混合转换。理解这三种模式是进行页表隔离选型的基础。
4.1 Stage-1 页表:虚拟地址到中间物理地址
Stage-1 转换类似于 CPU 的 MMU 页表,负责将设备使用的 I/O 虚拟地址(IOVA) 转换为 中间物理地址(IPA)。在虚拟化场景中,IPA 通常是 Guest OS 看到的物理地址空间。
- 输入:IOVA(设备发起的地址)
- 输出:IPA(中间物理地址)
- 典型用途:非虚拟化场景下的地址映射,或虚拟化场景中 Guest OS 的页表管理。
- 页表格式:支持 4KB、16KB、64KB 页面粒度,支持 4 级页表(L0-L3)或 3 级页表(L1-L3),具体取决于配置。
关键点:Stage-1 页表由 Stream Table Entry (STE) 中的
Config[1:0] 字段控制。当配置为 0b01 时,启用 Stage-1 转换。
4.2 Stage-2 页表:中间物理地址到物理地址
Stage-2 转换是 ARM 虚拟化扩展的核心,它负责将 中间物理地址(IPA) 转换为最终的 物理地址(PA)。这个阶段通常由 Hypervisor/VMM 管理,用于隔离不同虚拟机的物理内存访问。
- 输入:IPA(来自 Stage-1 的输出,或直接来自设备)
- 输出:PA(最终的物理地址)
- 典型用途:虚拟化场景中,Hypervisor 控制 Guest OS 对真实物理内存的访问。
- 页表格式:与 Stage-1 类似,但使用独立的页表基址寄存器(VMID 相关)。
隔离价值:Stage-2 页表是实现 内存隔离 的关键。即使 Guest OS 的 Stage-1 页表被攻破,Stage-2 页表仍能阻止恶意设备访问其他 VM 或 Hypervisor 的内存。
4.3 混合转换:Stage-1 + Stage-2 同时生效
混合转换是 SMMU 最强大的特性之一,它允许 Stage-1 和 Stage-2 页表同时生效,形成完整的 IOVA → IPA → PA 转换链。这种模式在虚拟化场景中至关重要,因为它同时提供了 Guest OS 的灵活映射和 Hypervisor 的强制隔离。
- 转换链:IOVA → (Stage-1) → IPA → (Stage-2) → PA
- 配置方式:STE 中的
Config[1:0]设置为0b11。 - 性能影响:两次页表遍历会增加 TLB 压力,但 SMMUv3 的 TLB 支持两阶段缓存(Combined TLB 或 Split TLB)。
注意事项:混合转换模式下,Stage-1 和 Stage-2 的页表属性(如内存类型、可缓存性)会进行组合。如果两者冲突,SMMU 的行为由架构定义,通常以更严格的属性为准。务必确保两阶段属性兼容。
4.4 三种模式对比与选型建议
下表总结了 Stage-1、Stage-2 和混合转换三种模式的核心差异,帮助你在实际项目中做出选择。
| 特性 | Stage-1 仅用 | Stage-2 仅用 | 混合转换 (Stage-1 + Stage-2) |
|---|---|---|---|
| 转换路径 | IOVA → IPA | IPA → PA | IOVA → IPA → PA |
| 管理方 | OS / Guest OS | Hypervisor | Guest OS + Hypervisor |
| 隔离粒度 | 进程级(ASID) | VM 级(VMID) | 进程级 + VM 级 |
| 典型场景 | 非虚拟化、DPDK | 虚拟化(直通设备) | 虚拟化(嵌套虚拟化、GICv4) |
| TLB 压力 | 低 | 低 | 高(需两阶段缓存) |
| 配置复杂度 | 低 | 中 | 高 |
选型建议:
- 裸机场景:优先使用 Stage-1 仅用,简化配置,性能最优。
- 虚拟化场景(设备直通):使用 Stage-2 仅用,由 Hypervisor 统一管理物理内存隔离。
- 嵌套虚拟化或高级隔离需求:使用 混合转换,实现 Guest OS 灵活映射 + Hypervisor 强制隔离的双重保障。
4.5 页表配置代码示例
以下代码展示了如何通过配置 STE 来启用不同的转换模式。代码基于 SMMUv3 驱动框架(Linux 内核)。
/* SMMUv3 Stream Table Entry (STE) 配置示例 */
struct arm_smmu_ste ste = {0};
/* 配置 Stage-1 仅用 */
ste.data[0] |= FIELD_PREP(STE_CONFIG, 0b01); // Config[1:0] = 01
ste.data[0] |= FIELD_PREP(STE_S1CTXPTR, s1_cfg->ptr); // Stage-1 页表基址
ste.data[0] |= FIELD_PREP(STE_S1CDMAX, s1_cfg->cdmax); // Context Descriptor 数量
/* 配置 Stage-2 仅用 */
ste.data[0] |= FIELD_PREP(STE_CONFIG, 0b10); // Config[1:0] = 10
ste.data[0] |= FIELD_PREP(STE_S2VMID, s2_cfg->vmid); // VMID
ste.data[0] |= FIELD_PREP(STE_S2TTB, s2_cfg->vttbr); // Stage-2 页表基址
/* 配置混合转换 (Stage-1 + Stage-2) */
ste.data[0] |= FIELD_PREP(STE_CONFIG, 0b11); // Config[1:0] = 11
ste.data[0] |= FIELD_PREP(STE_S1CTXPTR, s1_cfg->ptr);
ste.data[0] |= FIELD_PREP(STE_S2VMID, s2_cfg->vmid);
ste.data[0] |= FIELD_PREP(STE_S2TTB, s2_cfg->vttbr);
关键字段说明:
STE_CONFIG:控制转换模式(0b01=Stage-1, 0b10=Stage-2, 0b11=混合)。STE_S1CTXPTR:Stage-1 页表基址指针(指向 Context Descriptor 表)。STE_S2VMID:Stage-2 的 VMID,用于标识所属虚拟机。STE_S2TTB:Stage-2 页表基址(VTTBR_EL2 格式)。