2. Linux 内存管理基础:虚拟地址空间、物理内存、页表与 MMU 工作原理
在深入 Android HAL 层 mmap 实战之前,必须透彻理解 Linux 内存管理的核心基石。HAL 层驱动通过 mmap 实现用户空间与内核空间的数据零拷贝传输,其本质就是操作虚拟地址与物理地址的映射关系。本章将系统梳理虚拟地址空间、物理内存、页表及 MMU 的工作原理,为后续 mmap 机制剖析打下坚实的理论基础。
2.1 虚拟地址空间:进程的“内存幻象”
每个用户态进程都拥有独立的 32 位或 64 位虚拟地址空间。在 32 位 ARM Linux 中,虚拟地址空间通常按 3:1 比例划分:用户空间 0x00000000 – 0xBFFFFFFF(3GB),内核空间 0xC0000000 – 0xFFFFFFFF(1GB)。64 位架构下空间更大,但划分逻辑类似。
2.2 物理内存:真实的硬件资源
物理内存是 DRAM 芯片提供的真实存储介质,以字节为单位编址。在嵌入式 Android 设备中,物理内存通常从 0x80000000 或 0x40000000 开始映射。物理内存被划分为固定大小的页框(Page Frame),Linux 内核以页为单位管理物理内存,标准页大小为 4KB。
| 内存区域 | 物理地址范围(典型) | 用途 |
|---|---|---|
| DMA 区域 (ZONE_DMA) | 0x00000000 – 0x00FFFFFF | DMA 设备直接访问 |
| 普通区域 (ZONE_NORMAL) | 0x01000000 – 0x3FFFFFFF | 内核直接映射、用户进程 |
| 高端内存 (ZONE_HIGHMEM) | 0x40000000 以上 | 32 位系统访问 >1GB 物理内存 |
2.3 页表:虚实转换的“翻译官”
页表(Page Table)是操作系统维护的多级数据结构,用于将虚拟地址映射到物理地址。每个进程拥有独立的页表,存储在物理内存中,由 MMU 硬件解析。页表项(PTE)包含物理页框号、权限位、存在位、脏位等关键信息。
2.4 MMU:硬件加速的地址转换引擎
内存管理单元(Memory Management Unit)是 CPU 内部的硬件模块,负责自动完成虚拟地址到物理地址的转换。MMU 的工作流程如下:
- TLB 查找:CPU 发出虚拟地址,MMU 首先在 TLB(Translation Lookaside Buffer,快表)中查找缓存项。TLB 命中则直接获得物理地址,延迟仅 1-2 个时钟周期。
- 页表遍历:TLB 未命中时,MMU 硬件自动遍历多级页表,逐级读取 PGD、PUD、PMD、PTE 表项,最终找到物理页框号。
- 权限检查:MMU 同时检查 PTE 中的权限位(读/写/执行)和特权级,非法访问触发缺页异常或段错误。
- 物理地址生成:将物理页框号与虚拟地址中的页内偏移拼接,形成完整的物理地址,发送给内存控制器。
2.5 缺页异常与物理内存分配
当进程访问的虚拟地址尚未建立有效页表映射时,MMU 无法完成转换,触发缺页异常(Page Fault)。Linux 内核缺页异常处理程序执行以下步骤:
| 异常类型 | 触发条件 | 内核处理动作 |
|---|---|---|
| 有效缺页 | VMA 存在但 PTE 无效 | 分配物理页框,建立映射,返回用户空间 |
| 写时复制缺页 | 共享页被写入 | 复制物理页,更新 PTE 为可写 |
| 无效缺页 | VMA 不存在或权限不符 | 发送 SIGSEGV 信号,进程终止 |
2.6 内核空间与用户空间的数据交互
在 Android HAL 层驱动中,mmap 的核心价值在于绕过内核空间的数据拷贝,让用户空间直接访问物理内存或 DMA 缓冲区。理解以下关键点:
- 内核直接映射区:在 32 位系统中,物理内存前 896MB 被线性映射到内核空间 0xC0000000 起始的虚拟地址,
phys_to_virt()和virt_to_phys()实现简单转换。 - ioremap:外设寄存器物理地址通过 ioremap 映射到内核虚拟地址空间,HAL 层驱动通过 mmap 将同一段物理地址映射到用户空间。
- DMA 缓冲区:使用
dma_alloc_coherent()分配物理连续且 cache 一致的内存,通过 mmap 导出给用户空间,实现零拷贝数据传输。
mmap 文件操作,调用 remap_pfn_range() 或 dma_mmap_coherent() 将物理页映射到用户虚拟地址空间。理解页表结构和 MMU 行为是正确实现这些接口的前提。