2. Linux 内存管理基础:虚拟地址、物理地址、页表、MMU 工作原理
在深入 mmap 与寄存器直接访问之前,必须理解 Linux 内存管理的核心抽象:虚拟地址(Virtual Address, VA)与物理地址(Physical Address, PA)的映射关系。用户态程序无法直接操作物理地址,所有内存访问都经过 MMU(Memory Management Unit)和页表(Page Table)的转换。本章将拆解这一过程,为后续的 mmap 实现用户态直接寄存器访问打下理论基础。
2.1 虚拟地址空间与物理地址空间
每个用户态进程拥有独立的 虚拟地址空间,在 32 位系统上通常为 4 GiB(0x00000000 ~ 0xFFFFFFFF),在 64 位系统上则更大。物理地址空间是系统实际可用的 RAM 与 MMIO(Memory-Mapped I/O)区域的集合。
| 概念 | 描述 | 典型范围(32位) |
|---|---|---|
| 虚拟地址 (VA) | CPU 发出的地址,由 MMU 转换 | 0x00000000 ~ 0xFFFFFFFF |
| 物理地址 (PA) | 实际访问内存/外设寄存器的地址 | 0x00000000 ~ 物理 RAM 上限 |
| 用户空间 | 进程可访问的虚拟地址范围 | 0x00000000 ~ 0xBFFFFFFF (3 GiB) |
| 内核空间 | 内核与驱动使用的虚拟地址范围 | 0xC0000000 ~ 0xFFFFFFFF (1 GiB) |
关键点: 外设寄存器通常映射在物理地址的高端区域(如 0xF0000000 以上),用户态程序无法直接访问。通过
mmap 可以将这些物理地址映射到用户空间的虚拟地址上,从而绕过内核态的限制。
2.2 MMU 与地址转换流程
MMU 是 CPU 内部的一个硬件单元,负责将虚拟地址转换为物理地址。转换过程依赖页表,页表由操作系统维护,存放在内存中。MMU 通过页表基址寄存器(如 x86 的 CR3)找到当前进程的页表。
地址转换三步走:
- 分段:虚拟地址被拆分为页号(Page Number)和页内偏移(Offset)。
- 查表:MMU 以页号为索引,遍历多级页表,找到对应的物理页框号(Page Frame Number, PFN)。
- 拼接:物理地址 = 物理页框号 + 页内偏移。
2.3 页表结构与多级映射
现代操作系统使用多级页表(如 x86_64 的 4 级页表),以节省内存。页表项(PTE)不仅包含物理页框号,还包含权限位(读/写/执行)、存在位、脏位等控制信息。
| 页表级别 | 名称(x86_64) | 覆盖范围 | 典型大小 |
|---|---|---|---|
| L1 | PML4 (Page Map Level 4) | 512 GiB | 512 项 × 8 字节 = 4 KiB |
| L2 | PDPT (Page Directory Pointer Table) | 1 GiB | 512 项 × 8 字节 = 4 KiB |
| L3 | PD (Page Directory) | 2 MiB | 512 项 × 8 字节 = 4 KiB |
| L4 | PT (Page Table) | 4 KiB | 512 项 × 8 字节 = 4 KiB |
注意: 页表由内核管理,用户态程序无法直接修改。但通过
mmap 系统调用,内核会在当前进程的页表中插入新的映射条目,从而允许用户态访问特定的物理内存或寄存器。
2.4 TLB 与缓存一致性
每次地址转换都查询多级页表会带来巨大的性能开销。MMU 内部集成了 TLB(Translation Lookaside Buffer),即页表缓存,用于缓存最近使用的 VA→PA 映射。当进程切换或页表更新时,TLB 需要被刷新(Flush)。
TLB 刷新场景:
- 进程上下文切换:切换到不同进程时,TLB 中的旧映射失效。
- mmap / munmap:建立或解除内存映射后,需要刷新相关 TLB 条目。
- 修改页表权限:如通过
mprotect改变内存保护属性。
2.5 用户态直接寄存器访问的桥梁:mmap
理解了虚拟地址与物理地址的映射机制后,mmap 的角色就清晰了:
- 用户态调用:
mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset)。 - 内核处理:驱动中的
mmap操作函数将物理地址(寄存器基址)映射到用户空间的虚拟地址。 - 页表插入:内核在当前进程的页表中添加新的 PTE,将用户虚拟页指向物理寄存器页。
- 用户态直接访问:应用程序通过返回的虚拟地址指针直接读写寄存器,无需系统调用。
重要限制: 映射粒度受限于页面大小(通常为 4 KiB)。即使只需要访问一个 32 位寄存器,也必须映射整个物理页。此外,映射区域必须按页对齐。
2.6 本章小结
- 虚拟地址是进程看到的地址空间,物理地址是硬件实际使用的地址。
- MMU 负责将虚拟地址转换为物理地址,转换依据是页表。
- 页表采用多级结构(如 x86_64 的四级页表),以平衡内存占用与查询效率。
- TLB 缓存最近使用的地址映射,减少页表查询开销。
mmap的本质是在进程页表中插入新的映射条目,使用户态虚拟地址直接指向物理寄存器地址。