1. MMU 基础概念:虚拟地址与物理地址的桥梁

各位同学,咱们今天正式开讲 ARMv7 的 MMU。说实话,MMU 这玩意儿,我当年刚接触的时候也觉得挺玄乎的——不就是个地址转换吗?后来踩的坑多了,才明白它远不止这么简单。

1.1 什么是 MMU?

MMU,全称 Memory Management Unit,内存管理单元。说白了,它就是个硬件模块,负责把 CPU 发出的地址转换成实际物理内存的地址。

你想想看,CPU 执行指令时访问的地址,真的是直接往内存条上怼的吗?不是的。中间隔了一层 MMU,它帮你做映射。

核心定义:MMU 是一个硬件地址转换器,位于 CPU 核心和物理内存之间。

我在项目中遇到过不少刚入行的同事,觉得 MMU 就是个可有可无的东西。嗯,等他们遇到内存碎片、进程隔离、缓存一致性这些问题时,就知道 MMU 有多重要了。

1.2 为什么需要 MMU?

这个问题我问过很多学生。有人说是为了“省内存”,有人说是为了“跑 Linux”。都对,但不全。

我个人习惯把 MMU 的必要性归纳为三点:

  • 进程隔离——每个进程都有自己的虚拟地址空间,谁也碰不到谁。A 进程崩了,不会把 B 进程拖下水。
  • 内存保护——可以给不同的内存区域设置不同的访问权限。读、写、执行,想怎么控就怎么控。
  • 地址空间连续性——物理内存可能东一块西一块,但虚拟地址可以给你一个连续的“假象”。

我的经验:曾经有个项目,裸机跑得好好的,一上 Linux 就出问题。查到最后,是 MMU 的页表配置错了,导致某个外设的物理地址被映射成了不可缓存区域。这种坑,你光看书是学不到的。

1.3 虚拟地址与物理地址

这两个概念,我建议你从“地址空间”的角度去理解。

地址类型 谁在用 特点
虚拟地址 (VA) CPU 核心、软件 连续、独立、可映射
物理地址 (PA) 内存控制器、硬件 真实、离散、有限

举个例子。你写了个程序,malloc 了一块内存,地址是 0x10000。这个 0x10000 是虚拟地址。MMU 查页表,发现它对应物理地址 0x80000000。于是 CPU 真正访问的是 0x80000000 这个位置。

为什么会这样?因为物理内存可能只有 256MB,但虚拟地址空间是 4GB(32位)。你可以在虚拟空间里“画饼”,MMU 负责把饼分到真实的盘子里。

注意:虚拟地址和物理地址的转换不是一一对应的。多个虚拟地址可以映射到同一个物理地址(共享内存),一个虚拟地址也可以不映射到任何物理地址(段错误就是这么来的)。

1.4 MMU 在 ARMv7 架构中的位置

ARMv7 的 MMU 不是独立芯片,它集成在处理器内部。具体位置嘛,我画个图你就明白了。

ARMv7 处理器内部结构(MMU 位置) CPU Core ARMv7 处理器核心 MMU 内存管理单元 TLB (快表) Cache 总线接口单元 物理内存 (DDR/SRAM) 虚拟地址 物理地址 关键路径 1. CPU 发出虚拟地址 2. MMU 查 TLB / 页表 3. 得到物理地址 4. 通过总线访问内存

从图上你能看到,MMU 夹在 CPU Core 和总线接口之间。CPU 发出的虚拟地址先到 MMU,MMU 查页表(或者 TLB 快表),转换成物理地址,再通过总线去访问物理内存。

这里有个细节:TLB 是 MMU 内部的一个缓存,专门存最近用过的页表项。我刚开始做嵌入式的时候,不知道 TLB 的存在,总觉得 MMU 转换地址很慢。后来才明白,TLB 命中率高了,转换几乎不花时间。

避坑指南:我曾经在一个实时性要求很高的项目里,发现某些中断响应时间忽长忽短。查到最后,是 TLB miss 导致的。解决方案?提前做页表预取,或者锁住关键页面的 TLB 项。这种优化,不深入理解 MMU 结构是想不到的。

1.5 ARMv7 MMU 的关键特性

ARMv7 的 MMU 相比早期版本,有几个重要的改进:

  • 两级页表结构——支持一级页表(L1)和二级页表(L2),粒度更灵活
  • 域支持(Domain)——可以给不同的内存区域分配不同的访问权限域
  • ASID(地址空间标识符)——切换进程时不用刷整个 TLB,效率更高
  • XN(不可执行)位——防止代码在数据区执行,增强安全性

这些特性,咱们后面的章节会一个一个拆开讲。今天先把概念理清楚。

1.6 小结

这一章咱们聊了 MMU 是什么、为什么需要它、虚拟地址和物理地址的区别,以及 MMU 在 ARMv7 中的位置。说白了,MMU 就是个地址翻译官,没有它,现代操作系统根本跑不起来。