本文以x86為例,x86與嵌入式系統的區別在於多了乙個bios轉移到bootloader的過程。
linux核心引導的過程包含多個階段,接下來將依次解讀:
系統加電時,處理器會執行乙個位於已知位置處的**。pc中即我們熟知的bios,它儲存在主機板的快閃儲存器中。
bios從0xffff0處開始執行,首先執行post(加電自檢),檢查系統必備的引導裝置是否存在,如記憶體/磁碟等硬體裝置。然後bios進行本地裝置的列舉和初始化。bios由兩部分組成:post**和執行時服務,post完成後會被清出記憶體,而執行時服務會駐留於記憶體供目標作業系統呼叫服務。
然後bios讀取cmos中的引導裝置資訊來搜尋處於活動狀態的可引導裝置(可以是軟盤,cd-rom,硬碟上某一分割槽等),從引導裝置中讀取第乙個扇區,該扇區包含著引導程式。由上圖可知引導包含兩個階段。
當找到第乙個引導裝置後,第一階段的引導程式就會被裝載入ram並執行,該引導程式大小一般小於乙個扇區,其作用是載入第二階段的引導引導程式,mbr就是熟知的第一階段引導載入器。通常,linux都是從硬碟上引導的,其中主引導目錄(mbr)中包含主引導引導程式。mbr 是乙個 512 位元組大小的扇區,位於磁碟上的第乙個扇區中(0 道 0 柱面1 扇區)。當 mbr 被載入到 ram 中之後,bios 就會將控制權交給 mbr。
當第二階段的引導引導程式被裝入 ram 並執行時,通常會顯示乙個動畫螢幕,並將 linux 和乙個可選的初始 ram磁碟(臨時根檔案系統)載入到記憶體中。在載入映像時,第二階段的引導引導程式就會將控制權交給核心映像,然後核心就可以進行解壓和初始化了。在這個階段 中,第二階段的引導引導程式會檢測系統硬體、列舉系統鏈結的硬體裝置、掛載根裝置,然後載入必要的核心模組。
在引導程式grub被bios裝入到記憶體並獲得控制權後,讀取/boot/grub.conf中的引導列表選擇預設要啟動的核心映象bzimage。根據bzimage中前512byte的bootsect中的setup,vmlinux.bin所佔扇區的大小,以及核心是否為大核心映象將bootsect->0x00090000, setup->0x00090020, vmlinux.bin -> 0x00100000(big) 0x00010000(else)。
將核心搬到相應的位址後,引導程式跳轉到實體地址0x00090020,即setup所在的實體地址,開始執行setup**。
接下來會詳細介紹下兩階段的引導過程及有關grub的知識。
mbr 中的主引導引導程式是乙個 512 位元組大小的映像,其中包含程式**和乙個小分割槽表(參見圖 2)。前446個位元組是主引導引導程式,其中包含可執行**和錯誤訊息文字。接下來的 64 個位元組是分割槽表,其中包含 4 個分割槽的記錄(每個記錄的大小是 16 個位元組)。mbr 以兩個特殊數字的位元組(0xaa55)結束。這個數字會用來進行mbr的有效性檢查。
主引導引導程式的工作是查詢並載入次引導引導程式(第二階段)。它是通過在分割槽表中查詢乙個活動分割槽來實現這種功能的。當找到乙個活動分割槽時,它會掃瞄分 區表中的其他分割槽,以確保它們都不是活動的。當這個過程驗證完成之後,就將活動分割槽的引導記錄從這個裝置中讀入 ram 中並執行它。
次引導引導程式(第二階段引導引導程式)可以更形象地稱為核心引導程式。這個階段的任務是載入 linux核心和可選的初始 ram 磁碟。
在 x86 pc 環境中,第一階段和第二階段的引導引導程式一起稱為 linux loader(lilo)或 grand unified bootloader(grub)。由於 lilo 有一些缺點,而 grub 克服了這些缺點,因此下面讓我們就來看一下 grub。
該階段由檔案seup.s生成的**塊進行系統裝置的探索,將探測到的相關資訊儲存到記憶體位址中,在系統最終初始化時由系統使用。探測完成後跳轉到實體地址0x00100000,開始執行由/src/arch/i386/compressed/head.s生成的**塊。
該階段由head.s生成的**塊執行,0x00100000處及startup_32處,該彙編**為呼叫c語言函式設定相應的引數及棧指標後呼叫c函式decompress_kernel對壓縮的核心進行解壓縮,並將解壓的核心片段放置到兩個不同物理記憶體區域中,然後head.s中複製move,搬移的**段移動到實體地址0x00010000處。然後跳轉到該位址,執行該**塊。
該階段執行複製到實體地址0x00010000的搬遷**,該部分的搬遷**將位於兩個物理區域的解壓縮核心**片段移動到實體地址0x00100000.
執行完move後,跳到0x00100000,執行src/arch/i386/kernel/head.s中的startup_32的**段,注意與上面startup_32的不同,開始執行系統核心的初始化。
在startup_32函式(也就是系統初始化程序init_task,也叫0號程序,idle程序)中。該程序完成了系統記憶體管理子系統/程序管理子系統,中斷異常子系統,時間度量子系統等初始化工作.會對頁表進行初始化,並啟用記憶體分頁功能,為fpu檢測cpu型別,呼叫start_kernel函式,執行與體系結構無關的linux核心部分.
通過呼叫 start_kernel,會呼叫一系列初始化函式來設定中斷,執行進一步的記憶體配置,並載入初始 ram 磁碟。
注:在核心引導過程中,初始 ram 磁碟(initrd)是由階段 2 引導引導程式載入到記憶體中的,它會被複製到ram中並掛載到系統上。這個initrd會作為ram中的臨時根檔案系統使用,並允許核心在沒有掛載任何物理磁碟的情況下完整地實現引導。由於與外圍裝置進行互動所需要的模組可能是initrd的一部分,因此核心可以非常小,但是仍然需要支援大量可能的硬體配置。在核心引導之後,就可以正式裝備根檔案系統了(通過 pivot_root):此時會將 initrd 根檔案系統解除安裝掉,並掛載真正的根檔案系統。initrd 函式讓我們可以建立乙個小型的 linux核心,其中包括作為可載入模組編譯的驅動程式。這些可載入的模組為核心提供了訪問磁碟和磁碟上的檔案系統的方法,並為其他硬體提供了驅動程式。由於根檔案系統是磁碟上的乙個檔案系統,因此 initrd函式會提供一種啟動方法來獲得對磁碟的訪問,並掛載真正的根檔案系統。在乙個沒有硬碟的嵌入式環境中,initrd 可以是最終的根檔案系統,或者也可以通過網路檔案系統(nfs)來掛載最終的根檔案系統。
最後呼叫kernel_thread()建立乙個名為init的核心執行緒,然後0號程序呼叫排程器schedule(),釋放了處理器的使用權,成為了系統的idle程序。
在核心執行緒init獲得處理器後,首先完成對稱多處理器系統中應用處理器的初始化;然後掛載系統的根檔案系統,完成系統匯流排/網路協議棧等的初始化;最後通過呼叫execve()開始執行使用者態程式/sbin/init,此時核心執行緒init轉換成了使用者程序。/sbin/init是系統中所有程序(除idle程序)的祖先,它首先讀取系統的配置檔案/etc/inittab,根據該配置檔案完成系統的最終初始化.
這篇文章也是綜合了我看到的多個資料,每個資料都或多或少的有些遺漏,所以綜合起來,希望能全面。
接下來,我將介紹些有關kernel其他方面的知識。
Linux 2 6 核心引導過程分析
本文以x86為例,x86與嵌入式系統的區別在於多了乙個bios轉移到bootloader的過程。linux核心引導的過程包含多個階段,接下來將依次解讀 系統加電時,處理器會執行乙個位於已知位置處的 pc中即我們熟知的bios,它儲存在主機板的快閃儲存器中。bios從0xffff0處開始執行,首先執行...
Linux2 6核心啟動分析
我們已知u boot的終極目的是啟動核心,那麼核心啟動的開始必定是u boot傳入的引數。開啟armlinux.c 發現有一行的 為 thekernel 0,bd bi arch number,bd bi boot params 帶入三個引數 第乙個引數是0,第二個引數是機器id,第三個引數是引數所...
Linux 2 6核心編譯,核心公升級
本文描述了在fc8下公升級linux核心為2.6.25的詳細步驟.1.首先從如下 得到linux 2.6.25.2.然後在 usr src下untar這個包.tar xjfv linux 2.6.25.tar.bz2 3.配置核心 cd usr src linux 2.6.25 make mrpro...