x86_64 Linux内核MMU分页机制与CR3切换详解 - 第1节

1.1 MMU 在 x86_64 体系结构中的角色

内存管理单元(Memory Management Unit, MMU)是 x86_64 处理器中负责将虚拟地址转换为物理地址的硬件模块。它位于 CPU 核心与内存总线之间,是操作系统实现进程隔离、虚拟内存、按需分页等核心功能的基础。

核心角色:MMU 使得每个进程可以拥有独立的、连续的虚拟地址空间(0x0000000000000000 ~ 0x00007FFFFFFFFFFF 用户空间 + 0xFFFF800000000000 ~ 0xFFFFFFFFFFFFFFFF 内核空间),而实际物理内存可以是离散的、甚至被换出到磁盘。

MMU 在指令执行路径中的位置

当 CPU 执行一条访问内存的指令(如 mov rax, [rbx])时,地址转换流程如下:

  1. CPU 核心发出虚拟地址(VA)
  2. MMU 接收 VA,查询页表(Page Table)进行地址转换
  3. TLB(Translation Lookaside Buffer)作为页表的硬件缓存,加速转换
  4. MMU 输出物理地址(PA)到内存控制器
  5. 内存控制器访问物理内存
MMU 在指令执行路径中的位置 CPU 核心 MMU TLB 缓存 内存控制器 物理内存 虚拟地址 物理地址 数据
关键理解:MMU 的转换对软件(包括操作系统内核)是透明的。内核只需维护正确的页表结构,MMU 硬件自动完成每次地址查找。CR3 寄存器指向当前进程的顶级页表基址。

1.2 虚拟地址到物理地址的映射原理

x86_64 使用 4 级分页(在某些新处理器上支持 5 级分页)将 48 位虚拟地址转换为物理地址。映射的基本单位是页(Page),通常大小为 4KB。虚拟地址空间被划分为固定大小的页,物理内存也被划分为相同大小的页框(Page Frame)。

地址转换的核心公式

组件 说明 位数(4KB 页)
虚拟地址 程序使用的地址 48 位(有效)
页内偏移 页内的字节位置 12 位(0-4095)
虚拟页号(VPN) 虚拟地址的高 36 位,用于索引页表 36 位
物理页框号(PFN) 物理内存中页框的编号 取决于物理内存大小
物理地址 实际访问内存的地址 = PFN + 偏移 最多 52 位
虚拟地址到物理地址的映射原理 虚拟地址(48 位) 虚拟页号 VPN(36 位) 偏移(12 位) 页表(Page Table)→ 查询 VPN 对应的 PFN 物理页框号 PFN(由页表给出) 偏移(不变) 物理地址 = PFN × 4096 + 偏移
注意:虚拟地址的高 16 位(位 47 以上)必须是对位 47 的符号扩展。如果位 47 为 0,则高 16 位必须全为 0(用户空间);如果位 47 为 1,则高 16 位必须全为 1(内核空间)。否则 MMU 会触发一般保护异常(#GP)。

1.3 分页机制的基本概念

分页(Paging)是 x86_64 体系结构默认且唯一支持的内存管理方式(已移除分段机制的传统模式)。它将虚拟内存和物理内存都划分为固定大小的块,通过多级页表实现地址转换。

4 级分页结构

x86_64 使用 4 级页表层次结构,每一级都是一个页表(Page Table),包含若干页表项(Page Table Entry, PTE)。各级页表名称如下:

级别 名称 缩写 每项索引位数 每项大小
L4 Page Map Level 4 Table PML4 9 位 8 字节
L3 Page Directory Pointer Table PDPT 9 位 8 字节
L2 Page Directory Table PDT 9 位 8 字节
L1 Page Table PT 9 位 8 字节

虚拟地址的 48 位被划分为:9 位(PML4 索引) + 9 位(PDPT 索引) + 9 位(PDT 索引) + 9 位(PT 索引) + 12 位(页内偏移)。

x86_64 4 级分页结构 虚拟地址(48 位) PML4 (9位) PDPT (9位) PDT (9位) PT (9位) 偏移 (12位) CR3 → PML4 基址 PML4 表(512 项) PDPT 表(512 项) PDT 表(512 项) PT 表(512 项) 物理页(4KB)

页表项(PTE)结构

每个页表项为 8 字节(64 位),包含物理地址高位和标志位。关键标志位如下:

位域 名称 说明
位 0 P(Present) 页是否在物理内存中
位 1 R/W(Read/Write) 0=只读,1=读写
位 2 U/S(User/Supervisor) 0=内核态,1=用户态可访问
位 3 PWT(Page Write Through) 缓存写策略
位 4 PCD(Page Cache Disable) 禁止缓存
位 5 A(Accessed) 页是否被访问过(由硬件置位)
位 6 D(Dirty) 页是否被写入过(由硬件置位)
位 7 PS(Page Size) 仅在 PDPT/PDT 中有效,1=大页(2MB/1GB)
位 8 G(Global) 全局页,TLB 刷新时不被清除
位 12-51 物理地址高位 页框物理地址的高 40 位(4KB 页对齐)
位 52-62 软件可用位 操作系统可自定义使用
位 63 NX(No Execute) 1=禁止执行该页代码
Linux 内核视角:Linux 将页表项中的软件可用位(位 52-62)用于存储页状态标志,如 _PAGE_SOFT_DIRTY、_PAGE_SPECIAL 等。NX 位是实现 NX(No-Execute)保护的关键,防止代码在数据页上执行。

分页机制的关键特性

  • 进程隔离:每个进程拥有独立的页表层次结构,CR3 在进程切换时更新,确保进程间地址空间互不干扰。
  • 按需分页:页表项中的 Present 位为 0 时,访问该页会触发缺页异常(Page Fault),内核可据此从磁盘加载数据。
  • 大页支持:通过设置 PS 位,可以使用 2MB(在 PDT 级)或 1GB(在 PDPT 级)的大页,减少 TLB 压力。
  • 写时复制(COW):fork() 后父子进程共享只读页,写操作触发缺页异常,内核复制物理页。
  • TLB 刷新:修改页表后,必须刷新 TLB(通过 invlpg 指令或重新加载 CR3),否则 MMU 可能使用过时的缓存。
总结:MMU 是 x86_64 虚拟内存系统的硬件引擎,通过 4 级页表结构将 48 位虚拟地址转换为物理地址。分页机制提供了进程隔离、按需加载、大页优化等关键能力,是 Linux 内核内存管理的基石。CR3 寄存器作为页表层次结构的根指针,在进程上下文切换时被内核修改,从而实现地址空间的切换。