2. Linux 内存管理基础:虚拟地址、物理地址、MMU、页表、页框、页大小

在编写 mmap 驱动之前,必须透彻理解 Linux 内存管理的核心概念。mmap 的本质是在用户空间虚拟地址与物理内存(或设备 I/O 内存)之间建立映射,而这一过程完全依赖于硬件 MMU 和内核页表机制。本节将逐一拆解这些基础构件。

2.1 虚拟地址与物理地址

现代操作系统普遍采用虚拟内存管理。每个用户态进程拥有独立的 32 位或 64 位虚拟地址空间,而物理内存则由所有进程共享。

概念说明典型范围(32位)
虚拟地址 (VA)进程看到的线性地址,由 CPU 生成0x00000000 – 0xFFFFFFFF
物理地址 (PA)实际硬件总线上的地址,对应 RAM 或 I/O 寄存器0x00000000 – 0xFFFFFFFF
用户空间进程可访问的虚拟地址范围0x00000000 – 0xBFFFFFFF (3G)
内核空间内核代码和数据驻留的虚拟地址范围0xC0000000 – 0xFFFFFFFF (1G)
关键认知: 用户程序永远不能直接操作物理地址。所有内存访问都经过虚拟地址 → MMU → 物理地址的转换。mmap 驱动的作用就是让内核帮助用户程序建立这种转换关系,从而安全地访问物理内存或设备寄存器。

2.2 MMU:内存管理单元

MMU(Memory Management Unit)是 CPU 内部负责地址转换的硬件模块。它接收 CPU 发出的虚拟地址,通过查询页表(Page Table)输出对应的物理地址。

MMU 地址转换流程 CPU MMU 物理内存 页表 (Page Table) 虚拟地址 物理地址 查询页表 MMU 将虚拟地址拆分为页号 + 页内偏移,通过页号索引页表得到物理页框号,再拼接偏移得到最终物理地址。
MMU 核心职责:
  1. 地址转换: 将虚拟地址映射到物理地址。
  2. 权限检查: 检查当前访问是否违反页表权限(读/写/执行)。
  3. 缓存控制: 控制页面的 Cache 策略(Write-Back / Write-Through / Uncached)。
  4. 异常触发: 缺页(Page Fault)时通知内核加载页面。

2.3 页表与页框

页表是 MMU 进行地址转换的依据,存储在物理内存中。每个进程拥有独立的页表,由内核维护。页表项(PTE)记录了虚拟页号到物理页框号的映射关系。

2.3.1 页框(Page Frame)

物理内存被划分为固定大小的块,称为页框(或物理页)。Linux 内核使用 struct page 结构体管理每一个物理页框。

2.3.2 页大小(Page Size)

Linux 默认页大小为 4KB(ARM64 和 x86_64 均支持)。部分架构支持大页(Huge Pages):2MB 或 1GB,用于减少 TLB 缺失。

页大小典型用途TLB 覆盖范围
4 KB通用进程内存、堆、栈小
2 MB大页映射、数据库、虚拟化中
1 GB超大内存映射、GPU 显存大

2.4 多级页表结构

为了节省页表占用的物理内存,现代 CPU 采用多级页表。以 x86_64 为例,使用 4 级页表:PML4 → PDPT → PD → PT。

x86_64 四级页表地址转换 虚拟地址 (64位) PML4 PDPT PD PT Offset PML4 表 PDPT 表 PD 表 PT 表 物理页 每级页表占用一个 4KB 物理页框,包含 512 个 8 字节的页表项。 MMU 硬件自动遍历这四级表,最终得到物理页框号,加上 Offset 得到完整物理地址。

2.5 内核中的页表操作接口

驱动开发中,虽然不直接操作页表硬件,但需要理解内核提供的页表查询和映射函数:

// 内核虚拟地址 → 物理页框号
unsigned long virt_to_phys(volatile void *address);

// 物理地址 → 内核虚拟地址(直接映射区)
void *phys_to_virt(unsigned long address);

// 建立页表映射(内核内部使用)
int remap_pfn_range(struct vm_area_struct *vma,
                    unsigned long addr,
                    unsigned long pfn,
                    unsigned long size,
                    pgprot_t prot);

// 获取页表项内容
pte_t *pte_offset_map(pmd_t *pmd, unsigned long address);
驱动开发注意: 用户空间无法直接调用上述函数。mmap 驱动通过实现 file_operations 中的 .mmap 回调,在回调内调用 remap_pfn_range 来建立用户虚拟地址到物理页框的映射。这是整个课程的核心技术点。

2.6 物理内存与 I/O 内存

在嵌入式系统中,物理地址空间不仅包含 DDR RAM,还包含外设寄存器的 I/O 内存区域。mmap 驱动经常需要将这两类物理地址映射到用户空间:

类型物理地址范围示例映射方式
DDR 内存0x80000000 – 0x8FFFFFFF通过 remap_pfn_range 映射
GPIO 寄存器0x11000000 – 0x11000FFF通过 ioremap 后映射
帧缓冲 (Framebuffer)0x12000000 – 0x123FFFFF通过 dma_alloc_coherent 后映射

2.7 本节总结

  • 虚拟地址 是进程看到的地址,物理地址 是硬件总线上的真实地址。
  • MMU 负责将虚拟地址转换为物理地址,并执行权限和缓存策略。
  • 页表 是多级结构,存储虚拟页到物理页框的映射关系。
  • 页框 是物理内存的最小管理单元,Linux 默认页大小为 4KB。
  • 驱动通过 remap_pfn_range 在 mmap 回调中建立用户空间到物理页框的映射。