找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4564

积分

0

好友

594

主题
发表于 2 小时前 | 查看: 7| 回复: 0

CPU 访问内存时,地址从来不是直接“直通”的。中间隔着一层负责地址转换的硬件——MMU。而 SMMU 和 IOMMU 本质上解决的是同一类问题,只不过服务对象变成了外设。这三者与 cache 也深度绑定,不仅在配合使用时能提升读取性能,MMU 内部的 TLB 与 TWU 还会分别借助 cache 来缓存 VA-PA 映射关系以及不同级别的页表信息。

什么是 MMU

MMU 即内存管理单元(Memory Manage Unit)。无论是 MMU、SMMU 还是 IOMMU,最基本的功能都是将虚拟地址转换成物理地址。除此之外,MMU 还承担内存保护功能,进程无法直接访问物理内存,防止数据被随意篡改。MMU 内部主要由两个模块组成:

  • TLB 模块:缓存从虚拟地址到物理地址的转换结果
  • TWU 模块:负责页表的查表过程

ARM内核通过MMU进行地址转换与cache访问流程

术语定义

页表:

页表主要完成三件事:

  1. 将虚拟地址转换为物理地址
  2. 管理 CPU 对物理页的访问,检查是否具备读、写、可执行权限
  3. 隔离地址空间,使各进程互不影响

PTE 是描述虚拟内存与物理内存映射关系的数据结构,是页表中的一个条目,每个虚拟内存页对应一个 PTE。CPU 可以根据虚拟地址获取物理内存地址,同时检查访问权限。

PTE 通常包含以下信息:

  1. 物理页地址:虚拟内存所映射的物理内存页的地址
  2. 访问权限:指示当前页面是否可读、可写、可执行
  3. 脏位:标记页面是否被修改过,用于支持页面置换
  4. 共享位:指示页面能否被共享
  5. 缓存位:控制页面的缓存策略,例如是否可以缓存到 cache

页、页帧、页表与 PTE

MMU 负责将虚拟地址映射为物理地址。凡是“映射”,都要解决两个问题:映射的最小单位(粒度)和映射的规则。

  1. VA 到 PA 映射的最小单位称为页(Page),页大小通常是 4K。一次最少要把 4K 大小的 VA 页整体映射到 4K 的 PA 页,页内偏移不变。例如 VA 的一页 0x30004000~0x30004fff 映射到 PA 的一页 0x00008000~0x00008fff,当 CPU 访问 0x30004008 时,实际访问的物理地址是 0x00008008。不能把某个 VA 页拆成小块映射到不同 PA,必须页对页整体映射。

  2. 页帧(Page Frame)指物理内存中的一页内存,MMU 的虚实映射本质就是寻找物理页帧的过程。

  3. MMU 软件配置的核心是页表(Page Table),它描述映射规则:哪些虚拟页映射到哪些物理页帧。

  4. 页表由一条条映射规则记录组成,每条称为页表条目(PTE)。整个页表保存在片外内存,MMU 通过查找页表确定 VA 应该映射到什么 PA,以及是否有权限映射。

  5. 如果 MMU 每次地址转换都去外部内存查页表,转换速度会大打折扣。于是出现了 TLB(Translation Lookaside Buffers),即转换快表。它可以理解为 MMU 内部专用的页表 cache,保存最近使用的 PTE。MMU 收到虚拟地址后,先在 TLB 中查找,找到就直接转换;找不到再去页表查找并置换进 TLB。TLB 属于片上 SRAM,访问速度快,能显著加速虚实地址转换。

这段内容也正好呼应了计算机基础中关于地址翻译、高速缓存与操作系统协作的经典设计思路。

MMU 的内存保护功能

既然所有发往内存的地址信号都要经过 MMU,那让它只做地址转换确实浪费了这个转换层。它完全有能力对虚拟地址访问做更多限制,就像路由器转发网络包的同时还能过滤非法访问。具体做法是在 PTE 中预留几个比特位,设置访问权限属性,比如禁止访问、可读、可写、可执行等。CPU 访问某个 VA 时,MMU 找到对应 PTE,把指令的权限需求与 PTE 的限定条件比对,符合要求就转换,否则拒绝访问并产生异常。

多级页表

以 64 位虚拟地址为例,CR3 是 CPU 的一个寄存器,用来存放顶级页目录项。MMU 开启后,首先读取 CR3 的内容,再逐级向下查表。

64位虚拟地址多级页表结构与地址映射流程

操作系统和 MMU

MMU 本质上是为满足操作系统日益复杂的内存管理需求而产生的。OS 和 MMU 的关系可以简单概括为:

  1. 系统初始化代码在内存中生成页表,然后把页表地址写入 MMU 对应寄存器,让 MMU 知道页表在物理内存中的位置。随后通过专用指令启动 MMU。以此分界,之后程序中所有内存地址都变成虚地址,MMU 硬件开始自动完成查表和地址转换。

  2. OS 初始化后期创建第一个用户进程,这个过程同样需要创建页表,并把地址赋给进程结构体中的指针成员变量。也就是说,每个进程都有独立的页表。

MMU 映射失败的几种情况

  1. 访问了受内核保护的页面,或者访问了只读页面(比如 C 语言中存储字符串字面量和 const 变量的段),此时内核会抛出段错误。
  2. 页面和页框没有映射关系,但数据页已被其他进程加载到内存中,只需建立映射关系即可,这称为次级缺页中断。
  3. 页面和页框没有映射关系,数据页也没有加载到内存中(还在磁盘上),此时需要磁盘 IO 加载页面到内存并建立映射关系,称为严重缺页中断。

后两种情况内核会以降低自身运行速度来修复:通过中断形成页表映射,再重新执行引起中断的指令。

System MMU在DMA流量中的架构示意

PCIe设备、SMMU与CPU MMU到物理地址的数据流向

SoC中IOMMU集成示例架构

MMU 是在处理器中使用的,一个 MMU 仅支持一个 CPU,用于将多进程的虚拟地址映射到同一个物理内存,同时完成对物理地址访问的权限检查。

CPU通过MMU完成虚拟地址到物理地址的转换

MMU 与 cache 的顺序关系:物理 cache 与虚拟 cache

CPU高速缓存命中与TLB、MMU参与地址转换的流程

Cache 和 MMU 基本都是一起使用的,会同时开启或关闭。因为 MMU 页表中的 entry 属性控制着内存权限和 cache 缓存策略。

CPU 访问 DDR 时使用的是虚拟地址(VA),经 MMU 映射成物理地址(PA),再用物理地址查询高速缓存,这种称为物理高速缓存。物理高速缓存的缺点是 CPU 必须先查 TLB 或 MMU 才能访问 cache,增加了流水线延迟。

高速缓存未命中时CPU查询TLB和MMU获取PA的流程

CPU 使用虚拟地址直接寻址高速缓存,这种称为虚拟高速缓存。寻址时先把虚拟地址发给高速缓存,若命中就不再访问 TLB 和 DDR。

cache 缓存寻址方式:VIVT、VIPT、PIPT

用虚拟地址或物理地址作为 Index 和 Tag 对缓存行进行寻址,引申出了不同的缓存设计。

  • VIVT 速度最快,因为寻址时不经过 MMU/TLB,但对操作系统要求高,需要避免 Tag/Index 的歧义问题。

VIVT虚拟高速缓存地址分解与查找流程

VIVT-虚拟高速缓存 VIVT(Virtually-Indexed Virtually Tagged)

VIPT物理标记的虚拟高速缓存查找流程

VIPT-物理标记的虚拟高速缓存 VIPT(Virtually-Indexed Physically-Tagged)

PIPT物理高速缓存地址转换与缓存查找

PIPT-物理高速缓存 PIPT(Physically-Indexed,Physically-Tagged)

SMMU

SMMU 用于子系统之间,可以支持多个外设。为了区分这些外设,SMMU 使用 StreamID 来标识。同一个 SMMU 内的 StreamID 必须唯一,不同 SMMU 之间互不影响。

SMMU 能将离散的物理地址映射到连续的虚拟地址空间,避免内存分配中的碎片化问题,也用于解决越界和地址踩踏问题。

Device通过SMMU与PE的MMU协同完成DMA地址转换

SMMUv3.0 特性

SMMUv3 通过支持大量并发转换上下文,为 PCI Express 根复合体等大型 I/O 系统提供补充功能。

  1. 基于内存的配置结构,支持大量流。
  2. 实现可以只支持阶段 1、只支持阶段 2,或同时支持两个阶段的转换,这些能力可从寄存器接口中发现。
  3. 高达 16 位的 ASIDs。
  4. 高达 16 位的 VMIDs。
  5. 根据 Armv8.1 虚拟内存系统架构进行地址转换和保护。SMMU 转换表可与 PE 共享,允许软件选择共享现有表或创建 SMMU 私有表。
  6. 49 位的 VA,与 Armv8-A 的 2×48 位转换表输入大小匹配。

以下支持是可选的:

  1. 阶段 1 或阶段 2 中的任何一个。
  2. 对 AArch32(LPAE)和 AArch64 转换表格式的阶段 1 和 2 支持。
  3. 安全流支持。
  4. 广播 TLB 无效。
  5. 页面的访问标志和脏状态的硬件转换表更新(HTTU)。
  6. 与兼容根复合体一起使用时的 PCIe ATS 和 PRI。
  7. 16KB 和 64KB 页面粒度。建议在阶段 1 和阶段 2 都提供 64KB 页面粒度,以与服务器基础系统架构中的 PE 要求保持一致。

由于使用内存中的配置来支持大量流,SMMUv3 的编程接口与 SMMUv2 有显著不同,并非设计为向后兼容。

为什么需要 SMMU

要理解 SMMU 出现的背景,需要先了解两个概念:DMA 和虚拟化。

1. DMA

DMA(Direct Memory Access,直接内存存取)是一种外设不经过 CPU 而直接与系统内存交换数据的技术。外设可以通过 DMA 将数据批量传输到内存,然后发送中断通知 CPU 取数据。由于 DMA 不能像 CPU 一样通过 MMU 操作虚拟地址,所以 DMA 需要连续的物理地址。

关于 DMA、地址空间隔离以及内存保护机制背后的设计逻辑,在内存管理与体系结构相关资料中有更系统的展开。

2. 虚拟化

虚拟化场景中,所有 VM 都运行在中间层 hypervisor 上,每个 VM 独立运行自己的 guest OS,Hypervisor 完成硬件资源的共享、隔离和切换。

  • VA:虚拟地址(virtual addresses)
  • IPA:中间物理地址(intermediate physical address)
  • PA:物理地址(physical addresses)

虚拟化环境中VA、IPA、PA三层地址映射关系

地址转换

SMMU 和 MMU 一样,支持两级转换:Stage 1 Translation 和 Stage 2 Translation,例如 VA -> IPA -> PA。实际使用中可以 bypass、stage 1 only、stage 2 only,或者 Stage 1 + Stage 2。

SMMU分区与不同Stage转换流程

两阶段页表映射:虚拟地址空间经Stage 1和Stage 2到物理地址空间

内存保护

除了地址转换,内存属性也是(S)MMU 的重要组成部分。例如可以在页表内配置读写权限、执行权限、访问权限等。

内存区域权限由 AP、APX 和 Domain(域)共同控制:AP/APX 字段的不同组合形成不同访问权限。Privileged 指 CPU 处于 svc 等状态,Unprivileged 则是 user 状态。

Block Descriptor位域结构中的权限属性字段

隔离

SMMU 可以同时供多个 Master 使用。SMMUv2 支持 128 个 contexts,SMMUv3 支持更多,因为 v2 中 context 信息保存在寄存器里,v3 则存储在内存中,通过 32 位的 StreamID 查询。CPU 可以和其他 Master 使用同一套页表,也可以为 SMMU 单独建立页表,甚至为每个 Master 建立一套或多套页表,以控制不同访问区域。

多SMMU类型与设备通过I/O互联接入内存的架构

IOMMU

IOMMU 通常实现在北桥中。现在北桥基本被集成进 SoC,所以 IOMMU 通常也放在 SoC 内部,用于提供设备端的地址翻译能力。它让具有 DMA 能力的设备可以使用虚拟地址,经 IOMMU 翻译成能直接访问内存的物理地址。

设备端的地址翻译(DMA 重定向)只是 IOMMU 的功能之一,另一个重要功能是中断重映射。

RISC-V IOMMU 规范支持的功能

  1. 基于内存的设备上下文,使用硬件提供的唯一 device_id 定位,支持的 device_id 宽度可达 24 位。
  2. 基于内存的进程上下文,使用 hardware-provided 的唯一 process_id 定位,支持最多 20 位。
  3. 16 位 GSCID(Guest 软件上下文标识符)和 20 位 PSCID(进程软件上下文标识符)。
  4. 两阶段地址转换。
  5. RISC-V 特权规范规定的基于页的虚拟内存系统,允许软件灵活地为 CPU MMU 和 IOMMU 使用通用页表,或为 IOMMU 使用单独的页表。
  6. 最多 57 位虚拟地址宽度、56 位系统物理地址和 59 位 Guest 物理地址宽度。
  7. 硬件更新 PTE Accessed 和 Dirty 位。
  8. 使用 RISC-V 高级中断架构指定的 MSI 页表,识别虚拟中断文件的内存访问和 MSI 地址转换。
  9. Svnapot 和 Svpbmt 扩展。
  10. PCIe ATS 和 PRI 服务。支持根据转换请求将 IOVA 转换为 GPA,而不是 SPA。
  11. 硬件性能监控器(HPM)。
  12. MSI 和有线信号中断请求软件提供服务。
  13. 用于软件请求地址转换的寄存器接口,以支持调试。

IOMMU 支持的功能可通过 capabilities 寄存器发现。


原文链接:https://zhuanlan.zhihu.com/p/2026034950638515504?share_code=rx5CeecoKfLo&utm_psn=2038365090420938034;版权归原作者所有,如有侵权,请联系作者删除。




上一篇:嵌入式老兵的离职判断标准:身边有没有让你想追的人
下一篇:Linux内核35周年:代码从1万行飙至4000万行,增幅达4000倍
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-8-28 06:59 , Processed in 0.796659 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表