歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> Linux啟動過程學習

Linux啟動過程學習

日期:2017/3/1 12:04:40   编辑:關於Linux

該學習過程是一個Linux從主引導記錄到第一個用戶空間程序的指導.
啟動一個Linux系統的過程包含一系列步驟.但是無論你是啟動一個標准的X86桌面或嵌入式PowerPC,大部分流程是相似的.該文章探索Linux從最初的引導程序到開啟第一個用戶空間程序的過程.同時,我們也將會學到其他一些啟動相關的課題,例如引導裝載程序,內核解壓縮,最初的RAM和其他Linux啟動的元素.

早期,引導啟動一個計算機意味著提供一個包含啟動程序或使用前面板地址/數據/控制開關手動加載一個啟動程序的紙帶.現在的計算機裝備了設備來簡化啟動過程,但是並沒有使它變得簡單.

我們先從高層視角開始看Linux啟動.然後我們將會看每一步執行了哪些工作.

概覽


下面的圖片給了你20000英尺的視角:

這裡寫圖片描述vcb0tq8su/Kxu9bY1sMstKbA7cb31rTQ0M6709rWuLaozrvWw7XEtPrC6y7U2rj2yMu8xsvju/rW0CzV4rj2zrvWw77NzrvT2rv5sb7K5MjrL8rks/bPtc2zKEJJT1Mp1tAsQklPU7G7tOa0otTaxLiw5cnPtcRmbGFzaMTatObW0C7Ou9Pax7bI68q9z7XNs8nPtcTW0NHrtKbA7cb3KENQVSm199PD1tjWw8/ywb/AtMb0tq/Ou9PauePOqsjL1qq1xLXY1rfJz7XEs8zQ8iy4w7PM0PLOu9PaZmxhc2gvUk9N1tAu1NrIzrrOx+m/9s/CLL3hufu2vMrH0rvR+bXELtLyzqpQQ8zhuanBy9Xiw7S24LXEwem77tDULEJJT1Ox2NDrvva2qMTE0ru49snosbjKx9PD09rG9LavtcS68tGhyeixuC6688PmztLDx72rz+rPuL2yveIuPC9wPg0KPHA+tbHSu7j2xvS2r8nosbixu7eiz9YstdrSu73Xts5ib290IGxvYWRlcrG7vNPU2LW9UkFN1tDIu7rz1rTQ0C7V4rj2xvS2r9ew1NjG97OktsjJz8nZ09o1MTLX1r3aKNK7uPbJyMf4tcS089ChKSzL+7XEuaTX977NysfIpbzT1Ni12rb+vde2zrXEYm9vdCBsb2FkZXIuPC9wPg0KPHA+tbG12rb+vde2zmJvb3QgbG9hZGVysbu809TYtb1SQU3W0LKisbvWtNDQtcTKsbryLMb0tq+2r7utz9TKvtTaxsHEu8nPLExpbnV4us2/ydGhtcTX7rP1tcRSQU20xcXMKMHZyrG1xHJvb3TOxLz+z7XNsymxu7zT1Ni1vcTatObW0C61sb61z/Gxu9ew1Nostdq2/r3Xts5ib290IGxvYWRlcr2rv9jWxrSrtd24+MTausu+tc/xLMi7uvPE2rrLvrXP8bG7veLRubKisbuz9cq8u68u1NrV4rj2vde2ziy12rb+vde2zmJvb3QgbG9hZGVyvOyy6c+1zbPTsrz+LMHQvtnP4LnY07K8/snosbgsudLU2Lj5yeixuCzIu7rzvNPU2LHY0qq1xMTausvEo7/pLrWxzeqzydXi0Km5pNf31q668yy12tK7uPbTw7unv9W85LPM0PIoaW5pdCm/qsb0LLjfsuPPtc2zs/XKvLuvsbvUy9DQLjwvcD4NCjxwPtXivs3Kx7zyw/e1xMPoyvbBy0xpbnV4tcTG9Lavuf2zzC7P1tTaztLDx8nuyOvMvcv3TGludXjG9Lavuf2zzLXEz7i92i48L3A+DQo8aDIgaWQ9"系統開啟">系統開啟


系統啟動階段取決於引導Linux系統上的硬件。在一個嵌入式平台上,一個引導啟動環境是在系統被上電或重置之後啟用的.例子包含U-Boot,RedBoot,和來自Lucent的MicroMonitor.嵌入的平台被裝備一個啟動監視器.這些程序位於目標硬件上的flash內存中的特定區域,並且提供下載Linux內核鏡像到flash內存並且運行它的方法.除了擁有保存和啟動Linux內核鏡像之後,這些啟動監視器運行一些系統測試和硬件初始化.在一個嵌入式的目標平台中,這些啟動見識其通常覆蓋第一和第二階段的boot loader.

提取MBR
為了查看你的MBR的內容,使用下面這個命令:

# dd if=/dev/hda of=mbr.bin bs=512 count=1
# od -xa mbr.bin

dd命令,需要在root模式下運行,從/dev/hda中讀取第一個512字節然後將他們寫入到mbr.bin文件中.od命令以hex和ASCII格式打印二進制文件.

在PC中,啟動Linux從BIOS中的地址0XFFFF0處開始.BIOS的第一步就是啟動自我檢測(POST).POST的工作就是運行硬件檢查.BIOS的第二步就是本地設備列舉和初始化.

對於給定的BIOS功能的不同用法,BIOS由兩部分組成:POST代碼和運行時服務.在POST完成之後,它從內存中被清除,但是BIOS運行時服務被保留下來,並且在目標操作系統中都是可用的.

為了啟動一個操作系統,BIOS運行時按照CMOS定義的優先級的順序尋找那些既活躍又可啟動的設備.一個啟動設備可以是軟盤,一個CD-ROM,位於硬盤上的分區,位於網絡上的設備或者甚至是USB閃存棒.

通常情況下,Linux從硬盤中被啟動,在硬盤上的MBR包含基本的boot loader.MBR是一個512字節的扇區,位於磁盤的第一扇區(0磁頭,0磁道的第一個扇區).

階段1 boot loader


位於MBR中的基本boot loader是512字節的鏡像,包含程序源碼和一個小的分區表.前446字節是基本boot loader,其包含可執行嗲嗎和錯誤信息文本.後面64字節是分區表,其包含為每四個分區生成的記錄.MBR以兩個字節結尾,這兩個字節被定義成魔鬼數字(0XAA55).魔鬼數字位MBR的驗證檢查服務.

下面這張圖就是MBR的解剖圖:

這裡寫圖片描述

基本boot loader的工作就是寸照和加載第二boot loader(第二階段).它通過查詢分區表上的可用分區來工作.當它發現一個活躍的分區,他遍歷位於表上的剩下的分區來確保他們是不活躍的.當這個被驗證之後,活躍的分區上的啟動記錄從設備中被讀取到RAM中運行.

階段2 boot loader


第二個或者說是第二階段,boot loader可以更形象的稱為內核加載器.在這個階段的任務就是加載Linux內核和可選的最初的RAM磁盤.

GRUB階段 boot loaders:
/boot/grub目錄包含階段1,階段1.5和階段2的boot loaders,和交替加載器的數量一樣.

第一和第二階段的boot loaders 聯合起來被稱為Linux Loader(LILO)或是GRUB.因為LILO有一些缺點而在GRUB中被改正了,所以我們研究GRUB.

關於GRUB最棒的事情就是它包含對Linux文件系統的了解.而不是像LILO似的使用位於磁盤上的原生扇區,GRUB可以從ext2或ext3文件系統中加載一個Linux內核.它通過將二階段boot loader分解成三階段boot loader來實現的.階段1(MBR)啟動階段1.5 boot loader,該階段理解包含Linux內核鏡像的特殊文件系統.例子包括reiserfs_stage1_5(從Reiser日志文件系統中加載)或者是e2fs_stage1_5(從ext2或ext3文件系統中加載).當階段1.5 boot loader在加載並且運行的時候,階段2 boot loader就可以被加載了.

隨著階段2被加載,GRUB可以展示一個可用內核列表(定義在/etc/grub.conf,是從/etc/grub/menu.lst和/etc/grub.conf的軟連接).你可以選擇一個內核,你甚至可以使用其他內核選項修改它.你也可以使用命令行腳本通過啟動進程提高人工控制.

伴隨著第二階段的boot loader運行在內存中,文件系統被查詢,並且默認的內核鏡像和initrd鏡像被加載到內存中.隨著鏡像被准備好,階段2的boot loader調用內核鏡像.

內核


在GRUB中手動啟動
通過GRUB的命令行,你可以啟動一個帶有命名的`initrd`的特定內核.就像下面這樣:

grub> kernel /bzImage-2.6.14.2
    [Linux-bzImage, setup=0x1400, size=0x29672e]
grub> initrd /initrd-2.6.14.2.img
    [Linux-initrd @ 0x5f13000, 0xcc199 bytes]
grub> boot
Uncompressing Linux... OK, booting the kernel.

如果你不知道要啟動的內核的名稱,進需要輸入'/',然後按下Tab鍵即可.GRUB將會顯示內核和initrd鏡像的列表.

隨著內核鏡像運行在內存中以及階段2的boot loader給予的控制,內核階段開始了.內核鏡像不是一個可執行內核,而是一個壓縮的內核鏡像.這是一個zImage(壓縮的鏡像,小於512字節)或者是一個bzImage(大壓縮鏡像,大於512字節),他們是之前使用zlib被壓縮的.在這個內核鏡像的開頭部分是一個例程,進行一些硬件設置然後解壓內核鏡像,並將他放到高內存中.如果一個最初的RAM磁盤是可用的,則這個例程便會將他移到內存中,並且標記後期使用.然後例程調用內核,內核啟動開始了.

當bzImage被調用,程序便會從位於開始例程中的./arch/i386/boot/head.S開始運行.這個例程做一些基本的硬件設置和調用位於./arch/i386/boot/compressed/head.S中的startup_32例程.這個例程設置一個基本的環境(棧等),並且清空符號開始的塊(BSS).然後內核通過對函數decompress_kernel(位於./arch/i386/boot/compressed/misc.c)的調用而被解壓.當內核被解壓的內存的時候,他便會被調用.這是另外一個startup_32函數,但是該函數位於./arch/i386/kernel/head.S中.

在新的startup_32函數中(也被稱作交換器或0進程),頁表被初始化,內存頁變為可用.帶有任何就可選FPU的CPU的類型被檢測,並被存儲後面使用.start_kernel函數接著被調用(init/main.c),這會將你帶到非特異性Linux內核的體系結構.這就是本質上Linux 內核的main函數.

下面是Linux內核 i386啟動的主要函數流:

這裡寫圖片描述

隨著對start_kernel函數的調用,一系列初始化函數被調用來設置中斷,運行內存配置,加載最初的RAM磁盤.最後,一個對kernel_thread(位於arch/i386/kernel/process.c)的調用開始了init函數,這是第一個用戶空間進程.最後,idle進程被啟動,並且調度器可以進行控制了(在調用cpu_idle之後).伴隨著中斷的可用,搶先的調度器控制來提供多任務.

在內核啟動期間,被第2階段 boot loader 加載到內存中的初始化RAM磁盤(initrd)被復制到RAM中,並被掛載.這個initrd作為一個位於RAM中的臨時根文件系統服務,並且內核在沒有任何物理磁盤掛在的情況下全啟動.自從服務於外部設備的必要內核模塊可以是initrd的一部分之後,內核便可以非常小,但是之中支持大量的硬件配置.在內核引導之後,就可以正式裝備根文件系統了(圖那個過pivot_root),此時會將initrd根文件系統卸載掉,並掛載真正的根文件系統.

initrd函數允許你創建一個驅動被編譯為可加載模塊的微型Linux內核.這些可加載模塊給了內核訪問磁盤和位於磁盤上的文件系統的方法,就像是其他硬件資源的驅動一樣.因為根文件系統是位於磁盤上的一個文件系統,initrd函數提供了啟動引導程序訪問磁盤和掛載真正的根文件系統的方法.在沒有硬盤的嵌入式平台中,initrd可以是最終的根文件系統,或者是最終的根文件系統可以通過網絡文件系統(NFS)被掛載.

Init


在內核被啟動和初始化之後,內核開啟第一個用戶空間應用.這是第一個使用標准C庫編譯被調用的程序.在這個進程這個點之前,沒有標准C程序被執行.

在桌面Linux系統中,第一個啟動的應用程序通常是/sbin/init.但也不必是它.很少有嵌入式系統需要init提供的廣泛的初始化(就像通過/etc/inittab配置一樣).在大多數情況下,你可以調用一個簡單的shell腳本來啟動必要的嵌入式應用.

總結


很像Linux本身,Linux啟動進程是非常靈活的,支持大量的處理器和硬件平台.在開始的時候,加載的boot loader提了一個簡單的方式啟動Linux.LILO boot loader擴展了啟動能力,但是缺少文件系統意識.最新的boot loader實現,例如GRUB,允許Linux從文件系統中啟動.

Copyright © Linux教程網 All Rights Reserved