Linux内核6.6 内存管理 (17)内核镜像区和线性映射区
内核镜像区和线性映射区
map_kernel中所有虚拟地址均 > direct_map_end(0xffff800000000000),属于内核镜像专属虚拟区域,不在线性映射区内。内核正常运行时,CPU 直接访问这些虚拟地址执行代码(text 段)、读取数据(rodata、data 段),是内核 “工作时” 的主地址
线性映射区是内核用于直接访问物理内存的虚拟地址区域,由 map_mem 函数负责映射
物理地址到内核镜像区 __phys_to_kimg
https://elixir.bootlin.com/linux/v6.6/source/arch/arm64/include/asm/memory.h#L310
map_kernel的地址计算:(通过 kimage_voffset 转换)
内核镜像区的虚拟地址与物理地址通过 kimage_voffset 关联(物理地址 = 虚拟地址 - kimage_voffset):
以 text 段为例:
虚拟起始 = 0xffff800080010000
物理起始 = 0xffff800080010000 - 0xffff7ffffcc00000 = 0x83410000(与日志中 Kernel text+rodata segment range (physical) 起始一致)。
整个内核镜像的物理地址范围:0x83410000 ~ 0x84ef0000(text+rodata 段),位于物理内存中(> PHYS_OFFSET 0x80000000)。
该虚拟地址范围:所有虚拟地址均 > direct_map_end(0xffff800000000000),属于内核镜像专属虚拟区域,不在线性映射区内。
物理地址到线性映射区 __phys_to_virt
映射规则(物理地址 ↔ 虚拟地址)
通过线性映射公式转换:虚拟地址 = 物理地址 - PHYS_OFFSET + PAGE_OFFSET
验证:物理起始 0x83410000 对应的线性虚拟地址:
0x83410000 - 0x80000000 + 0xffff000000000000 = 0xffff000003410000(与日志完全一致)。
该虚拟地址范围:由 PAGE_OFFSET(起始)和 direct_map_end(结束)界定:0xffff000000000000 ≤ 虚拟地址 < 0xffff800000000000
完整日志
这里还是建议先把kaslr关掉,不然PHYS_OFFSET每次都会显示不同的地址,这里我们可以看到,物理地址偏移是0x80000000,这个正常就是设备树里memory的内容,应该是固定的
表格对照
__phys_to_virt 用于将任意物理地址转换为线性映射区的虚拟地址,供内核管理物理内存;
__phys_to_kimg 用于将内核镜像的物理地址转换为内核镜像区的虚拟地址,供内核访问自身代码和数据。
同样也是这两个区域的功能对照
#嵌入式笔面经分享##嵌入式转岗的难度怎么样##嵌入式##嵌入式软开#
海康威视公司福利 1121人发布