org 07c00h ;================================================ jmp short START nop ; 這個 nop 不可少 ;這個結構將要被寫在軟盤的第一個扇區,至關於格式化軟盤爲FAT12格式 BS_OEMName DB 'PAVKOOOO' ; OEM String, 必須 8 個字節 BPB_BytsPerSec DW 512 ; 每扇區512字節 BPB_SecPerClus DB 1 ; 每簇1扇區 簇的定義是爲了操做系統可以更加快速的去硬盤尋址,快速定位,而不僅是使用扇區號 BPB_RsvdSecCnt DW 1 ; 引導區使用1個扇區,不能有其餘值,由於BIOS啓動以後就會去取軟盤的第一個扇區全部數據到內存,而後將控制權交給這個引導區 BPB_NumFATs DB 2 ; 共有2 FAT 表 ;FAT格式(12,16,32)幾乎都是2個表,第二個表用來備份。因此內容和第一個表徹底同樣 BPB_RootEntCnt DW 224 ; 最多能存儲224個文件??不清楚爲何是這個值 BPB_TotSec16 DW 2880 ; 邏輯扇區總數:FAT12的扇區個數=2個磁頭*18個磁道*80個扇區 =2880 BPB_Media DB 0xF0 ; 媒體描述符 ?? BPB_FATSz16 DW 9 ; 每FAT扇9個 BPB_SecPerTrk DW 18 ; 每磁道18個扇區 BPB_NumHeads DW 2 ; 磁頭數(面數) BPB_HiddSec DD 0 ; 隱藏扇區數 BPB_TotSec32 DD 0 ; 總扇區數,若是前面16位已經記錄,這個就爲0 BS_DrvNum DB 0 ; 中斷 13 的驅動器號 BS_Reserved1 DB 0 ; 未使用 BS_BootSig DB 29h ; 擴展引導標記 (29h) BS_VolID DD 0 ; 卷序列號 BS_VolLab DB 'PAVKOOOOOOO'; 卷標, 必須 11 個字節 BS_FileSysType DB 'FAT12 ' ; 文件系統類型, 必須 8個字節 BaseofStack equ 07c00h FileEntryBegin equ 19 CsOfLoader equ 010000h ;在實模式下,將loader.bin加載的內存地址應該爲 07c00h+引導程序(512=200h)=07e00h以後 ipofLoader equ 0100h ;確保程序加載的內容在實模式尋址空間以內:1MB FileEntryCount equ 14 ;文件目錄區所佔用的扇區數 ;=============引導程序開始執行==================== START: xor eax,eax mov ax,cs mov ds,ax ;數據段,視頻段,附加段都指向當前段 mov ss,ax mov sp,BaseofStack ;棧頂ss:sp ==> 07C00h 也就是程序開始的位置 ,棧往低地址生長,這裏沒有作堆棧溢出檢查 ;復位軟驅 xor ah,ah xor dl,dl int 13h ;在軟盤中讀取1個扇區到內存 ;由於loader.bin存在於根目錄區,根目錄區在扇區號19(0---引導扇區,1~9---FAT表1,10~18---FAT表2),因此須要將19扇區加載到內存 ;整個目錄區佔用了多少個扇區? 224(個文件)*32(每一個文件佔用32個字節)/512(每一個扇區512個字節) = 14 佔用了14個扇區。 mov LoopSecNo,FileEntryBegin BEGINREADSEC: cmp LoopOfSec,0 jz NOLOADER dec LoopOfSec mov ax,CsOfLoader mov es,ax mov ax,ipofLoader mov bx,ax ;將數據讀到es:bx指向的緩存中 mov ax,LoopSecNo mov cl,1 ;只讀1個扇區 call ReadSector ;讀完以後,內存裏就有512字節的內容了,如今仍是尋找loader.bin mov si, LoaderFileName ; ds:si -> "LOADER BIN" mov di, ipofLoader cld mov dx, 10h ;一個扇區512 / 32有16(10H)個目錄項 BEGINLOOPFILENAME: ;開始一個個項目的比較 cmp dx, 0 jz NEXTSECTOR ;到下一個扇區尋找,因此須要從新加載一個扇區 dec dx ;11個字母的文件名 ; ┛就跳到下一個 Sector mov cx, 11 COMPARENAME: cmp cx, 0 jz FILEFOUND ;文件找到了 dec cx lodsb ; ds:si -> al cmp al, byte [es:di] jz NEXTCHAR jmp NEXTFILE NEXTCHAR: inc di jmp COMPARENAME NEXTFILE: and di, 0FFE0h loadsb會改變di,因此須要將di指定到文件條目的首地址 add di, 20h ;每一個文件條目佔有32個字符=20H jmp BEGINLOOPFILENAME NEXTSECTOR: add LoopSecNo,1 jmp BEGINREADSEC NOLOADER: jmp $ ;找不到的話,就卡死到這裏 ;若是文件找到了,就要把文件從數據區讀取到內存 ;目錄區以後就是數據區,因此數據區的第一個扇區號是19+14=33! FILEFOUND: and di, 0FFE0h ; di -> 當前條目的開始 add di, 01Ah ;01Ah = 26 也就是文件條目地址偏移26的位置:DRI_FSTCLUS ;文件所在的數據區扇區號爲:dir.DIR_FileSize -2 + 33 ==> [es:di] mov word ax,[es:di]; push ax ;保存序號,getfatentry的時候須要使用 sub ax 2 add ax 33 LABEL_GOON_LOADING_FILE: mov cl,1 ReadSec ;loader.bin可能大於512字節,就是說可能超過1個扇區(不能超過兩個,由於如今在實模式,實模式的最大尋址爲1M) ;因此須要讀取fat表,查看是否還有其餘的扇區 pop ax call GetFATEntry cmp ax, 0FFFh jz FILELOADED ;讀取下一個未完的扇區 sub ax 2 add ax 33 ;將數據讀到es:bx指向的緩存中 add bx, [BPB_BytsPerSec] ; 讀取的內存指針也應該後移512個字節(1個扇區) jmp LABEL_GOON_LOADING_FILE FILELOADED: ; ********************** ; 這一句正式跳轉到已加載到內 ; 存中的 LOADER.BIN 的開始處, ; 開始執行 LOADER.BIN 的代碼。 ; Boot Sector 的使命到此結束。 jmp CsofLoader:ipofLoader ; ********************** ;---------------------------------------------------------------------------- ; 函數名: GetFATEntry ;---------------------------------------------------------------------------- ; 做用: ; 找到序號DRI_FSTCLUS爲 ax 的 Sector 在 FAT 中的條目, 結果放在 ax 中 ; 須要注意的是, 中間須要讀 FAT 的扇區到 es:bx 處, 因此函數一開始保存了 es 和 bx GetFATEntry: push es push bx push ax mov ax, CsOfLoader; `. sub ax, 0100h ; | 在 BaseOfLoader 後面留出 4K 空間用於存放 FAT mov es, ax ; / pop ax mov byte [bOdd], 0 mov bx, 3 mul bx ; dx:ax = ax * 3 mov bx, 2 div bx ; dx:ax / 2 ==> ax <- 商, dx <- 餘數 cmp dx, 0 jz LABEL_EVEN mov byte [bOdd], 1 LABEL_EVEN:;偶數 ; 如今 ax 中是 FATEntry 在 FAT 中的偏移量,下面來 ; 計算 FATEntry 在哪一個扇區中(FAT佔用不止一個扇區) xor dx, dx mov bx, [BPB_BytsPerSec] div bx ; dx:ax / BPB_BytsPerSec ; ax <- 商 (FATEntry 所在的扇區相對於 FAT 的扇區號) ; dx <- 餘數 (FATEntry 在扇區內的偏移)。 push dx mov bx, 0 ; bx <- 0 因而, es:bx = (BaseOfLoader - 100):00 add ax, SectorNoOfFAT1 ; 此句以後的 ax 就是 FATEntry 所在的扇區號 mov cl, 2 call ReadSector ; 讀取 FATEntry 所在的扇區, 一次讀兩個, 避免在邊界 ; 發生錯誤, 由於一個 FATEntry 可能跨越兩個扇區 pop dx add bx, dx mov ax, [es:bx] cmp byte [bOdd], 1 jnz LABEL_EVEN_2 shr ax, 4 LABEL_EVEN_2: and ax, 0FFFh LABEL_GET_FAT_ENRY_OK: pop bx pop es ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;如何函數使用INT 13讀取軟盤 ;http://en.wikipedia.org/wiki/INT_13H ;傳入扇區號到ax ;讀取扇區數目到cl ;將數據讀到es:bx指向的緩存中 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;在函數裏面最好使用bp而不是使用SP ReadSec: push bp mov bp,sp sub sp,2 mov bype [bp-2],cl push bx mov bl,[BPB_SecPerTrk] div bl ;扇區號/18; ah=餘數,al=商 inc ah ;扇區號從0開始,因此須要加1 mov cl,ah mov dh,al ;al表示磁道號 shr al,1 ;al / 2 的值爲磁道號 mov ch,al and dh,1 ;dh磁頭號 mov dl=[BS_DrvNum] pop bx ;int 13所須要的值都已經附了 LoopWhenFeild: mov ah,2 mov cl,[bp-2] int 13 jc LoopWhenFeild add sp,2 pop bp ret ;-.- -.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.-! ;變量定義區 LoaderFileName db "LOADER BIN", 0 ; LOADER.BIN 之文件名 LoopOfSec dw FileEntryCount; LoopSecNo dw 0; bOdd db 0 ; 奇數仍是偶數 ;---------------------------------------------------------------------------- times 510-($-$$) db 0 ; 填充剩下的空間,使生成的二進制代碼剛好爲512字節 dw 0xaa55 ; 結束標誌