十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

__kernel_physical_mapping_init

__kernel_physical_mapping_init __kernel_physical_mapping_init是 Linux x86 架构内核启动过程中负责建立物理内存直接映射Direct Mapping的“施工队长”。它接收经过split_mem_range拆分和adjust_range_page_size_mask修正后的内存区间并在页表Page Table中为它们建立从物理地址到虚拟地址的映射关系。核心任务按“图”施工填充页表它的主要工作可以理解为根据已经规划好的内存区间struct map_range在init_mm.pgd这个内核页表根目录上用指定的页面尺寸4K、2M或1G和权限逐级填充各级页表项。工作前提它的输入是map_range数组这些区间的起始地址、结束地址和应使用的页面尺寸掩码page_size_mask都已被精确计算好。执行动作函数会遍历map_range数组依次调用更低级的辅助函数如phys_p4d_init、phys_pud_init等将每个区间的物理地址映射到对应的内核虚拟地址通常是PAGE_OFFSET以上的区域。最终产物它将前序所有“规划”工作落实为实际的页表条目使 CPU 能够通过虚拟地址访问物理内存。关键特性__meminit与热插拔__kernel_physical_mapping_init及其封装kernel_physical_mapping_init被标记为__meminit而不是__init。这是一个重要的设计考量。__initvs__meminit__init标记的函数和数据在初始化完成后会被释放以节省内存。而__meminit标记的代码在初始化完成后如果是为内存热插拔Memory Hotplug功能编译的内核其代码段会被保留。为何需要因为内存热插拔比如在虚拟机中动态增加或减少内存需要在系统运行期间再次调用此函数来为新加入的物理内存建立页表映射。如果它被标记为__init热插拔时调用的代码可能已被释放导致系统崩溃。调用链路与封装在实际调用中__kernel_physical_mapping_init通常由kernel_physical_mapping_init这个封装函数调用后者为其提供默认的prot页面保护属性参数。从较新的内核补丁可以看出该函数的签名正在演进例如返回值类型可能从unsigned long变为void表明其内部可能通过指针参数来通知调用者页表是否被修改过。实现原理__kernel_physical_mapping_init的实现原理是按物理地址从低到高逐级遍历以PML4→P4D/PUD→PMD→PTE的顺序为直接映射区PAGE_OFFSET区域填充对应的各级页表项并在这个过程中处理内存空洞、合理使用大页以优化TLB性能。实现原理分解这个函数是连接“映射规划”与“页表填写”的执行者其核心逻辑包含以下几个层面1. 层级遍历与填充该函数并不直接操作页表条目而是通过调用底层的辅助函数来完成工作。这些辅助函数负责处理页表的特定层级phys_pgd_init()顶层入口。接收init_mm.pgd作为根负责将映射任务下发给下一级。phys_p4d_init()/phys_pud_init()根据内核配置是否支持5级页表逐级处理P4D、PUD层级。这些函数会检查每个物理地址区间能否使用1GB大页PUD_SIZE进行映射如条件满足则直接设置对应条目否则继续下发给PMD层级。phys_pmd_init()负责最终处理PMD层级决定使用2MB大页PMD_SIZE还是降级为4KB页PTE进行精细映射。这种层次化的设计使得映射逻辑可以在每一级根据地址对齐情况独立决策使用何种页面大小。2. 两阶段映射 (历史优化)为了遵循Intel的TLB使用规范避免在同一线性地址上同时改变页面大小和页框/属性该函数在历史上曾采用过“两阶段映射”策略第一阶段在head_64.S等早期汇编代码已经建立好初始页表的基础上使用相同的属性但优化后的页面尺寸重新建立映射。第二阶段在TLB刷新后再以最终正确的属性如_PAGE_NX填充页表完成映射。虽然现代内核实现已将此过程优化但其核心思想——通过分步避免对已存在的映射条目进行“属性尺寸”的“双变量原子修改”依然影响着该函数的逻辑。3. 安全填充与热插拔支持__kernel_physical_mapping_init以及它的底层辅助函数设计上遵循一个核心约束只能用于填充“不存在”non-present的页表项不能修改已存在的映射。这个约束确保了在内存热插拔等动态场景下的安全性。正是为了支持内存热插拔Hotplug该函数及相关的页表填充逻辑都被标记为__meminit而非__init。这保证了在系统初始化完成后相关代码段不会因内存释放而消失从而能在运行时为新加入的物理内存建立映射。总结__kernel_physical_mapping_init的实现原理是一个按照PML4 → P4D/PUD → PMD → PTE的顺序对每个物理地址区间进行逐级“精加工”的过程。它通过层级化的辅助函数调用将经过split_mem_range规划好的“映射蓝图”转化为硬件可识别、可执行的页表条目。其设计始终围绕着性能优化善用大页、遵守规范遵从TLB约束和安全扩展支持热插拔这三个核心目标。
返回列表