Llinux啓動流程

部分引用他人總結,如有侵權,請告知本人刪除
一、引導過程
    內核引導過程依次涉及的文件爲
    src/arch/i386/boot/bootsect.S
    src/arch/i386/boot/setup.S
    src/arch/i386/boot/compressed/head.S
    src/arch/i386/boot/compressed/misc.c
    src/arch/i386/boot/kernel/head.S
    src/init/main.c

1、傀儡引導扇區
    舊的內核,使用BIOS的啓動後加載啓動存儲介質的第一個扇區到0x7c00這個位置並交出執行權限的機制來引導內核。因此這個扇區也稱爲引導扇區,現在這個機制已棄之不用了,一般使用其他引導器引導,流行的有LILO(Linux Loader)和Grub,引導器通過在主引導記錄或分區引導記錄裏插入代碼來獲得CPU控制權,進而引導內核。
    傀儡引導扇區的代碼由文件src/arch/i386/boot/bootsect.S生成,一般情況下不會被執行,現在的功能僅爲輸出以下信息
    "Direct booting from floppy is no longer supported"
    "Please use a boot loader program instead"
    "Remove disk and press any key to reboot"
和存儲少量由引導器設置給內核的參數。

2、引導器
    引導器依據引導協議將bootsect裝載到地址0x9000:0000的位置,然後在bootsect中設置相關參數,由內核識別和使用。關於引導協議,參見內核文檔src/Documention/i386/boot.txt描述,引導器還將向內核傳遞其它信息,在後文介紹

3、探測系統資源
    探測系統可用資源的任務由src/arch/i386/boot/setup.S完成,引導器完成內核鏡像的裝載後,系統控制權轉移至該文件生成的二進制代碼。由於bootsect長512字節,該二進制代碼被加載至0x9020:0000的位置。
    此部分對系統的影響主要爲探測系統配置信息,並將探測到的信息存到相應的內存單元中,設置系統的全局描述符GDT和中斷描述符IDT,系統進入保護模式。
    
    源代碼依據作用可以分爲幾個模塊
    1、預留內存空間
        根據引導協議,這裏預留一部分空間用於內核和引導器交換信息。
    2、重置硬盤控制器
    3、完整性驗證
        用於判斷bzImage中的setup是否完整裝入,老的引導器默認setup佔用4個扇區4*512字節,對於大於4個扇區的setup可能不能完全裝入,所以setup執行後會立即進行完整性驗證。內核構建程序最後階段調用build程序生成內核鏡像bzImage,該程序在setup的實際大小超過4扇區時修改bootsect中的參數記錄setup的真實大小,以使新的引導器能完整裝入setup。
    4、引導能力判斷
        判斷引導程序是否有能力正確裝入內核鏡像,通過引導協議規定傳遞的參數,讓內核鏡像知道引導程序是否有能力正確裝載自己。與上一條不同,內核鏡像發展出不同的形式,zp_w_picpath構建生成的是小內核鏡像,被裝載到0x100,bzp_w_picpath生成的爲大內核鏡像,被裝載到0x100000。
    5、系統內存探測
        三種bios中斷都用一遍,預防部分主板不支持某些探測中斷
    6、探測其他信息
        包括硬盤信息,處理VOYAGER架構,檢測ps/2鼠標
    7、設置跳轉地址
        跳轉地址依據內核鏡像的類型而定,bzp_w_picpath生成的大內核的跳轉地址爲0x100000
    8、開啓A20地址線
        但仍不能訪問1MB以上的空間
    9、設置GDT、IDT
        內核會重設
    10、開啓保護機制
    11、控制權跳轉
    
4、解壓縮內核
    此部分代碼在src/arch/i386/boot/compressed/head.S中,由setup跳入。
    經過少量檢測後解壓縮內核代碼到臨時空間,然後判斷是否需要合併和搬移內核,此處爲大內核(參見附錄內核構建過程),需要搬移,所以先將搬移和合並內核的代碼先複製到0x10000處,然後跳轉到0x10000,該處代碼完成內核的合併和搬移到0x100000處,最後跳轉到該位置。
    
5、進入內核核心初始化
    此部分代碼在src/arch/i386/boot/kernel/head.S,由src/arch/i386/boot/compressed/head.S跳入。
    本部分開始涉及真正的內核,爲系統建立一個初步的頁表,啓用分頁機制,裝載新的GDT、IDT,設置棧指針寄存器%esp指向0號進程init_task內核態棧的棧低,最後跳轉位於文件src/init/main.c的系統初始化入口函數start_kernel()進行系統初始化工作。

二、初始化過程
    初始化過程由系統初始化進程init_task完成(也叫0號進程、idle進程,最後會變成空閒進程)。該進程完成系統內存管理子系統、進程管理子系統、中斷異常子系統、時間度量子系統等初始化工作。最後通過函數kernel_thread()創建一個名爲init的內核線程,然後0號進程調用調度器schedule(),釋放處理器的使用權,成爲系統空閒進程。
    內核線程init獲得處理器後,首先完成對稱多處理器系統中應用處理器的初始化,然後掛載系統的根文件系統,完成系統總線、網絡協議棧等的初始化。最後調用execve()開始執行用戶態程序/sbin/init,此時內核線程init轉換稱爲用戶進程。
    init進程會讀取/etc/inittab文件(debian沒有該文件,所有的配置信息都在/etc/event.d/目錄下),並依據此文件來進行初始化工作。/etc/inittab(參見附註)中有這麼一句"si::sysinit:/etc/rc.d/rc.sysinit",表明系統需要主動使用"rc.sysinit"這個shell腳本來設置系統環境。但這個文件的文件名在各個版本中是不一樣的,需要自行查看確認。
    /etc/rc.d/rc.sysinit的主要初始化流程爲:
(1)獲取網絡環境與主機類型。首先會讀取網絡環境設置文件"/etc/sysconfig/network",獲取主機名稱與默認網關等網絡環境。
(2)測試與載入內存設備/proc及usb設備/sys。除了/proc外,系統會主動檢測是否有usb設備,並主動加載usb驅動,嘗試載入usb文件系統。
(3)決定是否啓動SELinux。
(4)接口設備的檢測與即插即用(pnp)參數的測試。
(5)用戶自定義模塊的加載。用戶可以再"/etc/sysconfig/modules/*.modules"加入自定義的模塊,此時會加載到系統中。
(6)加載核心的相關設置。又一個文件"/etc/sysctl.conf",按這個文件的設置值配置功能。
(7)設置系統時間(clock)。
(8)設置終端的控制檯的字形。
(9)設置raid及LVM等硬盤功能。
(10)以方式查看檢驗磁盤文件系統。
(11)進行磁盤配額quota的轉換。
(12)重新以讀取模式載入系統磁盤。
(13)啓動quota功能。
(14)啓動系統隨機數設備(產生隨機數功能)。
(15)清楚啓動過程中的臨時文件。
(16)將啓動信息加載到"/var/log/dmesg"文件中。

結束rc.sysinit之後,將根據文件/etc/inittab中指定的運行級別,運行相應級別的啓動腳本,這些腳本負責控制一個後臺服務進程運行,每個運行級別的啓動腳本位於/etc/rc.d/rc<運行級別>.d目錄中。最後將執行用於用戶自定義啓動執行程序的腳本/etc/rc.d/rc.loacl。這個腳本開頭有一段表述可以清晰知道它的作用
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don’t
# want to do the full Sys V style init stuff.

完成系統所有的啓動任務後,linux會啓動終端或X-Window來等待用戶登錄

附:
一、內核鏡像構建過程
1、構建內核鏡像vmlinux
    根據內核配置文件src/.config中的配置,將系統核心組件和選項爲built-in的系統組件進行編譯,最終依據鏈接腳本arch/i386/kernel/vmLinux.lds生成沒有壓縮的內核核心src/vmLinux
2、對vmlinux進行壓縮
    用objcopy來刪除vmlinux多餘的信息,轉化爲raw binrary格式,然後使用gzip進行壓縮,最後使用鏈接器ld根據鏈接腳本arch/i386/boot/compressed/vmLinux.scr將壓縮生成的vmlinux.bin.gz轉化爲可鏈接的、可重定位格式個文件piggy.o。
3、構建包含解壓縮代碼的vmlinux鏡像
    用ld鏈接器將piggy.o和head.o和misc.o進行鏈接產生新的文件vmlinux,其中misc.o包含zlib算法的解壓縮代碼c語言的實現,head.o中包含的彙編代碼用於調用解壓縮程序設置參數和解壓縮過程使用的堆、棧。然後調用misc.o中的解壓縮代碼將壓縮的內核解壓縮。
4、對vmlinux進行再次刪減信息
    通過objcopy刪除vmlinux的多餘信息
5、構建內核鏡像bzImage
    利用內核鏡像構建工具build將bootsect(src/arch/i386/boot/bootsect.S)、setup(src/arch/i386/boot/setup.S)、vmlinux.bin三個文件依次存放到新建的bzImage文件中

二、/etc/inittab示例:
[root@linux ~]#vi /etc/inittab
# 設置系統啓動默認的運行等級設置項目
id:3:initdefault:

# 開始啓動運行等級的服務前,使用檢測與初始化系統環境的設置文件:
si::sysinit:/etc/rc.d/rc.sysinit

# 7個不同運行等級需要啓動的服務的腳本放置位置路徑:
10:0:wait:/etc/rc.d/rc 0
11:1:wait:/etc/rc.d/rc 1
12:2:wait:/etc/rc.d/rc 2
13:3:wait:/etc/rc.d/rc 3
14:4:wait:/etc/rc.d/rc 4
15:5:wait:/etc/rc.d/rc 5
16:6:wait:/etc/rc.d/rc 6

# 是否運行按下[ctrl]+[alt]+[del]就重新啓動的設置項目:
ca::ctrlatdel:/sbin/shutdown -t3 -r now

# 本機終端啓動的個數:
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6

# 在X Window(運行級別5)環境下啓動腳本設置項目
x:5:once:/etc/X11/prefdm -nodaemon

三、現代引導簡述
現代Linux大多采用獨立的引導程序來完成內核的加載,例如最常用的GRUB引導加載器。

GRUB加載流程
安裝在硬盤中的GRUB,完整的加載到內存中需要三步:
1.BIOS加載主引導記錄MBR(512字節)到內存0x7C00~0x7DFF位置,並跳轉執行0x7C00處指令。這些指令設置堆棧(SP=0x2000),探測硬盤/軟盤讀取模式(LBA/CHS)並保存。無論LBA或者CHS,都將加載另一扇區(該扇區位置在安裝過程中確定)代碼到內存0x7000位置,然後拷貝到內存0x8000處。跳轉至0x8000執行。
2.0x8000~0x81FF處存放第一步中加載的扇區。這部分代碼利用第一步中保存的讀取模式(mode)、以及堆棧(0x2000),以及安裝時指定的扇區位置和扇區數,循環加載GRUB剩餘部分到內存0x8200開始的位置。在循環加載時,對於每次迭代,都是先加載到內存0x7000處,然後拷貝到從0x8200開始的正確位置。
3.0x8200~x(x<0x10000) 處存放第二步中加載的指令。這部分指令是一個包含自解壓算法lzma的壓縮包(啓動和解壓縮部分是未壓縮的,對應爲startup.S和lzma_decode.S文件)。GRUB在這裏進入CPU保護模式,自解壓並釋放到0x10000開始內存處,解壓完成後再拷貝回原來位置,然後調用grub_main,初始化系統,加載模塊,並進入normal或者rescue模式。GRUB將根據配置文件或者用戶輸入,加載操作系統並運行。
4.如果需要啓動Linux,GRUB會根據相應的配置文件(grub.cfg或其他文件)將Linux的內核鏡像vmlinuz和initrd的臨時RAM盤加載到內存,並且按照multiboot引導規範傳遞相關內核參數等信息。
5.如果需要啓動如Windows等操作系統,可以使用兩種方案:①使用GRUB將原本Windows的MBR或者PBR加載到0x7c00,恢復到實模式,跳轉執行,重新完成系統的引導。②加載微軟的引導管理器ntldr或者bootmgr,直接完成微軟系統的啓動。

新的電腦已經採用了UEFI的電腦固件來代替傳統的BIOS,並且將使用多年的MBR式磁盤分區類型變更爲GPT磁盤類型。
兩種磁盤類型對比如下:
    MBR使用磁盤第一扇區中的64字節來保存磁盤分區表,僅支持4個主分區。由於歷史原因,在分區表中對分區大小描述使用了32位整數,所以支持的最大的硬盤容量爲2^32扇區,計2TB,現在看來,硬盤容量已經並超過了這個極限;
    GPT分區的第一個扇區和MBR類似,但是僅有一個主分區,這個主分區大小爲整個磁盤大小,分區ID爲(0xFE),這樣的目的是爲了防止不認識GPT的軟件將GPT磁盤當做未分區的磁盤。GPT磁盤的扇區2存放GPT磁盤信息,定義了GPT磁盤簽名、分區表大小、分區表位置、數據校驗和等信息。從3扇區開始的若干個扇區爲GPT分區表,每個分區表項128字節,其中包括分區起始扇區64位整數,分區結束扇區64位整數,因此GPT分區最大支持2^64個扇區,大小計8ZB大小的磁盤。從磁盤最後一扇區逆序向前,存放着GPT分區表的備份。
兩種計算機固件對比如下:
    BIOS使用匯編編寫,整個系統運行在x86的實模式下,存在着編程難度大、硬件尋址能力受限的限制。
    UEFI的代碼大部分使用C語言編寫。
    
    在BIOS啓動時,加載操作系統的步驟是通過加載磁盤的MBR來完成的。
    在UEFI啓動時,UEFI首先會初始化CPU和內存等,對於目前常見的UEFI_x64,UEFI將處理器初始化位64位模式,內存採用平坦模式。UEFI支持分區表和文件系統。UEFI將會從EFI(ESP)分區中加載/EFI/Boot/BOOTx64.efi作爲系統啓動文件。於此同時,UEFI支持在主板的儲存中儲存多個操作系統的引導管理器加載路徑,從而實現對多系統的支持。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章