Arm64的汇编阶段
__create_page_tables
这个函数是系统入口调用的stext函数的一部分,属于最早期的和内存相关的函数,其作用是创建内核映射页表。由于在打开MMU时,有一个地址映射ON/OFF的切换过程,需要一段恒等映射(identity mapping,有资料翻译为一致性映射,即物理地址和虚拟地址相同)的空间可以保证在打开MMU那一点附近的程序代码可以平滑切换。
stext-->__create_page_tables
__create_page_tables函数的代码如下:
__create_page_tables:
mov x28, lr
这里将(idmap_pg_dir, swapper_pg_end)这段物理地址范围对应的dcache进行invalidate
adrp x0, idmap_pg_dir 页表的起始地址
ldr x1, =(IDMAP_DIR_SIZE + SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE) 长度
bl __inval_dcache_area 调用invalid函数 参数为虚拟地址和长度
在arch/arm64/kernel/vmlinux.lds.S定义了上面的invalid dcache地址范围,这个地址空间将用于保存恒等映射和内核映射的各级页表。
221 idmap_pg_dir = .;
222 . += IDMAP_DIR_SIZE;
223 swapper_pg_dir = .; 存放PGD、PUD和PMD表项
224 . += SWAPPER_DIR_SIZE;
226 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
227 reserved_ttbr0 = .;
228 . += RESERVED_TTBR0_SIZE;
229 #endif
小知识
我们观察内核使用的页面大小为4KB对应的地址分配(虚拟地址有效位为48bit),对应的是4级页表
48bit的有效地址可管理2^48 =256TB大小的内存空间。具体就是每级中的每个页表项
Level0:512GB ------------------------------ 对应Linux中的PGD
Level1:1GB ------------------------------ 对应Linux中的PUD
Level2:2MB ------------------------------ 对应Linux中的PMD
Level3:4KB ------------------------------ 对应Linux中的PTE
每级页表都是9bit有效位 因为(48-12)/4 = 9,那么每级页表都有2^9=512个页表项,每个页表项大小为64bit 即8字节。
那么如果想映射256TB需要多少内存作页表呢,那就是
(512+512^2+512^3+512^4)x8 Bytes
这个数字就不计算了 因为非常巨大,好在系统只是用了256TB空间的一个小小的零头,所以页表空间也就不会太过巨大了。
那么映射4MB空间到虚拟0地址要多少页表空间呢 很简单 level0~leve1均只需要1个页表项。Level2需要2个页表项,level3需要2×512 所需空间共需 (1+1+2+2x512)x8 = 8224 Bytes就够了。
那么映射4MB空间到虚拟非0地址要多少页表空间呢,看就要看该虚拟地址在每级页表内页表项的偏移了,但是肯定会大于映射到0地址。
如果虚拟地址有效bit小于48,对应4kB粒度的还有39bit可以使用。