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 不是独立芯片,它集成在处理器内部。具体位置嘛,我画个图你就明白了。
从图上你能看到,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 就是个地址翻译官,没有它,现代操作系统根本跑不起来。