BIOS 時期
計算機啓動,主板上電,可這個時候沒有操作系統,內存也是空的,CPU 該怎麼辦呢?
在主板上,有一個東西叫 ROM(Read Only Memory,只讀存儲器),上面早就固化了一些初始化的程序,也就是 BIOS(Basic Input and Output System,基本輸入輸出系統)。如下圖
此時處於實模式,20位的地址總線可訪問1M的內存地址空間
1M 空間最上面的 0xF0000 到 0xFFFFF 這 64K 映射給 ROM
當電腦剛加電的時候,會做一些重置的工作,將 CS 設置爲 0xFFFF,將 IP 設置爲 0x0000,03中有講起始地址 *16+ 偏移量” 湊夠20位,所以第一條指令就會指向 0xFFFF0,正是在 ROM 的範圍內,這裏,有一個 JMP 命令會跳到 ROM 中做初始化工作的代碼,BIOS 開始進行初始化的工作
BIOS的初始化工作有哪些呢?
1、檢查一下系統的硬件是不是都好着
2、要建立一箇中斷向量表和中斷服務程序,要用鍵盤和鼠標,它們都要通過中斷進行的
3、在顯示器上顯示一些字符,在內存空間映射顯存的空間
bootloader 時期
BIOS完成了初始化工作,但BIOS如何找到操作系統並加載運行起來呢?Linux 裏面有一個工具,叫 Grub2,全稱 Grand Unified Bootloader Version 2。
操作系統一般都安裝在硬盤上,在BIOS中也會發現一個啓動盤的選項。啓動盤的特點:在第一個扇區,佔 512 字節,而且以 0xAA55 結束。在 512 字節以內會啓動相關的代碼。
啓動相關的那些代碼是通過Grub2放進去的。
通過 grub2-mkconfig -o /boot/grub2/grub.cfg 來配置系統啓動的選項,cat /boot/grub2/grub.cfg | more 查看grub.cfg配置信息,如下圖
grub.cfg裏面的選項會在系統啓動的時候,成爲一個列表。最終顯示出來的結果如圖
那麼Grub2是如何將啓動程序安裝到相應的位置
使用 grub2-install /dev/sda
1、grub2 第一個要安裝的就是 boot.img。
- boot.S 編譯而成,一共 512 字節,正式安裝到啓動盤的第一個扇區。這個扇區通常稱爲MBR(Master Boot Record,主引導記錄 / 扇區)。
- BIOS 完成任務後,會將 boot.img 從硬盤加載到內存中的 0x7c00 來運行
2、boot.img加載 grub2 的另一個鏡像 core.img
core.img 由 lzma_decompress.img、diskboot.img、kernel.img 和一系列的模塊組成,功能比較豐富,能做很多事情。
a、boot.img 先加載core.img 的第一個扇區diskboot.img,對應的代碼是 diskboot.S,boot.img 將控制權交給 diskboot.img
b、diskboot.img 的任務就是將 core.img 的其他部分加載進來
- 先是解壓縮程序 lzma_decompress.img,再往下是 kernel.img,最後是各個模塊 module 對應的映像。kernel.img,不是 Linux 的內核,而是 grub 的內核。
- lzma_decompress.img 對應的代碼是 startup_raw.S,用於解壓壓縮過的kernel.img
- lzma_decompress.img 還做了一個重要的決定,就是調用 real_to_prot,切換到保護模式,如果是32位系統地址總線變爲32位,尋址空間由1M變爲4G
從實模式切換到保護模式
切換到保護模式要幹很多工作,大部分工作都與內存的訪問方式有關。第一項是啓用分段,就是在內存裏面建立段描述符表,將寄存器裏面的段寄存器變成段選擇子,指向某個段描述符,這樣就能實現不同進程的切換了。第二項是啓動分頁。
切換保護模式的函數 DATA32 call real_to_prot 會打開 Gate A20,也就是第 21 根地址線的控制線,尋址空間由1M變爲4G。
對壓縮過的 kernel.img 進行解壓縮,然後跳轉到 kernel.img 開始運行。
- kernel.img 對應的代碼是 startup.S 以及一堆 c 文件,在 startup.S 中會調用 grub_main,這是 grub kernel 的主函數。
- grub_main這個函數裏面,grub_load_config() 開始解析上面grub.conf 文件裏的配置信息。
- grub_main 最後會調用 grub_command_execute (“normal”, 0, 0),最終會調用 grub_normal_execute() 函數,這個函數裏面的grub_show_menu() 會顯示出讓你選擇的哪個操作系統的列表。
- 從列表中啓動某個操作系統,就要開始調用 grub_menu_execute_entry() ,開始解析並執行你選擇的那一項。
裏面的 linux16 命令,表示裝載指定的內核文件,並傳遞內核啓動參數。grub_cmd_linux() 函數會被調用,用於檢查linux內核鏡像頭部的一些數據結構,如果通過則讀取整個內核鏡像到內存
最後會調用 grub_command_execute (“boot”, 0, 0) 纔開始真正地啓動內核。
參考資料:
趣談Linux操作系統(極客時間)鏈接:
http://gk.link/a/10iXZ
歡迎大家來一起交流學習