1.前言
本文基于高通8996平台,kernel版本为3.18.31。
本文主要介绍head.S的__switch_data执行流程
2. __switch_data
这段代码分成两个部分,一部分是清BSS,另外一部分是为进入c代码做准备(主要是stack)。
.align 3
.type __switch_data, %object
__switch_data:
.quad __mmap_switched
.quad __bss_start // x6
.quad __bss_stop // x7
.quad processor_id // x4
.quad __fdt_pointer // x5
.quad memstart_addr // x6
.quad init_thread_union + THREAD_START_SP // sp
/*
* The following fragment of code is executed with the MMU on in MMU mode, and
* uses absolute addresses; this is not position independent.
*/
__mmap_switched:
// 跳过__mmap_switched
adr x3, __switch_data + 8
// x6 = __bss_start // x7 = __bss_stop
ldp x6, x7, [x3], #16
1: cmp x6, x7
b.hs 2f
// Clear BSS// 循环清除bss段,BSS段用来存放程序中未初始化的全局变量和静态变量
str xzr, [x6], #8
b 1b
2:
// x4 = processor_id // x5 = __fdt_pointer
ldp x4, x5, [x3], #16
// x6 = memstart_addr
ldr x6, [x3], #8
// init_thread_union + THREAD_START_SP // sp // THREAD_START_SP = THREAD_SIZE - 16
ldr x16, [x3]
// 跳转到c语言前,必须设置好栈
mov sp, x16
// Save processor ID
// 将x22保存的当前cpu id保存到processor_id(在kernel/arch/arm64 /kernel/setup.c中定义的 )中
str x22, [x4]
// Save FDT pointer
// 将x21暂存的device tree的地址保存到__fdt_pointer(在kernel/arch/arm64 /kernel/setup.c中定义的)中
str x21, [x5]
// Save PHYS_OFFSET
// 将x24保存的kernel起始的地址保存到memstart_addr(在kernel/arch/arm64/mm/init.c中定义的)中
str x24, [x6]
// 将x29清0,还不清楚为什么要特别的做这一步
mov x29, #0
#ifdef CONFIG_KASAN
bl kasan_early_init
#endif
b start_kernel
ENDPROC(__mmap_switched)
3.总结
__switch_data主要功能分为两个部分,一部分是清BSS,另外一部分是为进入c代码做准备(主要是stack)。
-
clear BSS段就是把未初始化的全局变量设定为0的初值。
-
为start_kernel这样的c代码执行设置内核栈,实际上就是该进程的thread info内存段(4K或者8K)的顶部。
对于swapper进程(0号进程),原理是类似的:
如果说之前的代码执行都处于一个孤魂野鬼的状态,“mov sp, x16”指令执行之后,初始化代码终于找到了归宿,初始化代码有了自己的thread info,有了自己的task struct,有了自己的pid,有了进程(内核线程)应该拥有的一切,从此之后的代码归属idle进程,pid等于0的那个进程。
为了方便后面的代码的访问,这里还初始化了两个变量,分别是__fdt_pointer(设备树信息,物理地址)和memstart_addr(kernel image所在的物理地址,一般而言是main memory的首地址)。 memstart_addr主要用于main memory中物理地址和虚拟地址的转换,具体可以参考__virt_to_phys和__phys_to_virt的实现
参考文档
1.https://blog.csdn.net/xichangbao/article/details/51568782
2.https://www.cnblogs.com/smartjourneys/diary/2017/04/27/6774121.html
3.http://www.wowotech.net/armv8a_arch/arm64_initialize_1.html ARM64的启动过程之(一):内核第一个脚印
3.http://www.wowotech.net/armv8a_arch/create_page_tables.html ARM64的启动过程之(二):创建启动阶段的页表
4.http://www.wowotech.net/armv8a_arch/__cpu_setup.html ARM64的启动过程之(三):为打开MMU而进行的CPU初始化
5.http://www.wowotech.net/armv8a_arch/turn-on-mmu.html ARM64的启动过程之(四):打开MMU
6.https://blog.csdn.net/xichangbao/article/details/51568782 Kernel启动流程源码解析 1 head.S
7.https://blog.csdn.net/xichangbao/article/details/51605462 Kernel启动流程源码解析 2 head.S