操做系統實現(一):從Bootloader到ELF內核(轉載)

原文連接:html

http://www.cppblog.com/airtrack/archive/2014/10/30/208729.html數據結構

Bootloader

咱們知道計算機啓動是從BIOS開始,再由BIOS決定從哪一個設備啓動以及啓動順序,好比先從DVD啓動再從硬盤啓動等。計算機啓動後,BIOS根據配置找到啓動設備,並讀取這個設備的第0個扇區,把這個扇區的內容加載到0x7c00,以後讓CPU從0x7c00開始執行,這時BIOS已經交出了計算機的控制權,由被加載的扇區程序接管計算機。
這第一個扇區的程序就叫Boot,它通常作一些準備工做,把操做系統內核加載進內存,並把控制權交給內核。因爲Boot只能有一個扇區大小,即512字節,它所能作的工做頗有限,所以它有可能不直接加載內核,而是加載一個叫Loader的程序,再由Loader加載內核。由於Loader不是BIOS直接加載的,因此它能夠突破512字節的程序大小限制(在實模式下理論上能夠達到1M)。若是Boot沒有加載Loader而直接加載內核,咱們能夠把它叫作Bootloader。
Bootloader加載內核就要讀取文件,在實模式下能夠用BIOS的INT 13h中斷。內核文件放在哪裏,怎麼查找讀取,這裏牽涉到文件系統,Bootloader要從硬盤(軟盤)的文件系統中查找內核文件,所以Bootloader須要解析文件系統的能力。GRUB是一個專業的Bootloader,它對這些提供了很好的支持。
對於一個Toy操做系統來講,能夠簡單處理,把內核文件放到Bootloader以後,即從軟盤的第1個扇區開始,這樣咱們能夠不須要支持文件系統,直接讀取扇區數據加載到內存便可。

實模式到保護模式

咱們知道Intel x86系列CPU有實模式和保護模式,實模式從8086開始就有,保護模式從80386開始引入。爲了兼容,Intel x86系列CPU都支持實模式。現代操做系統都是運行在保護模式下(Intel x86系列CPU)。計算機啓動時,默認的工做模式是實模式,爲了讓內核能運行在保護模式下,Bootloader須要從實模式切換到保護模式,切換步驟以下:
  1. 準備好GDT(Global Descriptor Table)
  2. 關中斷
  3. 加載GDT到GDTR寄存器
  4. 開啓A20,讓CPU尋址大於1M
  5. 開啓CPU的保護模式,即把cr0寄存器第一個bit置1
  6. 跳轉到保護模式代碼
GDT是Intel CPU保護模式運行的核心數據結構,全部保護模式操做的數據都從GDT表開始查找,這裏有GDT的詳細介紹。
GDT中的每個表項由8字節表示,以下圖:


其中Access Byte和Flags以下圖:


這裏
是詳細說明。
GDTR是一個6字節的寄存器,有4字節表示GDT表的基地址,2字節表示GDT表的大小,即最大65536(實際值是65535,16位最大值是65535),每一個表項8字節,那麼GDT表最多能夠有8192項。
實模式的尋址總線是20bits,爲了讓尋址超過1M,須要開啓A20,能夠經過如下指令開啓:
    in al, 0x92
    or al, 2
    out 0x92, al
把上述步驟完成以後,咱們就進入保護模式了。在保護模式下咱們要使用GDT經過GDT Selector完成,它是GDT表項相對於起始地址的偏移,所以它的值通常是0x0 0x8 0x10 0x18等。

ELF文件

Bootloader程序是原始可執行文件,若是程序由彙編寫成,彙編編譯器編譯生成的文件就是原始可執行文件,也可使用C語言編寫,編譯成可執行文件以後經過objcopy轉換成原始可執行文件,這篇文章介紹了用C語言寫Bootloader。
那麼內核文件是什麼格式的呢?跟Bootloader同樣的固然能夠。內核通常使用C語言編寫,每次編譯連接完成以後調用objcopy是能夠的。咱們也能夠支持通用的可執行文件格式,ELF(Executable and Linkable Format)便是一種通用的格式,它的維基百科
ELF文件有兩種視圖(View),連接視圖和執行視圖,以下圖:



連接視圖經過Section Header Table描述,執行視圖經過Program Header Table描述。Section Header Table描述了全部Section的信息,包括所在的文件偏移和大小等;Program Header Table描述了全部Segment的信息,即Text Segment, Data Segment和BSS Segment,每一個Segment中包含了一個或多個Section。
對於加載可執行文件,咱們只需關注執行視圖,即解析ELF文件,遍歷Program Header Table中的每一項,把每一個Program Header描述的Segment加載到對應的虛擬地址便可,而後從ELF header中取出Entry的地址,跳轉過去就開始執行了。對於ELF格式的內核文件來講,這個工做就須要由Bootloader完成。Bootloader支持ELF內核文件加載以後,用C語言編寫的內核編譯完成以後就不須要objcopy了。
相關文章
相關標籤/搜索