在ARM Linux系统启动过程中,对2GB物理内存的映射实现分为以下几个关键阶段:
一、设备树解析与内存信息获取
1.设备树定义
物理内存范围通过设备树(DTS)的memory节点定义,例如:
memory@60000000 {
device_type = "memory";
reg = <0x60000000 0x80000000>; // 起始地址0x60000000,大小2GB
};
作用:内核启动时通过early_init_dt_scan_memory()解析该节点,获取物理内存基地址(base)和大小(size)。
2.注册到memblock子系统
解析后的内存区域通过memblock_add()注册到内核早期内存管理器memblock中,临时管理物理内存分配。
二、初始页表建立(段映射阶段)
1.临时页表(swapper_pg_dir)
位置:物理内存16KB对齐区域,由汇编代码在head.S中初始化。
映射方式:采用段映射(Section Mapping),每个段1MB,直接映射物理地址到内核虚拟地址。
// 物理地址0x60000000 → 虚拟地址0xC0000000(PAGE_OFFSET=3G)
create_section_mapping(swapper_pg_dir, 0x60000000, 0xC0000000, 0x80000000);
2.映射范围
初始页表覆盖整个2GB物理内存,建立1:1线性映射(物理地址+3G偏移),确保内核启动时可直接访问所有内存。
确定映射偏移量(PAGE_OFFSET)
典型配置:内核虚拟地址偏移 PAGE_OFFSET = 0xC0000000。
物理地址 0x60000000 对应的内核虚拟地址为:
虚拟地址 = 物理地址 + (PAGE_OFFSET - PHYS_OFFSET)
其中 PHYS_OFFSET 是物理内存的起始地址(此处为 0x60000000)。
计算示例:
PAGE_OFFSET = 0xC0000000 // 内核空间起始地址
PHYS_OFFSET = 0x60000000 // 物理内存起始地址
虚拟地址偏移量 = PAGE_OFFSET - PHYS_OFFSET = 0xC0000000 - 0x60000000 = 0x60000000
因此,物理地址 0x60000000 对应的内核虚拟地址为:
0x60000000 + 0x60000000 = 0xC0000000
物理地址 0xE0000000(结束地址)对应的虚拟地址为:
0xE0000000 + 0x60000000 = 0x140000000(超过 32 位地址空间,需特殊处理)。
虚拟地址空间布局
内核空间:0xC0000000-0xFFFFFFFF(1GB,默认配置)。
若物理内存超过 1GB(如本例的 2GB),需调整 PAGE_OFFSET 或启用 HIGHMEM,但 ARMv7 通常不推荐此操作。
冲突处理:
当 PHYS_OFFSET + 内存大小 > PAGE_OFFSET + 1GB 时,内核会触发错误或截断映射。需确保设备树中 reg 范围与内核配置一致。
三、详细页表重构(paging_init阶段)
1.清除临时映射
在paging_init()函数中,调用memblock_free()释放临时页表占用的内存。
2.重构低端内存映射
函数路径:paging_init() → map_lowmem() → create_mapping()。
映射策略:
使用2MB大页(Huge Page)或4KB小页,替代初始的1MB段映射。
保留线性映射关系(phys_to_virt(addr) = addr + PAGE_OFFSET)。
3.高端内存处理(如适用)
若物理内存超过内核直接映射区(如32位系统默认896MB),超出部分标记为高端内存(Highmem),通过kmap()动态映射。
2GB内存案例:在32位ARM系统(内核空间1G)中,若配置为3:1划分,2GB物理内存需部分使用高端内存机制。
四、内存管理子系统初始化
1.伙伴系统接管
memblock将内存信息移交伙伴系统(Buddy System),完成精细化分页管理:
start_kernel() → mm_init() → mem_init() → free_all_bootmem();
2.内存区域(Zone)划分
ZONE_NORMAL:直接映射的低端内存(如0x60000000-0xE0000000)。
ZONE_HIGHMEM:动态映射的高端内存(若存在)。
五、验证与调试
查看内核日志
dmesg | grep "Memory" # 输出示例:
# [0.000000] Memory: 2048MB/2048MB available
检查物理内存映射
cat /proc/iomem | grep "System RAM"
# 输出示例:
# 60000000-7fffffff : System RAM
关键代码路径与配置文件阶段
关键函数/文件 作用
设备树解析 early_init_dt_scan_memory() 解析DTS内存节点
初始页表构建 arch/arm/kernel/head.S 创建临时段映射
详细页表重构 arch/arm/mm/mmu.c → map_lowmem() 建立低端内存永久映射
内存管理移交 mm/memblock.c → memblock_free() 释放临时页表,移交伙伴系统
实际映射策略可能因内核配置(如CONFIG_VMSPLIT调整用户/内核空间比例)或芯片架构差异而不同。