目录
内核启动过程中完成临时的内核空间页表创建后,就可以实现内核空间物理地址与对应虚拟地址间的相互转化,该转化过程可以通过__phys_to_kimg 、__kimg_to_phys实现。
内核空间物理与虚拟地址转换逻辑
从页表创建过程看,一段连续物理内存空间连续映射到虚拟空间时,其对应的虚拟空间、页表均是连续空间。如下图A Phy Region物理空间映射连续映射到虚拟空间A Virtual Region,A Region 在虚拟空间中保持了在物理空间时的地址顺序性,唯独虚拟空间与物理空间对应的地址不同;故A Region中的内容的物理地址和虚拟地址差值固定,且等于 A va_addr start - A phy_add start 。
连续物理内存空间连续映射到虚拟空间时,连续物理内存地址与其对应虚拟内存地址差值固定。这是物理地址和虚拟地址相互转换的逻辑基础。
内核段物理地址与虚拟地址的转换函数
#define __phys_to_kimg(x) ((unsigned long)((x) + kimage_voffset))
__phys_to_kimg 实现内核段物理地址转为虚拟地址,从函数实现看内核物理地址与虚拟地址的差值为kimage_voffset。
kimage_voffset赋值过程,需要看如下几段代码:
代码段1,取__PHYS_OFFSET的物理页地址(内核在内存中的起始页地址)赋给x0寄存器,然后跳转执行__primary_switched函数。
代码段2,定义 kimage_vaddr = _text - TEXT_OFFSET,kimage_vaddr为内核在虚拟空间中的起始地址
代码段3, (取自__primary_switched函数中的一段)将内核在虚拟空间的起始地址与物理空间的起始地址做差值后赋给kimage_voffset;即 内核空间虚拟地址 = kimage_voffset + 内核空间物理地址。
代码段1
ldr x8, =__primary_switched
/* 获取内核在内存中的起始物理地址*/
adrp x0, __PHYS_OFFSET
/* 跳转到__primary_switched函数执行*/
br x8
代码段2
ENTRY(kimage_vaddr)
.quad _text - TEXT_OFFSET
代码段3
__primary_switched:
...
/* Save the offset between,
* kimage_vaddr = _text - TEXT_OFFSET = __PHYS_OFFSET
* 加载内核起始虚拟地址到X4
*/
ldr_l x4, kimage_vaddr
/*
* X4 内核在虚拟内存中起始地址
* X0 内核在物理内存中起始地址
*/
sub x4, x4, x0
/*
* 将X4 内核虚拟地址与物理的地址的差值赋给kimage_voffset
* 故内核空间 虚拟地址 = 物理地址 + kimage_voffset
*/
str_l x4, kimage_voffset, x5 // physical mappings
...
#define __kimg_to_phys(addr) ((addr) - kimage_voffset)
__kimg_to_phys 与__phys_to_kimg相反,__kimg_to_phys实现的内核空间虚拟地址到物理地址的转化。