Linux内核页表结构解析
Linux swapper_pg_dir
在Linux内核中,swapper_pg_dir
是一个关键的数据结构,用于管理系统的页表(Page Tables)。以下是详细解释:
1. 定义与作用
- 初始内核页表:
swapper_pg_dir
是内核启动时使用的 顶级页全局目录(Page Global Directory, PGD)。它在系统引导阶段初始化,负责建立内核空间的初始虚拟地址到物理地址的映射。 - 内核空间映射:它直接映射内核代码、数据、设备内存(如
vmalloc
区域)等核心区域。所有进程共享内核空间的映射,因此swapper_pg_dir
的内核部分在进程切换时保持不变。
2. 生命周期与使用场景
- 引导阶段:在系统启动时(如
start_kernel()
函数),内核通过swapper_pg_dir
启用分页机制(MMU)。此时它提供临时的1:1线性映射(物理地址 = 虚拟地址 - 固定偏移)。 - 运行时:系统初始化完成后,内核切换到完整的页表结构,但
swapper_pg_dir
仍保留:- 作为 内核主页表,为所有进程的内核空间提供统一映射。
- 在进程切换时,用户空间的页表(PGD)会变化,但内核部分通过复制
swapper_pg_dir
的映射项保持一致性。
3. 代码中的位置
- 架构相关实现:
- x86_64:定义于
arch/x86/mm/pgtable.c
,符号swapper_pg_dir
。 - ARM64:定义于
arch/arm64/kernel/vmlinux.lds.S
(链接脚本),作为初始页表的存储位置。
- x86_64:定义于
- 初始化:在
paging_init()
函数中填充页表项(如映射内核镜像、设备树等)。
4. 与进程页表的关系
每个进程的task_struct->mm_struct->pgd
指向其私有页表:
- 用户空间:独立映射,进程隔离。
- 内核空间:直接从
swapper_pg_dir
复制而来(如fork()
时通过pgd_alloc()
复制内核部分),确保所有进程访问相同的内核地址。
5. 高级优化
- 共享映射:现代内核(如x86_64的
KAISER
补丁后)使用独立的内核页表(init_top_pgt
),但原理类似——仍存在全局内核页表。 - TLB刷新:修改
swapper_pg_dir
时需广播TLB刷新(如flush_tlb_all()
),保证多核一致性。
示例代码片段(x86_64)
1 | // arch/x86/include/asm/pgtable_64_types.h |
总结
swapper_pg_dir
是 内核空间的全局页表根目录,核心作用包括:
- 引导阶段提供初始内存映射。
- 运行时作为所有进程共享的内核空间映射基准。
- 确保高效、一致的内核地址访问。
理解它对分析内存管理(如mm/
目录代码)、进程切换及硬件交互(MMU/TLB)至关重要。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Helloeuler!