【DeepSeek】ARM MMU 控制器有几套?
这是一个非常好的问题,触及了ARM架构(特别是ARMv8-A/ARMv9-A)最核心的内存管理机制。
简单直接的回答是:物理上通常只有一个MMU硬件,但逻辑上每个异常级别都有自己的“一套”控制寄存器。
你提到的“用户层MMU”和“内核层MMU”的区分,实际上是通过寄存器配置和地址空间划分来实现的,而不是真的有多个独立的物理MMU部件。
下面我为你详细拆解这个机制:
1. 到底有几套 MMU?
在ARMv8架构中,有4个异常级别:EL0(用户)、EL1(内核)、EL2(Hypervisor)、EL3(Secure Monitor)。
物理层面:
一个CPU核心通常只有一个物理MMU转换部件。它负责将虚拟地址(VA)转换为物理地址(PA)。
逻辑/寄存器层面:
为了支持不同特权级别的隔离,ARM为每个异常级别都配备了一组独立的系统控制寄存器。你可以理解为有“四套配置面板”,但只有一个“执行引擎”。
这几套配置寄存器如下:
| 异常级别 | 角色 | 对应的MMU控制寄存器 | 说明 |
|---|---|---|---|
| EL3 | Secure Monitor | TTBR0_EL3, TCR_EL3 |
最高特权,管理安全世界的内存映射。 |
| EL2 | Hypervisor | TTBR0_EL2, TCR_EL2 |
管理虚拟化扩展,控制客户机的内存。 |
| EL1 | OS Kernel | TTBR0_EL1, TTBR1_EL1, TCR_EL1 |
最关键的一套,内核和用户空间都在这里管理。 |
| EL0 | Application | 无独立寄存器 | 用户层没有配置寄存器,它“借用”EL1的配置进行转换。 |
2. 怎么区分用户层和内核层的 MMU?
你感到困惑的地方通常在于 EL1(内核)和 EL0(用户)的关系。既然EL0没有寄存器,它是怎么工作的?
核心机制:TTBR0 与 TTBR1 的“顶半部/底半部”划分
ARM在设计EL1时,引入了一个非常巧妙的机制:一个MMU硬件,两张页表基址寄存器。
- TTBR0_EL1 (Translation Table Base Register 0):通常用于用户空间。
- TTBR1_EL1 (Translation Table Base Register 1):通常用于内核空间。
硬件通过虚拟地址的最高位(具体位数由 TCR_EL1 寄存器配置决定)来自动选择使用哪张页表:
工作流程示意图:
假设我们配置地址空间划分为高位内核,低位用户:
-
当 CPU 运行在 EL0 (用户态) 时:
- 用户程序发出的虚拟地址通常是低位地址(例如
0x0000_7FFF_XXXX)。 - MMU 看到高位是 0,于是自动选择 TTBR0_EL1 指向的页表进行查表。
- 结果:进程只能访问自己的用户空间内存。
- 用户程序发出的虚拟地址通常是低位地址(例如
-
当 CPU 发生异常陷入 EL1 (内核态) 时:
- 内核代码通常运行在高半部地址(例如
0xFFFF_8000_XXXX)。 - MMU 看到高位是 1,于是自动选择 TTBR1_EL1 指向的页表进行查表。
- 结果:内核访问自己的全局映射。
- 内核代码通常运行在高半部地址(例如
-
内核访问用户数据时:
- 内核有时候需要拷贝用户数据。此时内核虽然处于 EL1,但它故意构造一个低位虚拟地址。
- MMU 看到高位是 0,依然会去查 TTBR0_EL1。
- 关键点:虽然内核在查用户页表,但因为它运行在 EL1,它有权限访问,而用户进程(EL0)如果试图访问高位地址(内核区域),MMU会直接报错。
3. 为什么这样设计?
这种设计解决了传统架构(如ARMv7或x86早期)的一个痛点:
- 无需频繁重载页表基址:
在旧架构中,进入内核需要切换 CR3(页表基址),这会导致 TLB(快表)被清空,性能损失巨大。
在ARMv8中,内核页表(TTBR1)永远驻留。从用户态陷入内核态时,不需要切换寄存器,只需要切换权限等级,TLB中关于内核的映射依然有效,大大加速了系统调用和中断处理的速度。
4. 总结:如何区分?
回到你的问题,区分方法如下:
-
不同异常级别(EL3/EL2/EL1)的区分:
靠物理切换。当CPU从EL1切换到EL2时,硬件会自动使用TTBR0_EL2而不再是TTBR0_EL1。这是完全隔离的,每个级别都有自己独立的控制寄存器组。 -
同级别内 用户 vs 内核(EL0 vs EL1)的区分:
靠地址范围划分。- 高地址 -> 自动路由到
TTBR1_EL1(内核页表)。 - 低地址 -> 自动路由到
TTBR0_EL1(用户页表)。 - EL0 进程切换时,OS 只需要更新
TTBR0_EL1的值,而TTBR1_EL1保持不变。
- 高地址 -> 自动路由到
所以,EL3、EL2、EL1(内核部分) 各有一套独立的MMU配置,而 EL0(用户) 是依附在 EL1 的 TTBR0 机制下的。
这是一个非常核心的问题。在ARMv8架构中,MMU的控制寄存器组(SCTLR, TCR, TTBR, MAIR等)就像是一个复杂的“控制面板”,它们共同决定了CPU如何看到内存。
我们可以将这些控制功能分为五大类:总开关、地址映射规则、页表存放位置、内存属性定义、以及权限控制。
以下是详细的拆解:
1. 总开关与全局控制 (SCTLR_ELx)
SCTLR (System Control Register) 是最高层的控制寄存器,它决定了MMU是否工作。
- M 位:MMU使能位。
1:开启MMU,所有地址访问都经过翻译。0:关闭MMU,虚拟地址直接等于物理地址(平坦映射)。
- C 位:数据缓存使能。
- I 位:指令缓存使能。
- A 位:对齐检查。如果开启,非对齐的内存访问会触发异常。
2. 地址映射规则与范围 (TCR_ELx)
TCR (Translation Control Register) 是配置最复杂的寄存器,它定义了“如何翻译地址”。它决定了你之前问的“用户/内核空间划分”。
- T0SZ / T1SZ (Translation Size):
- 功能:控制地址空间的范围大小。
- 应用:这是区分用户和内核的关键。
T0SZ决定了TTBR0(用户空间)映射多大的地址范围(例如 48位地址空间)。T1SZ决定了TTBR1(内核空间)映射多大的地址范围。- 通过这两个值,硬件计算出分界线(例如高 16位是全1则用TTBR1,否则用TTBR0)。
- TG0 / TG1 (Translation Granule):
- 功能:设置页块大小。
- 应用:决定页表粒度是 4KB、16KB 还是 64KB。这对性能和内存碎片管理有直接影响。
- IPS / PS (Intermediate Physical Size):
- 功能:设置输出的物理地址位宽。
- 应用:告诉MMU你的物理内存有多大(例如36位、40位或48位),防止翻译出超出物理总线范围的地址。
- SH0 / SH1 (Shareability):
- 功能:设置页表遍历时的共享属性。
- 应用:决定页表本身是Inner Shareable还是Outer Shareable,影响多核CPU的缓存一致性。
3. 页表存放位置 (TTBRx_ELx)
TTBR (Translation Table Base Register) 是最直观的寄存器,它告诉MMU“字典”放在哪里。
- BADDR (Base Address):
- 功能:存放一级页表(L0 Table)的物理基地址。
- ASID (Address Space Identifier):
- 功能:进程上下文标识符。
- 应用:这是区分不同进程的关键。当CPU切换进程时,OS会修改这里的ASID。TLB(快表)在缓存翻译结果时,会打上ASID的标签。这样切换进程时不需要清空整个TLB,只需要匹配ASID即可,极大提升性能。
4. 内存属性定义 (MAIR_ELx)
MAIR (Memory Attribute Indirection Register) 是一个“属性调色板”。因为页表项(Descriptor)里的位宽有限,不能存下所有的属性细节,所以使用了索引机制。
- Attr[n] (8个字节属性组):
- 功能:定义具体的内存类型,例如:
- Normal Memory:普通内存,支持缓存。
- Device Memory:设备内存(如外设寄存器),不支持缓存,必须严格顺序访问。
- Cacheability:Write-Back (回写) 还是 Write-Through (直写)。
- 应用:页表项里只需存一个索引号(如
AttrIdx=0),MMU就会去查 MAIR 的第0段,得知这块内存是“带缓存的普通内存”。
- 功能:定义具体的内存类型,例如:
5. 权限控制 (在页表描述符中)
虽然具体的读写权限位主要存放在页表项中,但控制寄存器组定义了权限检查的基准规则:
- 页表项中的 AP (Access Permissions):
- 控制读/写权限。
- 控制特权级访问权限(EL0可访问,还是仅EL1可访问)。这就是区分“用户空间”和“内核空间”数据的根本屏障。
- PXN (Privileged Execute Never) / XN (Execute Never):
- 功能:执行权限控制。
- 应用:防止内核执行用户空间代码(防止ret2usr攻击),或者防止执行数据区代码(防止栈溢出攻击)。
总结:一个完整的控制流程
当CPU发起一次地址访问时,MMU控制寄存器组协同工作的流程如下:
- SCTLR 说:“MMU是开的,开始干活。”
- TCR 看了一下虚拟地址的高位:“这个地址高位是1,属于内核空间,去查 TTBR1;那个地址高位是0,属于用户空间,去查 TTBR0。”
- TTBR 给出页表基址:“页表在物理内存的
0x8000_0000处。” - MMU 开始遍历页表,遇到页表项里的属性索引。
- MAIR 说:“索引0对应的是‘普通内存、可缓存’,那就把数据放入Cache吧。”
- 页表项里的 AP位 检查:“当前是EL0(用户态),想写这块内存?不行!权限不够,触发异常!”
通过这套寄存器组,ARM实现了极其灵活且安全的内存管理。
更多推荐


所有评论(0)