ARM64 Linux的启动分析
ARM64 Linux的启动分析
1. 找到Linux启动流程
Linux启动,会启动内核编译后的文件vmlinux
vmlinux是一个ELF文件,按照./arch/arm64/kernel/vmlinux.lds设定的规则进行链接的
./arch/arm64/kernel/vmlinux.lds 是 ./arch/arm64/kernel/vmlinux.lds.S编译之后生成的
通过readelf可以看到vmlinux的入口地址为:0xfffffe0000080000
这个地址是怎么来的,对应内核代码中的哪个代码呢?最简单的方法是反汇编
对vmlinux反汇编的命令为:objdump -dxh vmlinux > vmlinux.s
在查找地址0xfffffe0000080000:grep fffffe0000080000 vmlinux.s
可以看到linux的第一条指令为:x13, x18, #0x16,对应的符号是:.head.text efi_head _text
查看ARM64的head.S可以看到如下代码
/* * 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 + TEXT_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
/* * DO NOT MODIFY. Image header expected by Linux boot-loaders. */ #ifdef CONFIG_EFI efi_head: /* * This add instruction has no meaningful effect except that * its opcode forms the magic "MZ" signature required by UEFI. */ add x13, x18, #0x16 b stext #else b stext // branch to kernel start, magic .long 0 // reserved #endif |
HEAD为一个宏定义:#define __HEAD .section ".head.text","ax"
如此就都对应上了:
第一个地址为__HEAD下面的指令,即efi_head标号内容
第一个指令为add x13, x18,#0x16
紧接着就跳转到传统的启动地方b stext
Stext 最后会调用启动内核函数 start_kernel
其实,总结一句话,就是在head.S中,紧挨着_HEAD下面的就是第一条执行的指令
在看ARM32的
__HEAD ENTRY(stext) ……
|
所以,加载vmlinux后,第一个就开始执行stext
2. Vmlinux地址链接原理
前面讲了,vmlinux是按照vmlinux.lds链接的,vmlinux.lds是由vmlinux.lds.S生成的
看看vmlinux.lds.S就可以理解了
TEXT_OFFSET是在Makefile中定义的
vim ./arch/arm64/Makefile
可以是随机的,一般情况下定义为固定的0x80000
3. 地址的跳转
上电,CPU跳转到固定的一个地址执行UEFI代码
UEFI从vmlinux的头读取到入口地址为0xfffffe0000080000
因为已经使能过了MMU,所以找到虚拟地址0xfffffe0000080000,跳转到内核入口,开始加重内核