1 Bootloader
對於一般的ARM處理器,CPU上電或複位執行第一條指令所在地址,即第一段程式Bootloader的開始地址,Bootloader一般存於Nor-flash(XIP),支援晶片內執行。
Bootloader的功能可總結為:1)初始化CPU時鐘,記憶體,串口等。2)設定Linux啟動參數。3)載入Linux核心鏡像。Android源碼位於根目錄下的/bootable檔案夾。
系統正常啟動,運行Bootloader,初始化晶片,根據設定的啟動參數cmdline,載入Linux核心鏡像,將控制權交給核心。
系統在Bootloader模式下(非正常啟動模式),可使用fastboot, mmcboot等工具燒寫核心和檔案系統,順便提一下,Android手機分區一般分為核心區boot.img,系統區system.img,使用者資料區userdata.img,資料恢複區recovery.img等。
2 Linux核心鏡像
核心鏡像被載入到記憶體,首先進行自解壓,zImage, bzImage或uImage的頭部都內嵌有解壓縮程式,最終將核心解壓到記憶體的指定位置,開始運行核心。
3 啟動核心
源碼位於/kernel/init/main.c,線索可歸納為:啟動核心start_kernel() => 初始化Linux各大模組 + rest_init() => 開啟核心線程kthreadd和kernel_init() => 初始化裝置驅動程式do_basic_setup() + init_post() => 開啟第一個使用者進程init。
3.1 start_kernel()
源碼位於/kernel/init/main.c的start_kernel()函數,完成初始化Linux系統的進程管理,記憶體管理,檔案系統等工作,可以說個個都是重量級的工作。
這裡有必要解釋下核心選項,因為Linux各個子系統的初始化都建立在核心選項的解析之後。
parse_early_param();
parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param, &unknown_bootoption);
1) 核心選項的註冊
通過__early_parm(str, fn)或__setup(str, fn)宏來註冊。兩者都調用__setup_param宏實現,它將註冊的核心選項str所關聯的函數fn存放到.init.setup節。
2) 核心選項的解析
兩次註冊對應兩次解析,即parse_early_param()和parse_param(),解析時,會在__setup_start和__setup_end之間尋找核心選項,當識別有核心選項時,即會調用相應的處理函數。核心解析完後,各個子系統的初始化就可通過kernel_init()=>do_basic_setup()=>do_initcalls()來完成。
3.2 reset_init()
開啟核心線程kthreadd和kernel_init,kthreadd用來運行kthread_create_list全域鏈表中的kthread,然後建立idle線程來佔用掉cpu閒置時間片。
核心線程又叫守護進程,關於核心線程和Linux普通進程的區別,歸納為以下三點:
- 核心線程執行的是核心中的函數,而普通進程只有通過系統調用才能執行核心中的函數。
- 核心線程只運行在核心態,而普通進程既可以運行在使用者態,也可以運行在核心態。
- 因為核心線程指只運行在核心態,因此,它只能使用大於PAGE_OFFSET(3G)的地址空間。另一方面,不管在使用者態還是核心態,普通進程可以使用4GB的地址空間。
3.3 kernel_init()
此時與體系相關的部分已經初始化完成,do_basic_setup()開始初始化裝置,完成外設及驅動程式(直接編譯進核心的模組)的載入和初始化。
3.4 init_post()
開啟init使用者進程,所謂Android的啟動流程從這裡才剛剛開始。
Android部分的啟動流程參考http://blog.csdn.net/qianjin0703/article/details/8468312