这段代码的目的
VA_BITS_MIN=48 VA_BITS_MIN 是内核虚拟地址空间的位数(例如 48 位)。所以定义的虚拟地址空间范围是 [0, 2^48),也就是[0, 0xFFFF_FFFF_FFFF]。
抛出问题
恒等映射要求 虚拟地址 == 物理地址。如果系统 RAM 的物理起始地址非常高,例如 0x1_0000_0000_0000 == 2^48,那么直接用 VA_BITS 定义的虚拟地址空间无法容纳整个 ID 映射区域。
这个[0, 2^48)虚拟地址空间无法直接映射到高达 0x1_0000_0000_0000 的物理地址,因为 0x1_0000_0000_0000 已经超出了 2^48 的范围。
这段代码就是解决上述的问题,探测出恒等映射结束部分的物理地址,与VA_BITS_MIN进行比较,如果前者 大于VA_BITS_MIN,则扩充恒等映射的虚拟地址范围。
总体逻辑
检测:通过计算__idmap_text_end地址的前导零,判断默认的虚拟地址空间是否足以覆盖所有需要恒等映射的物理地址。
决策:如果足够,跳过扩展流程。如果不够,继续执行。
准备:存储计算出的新T0SZ值,并确保缓存一致性。
扩展:根据当前是VA_BITS < 48还是VA_BITS == 48,采取两种不同的策略来调整页表结构:
对于小VA空间:需要增加一个额外的页表转换级别。调用create_table_entry创建新级别的页表。
对于48位VA空间:不需要增加级别,但需要扩展顶级页表(PGD)的条目数。计算出新的条目数并保存。
最终目的:动态地配置ID映射的页表结构,确保即使物理内存地址非常高,也能成功创建 虚拟地址 = 物理地址 的恒等映射,从而保证内核在开启MMU后能继续正确执行。这体现了Linux内核强大的可移植性,能够适应各种不同的硬件地址布局。
分析代码
/*
* Create the identity mapping.
*/
adrp x0, idmap_pg_dir
adrp x3, __idmap_text_start // __pa(__idmap_text_start)
#ifdef CONFIG_ARM64_VA_BITS_52
mrs_s x6, SYS_ID_AA64MMFR2_EL1
and x6, x6, #(0xf << ID_AA64MMFR2_LVA_SHIFT)
mov x5, #52
cbnz x6, 1f
#endif
mov x5, #VA_BITS_MIN
1:
adr_l x6, vabits_actual
str x5, [x6]
dmb sy
dc ivac, x6 // Invalidate potentially stale cache line
/*
* VA_BITS may be too small to allow for an ID mapping to be created
* that covers system RAM if that is located sufficiently high in the
* physical address space. So for the ID map, use an extended virtual
* range in that case, and configure an additional translation level
* if needed.
*
* Calculate the maximum allowed value for TCR_EL1.T0SZ so that the
* entire ID map region can be mapped. As T0SZ == (64 - #bits used),
* this number conveniently equals the number of leading zeroes in
* the physical address of __idmap_text_end.
*/
adrp x5, __idmap_text_end
clz x5, x5
cmp x5, TCR_T0SZ(VA_BITS_MIN) // default T0SZ small en

最低0.47元/天 解锁文章
1511

被折叠的 条评论
为什么被折叠?



