一步一步學linux操作系統: 04 從BIOS到bootloader

BIOS 時期

計算機啓動,主板上電,可這個時候沒有操作系統,內存也是空的,CPU 該怎麼辦呢?

在主板上,有一個東西叫 ROM(Read Only Memory,只讀存儲器),上面早就固化了一些初始化的程序,也就是 BIOS(Basic Input and Output System,基本輸入輸出系統)。如下圖

圖片來自極客時間趣談linux操作系統

此時處於實模式,20位的地址總線可訪問1M的內存地址空間
圖片來自極客時間趣談linux操作系統
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.imgdiskboot.imgkernel.img 和一系列的模塊組成,功能比較豐富,能做很多事情。
圖片來自極客時間趣談linux操作系統

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
歡迎大家來一起交流學習

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章