《一個操作系統的實現》(四):讓操作系統走進保護模式

一個操作系統從開機到開始運行,大致經歷“引導->加載內核入內存->跳入保護模式->開始執行內核”這樣一個過程。

幾乎所有的文件系統都會把磁盤劃分爲若干層次以方便組織和管理,這些層次包括扇區(磁盤上的最小數據單元),簇(一個或多個扇區),分區(通常指整個文件系統)。

對於FAT12文件系統來說,第0號扇區爲引導扇區,其中有一個叫做BPB(BIOS Parameter Block)的數據結構,格式如下表,其中BPB_開頭的屬於BPB,其餘的只是引導扇區的一部分。

FAT12引導扇區的格式
名稱 偏移 長度 內容 Orange's的值
BS_jmpBoot 0 3 一個短跳轉指令 jmp LABEL_START
nop
BS_OEMName 3 8 廠商名 'ForrestY'
BPB_BytesPerSec 11 2 每扇區字節數 0x200
BPB_SecPerClus 13 1 每簇扇區數 0x1
BPB_RsvdSecCnt 14 2 Boot記錄佔用多少扇區 0x1
BPB_NumFATs 16 1 共有多少FAT表 0x2
BPB_RootEntCnt 17 2 根目錄文件最大值 0xE0
BPB_TotSec16 19 2 扇區總數 0xB40
BPB_Media 21 1 介質描述符 0xF0
BPB_FATSz16 22 2 每FAT扇區數 0x9
BPB_SecPerTrk 24 2 每磁道扇區數 0x12
BPB_NumHeads 26 2 磁頭數(面數) 0x2
BPB_HiddSec 28 4 隱藏扇區數 0
BPB_TotSec32 32 4 如果BPB_TotSec16是0,由這個值記錄扇區數 0
BS_DrvNum 36 1 中斷13的驅動器號 0
BS_Reserved1 37 1 未使用 0
BS_BootSig 38 1 擴展引導標記(29h) 0x29
BS_VolID 39 4 卷序列號 0
BS_VolLab 43 11 卷標 'OrangeS0.02'
BS_FileSysType 54 8 文件系統類型 'FAT12'
引導代碼及其他 62 448 引導代碼、數據及其他填充字符等 引導代碼(剩餘部分被0填充)
結束標誌 510 2 0xAA55 0xAA55
接下來扇區號1-9、10-18分別由兩個完全相同的表(FAT1和FAT2)佔用,接下來是根目錄區(長度非固定,需計算),剩餘的是數據區(截止到2879號)。

根目錄區由若干個目錄條目組成,每個條目佔32字節,條目最多有BPB_RootEntCht個,即根目錄區大小依賴於BPB_RootEntCht。

根目錄區中的條目格式
名稱 偏移 長度 描述
DIR_Name 0 0xB 文件名8字節,擴展名3字節
DIR_Attr 0xB 1 文件屬性
保留位 0xC 10 保留位
DIR_WrtTime 0x16 2 最後一次寫入時間
DIR_WrtDate 0x18 2 最後一次寫入日期
DIR_FstClus 0x1A 2 此條目對應的開始簇號
DIR_FileSize 0x1C 4 文件大小
注意,數據區的第一個簇號是2,而不是0或1。

實際上,對於小於512字節的文件來說,FAT表用處不大,但如果文件大於512字節,就需要FAT表來找到所有的簇(扇區)。通常FAT項的值代表的是文件下一個簇號。還需要注意的是一個FAT項可能會跨越兩個扇區。

引導扇區需要有BPB等頭信息才能被識別,書上BPB的代碼如下:

jmp short LABEL_START		; Start to boot.
	nop				; 這個 nop 不可少

	; 下面是 FAT12 磁盤的頭
	BS_OEMName	DB 'ForrestY'	; OEM String, 必須 8 個字節
	BPB_BytsPerSec	DW 512		; 每扇區字節數
	BPB_SecPerClus	DB 1		; 每簇多少扇區
	BPB_RsvdSecCnt	DW 1		; Boot 記錄佔用多少扇區
	BPB_NumFATs	DB 2		; 共有多少 FAT 表
	BPB_RootEntCnt	DW 224		; 根目錄文件數最大值
	BPB_TotSec16	DW 2880		; 邏輯扇區總數
	BPB_Media	DB 0xF0		; 媒體描述符
	BPB_FATSz16	DW 9		; 每FAT扇區數
	BPB_SecPerTrk	DW 18		; 每磁道扇區數
	BPB_NumHeads	DW 2		; 磁頭數(面數)
	BPB_HiddSec	DD 0		; 隱藏扇區數
	BPB_TotSec32	DD 0		; wTotalSectorCount爲0時這個值記錄扇區數
	BS_DrvNum	DB 0		; 中斷 13 的驅動器號
	BS_Reserved1	DB 0		; 未使用
	BS_BootSig	DB 29h		; 擴展引導標記 (29h)
	BS_VolID	DD 0		; 卷序列號
	BS_VolLab	DB 'OrangeS0.02'; 卷標, 必須 11 個字節
	BS_FileSysType	DB 'FAT12   '	; 文件系統類型, 必須 8個字節  

LABEL_START:

要加載一個文件如內存的話免不了要讀軟盤。這時候需要用到int 13h中斷,此中斷參數詳見這篇文章。中斷參數需要柱面號、磁頭號、當前柱面上的扇區號三個分量,這三個分量的計算方法如下:

扇區號/每磁道扇區數(18),得商Q和餘數R。柱面號爲Q>>1,磁頭號爲Q&1,起始扇區號爲R+1。

Loader要做的事情至少有兩件:加載內核入內存;跳入保護模式。因爲內核開始執行的時候一定在保護模式下。.COM的內核可以直接放入內存,但是ELF格式的內核不能直接放進內存(下一章會講)。


---------------------

在編譯生成boot.bin後,還需要這樣做:首先用bximage生成一個軟盤映像(直接執行bximage),然後執行如下命令

nasm loader.asm -o loader.bin

dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc

sudo mount -o loop a.img /mnt/floppy/

sudo cp loader.bin /mnt/floppy/ -v

sudo umount /mnt/floppy/

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