1. MMU概述:为什么需要MMU?

各位同学,咱们今天聊聊MMU。说实话,我刚入行那会儿,觉得MMU就是个可有可无的东西——不就是把地址转来转去嘛,多此一举。直到有一次,我在一个嵌入式项目里,两个任务同时访问了同一块物理内存,结果数据乱得一塌糊涂。从那以后,我才真正理解了MMU的价值。

1.1 为什么需要MMU?

你想想看,如果没有MMU,程序直接操作物理地址,会是什么场景?

  • 多个程序打架:两个程序同时写0x1000这个地址,谁先写谁后写?数据全乱套。
  • 内存不够用:一个程序需要2GB内存,但物理内存只有1GB,怎么办?
  • 权限形同虚设:任何程序都能读写任何地址,恶意代码轻松搞破坏。

MMU就是来解决这些问题的。它给每个程序一个「假想世界」——虚拟地址空间。每个程序都觉得自己独占整个内存,互不干扰。

核心思想:MMU让每个进程拥有独立的虚拟地址空间,通过地址翻译实现隔离和保护。

1.2 虚拟地址与物理地址的概念

这两个概念,我习惯用一个比喻来解释。

物理地址:就是内存芯片上真实的地址线。比如你的板子有512MB DDR3,物理地址范围就是0x00000000到0x1FFFFFFF。这是硬件决定的,改不了。

虚拟地址:是CPU发出的地址。程序里写的指针、变量地址,全是虚拟地址。每个进程都有自己的虚拟地址空间,比如32位系统是0到4GB。

MMU干的事,就是把虚拟地址翻译成物理地址。这个过程叫「地址翻译」或「地址转换」。

我个人经验:调试时经常遇到「段错误」,十有八九是虚拟地址没映射好。记住一点——CPU永远看不到物理地址,它只认虚拟地址。

1.3 MMU的核心功能

MMU不是只会做地址翻译,它还有三个看家本领。

1.3.1 地址翻译

这是MMU最基础的功能。CPU发出虚拟地址,MMU查页表,找到对应的物理地址。

举个例子,ARMv8-A架构下,页表查找过程是这样的:

// 虚拟地址拆分(以4KB页、4级页表为例)
// 假设虚拟地址:0x7F8A_3B2C

// 第0级索引:VA[47:39]  -> 9位
// 第1级索引:VA[38:30]  -> 9位  
// 第2级索引:VA[29:21]  -> 9位
// 第3级索引:VA[20:12]  -> 9位
// 页内偏移:  VA[11:0]   -> 12位

// 翻译过程:
// 1. 从TTBR0_EL1寄存器拿到页表基地址
// 2. 用第0级索引找到下一级页表的地址
// 3. 逐级查找,直到第3级页表
// 4. 第3级页表项里存的就是物理页帧号
// 5. 物理地址 = 物理页帧号 + 页内偏移

嗯,这里要注意,每次地址翻译都要查4次页表,性能开销不小。所以MMU里有个TLB(快表),缓存最近用过的翻译结果。

避坑指南:我曾经在一个项目里,频繁切换进程导致TLB不断刷新,性能直接掉了30%。后来用了ASID(地址空间标识符)才解决。记住,TLB miss是性能杀手。

1.3.2 权限控制

MMU不光管地址翻译,还管「谁可以访问、怎么访问」。

每个页表项里都有一堆权限位:

权限位 含义 我常用的场景
AP[2:1] 访问权限(读/写/执行) 代码段设为只读+可执行,数据段设为读写
XN 禁止执行 栈和堆绝对不能执行代码,防溢出攻击
PXN 特权模式禁止执行 用户态代码不能执行内核地址
AF 访问标志位 用于页面置换算法,判断页面是否被访问过

说白了,权限控制就是给内存上了三把锁——读锁、写锁、执行锁。哪个程序能开哪把锁,MMU说了算。

实际案例:我在做安全启动时,把关键配置寄存器映射到虚拟地址后,直接设成「特权模式只读」。就算用户态程序拿到物理地址,也改不了配置。这就是MMU权限控制的威力。

1.3.3 缓存管理

MMU还管缓存?没错。它决定了哪些内存区域可以被缓存,以及怎么缓存。

页表项里有几个关键属性:

  • Shareability:是否被多个核共享。共享内存要设成「共享」,否则缓存一致性会出问题。
  • Cacheability:是否允许缓存。外设寄存器通常要设成「非缓存」,否则读到的是旧数据。
  • 内存类型:Normal(普通内存)还是Device(设备内存)。设备内存必须严格按顺序访问。

你想想看,如果DMA和外设共享一块内存,MMU却把这块内存缓存了,DMA写完后CPU读到的还是缓存里的旧数据。这就是经典的缓存一致性问题。

我的习惯:做驱动开发时,外设寄存器一律映射为「非缓存、非推测、严格顺序」。虽然性能差点,但不会出诡异bug。等调通了再考虑优化。

1.4 小结

MMU说白了就三件事:

  1. 地址翻译:虚拟地址→物理地址,让每个进程觉得独占内存
  2. 权限控制:读/写/执行权限,保护系统不被恶意破坏
  3. 缓存管理:控制缓存策略,保证数据一致性

没有MMU,现代操作系统根本跑不起来。Linux的进程隔离、内存保护、虚拟内存,全建立在MMU之上。下一章咱们深入ARM的MMU实现,看看它和RISC-V到底有什么不同。

一句话总结:MMU是现代操作系统的基石,理解它,你就理解了整个内存管理体系的灵魂。