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