2)
#ifdef CONFIG_RELOCATABLE
#ifdef CONFIG_RELR
mov x24, #0 // no RELR displacement yet
#endif
bl __relocate_kernel
#ifdef CONFIG_RANDOMIZE_BASE
ldr x8, =__primary_switched
adrp x0, __PHYS_OFFSET
blr x8
/*
* If we return here, we have a KASLR displacement in x23 which we need
* to take into account by discarding the current kernel mapping and
* creating a new one.
*/
pre_disable_mmu_workaround
msr sctlr_el1, x20 // disable the MMU
isb
bl __create_page_tables // recreate kernel mapping
tlbi vmalle1 // Remove any stale TLB entries
dsb nsh
isb
set_sctlr_el1 x19 // re-enable the MMU
bl __relocate_kernel
#endif
#endif
ldr x8, =__primary_switched //x8 = __primary_switched编译后的链接地址,即虚拟地址【重点关注】
adrp x0, __PHYS_OFFSET //_text的值(kernel image存放的物理地址)
br x8 //无条件跳转到芯片支持的所有地址范围,dst→x8 ---(2.6.3)
SYM_FUNC_END(__primary_switch)
2.6.1 内核地址空间布局随机化
??主要是为了防止黑客的攻击,在早期阶段内核镜像映射到虚拟地址空间的地址是固定的,黑客利用这个特性很容易进行攻击。
2.6.2 打开MMU
/*
* Enable the MMU.
*
* x0 = SCTLR_EL1 value for turning on the MMU. //2.5.11
* x1 = TTBR1_EL1 value //2.6
*
* Returns to the caller via x30/lr. This requires the caller to be covered
* by the .idmap.text section.
*
* Checks if the selected granule size is supported by the CPU.
* If it isn't, park the CPU
*/
SYM_FUNC_START(__enable_mmu)
mrs x2, ID_AA64MMFR0_EL1 //
ubfx x2, x2, #ID_AA64MMFR0_TGRAN_SHIFT, 4 //假设我们定义了CONFIG_ARM64_4K_PAGES:这里就是ID_AA64MMFR0_EL1.TGran4域(bits [31:28])的值赋值给x2寄存器
cmp x2, #ID_AA64MMFR0_TGRAN_SUPPORTED_MIN //ID_AA64MMFR0_TGRAN_SUPPORTED_MIN=0
b.lt __no_granule_support //非法粒度
cmp x2, #ID_AA64MMFR0_TGRAN_SUPPORTED_MAX //ID_AA64MMFR0_TGRAN_SUPPORTED_MIN=7
b.gt __no_granule_support //非法粒度
update_early_cpu_boot_status 0, x2, x3 //把0写入到全局变量__early_cpu_boot_status中
adrp x2, idmap_pg_dir //加载idmap_pg_dir的物理地址到x2寄存器,idmap_pg_dir是恒等映射的一级页表起始地址【重点关注,下面TTBR0会用这个值】
phys_to_ttbr x1, x1 //对于48bit不进行操作
phys_to_ttbr x2, x2 //对于48bit不进行操作
msr ttbr0_el1, x2 // load TTBR0:Translation Table Base Register 0 (EL1)
offset_ttbr1 x1, x3
msr ttbr1_el1, x1 // load TTBR1:Translation Table Base Register 0 (EL1)
isb
set_sctlr_el1 x0 //打开mmu
ret
SYM_FUNC_END(__enable_mmu)
2.6.3 __primary_switched
??此时MMU已经打开,我们运行在虚拟地址空间内。
/*
* The following fragment of code is executed with the MMU enabled.
*
* x0 = __PHYS_OFFSET
*/
SYM_FUNC_START_LOCAL(__primary_switched)
adr_l x4, init_task
init_cpu_task x4, x5, x6 // ---(1)
adr_l x8, vectors // load VBAR_EL1 with virtual
msr vbar_el1, x8 // vector table address ---(2)
isb
stp x29, x30, [sp, #-16]! // ---(3)
mov x29, sp
str_l x21, __fdt_pointer, x5 // Save FDT pointer ---(4)
ldr_l x4, kimage_vaddr // Save the offset between
sub x4, x4, x0 // the kernel virtual and
str_l x4, kimage_voffset, x5 // physical mappings ---(5)
// Clear BSS ---(6)
adr_l x0, __bss_start // 起始地址
mov x1, xzr // 要写入的值,xzr是一个特殊的寄存器,值为64位的0
adr_l x2, __bss_stop // 结束地址
sub x2, x2, x0 // size = __bss_stop - __bss_start
bl __pi_memset // memset(x0, x1, x2)
dsb ishst // Make zero page visible to PTW
#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
bl kasan_early_init
#endif
mov x0, x21 // pass FDT address in x0
bl early_fdt_map // Try mapping the FDT early ---(7)
bl init_feature_override // Parse cpu feature overrides 根