2017年11月23日 星期四

ARM64 Linux的啟動分析

ARM64 Linux的啟動分析

原文 https://blog.csdn.net/leoufung/article/details/50582640
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的
__HEADENTRY(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,跳轉到內核入口,開始加重內核

沒有留言: