根据上一章节,bootloader将控制权交给内核,内核从__HEAD段的开头执行。该段的起始位置是_head
代码分析
_head
/*
* Kernel startup entry point.
* ---------------------------
*
* The requirements are:
* MMU = off, D-cache = off, I-cache = on or off,
* x0 = physical address to the FDT blob.
*
* This code is mostly position independent so you call this at
* __pa(PAGE_OFFSET).
*
* Note that the callee-saved registers are used for storing variables
* that are useful before the MMU is enabled. The allocations are described
* in the entry routines.
*/
__HEAD
_head:
/*
* DO NOT MODIFY. Image header expected by Linux boot-loaders.
*/
/*
* The following callee saved general purpose registers are used on the
* primary lowlevel boot path:
*
* Register Scope Purpose
* x21 primary_entry() .. start_kernel() FDT pointer passed at boot in x0
* x23 primary_entry() .. start_kernel() physical misalignment/KASLR offset
* x28 __create_page_tables() callee preserved temp register
* x19/x20 __primary_switch() callee preserved temp registers
* x24 __primary_switch() .. relocate_kernel() current RELR displacement
*/
b primary_entry // branch to kernel start, magic
通过如上代码我们可以看出,_head开始是一句跳转语句,跳入到函数 primary_entry开始执行。
而我们看_head的上下文注释,我们可以得知,此时MMU尚未开启,所以链接地址和物理地址不相等的情况下,该段代码注定是位置无关代码,另外,bootloader给x0赋值,其值为设备树的基地址。下面我们接着分析primary_entry
primary_entry
该函数的代码如下
SYM_CODE_START(primary_entry)
bl preserve_boot_args
bl el2_setup // Drop to EL1, w0=cpu_boot_mode
adrp x23, __PHYS_OFFSET
and x23, x23, MIN_KIMG_ALIGN - 1 // KASLR offset, defaults to 0
bl set_cpu_boot_mode_flag
bl __create_page_tables
/*
* The following calls CPU setup code, see arch/arm64/mm/proc.S for
* details.
* On return, the CPU will be ready for the MMU to be turned on and
* the TCR will have been set.
*/
bl __cpu_setup // initialise processor
b __primary_switch
SYM_CODE_END(primary_entry)
我们可以看出,该函数短小精函,但是调用的函数可不少。我们只能一个函数一个函数分析
首先是preserve_boot_args
preserve_boot_args
/*
* Preserve the arguments passed by the bootloader in x0 .. x3
*/
SYM_CODE_START_LOCAL(preserve_boot_args)
mov x21, x0 // x21=FDT
adr_l x0, boot_args // record the contents of
stp x21, x1, [x0] // x0 .. x3 at kernel entry
stp x2, x3, [x0, #16]
dmb sy // needed before dc ivac with
// MMU off
mov x1, #0x20 // 4 x 8 bytes
b __inval_dcache_area // tail call
SYM_CODE_END(preserve_boot_args)
该函数的注释很清楚,保存bootloader传递下来的参数x0~x3
第一句表示先将x0,也就是设备树的基地址存放在x21
第二句表示将boot_args的物理地址加载到x0,为什么用adr_l这种加载物理地址的指令,就如之前说过的,这段代码是位置无关代码,不能用ldr命令,只能用adr命令
那么boot_args是什么东东呢
arch/arm64/kernel/setup.c:83:u64 __cacheline_aligned boot_args[4];
boot_args是个数组,里面有4个元素,正好对应preserve_boot_args注释的x0~x3
第三句和第四句分别是x0.x1,x2,x3的值存放到数组boot_args里面
然后在x1里面存放32,表示32个B,表示数组的长度,没毛病
参考
参考1
ARM64启动过程分析
https://blog.csdn.net/maybeYoc/article/details/111871673