参考代码:Linux 5.10.129
内核初始化
内核初始化分为汇编语言部分和C语言部分
(1)汇编语言部分
arm64架构的内核的入口标号是_head,直接跳转到标号primary_entry。
/arch/arm64/kernel/head.S
_head:
/*
* DO NOT MODIFY. Image header expected by Linux boot-loaders.
*/
#ifdef CONFIG_EFI
/*
* This add instruction has no meaningful effect except that
* its opcode forms the magic "MZ" signature required by UEFI.
*/
add x13, x18, #0x16
b primary_entry
#else
b primary_entry // 跳转到内核起始位置
.long 0 // reserved
#endif
配置宏 CONFIG_EFI 表示提供UEFI运行时支持,UEFI(Unified Extensible Firmware Interface)是统一的可扩展固件接口,用于取代BIOS。
/arch/arm64/kernel/head.S
SYM_CODE_START(primary_entry)
bl preserve_boot_args
bl el2_setup // 降级到异常级别1,寄存器w0存放在 cpu_boot_mode
adrp x23, __PHYS_OFFSET
and x23, x23, MIN_KIMG_ALIGN - 1 // KASLR 偏移,默认值是0
bl set_cpu_boot_mode_flag
bl __create_page_tables
/*
* 下面调用设置处理器的代码, 请看文件/arm64/mm/proc.S
* 了解细节。
* 返回的时候,处理器已经开启内存管理单元做好准备,
* 转换控制寄存器已经设置好。
*/
bl __cpu_setup // 初始化处理器
b __primary_switch
SYM_CODE_END(primary_entry)
1、调用函数 preserve_boot_args,把引导程序传递的4个参数保存在全局数组boot_args中。
2、调用函数 el2_setup:如果处理器当前的异常级别是2,判断是否需要降级到异常级别1。
3、调用函数 set_cpu_boot_mode_flag,根据处理器进入内核时的异常级别设置数组__boot_cpu_mode[2]。__boot_cpu_mode[0]的初始值是BOOT_CPU_MODE_EL2,__boot_cpu_mode[1]的初始值是BOOT_CPU_MODE_EL1。如果异常级别是1,那么把__boot_cpu_mode[0]设置为 BOOT_CPU_MODE_EL1,如果异常级别是2,那么把__boot_cpu_mode[1]设置为 BOOT_CPU_MODE_EL2。
4、调用函数 __create_page_tables,创建页表映射。
5、调用函数 __cpu_setup,为开启处理器的内存管理单元做准备,初始化处理器。
6、调用函数 __primary_switch,为主处理器开启内存管理单元,搭建C语言执行环境,进入C语言部分的入口函数start_kernel。