ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

init INIT_PGD_PAGE_COUNT

init INIT_PGD_PAGE_COUNT INIT_PGD_PAGE_COUNT是 Linux 内核 x86 架构启动过程中定义的一个宏它规定了早期页表缓冲区pgt_buf可以容纳的页表页数量。这个缓冲区在系统启动早期、正式的内存分配器如伙伴系统尚未就绪时为建立初始内核页表提供内存。核心定义与用途在arch/x86/mm/init.c中你可以找到类似这样的代码片段展示了该宏的完整定义和使用方式/* 根据是否启用5级页表定义每个映射层级所需的页表页数 */ #ifndef CONFIG_X86_5LEVEL #define INIT_PGD_PAGE_TABLES 3 #else #define INIT_PGD_PAGE_TABLES 4 #endif /* 根据是否启用KASLR计算总页表页数 */ #ifndef CONFIG_RANDOMIZE_MEMORY #define INIT_PGD_PAGE_COUNT (2 * INIT_PGD_PAGE_TABLES) #else #define INIT_PGD_PAGE_COUNT (4 * INIT_PGD_PAGE_TABLES) #endif #define INIT_PGT_BUF_SIZE (INIT_PGD_PAGE_COUNT * PAGE_SIZE) RESERVE_BRK(early_pgt_alloc, INIT_PGT_BUF_SIZE);所以它主要是一个编译期的配置参数用来决定启动早期页表缓冲区的大小而不是在某个运行时函数里被频繁调用。根据内核源码中的提交记录INIT_PGD_PAGE_COUNT的定义经历了演进其核心目的是为启动早期必须建立的页表预留足够的内存。在较早的内核版本中相关的宏是INIT_PGT_BUF_SIZE它被定义为(6 * PAGE_SIZE)。后来这个宏被替换为更清晰的INIT_PGD_PAGE_COUNT并配合RESERVE_BRK机制来预留内存#define INIT_PGD_PAGE_COUNT 6 #define INIT_PGT_BUF_SIZE (INIT_PGD_PAGE_COUNT * PAGE_SIZE) RESERVE_BRK(early_pgt_alloc, INIT_PGT_BUF_SIZE);为什么是 6 个页面INIT_PGD_PAGE_COUNT的值如 6并非随意设定它是为了满足启动早期最基础的地址映射需求。根据内核文档的描述这 6 个页面用于满足两类关键的早期映射ISA 映射1 MiB为传统的 ISA 设备如 VGA、键盘控制器在低端内存建立映射。首个直接映射2 MiB建立内核直接映射区的第一个 2 MiB 映射。为了建立这两类映射至少需要分配 PUD、PMD、PTE 三个层级的页表。由于在某些场景下如启用 KASLR映射可能更复杂或需要重复分配因此这个数量通常会被翻倍最终定为 6 个页面。5级页表的适配与动态扩展随着硬件的发展这个固定值也遇到了挑战5级页表的需求对于支持 5 级页表5-level paging的 CPU地址空间从 48 位扩展到 57 位这需要在 PUD 之上增加一个P4D层级。因此内核提交了补丁将INIT_PGD_PAGE_COUNT的值翻倍以容纳这个额外的页表层级。大内存机器的边界情况即使初始值被翻倍对于拥有超大物理内存如 512 GiB的机器如果内核使用 4 KiB 页面首次直接映射可能需要跨越多个 PGD 条目导致预留的页表缓冲区不足。内核文档指出在这种情况下可能还需要额外 3 到 4 个页表页。这说明INIT_PGD_PAGE_COUNT是一个在通用性与极端情况之间权衡的静态估算值并非在所有硬件配置下都绝对充裕。使用链路它最核心的用途是配合INIT_PGT_BUF_SIZE宏为RESERVE_BRK预留一块用于早期页表分配的内存。定义与计算该宏定义了初始页表所需的页表页数量。其值会根据是否启用 KASLR内存随机化和 5 级页表支持而动态调整。内存预留计算出的INIT_PGT_BUF_SIZE会被RESERVE_BRK(early_pgt_alloc, INIT_PGT_BUF_SIZE)使用在内核启动早期从brk区域预留出这块内存专门用于分配页表。定义缓冲区大小INIT_PGT_BUF_SIZE通过INIT_PGD_PAGE_COUNT计算得出决定了需要为早期页表预留多少内存。#define INIT_PGT_BUF_SIZE (INIT_PGD_PAGE_COUNT * PAGE_SIZE)预留内存 (BRK)紧接着RESERVE_BRK(early_pgt_alloc, INIT_PGT_BUF_SIZE)宏会在内核镜像的brk区域预留出这块内存。brk区域是内核镜像的一部分在启动早期必然被映射因此可以作为页表分配的“启动资本”。初始化缓冲区指针在setup_arch()函数中会调用early_alloc_pgt_buf()。这个函数负责初始化几个关键的全局变量pgt_buf_start、pgt_buf_end、pgt_buf_top将预留的brk内存正式纳入页表分配器的管理。供分配器使用之后当alloc_low_page()函数需要分配页表页时它会优先从pgt_buf这个缓冲区中取用内存直到耗尽。耗尽后才会转向memblock去查找更多已映射的内存。
返回列表