内存管理-79-MMU-1-疑问chatGPT


一、Linux系统中有哪些MMU,作用分别是什么?用于把什么地址翻译成什么地址?

注: 基于 Linux + QNX 虚拟化平台。

1. 先给结论Linux

内核本身不实现 MMU,MMU 是 SoC 硬件;Linux 只负责建立页表、处理缺页异常、刷新 TLB。按“谁发起地址访问”来划分,一颗 ARM SoC 上通常有三类软件可见的地址翻译单元:
(1) CPU MMU:每个 CPU core 内部一个,把 CPU 的虚拟地址(VA)翻译成物理地址(PA);在虚拟化环境下变成 VA → IPA → PA。
(2) IOMMU / ARM SMMU:系统级外设地址翻译单元,把设备 DMA 使用的 I/O 虚拟地址(IOVA)翻译成 PA;在虚拟化环境下变成 IOVA → IPA → PA。
(3) GPU MMU:GPU 专用的地址翻译单元,把 GPU 虚拟地址(GPU VA)翻译成 PA(或 IPA);在 Adreno 平台上通常由 KGSL 通过 SMMU context bank + GPU 页表实现。

除此之外,DSP、NPU、ISP、VPU 等加速器一般没有 Linux 独立管理的 MMU,而是挂到某个系统 SMMU 的 context bank 上;虚拟化层的 stage-2 MMU 也不是独立硬件,而是 CPU/SMMU 内部的第二级翻译。


2. 先把地址名词统一

---------------------------------------------------------------------------------------------------------------------------------------
地址              含义                                                                         谁产生
---------------------------------------------------------------------------------------------------------------------------------------
VA               虚拟地址(Virtual Address)                                                    CPU 的 load/store、取指
IPA              中间物理地址(Intermediate Physical Address),即 guest 看到的“物理地址”            Guest 的 stage-1 翻译输出
PA               真正的物理地址(Physical Address)                                              Hypervisor stage-2 输出
IOVA             I/O 虚拟地址,设备 DMA 使用的地址                                                驱动通过 DMA/IOMMU API 分配
GPU VA           GPU 虚拟地址,GPU 命令流、纹理、缓冲使用                                           GPU/KGSL 分配
---------------------------------------------------------------------------------------------------------------------------------------

关键点:Linux guest 里的 phys_addr_t / virt_to_phys() 返回的是 IPA,不是 PA。Linux 看不到真正的 PA,PA 由 QNX Hypervisor 的 stage-2 页表管理。


3. CPU MMU

3.1 位置

ARM64 每个 CPU core 内部都有 MMU,负责该 core 上所有 EL0/EL1 的取指和数据访问。

3.2 翻译方向

Stage 1:VA → PA(没有虚拟化时);VA → IPA(有 stage 2 时)
Stage 2:IPA → PA,由 Hypervisor(QNX)在 EL2 配置 VTTBR_EL2

Linux 在 EL1 只控制 stage 1 页表(TTBR0_EL1 用户空间、TTBR1_EL1 内核空间),stage 2 由 EL2 的 Hypervisor 控制。

3.3 主要作用

(1) 进程地址空间隔离:每个进程一套 mm_struct + 页表;
(2) 用户态/内核态权限隔离(EL0/EL1、AP、UXN/PXN);
(3) 按需分页、缺页异常、COW、mmap;
(4) 内存属性控制(Normal/Device、Cacheable、Shareability);
(5) ASID 标记 TLB,上下文切换减少 TLB flush。

3.4 Linux 对应代码

页表管理:arch/arm64/mm/mmu.c、mm/memory.c(缺页)、mm/mmap.c
TLB:arch/arm64/include/asm/tlbflush.h

在 8295 上,Linux guest 的 stage 1 输出 IPA,QNX Hypervisor 的 stage 2 再翻译成 PA。


4. IOMMU / ARM SMMU

4.1 位置

SMMU 是 SoC 内独立的系统级 IP,通常有多个实例。Qualcomm 平台常见的有:

(1) apps_smmu:显示、Camera、Video、PCIe、USB 等大多数外设;
(2) kgsl_smmu:GPU 专用;
(3) 部分平台还有 adsp_smmu、cdsp_smmu 等。

具体节点名因平台而异,Linux 通过设备树的 iommus 属性把设备绑定到某个 SMMU。

4.2 翻译方向

Stage 1:IOVA → PA(非虚拟化);IOVA → IPA(虚拟化)
Stage 2:IPA → PA

SMMU 的查表过程大致是:设备 DMA 请求 → Stream ID(标识设备) → Stream Table Entry (STE) → Context Descriptor (CD) → TTBR0 页表 → 输出 PA / IPA

不同 Stream ID、不同 context bank 相互隔离,所以一块 SMMU 可以同时服务很多设备。

4.3 主要作用

(1) DMA 隔离与安全:设备只能访问驱动为它映射的地址,不能随意读写物理内存;
(2) Scatter-gather:把分散的物理页映射成一段连续 IOVA,交给设备使用;
(3) 地址范围适配:让只有 32 位 DMA 能力的设备访问 4GB 以上内存;
(4) dma-buf 共享:Camera/Display/GPU/Video 之间共享缓冲时,各自映射到自己的 IOVA;
(5) 设备直通/虚拟化:stage 1 由 guest 管理,stage 2 由 hypervisor 管理;
(6) 故障上报:非法 DMA 触发 SMMU fault,而不是静默踩内存。

4.4 Linux 对应代码

框架:drivers/iommu/
ARM SMMUv2:drivers/iommu/arm/arm-smmu/arm-smmu.c
ARM SMMUv3:drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
驱动接口:iommu_map() / iommu_unmap()、dma_map_single() / dma_map_sg()

一个实用判断:dma_addr_t 在使能 IOMMU 时是 IOVA,未使能时才是总线/物理地址;驱动不能假设 dma_addr_t == phys_addr_t。


5. GPU MMU

5.1 位置

GPU 侧的地址翻译单元。在 Adreno 平台上,它通常不是一颗完全独立的芯片,而是:
GPU 内部/旁边的地址翻译硬件;
加上 KGSL 为每个进程维护的 GPU 页表;
在新平台上,这些页表通常挂到专用的 SMMU context bank(如 kgsl_smmu);
历史平台(如更早的 a3xx/a4xx)则使用独立的 GPUMU。

5.2 翻译方向

GPU VA → PA(非虚拟化);
GPU VA → IPA → PA(GPU 直通给 GVM 时,stage 2 由 Hypervisor 叠加)。

5.3 主要作用

(1) 给每个进程独立的 GPU 虚拟地址空间,实现 GPU 侧进程隔离;
(2) 把 GPU 缓冲、纹理、命令流(ringbuffer)、页表自身映射到 GPU VA;
(3) 导入 dma-buf 时,把同一批物理页映射到 GPU VA,避免拷贝;
(4) GPU 页错误隔离和 fault 上报(KGSL 捕获后终止/重启 GPU context);
(5) 部分平台支持 SVA(Shared Virtual Addressing),让 GPU 直接使用 CPU 页表。

5.4 Linux 对应代码

vendor/qcom/opensource/graphics-kernel/kgsl_mmu.c
kgsl_iommu.c(SMMU 路径)、kgsl_gpummu.c(历史 GPUMU 路径)
GPU 映射/缺页:kgsl_mmap()、kgsl_paged_vmfault() 等。

注意:GPU VA 和 CPU VA 是两个独立地址空间。同一个物理页可以同时出现在某进程的 CPU VA 和 GPU VA 中,但两个 VA 数值通常不同。


6. 其它加速器与虚拟化 stage-2

6.1 DSP/NPU/ISP/VPU

大多数情况下没有 Linux 直接管理的独立 MMU;它们作为 SMMU 的 client,使用某个 context bank,由 Linux IOMMU 驱动或固件配置;例如 FastRPC 把 dma-buf 映射给 ADSP/CDSP,底层仍走 SMMU;Hexagon 等处理器内部可能还有自己的地址转换机制,但通常由 DSP 固件管理,Linux 不直接操作。

6.2 Stage-2 MMU

不是独立硬件,而是 CPU MMU / SMMU 的第二级翻译;CPU 侧根页表是 VTTBR_EL2,SMMU 侧是 STE/CD 中的 stage-2 配置;在 8295 上由 QNX Hypervisor 管理,Linux 只看到 IPA;linux-la.config 里配置的内存预留地址是 IPA 范围,不是 PA;Hypervisor 用 stage 2 把它们映射到实际 PA。

实测:

linux-la.config 里配置的内存预留地址(IPA),比如 __GVM_SYSRAM1_START__/__GVM_SYSRAM1_SIZE__ 就是 Linux 内核中能看到的物理地址,已通过 cat 下面两个文件进行了确认。

# cat /sys/kernel/debug/memblock/reserved
# cat /sys/kernel/debug/memblock/memory

 

7. 一张总表

---------------------------------------------------------------------------------------------------------------------------------------
翻译单元            输入地址      输出地址          页表/上下文                      主要作用
---------------------------------------------------------------------------------------------------------------------------------------
CPU MMU stage 1    VA          PA 或 IPA        TTBR0_EL1/TTBR1_EL1             进程/内核地址空间、权限、缺页
CPU MMU stage 2    IPA         PA               VTTBR_EL2                       Hypervisor 虚拟机内存隔离
SMMU stage 1       IOVA        PA 或 IPA        Stream Table + CD + TTBR0       外设 DMA 隔离、scatter-gather
SMMU stage 2       IPA         PA               STE/CD stage-2                  设备直通、VM 隔离
GPU MMU            GPU VA      PA 或 IPA        GPU 页表 / SMMU context bank     GPU 进程隔离、缓冲映射、GPU fault
---------------------------------------------------------------------------------------------------------------------------------------


8. 8295 + QNX 虚拟化下的完整链路

Linux 进程/内核: VA ──[CPU stage1, TTBR0/1]──► IPA ──[QNX stage2, VTTBR_EL2]──► PA
Linux 外设 DMA : IOVA ──[SMMU stage1]──► IPA ──[SMMU stage2 / Hypervisor]──► PA
GPU:          : GPU VA ──[KGSL GPU页表 / kgsl_smmu CB]──► IPA ──[stage2]──► PA

对应关系:

Linux 里 cat /proc/meminfo 看到的 MemTotal 是 IPA 总量;
Linux 驱动 dma_map_sg() 得到的 dma_addr_t 是 IOVA;
GPU 驱动拿到的 GPU VA 由 KGSL 分配,和 CPU VA 无关;
真正的 PA 只有 QNX Hypervisor 知道,Linux 无法直接访问。


9. 容易混淆的几个点

(1) MMU 不只是“地址翻译”:它还做权限检查、内存属性控制、缺页支持;IOMMU 还做 DMA 隔离。
(2) TLB 不是 MMU:TLB 只是页表项的缓存,MMU 才是翻译单元。
(3) IOMMU 的方向是 IOVA → PA,不是 PA → IOVA;IOVA 是驱动/设备使用的地址。
(4) GPU VA ≠ CPU VA:两者是独立地址空间,通过页表映射到同一 PA 才能共享数据。
(5) stage 2 不是独立 MMU:它是 CPU/SMMU 内部的第二级翻译,根页表由 Hypervisor 管理。
(6) mmu_notifier、mmu_gather 不是硬件 MMU:
a. mmu_notifier 是 Linux 在 CPU 页表变化时通知 GPU/KVM/RDMA 等 secondary MMU 失效映射的机制;
b. mmu_gather 是批量 TLB flush 的优化机制;
c. KVM MMU 是管理 guest stage-2 页表的软件模块。


10. 一句话总结

ARM Linux 上主要是 CPU MMU(VA→PA/IPA)、IOMMU/SMMU(IOVA→PA/IPA)、GPU MMU(GPU VA→PA/IPA) 三类;在 8295 的 QNX+Linux 虚拟化架构里,它们的第一级输出都是 IPA,再由 Hypervisor 的 stage 2 统一翻译成真正的 PA。

 

posted on 2026-10-24 21:40  Hello-World3  阅读(12)  评论(0)    收藏  举报

导航