一個操作系統從開機到開始運行,大致經歷“引導->加載內核入內存->跳入保護模式->開始執行內核”這樣一個過程。
幾乎所有的文件系統都會把磁盤劃分爲若干層次以方便組織和管理,這些層次包括扇區(磁盤上的最小數據單元),簇(一個或多個扇區),分區(通常指整個文件系統)。
對於FAT12文件系統來說,第0號扇區爲引導扇區,其中有一個叫做BPB(BIOS Parameter Block)的數據結構,格式如下表,其中BPB_開頭的屬於BPB,其餘的只是引導扇區的一部分。
名稱 | 偏移 | 長度 | 內容 | 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 |
根目錄區由若干個目錄條目組成,每個條目佔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 | 文件大小 |
實際上,對於小於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/