
init_range_memory_mapping是 x86 架构内核在启动时用于为一段指定的物理地址范围建立直接映射Direct Mapping的核心函数。它的核心作用是遍历 E820 内存映射表找出目标范围内所有真正可用的 RAM 区域跳过内存空洞和保留区域并只对这些区域建立页表映射。核心功能与设计意图这个函数并非简单地将[r_start, r_end)整段地址直接映射而是非常精细地处理了物理内存中可能存在的“空洞”。其设计意图在源码注释中说得非常清楚We need to iterate through the E820 memory map and create direct mappings for only E820_TYPE_RAM and E820_KERN_RESERVED regions. We cannot simply create direct mappings for all pfns from [0 to max_low_pfn) and [4GB to max_pfn) because of possible memory holes in high addresses that cannot be marked as UC by fixed/variable range MTRRs.也就是说物理地址空间中可能并非全是可用的 RAM中间会夹杂着保留区域或设备 MMIO 空洞。如果强行映射这些非 RAM 区域可能会因为缓存属性问题导致系统不稳定。因此init_range_memory_mapping会跳过这些空洞只映射真正的 RAM。函数逻辑逐行解析static unsigned long __init init_range_memory_mapping( unsigned long r_start, unsigned long r_end) { unsigned long start_pfn, end_pfn; unsigned long mapped_ram_size 0; int i; for_each_mem_pfn_range(i, MAX_NUMNODES, start_pfn, end_pfn, NULL) { u64 start clamp_val(PFN_PHYS(start_pfn), r_start, r_end); u64 end clamp_val(PFN_PHYS(end_pfn), r_start, r_end); if (start end) continue; can_use_brk_pgt max(start, (u64)pgt_buf_endPAGE_SHIFT) min(end, (u64)pgt_buf_topPAGE_SHIFT); init_memory_mapping(start, end); mapped_ram_size end - start; can_use_brk_pgt true; } return mapped_ram_size; }遍历 E820 内存范围for_each_mem_pfn_range宏会遍历内核维护的 E820 内存映射表e820_table逐项取出每一个可用的物理内存区域标记为E820_TYPE_RAM等的起始和结束页帧号PFN。裁剪到目标范围clamp_val将当前 E820 内存项的物理地址PFN_PHYS(start_pfn)和PFN_PHYS(end_pfn)裁剪到[r_start, r_end)这个目标范围内。这样做的目的是即使一个 E820 内存项只与目标范围部分重叠也能得到精确的交集。如果裁剪后start end说明该 E820 项与目标范围没有交集直接跳过。处理页表缓冲区冲突can_use_brk_pgt这个全局标志位用于判断当前要映射的内存区域是否与内核页表自身的临时缓冲区pgt_buf重叠。如果重叠就不能使用 BRK 区域来分配新的页表而必须从 memblock 分配器获取内存以防止自我覆盖导致的崩溃。建立映射对于裁剪后的有效区间调用init_memory_mapping(start, end)来完成实际的页表建立工作。该函数内部会根据地址对齐情况智能选择使用 4KB、2MB 或 1GB 的页面大小以最大化页表效率。统计与重置累加已映射的 RAM 大小到mapped_ram_size并在每次循环结束时将can_use_brk_pgt重置为true为处理下一个内存项做准备。在启动流程中的位置这个函数通常由init_mem_mapping()调用。init_mem_mapping会决定采用自顶向下top-down还是自底向上bottom-up的策略来扫描整个物理内存并分多次调用init_range_memory_mapping逐步为所有 RAM 建立直接映射。返回的mapped_ram_size用于判断映射进度并动态调整每次映射的步长step_size以平衡页表分配效率和内存占用。