這篇說一下電腦的啟動過程,主要是PC系統上Linux的啟動過程,嵌入式的稍微提到一下,這上面的東西不一定非常正確,大多從網上相關的技術文章中擷取的資訊,以及查閱了部分Linux的代碼。
總的來說這個文章定位於學習交流的性質,如果您覺得有不對的地方請一定指出來。
本文開始:
系統複位完成後,CPU從一個確定的地址開始執行代碼,PC就是從BIOS中開始執行。嵌入式CPU則是在複位後從一個位於快閃記憶體或者ROM的已知地址處開始執行,具體這個地址在哪兒應該去查閱所使用CPU的datasheet,一般上面都有說明。
下面接著說PC,在PC中,是從地址0xFFFF0處開始執行的,這個地址正好在BIOS的位址範圍之內,這裡是一條跳轉指令,跳轉到BIOS真正的啟動代碼處(此處更具體的過程應該查閱PC相關的架構設計文檔,Intel那幾大本應該有用)。BIOS一開始是加電自檢,即所謂POST過程,POST過程完成後,其代碼就被清除出記憶體了,然後是BIOS的第二階段,這個階段進行本地裝置的枚舉和初始化,這部分代碼在BIOS結束後仍然駐留記憶體,目標作業系統可以使用這些服務。BIOS最後會根據使用者的配置來尋找使用中的磁碟分割,這裡以硬碟為例。系統BIOS將讀取並執行硬碟上MBR處的代碼,這裡就進入了引導載入程式的部分,我們以當前大多數Linux發行版中使用的grub為例來進行說明。由於BIOS訪問的儲存空間有限,所以大多把引導載入程式分成兩個階段來進行引導。
GRUB(GNU GRand Unified Bootloader)
MBR(Master Boot Record),一共512位元組,位於磁碟的0道0柱面1扇區,即第一扇區。當MBR被載入到RAM後,BIOS將控制權交給了MBR,MBR中的主引導載入程式是一個512位元組的映像,其中包含程式碼和一個分區表。其中前446個位元組是第一階段引導載入程式,其中包含了可執行代碼和錯誤訊息文本,接下來64位元組是分區表,其中包含4個分區的記錄(每個記錄大小為16位元組)。MBR以兩個特殊位元組(0xAA55)結尾,用作MBR的有效性檢查。
第一階段引導載入程式的工作是尋找並載入第二階段的引導程式,它通過在分區表中尋找一個使用中的磁碟分割來實現這種功能,當找到一個使用中的磁碟分割的時候,它會掃描分區表中的其他分區,以確保它們是不活動的,當這個過程驗證完成後,就將使用中的磁碟分割的引導記錄從這個裝置中讀入RAM並執行。
在這裡要提到一下,grub存在一個1.5階段,之所以存在這個階段是因為在這裡grub可以識別檔案系統,能夠訪問/boot/grub目錄下的設定檔,而不是訪問磁碟塊的方式,這個在啟動以後可以看一下/boot/grub目錄下面有許多檔案系統格式+1.5這樣命名的檔案,比如在我的機器上就有:
fat_stage1_5
jfs_stage1_5
minix_stage1_5
e2fs_stage1_5
reiserfs_stage1_5
xfs_stage1_5
可以看到這裡包含了Linux常用的多種檔案系統。在grub1.5階段載入grub.conf之後,就可以看到啟動選項的介面了,這裡有許多可以配置的選項,鑒於本文的目的就不介紹了,可以參看grub的文檔說明。
當1.5引導載入程式載入運行以後,第二階段載入引導程式被載入到記憶體,並接管接下來的工作。它負責對檔案系統進行查詢定位核心和initrd映像的位置,並將它們載入到記憶體中,當這些映像準備完畢,階段2引導載入程式調用核心入口函數,引導載入程式釋放控制權,核心階段開始。
一般核心是一個壓縮過的核心映像,在解壓縮之前,先有少量代碼進行一些硬體設定,然後解壓核心並將其放入到高端記憶體中,如果有initrd的話,會將它移到記憶體中,並表明以後可用,然後調用核心,開始啟動核心引導過程。具體過程一般是從arch/i386/boot/head.S的start彙編函數開始執行,這個函數執行一些基本硬體設定,然後調用arch/i386/boot/compressed/head.S中的startup_32函數,該函數然後調用decompress_kernel解壓核心,然後調用位於arch/i386/kernel/head.S中的startup_32函數,由它進一步初始化硬體,包括記憶體等,然後調用start_kernel,啟動核心,最後由start_kernel函數在最後調用init啟動第一個使用者空間進程,然後開始使用者空間的啟動過程,直到整個系統啟動完畢。
就先如此吧,下次可以將代碼更好的結合一下。
參考資料:
[1] http://en.wikipedia.org/wiki/BIOS
[2] http://www.ibm.com/developerworks/cn/linux/l-linuxboot/
[3] http://www.ibm.com/developerworks/cn/linux/l-bootload.html