2. Linux 内存管理基础:虚拟地址空间、页表、物理内存与页框、TLB 缓存机制
在深入 mmap 与 DMA 协同工作模式之前,必须牢固掌握 Linux 内存管理的核心抽象层。驱动开发者面对的“地址”并非真实的物理位置,而是经过多层映射的虚拟地址。本章将拆解虚拟地址空间、页表、物理页框以及 TLB 缓存机制,为后续理解 mmap 的缺页中断与 DMA 的物理连续性要求奠定基础。
2.1 虚拟地址空间:进程的“内存幻觉”
每个用户态进程都拥有独立的 3GB 用户空间 (0x00000000 – 0xBFFFFFFF) 和共享的 1GB 内核空间 (0xC0000000 – 0xFFFFFFFF)(以 32 位系统为例)。这种隔离机制让每个进程误以为自己独占整个内存,从而简化内存分配与保护。
| 区域 | 地址范围 (32位) | 权限 | 驱动关注点 |
|---|---|---|---|
| 用户空间 (User Space) | 0x00000000 – 0xBFFFFFFF | 读/写/执行 (受限) | mmap 映射目标区域,缺页时填充物理页 |
| 内核空间 (Kernel Space) | 0xC0000000 – 0xFFFFFFFF | 读/写 (特权模式) | DMA 缓冲区分配、ioremap、kmalloc 区域 |
| 内核直接映射区 (ZONE_NORMAL) | 0xC0000000 – 0xC8000000 (典型) | 线性映射 | 物理地址 = 虚拟地址 – 0xC0000000 |
| vmalloc 区域 | VMALLOC_START – VMALLOC_END | 非连续映射 | 适用于大块但非连续的 DMA 缓冲区 |
驱动提示: 用户空间地址 不能 直接在内核态解引用。驱动必须通过
copy_from_user、get_user_pages 或 mmap 的 fault 处理来安全访问。这是 mmap 与 DMA 交互时最容易出错的地方。
2.2 页表:虚拟到物理的转换桥梁
页表是 CPU 内存管理单元 (MMU) 使用的多级查找结构。Linux 采用 四级页表 模型(PGD → P4D → PUD → PMD → PTE),以适应不同架构的位宽。每一级页表项指向下一级页表的物理地址,最后一级 PTE 指向实际的物理页框。
/* 四级页表查找路径(x86_64 简化示意) */
虚拟地址 = [ 全局页目录偏移 | 上层页目录偏移 | 中间页目录偏移 | 页表偏移 | 页内偏移 ]
PGD = mm->pgd + 全局偏移
P4D = *PGD + 上层偏移
PUD = *P4D + 中间偏移
PMD = *PUD + 页表偏移
PTE = *PMD + 页内偏移
物理页框 = PTE & PAGE_MASK
最终物理地址 = 物理页框 + 页内偏移
关键指标: 页表项 (PTE) 不仅包含物理页框号,还包含权限位 (R/W, Present, User/Supervisor)、脏位 (Dirty)、访问位 (Accessed) 以及缓存属性 (PAT, PCD, PWT)。DMA 一致性映射需要特别注意缓存属性位,避免硬件与 CPU 缓存不一致。
2.3 物理内存与页框 (Page Frame)
物理内存被划分为固定大小的 页框 (Page Frame),通常为 4KB。Linux 内核通过 struct page 结构体管理每一个物理页框。页框的状态(空闲、匿名页、文件缓存、DMA 缓冲区)决定了它能否被映射或用于 DMA 传输。
- ZONE_DMA (0 – 16MB):兼容 ISA 设备 DMA 限制,物理地址连续。
- ZONE_NORMAL (16MB – 896MB):内核直接线性映射区域,大多数驱动分配首选。
- ZONE_HIGHMEM (>896MB):32 位系统无法直接映射,需通过 kmap 临时映射。
- 页框回收 (Page Reclaim):当内存紧张时,内核会回收文件缓存页或交换匿名页。
DMA 陷阱: 默认的
kmalloc 分配的内存来自 ZONE_NORMAL,物理地址连续,适合小规模 DMA。但对于大块缓冲区(> 128KB),应使用 dma_alloc_coherent 或 __get_free_pages 确保物理连续性。mmap 映射的匿名页可能分布在任意 ZONE,DMA 引擎无法直接访问非连续物理页框。
2.4 TLB 缓存机制:加速地址转换
TLB (Translation Lookaside Buffer) 是 CPU 内部的高速缓存,用于缓存最近使用的虚拟地址到物理地址的映射关系。每次 CPU 访问内存时,MMU 优先查询 TLB,若命中则无需遍历多级页表,大幅降低地址转换延迟。
| TLB 特性 | 说明 | 驱动影响 |
|---|---|---|
| TLB 命中 (Hit) | 虚拟地址在 TLB 中找到对应物理页框 | 正常访问,无额外开销 |
| TLB 未命中 (Miss) | MMU 遍历页表,填充 TLB | 增加 10-100 个周期延迟 |
| TLB 冲刷 (Flush) | 进程切换或页表修改后使 TLB 失效 | mmap 建立映射后需 TLB 刷新 |
| 大页 (Huge Pages) | 使用 2MB/1GB 页表项,减少 TLB 压力 | DMA 大缓冲区建议使用大页映射 |
2.5 关键概念总结
- 虚拟地址空间 提供了进程隔离与简化编程模型,驱动必须通过内核 API 进行地址转换。
- 四级页表 是 MMU 实现虚拟到物理映射的核心数据结构,每次缺页或映射修改都会更新页表。
- 物理页框 是内存分配的最小单元,DMA 要求物理连续性,驱动需选择合适的分配 zone。
- TLB 缓存 加速地址转换,但进程切换或页表修改后需要冲刷 TLB,mmap 建立映射后需调用
flush_tlb_page或依赖内核自动处理。
mmap 与 DMA 协同的基石: mmap 的本质是在用户虚拟地址空间与物理页框之间建立页表映射;DMA 引擎直接访问物理页框。两者通过页表项中的物理地址和缓存属性位实现数据一致性。理解本章的内存管理基础,是后续掌握
dma_map_single、dma_sync_single_for_cpu 以及 mmap 缺页处理的关键前提。