本文針對arm linux, 從kernel的第一條指令開(kāi)始分析,一直分析到進(jìn)入start_kernel()函數.
我們當前以linux-2.6.19內核版本作為范例來(lái)分析,本文中所有的代碼,前面都會(huì )加上行號以便于和源碼進(jìn)行對照.
例:
在文件init/main.c中:
00478: asmlinkage void __init start_kernel(void)
前面的"00478:" 表示478行,冒號后面的內容就是源碼了.
在分析代碼的過(guò)程中,我們使用縮進(jìn)來(lái)表示各個(gè)代碼的調用層次.
由于啟動(dòng)部分有一些代碼是平臺特定的,雖然大部分的平臺所實(shí)現的功能都比較類(lèi)似,但是為了更好的對code進(jìn)行說(shuō)明,對于平臺相關(guān)的代碼,我們選擇at91(ARM926EJS)平臺進(jìn)行分析.
另外,本文是以uncompressed kernel開(kāi)始講解的.對于內核解壓縮部分的code,在 arch/arm/boot/compressed中,本文不做討論.
一. 啟動(dòng)條件
通常從系統上電到執行到linux kenel這部分的任務(wù)是由boot loader來(lái)完成.
關(guān)于boot loader的內容,本文就不做過(guò)多介紹.
這里只討論進(jìn)入到linux kernel的時(shí)候的一些限制條件,這一般是boot loader在最后跳轉到kernel之前要完成的:
1. CPU必須處于SVC(supervisor)模式,并且IRQ和FIQ中斷都是禁止的;
2. MMU(內存管理單元)必須是關(guān)閉的, 此時(shí)虛擬地址對物理地址;
3. 數據cache(Data cache)必須是關(guān)閉的
4. 指令cache(Instruction cache)可以是打開(kāi)的,也可以是關(guān)閉的,這個(gè)沒(méi)有強制要求;
5. CPU 通用寄存器0 (r0)必須是 0;
6. CPU 通用寄存器1 (r1)必須是 ARM Linux machine type (關(guān)于machine type, 我們后面會(huì )有講解)
7. CPU 通用寄存器2 (r2) 必須是 kernel parameter list 的物理地址(parameter list 是由boot loader傳遞給kernel,用來(lái)描述設備信息屬性的列表,詳細內容可參考"Booting ARM Linux"文檔).
二. starting kernel
首先,我們先對幾個(gè)重要的宏進(jìn)行說(shuō)明(我們針對有MMU的情況):
宏 位置 默認值 說(shuō)明
KERNEL_RAM_ADDR arch/arm/kernel/head.S +26 0xc0008000 kernel在RAM中的的虛擬地址
PAGE_OFFSET include/asm-arm/memeory.h +50 0xc0000000 內核空間的起始虛擬地址
TEXT_OFFSET arch/arm/Makefile +137 0x00008000 內核相對于存儲空間的偏移
TEXTADDR