__INITDATA NEXT_PGD_PAGE(early_top_pgt) .fill 512,8,0 .fill PTI_USER_PGD_FILL,8,0 /* 512 */
这段汇编代码是 Linux 内核启动时,定义和初始化早期顶层页表 early_top_pgt(PML4 页表)的核心部分。它在 arch/x86/kernel/head_64.S 文件中,结合了数据段声明、页对齐和填充指令,为内核启动早期建立了一个干净的页表框架。
可以将其拆分为三个部分来深入理解。
代码逐段解析
__INITDATA 这是一个宏,用于将接下来的数据放入 .init.data 段。这个段中的数据仅在系统初始化阶段使用,启动完成后会被内核释放回收。
NEXT_PGD_PAGE(early_top_pgt) 这是一个自定义宏,用于两个目的:
-
按 2 个页的大小(8192 字节)对齐:确保 early_top_pgt 的起始地址符合其作为关键页表结构的要求。
-
声明全局符号:使 early_top_pgt 在其他汇编或 C 代码中可见,以便在启动流程中被引用。
数据填充指令
-
.fill 512,8,0:填充 512 个 8 字节的条目,每个条目初始化为 0。这构成了 early_top_pgt 页表的主体部分,共占用一个页(4096 字节)的大小。
-
.fill PTI_USER_PGD_FILL,8,0:再次填充 PTI_USER_PGD_FILL 个 8 字节条目,初始化为 0。PTI_USER_PGD_FILL 通常也是一个常量,这确保了整个 early_top_pgt 页表正好占用 2 个页的大小。
设计意图:页表与 PTI 兼容
这种设计是内核为了支持 PTI(Page Table Isolation,页表隔离) 特性而做出的安排。
-
第一个 .fill:用于内核空间自身的页表映射。
-
第二个 .fill:为 PTI 预留空间,用于独立的用户空间页表映射。
-
NEXT_PGD_PAGE 的 2 页对齐:保证了整个 early_top_pgt 结构体可以从一个 2 页对齐的地址开始,这正好对应了内核页表和用户页表各占一页的布局,简化了代码中通过 PTI_USER_PGD_FILL 计算偏移的逻辑。
全局作用
early_top_pgt 是内核启动过程中使用的第一个页表。它的内容在后续的 __startup_64() 函数中会被动态修正,填充上正确的物理地址和属性,然后其基地址被加载到 %cr3 寄存器中,正式启用分页。
这段代码为这一系列操作提供了对齐良好、大小固定的“画布”,是 x86_64 内核成功进入虚拟内存世界的基石。





