天天看點

深入了解 GNU GRUB - 03 diskboot.S 3.1 diskboot.S執行時的環境 & 3.2 diskboot.S代碼結構

轉載注明出處(cppgp: http://blog.csdn.net/cppgp )

diskboot.S位于目錄boot/i386/pc/,最終生成diskboot.img。這部分指令被加載到0x8000~0x81FF。diskboot.img加載GRUB核心到0x8200開始的記憶體位置,并将系統控制權交給GRUB核心。用到的BIOS例程和boot.S中相同。是以本章隻描述如下内容:

  1)    diskboot.S執行時的環境

  2)    diskboot.S代碼結構

  3)    diskboot.S詳細注釋

  4)    diskboot.S模拟實作

本章最後也模拟一個diskboot的實作。

3.1 diskboot.S執行時的環境

boot.img跳轉到bootdisk.img之前,已經配置好堆棧和一些寄存器及參數值。是以diskboot假設如下條件已經是滿足的:

  1)    堆棧。SS和SP已配置好,有可用的堆棧。

  2)    寄存器DL。DL中儲存正确的引導驅動器。

  3)    寄存器SI。SI中儲存DAP位址。

  4)    寄存器DS。設定有正确的資料段DS。

事實上,在跳轉到diskboot.img之前,boot.img确實做好了配置。堆棧SS:SP=0x0000:0x2000;DL中包含正确的引導驅動器;SI指向DAP位址,是以-1(%si)确定磁盤讀取模式(LBA為1,CHS為0),如果是CHS讀取,磁盤CHS參數含有正确值;資料段寄存器DS=0。

3.2 diskboot.S代碼結構

diskboot.S生成512位元組機器碼,其中0x0~0x147共328位元組是指令,0x148~0x1FF共184位元組用來儲存資料集,每個資料集占用12位元組,可以儲存15個資料集。對于每個資料集,其中0~7位元組表示起始扇區數,在安裝時候指定;8~9位元組表示扇區數,10~11位元組表示目的段位址,都在生成鏡像(grub-mkimage)時确定。必須存在一個扇區數為0的資料集表示資料集讀取結束,是以可以存在14個有效資料集。目前隻使用了一個。我反解了一個安裝後的diskboot.img,顯示隻用了一個資料集,其值如下:

  起始扇區LBA位址: 0x0000 0000 0000 0002

  扇區數: 0x002e

  目的段位址: 0x0820

可知,grub核心的起始扇區是2扇區,扇區數46(0x2E==46),加載到0x8200起始記憶體處。這個grub核心的大小為46*512=23KiB。

diskboot.S壓棧首先儲存驅動器。輸出提示資訊”loading”,設定第一個資料集的位址,然後進入循環讀取資料。

根據boot.img中設定的讀取模式(LBA/CHS)和資料集中的起始扇區、扇區數、目的段位址,讀取資料并儲存到記憶體中(偏移量為0,是以目的段位址唯一确定記憶體位址)。每調用一次讀中斷,都提示一個”.”到終端,對于慢速儲存設備,使用者可以快速得到回報,以免在加載資料期間,使用者誤以為當機而進行強制性關機措施等。

在一個資料集内循環讀取時,循環标簽是LOCAL(setup_sectors),一個資料集完成後,設定處理上一資料集,并跳轉到LOCAL(bootloop)開始處理,如果這個資料集的扇區數為0,則跳轉到LOCAL(bootit),否則繼續資料集内的循環LOCAL(setup_sectors)。

資料讀取完畢後,執行LOCAL(bootit)處代碼,這裡将輸出提示資訊”/r/n”,還原DX寄存器(儲存引導驅動器),并以CS:IP=0x0000:0x8200跳轉執行,這裡正是kernel.img所在記憶體位址。

BIOS讀中斷過程(LBA/CHS)參考boot.S中的注釋,此處不再重複。