boot.asm文件注释
生活随笔
收集整理的這篇文章主要介紹了
boot.asm文件注释
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;?????????????????????????????? boot.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;????????????????????????????????????????????????????? Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;???????????????????????????????????????????????????? Noted by Ethan_zhang, 2011
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;%define?? ?_BOOT_DEBUG_?? ?; 做 Boot Sector 時一定將此行注釋掉!將此行打開后用 nasm Boot.asm -o Boot.com 做成一個.COM文件易于調試
%ifdef?? ?_BOOT_DEBUG_
?? ?org? 0100h?? ??? ??? ?; 調試狀態, 做成 .COM 文件, 可調試
%else
?? ?org? 07c00h?? ??? ??? ?; Boot 狀態, Bios 將把 Boot Sector 加載到 0:7C00 處并開始執行
%endif
;================================================================================================
;因為堆棧是從高往底走的,而程序是從0100h或07c00h的位置開始往高地址走的,所以定義堆棧的棧頂為程序的加載地址
%ifdef?? ?_BOOT_DEBUG_
BaseOfStack?? ??? ?equ?? ?0100h?? ?; 調試狀態下堆?;刂?棧底, 從這個位置向低地址生長)
%else
BaseOfStack?? ??? ?equ?? ?07c00h?? ?; Boot狀態下堆?;刂?棧底, 從這個位置向低地址生長)
%endif
%include?? ?"load.inc"
;================================================================================================
;=================================Ethan_zhang========================================
;jmp short 段內短轉移,以當前ip的相對跳轉地址的偏依量作為轉移量,但偏移量只允許在-128 ~ +127字節之間
;nop是fat12文件頭格式中的BS_jmpBoot固定格式
;=================================Ethan_zhang========================================
?? ?jmp short LABEL_START?? ??? ?; Start to boot.
?? ?nop?? ??? ??? ??? ?; 這個 nop 不可少
; 下面是 FAT12 磁盤的頭, 之所以包含它是因為下面用到了磁盤的一些信息
%include?? ?"fat12hdr.inc"
LABEL_START:?? ?
?? ?mov?? ?ax, cs
?? ?mov?? ?ds, ax
?? ?mov?? ?es, ax
?? ?mov?? ?ss, ax
?? ?mov?? ?sp, BaseOfStack
?? ?; 清屏
?? ?mov?? ?ax, 0600h?? ??? ?; AH = 6,? AL = 0h
?? ?mov?? ?bx, 0700h?? ??? ?; 黑底白字(BL = 07h)
?? ?mov?? ?cx, 0?? ??? ??? ?; 左上角: (0, 0)
?? ?mov?? ?dx, 0184fh?? ??? ?; 右下角: (80, 50)
?? ?int?? ?10h?? ??? ??? ?; int 10h
;=================================Ethan_zhang========================================
;在后面定義了一系列固定長度的字符串,所以這里只要用dh來表示要顯示第幾個固定長度的字符地址就可以顯示字符了
;=================================Ethan_zhang========================================
?? ?mov?? ?dh, 0?? ??? ??? ?; "Booting? "
?? ?call?? ?DispStr?? ??? ??? ?; 顯示字符串
?? ?
?? ?xor?? ?ah, ah?? ?; ┓
?? ?xor?? ?dl, dl?? ?; ┣ 軟驅復位
?? ?int?? ?13h?? ?; ┛
;=================================Ethan_zhang========================================
;尋找LOADER.BIN文件的大體思路為:
;LOADER.BIN文件存儲在A盤中,我們知道A盤的格式是FAT12格式,具體格式見書本P103,其主要是有引導扇區、
;FAT1區、FAT2區、根目錄區(長度不固定,需要計算)和 數據區組成。引導扇區放的就是我們寫的引導代碼boot.bin
;文件,我們的LOADER.BIN文件是放在數據區中的,而文件的文件名是放在根目錄中,因此,如果我們想查看該盤是否
;含有我們想要的文件時,我們應該先到根目錄中查看是否含有該文件名,如果有,說明該盤存在該文件,那么下面可以
;從盤中讀取該文件了,文件在盤中是按照簇來進行存儲的,而在FAT12盤中,一個簇中只含有一個扇區,故下面我們只以
;扇區來進行說明。所以文件在FAT12中是按照扇區(一個扇區512字節)來進行存儲的,所以一個文件一般會占多個扇區,
;而每個文件占的扇區數會記錄在FAT1區中,我們只要從文件根目錄中獲取該文件在FAT1區中的起始地址,只要該地址
;存儲的不是0xFFF說明該文件還占有其他扇區,我們繼續讀取該地址指向的扇區,直到FAT1項中的值為0xFFF,這表示文件
;結束,讀取完畢而根目錄也是按照扇區進行存儲的,所以我們得從根目錄起始扇區開始順序讀取每個扇區,直到根目錄區結束。
;而每個根目錄項是32個字節,因此一個扇區可以有16個根目錄項,我們挨個比較每個根目錄項中的文件名和我們期望查找的文件名
;是否相同,如果相同就表示已經找到,只要取出根目錄項中的DIR_FstClus,然后從FAT1項中取出相應的數據即可。
;如果沒有找到,那么就到下一個根目錄項中查找,如果當前扇區都沒有找到,那么讀取下一個扇區,知道這個根目錄區結束。
;=================================Ethan_zhang========================================
; 下面在 A 盤的根目錄尋找 LOADER.BIN
?? ?mov?? ?word [wSectorNo], SectorNoOfRootDirectory
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
?? ?cmp?? ?word [wRootDirSizeForLoop], 0?? ?; ┓
?? ?jz?? ?LABEL_NO_LOADERBIN?? ??? ??? ??? ??? ??? ??? ?; ┣ 判斷根目錄區是不是已經讀完
?? ?dec?? ?word [wRootDirSizeForLoop]?? ??? ???? ; ┛ 如果讀完表示沒有找到 LOADER.BIN
?? ?mov?? ?ax, BaseOfLoader
?? ?mov?? ?es, ax?? ??? ??? ?; es <- BaseOfLoader
?? ?mov?? ?bx, OffsetOfLoader?? ?; bx <- OffsetOfLoader?? ?于是, es:bx = BaseOfLoader:OffsetOfLoader
?? ?mov?? ?ax, [wSectorNo]?? ?; ax <- Root Directory 中的某 Sector 號
?? ?mov?? ?cl, 1?? ??? ??? ??? ?; 要讀取的扇區數目
?? ?call?? ?ReadSector?? ?;將cl個Sector中的數據讀到內存es:bx處
?? ?mov?? ?si, LoaderFileName?? ?; ds:si -> "LOADER? BIN"
?? ?mov?? ?di, OffsetOfLoader?? ?; es:di -> BaseOfLoader:0100 = BaseOfLoader*10h+100
?? ?cld?? ??? ??? ? ;清除方向標志,告訴程序si,di向前移動;std指令為設置方向,告訴程序si,di向后移動
?? ?mov?? ?dx, 10h?? ??? ??? ??? ??? ??? ?;10h表示的是16,因為一個扇區是512字節,而每個根目錄項是32字節,
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?;故每個扇區含有512/32=16個根目錄項
LABEL_SEARCH_FOR_LOADERBIN:
?? ?cmp?? ?dx, 0?? ??? ??? ??? ??? ?; ┓循環次數控制,
?? ?jz?? ?LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR?? ?; ┣如果已經讀完了一個 Sector,
?? ?dec?? ?dx?? ??? ??? ??? ??? ?; ┛就跳到下一個 Sector
?? ?mov?? ?cx, 11
LABEL_CMP_FILENAME:
?? ?cmp?? ?cx, 0
?? ?jz?? ?LABEL_FILENAME_FOUND?? ?; 如果比較了 11 個字符都相等, 表示找到
dec?? ?cx
?? ?lodsb?? ??? ??? ??? ?;將 ds:si 指向的地址內容加載到 al
?? ?cmp?? ?al, byte [es:di]
?? ?jz?? ?LABEL_GO_ON
?? ?jmp?? ?LABEL_DIFFERENT?? ??? ?; 只要發現不一樣的字符就表明本 DirectoryEntry 不是
; 我們要找的 LOADER.BIN
LABEL_GO_ON:
?? ?inc?? ?di
?? ?jmp?? ?LABEL_CMP_FILENAME?? ?;?? ?繼續循環
LABEL_DIFFERENT:
?? ?and?? ?di, 0FFE0h?? ??? ?;????? ┓di &= E0 為了讓它指向本條目開頭;因為E0的二進制為1110 0000,后面五位
?? ??? ??? ??? ??? ??? ??? ??? ??? ?;?? ??? ┃剛好是32個字節,因此di與上一個OFFE0h,可以回到本條目錄的開頭
?? ?add?? ?di, 20h?? ??? ??? ?;????? ┃讓di增加32個字節,即一個根目錄項的大小,從而進入下一個根目錄項
?? ?mov?? ?si, LoaderFileName?? ?;????? ┣ 讓si重新指向LoaderFileName的起始位置,因為在前面的比較過程中
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?;?? ??? ┃si移動了,要重新比較的話,還得重新回到起始點
?? ?jmp?? ?LABEL_SEARCH_FOR_LOADERBIN;??? ┛
LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
?? ?add?? ?word [wSectorNo], 1
?? ?jmp?? ?LABEL_SEARCH_IN_ROOT_DIR_BEGIN
LABEL_NO_LOADERBIN:
?? ?mov?? ?dh, 2?? ??? ??? ?; "No LOADER."
?? ?call?? ?DispStr?? ??? ??? ?; 顯示字符串
%ifdef?? ?_BOOT_DEBUG_
?? ?mov?? ?ax, 4c00h?? ??? ?; ┓
?? ?int?? ?21h?? ??? ??? ?; ┛沒有找到 LOADER.BIN, 回到 DOS,21號中斷是回到DOS中
%else
?? ?jmp?? ?$?? ??? ??? ?; 沒有找到 LOADER.BIN, 死循環在這里
%endif
LABEL_FILENAME_FOUND:?? ??? ??? ?; 找到 LOADER.BIN 后便來到這里繼續
?? ?mov?? ?ax, RootDirSectors
?? ?and?? ?di, 0FFE0h?? ??? ?; 同上面一樣,回到當前根目錄項的起始位置
?? ?add?? ?di, 01Ah?? ??? ?; 01Ah是DIR_FstClus 在根目錄項中的偏移地址,它表示該文件在FAT1區中的起始序號
?? ?mov?? ?cx, word [es:di]
?? ?push?? ?cx?? ??? ??? ?; 保存此 Sector 在 FAT 中的序號
?? ?add?? ?cx, ax
?? ?add?? ?cx, DeltaSectorNo?? ?; 這句完成時 cl 里面變成 LOADER.BIN 的起始扇區號 (從 0 開始數的序號)
?? ?mov?? ?ax, BaseOfLoader
?? ?mov?? ?es, ax?? ??? ??? ?; es <- BaseOfLoader
?? ?mov?? ?bx, OffsetOfLoader?? ?; bx <- OffsetOfLoader?? ?于是, es:bx = BaseOfLoader:OffsetOfLoader = BaseOfLoader * 10h + OffsetOfLoader
?? ?mov?? ?ax, cx?? ??? ??? ?; ax <- Sector 號
LABEL_GOON_LOADING_FILE:
?? ?push?? ?ax?? ??? ??? ?; ┓
?? ?push?? ?bx?? ??? ??? ?; ┃
?? ?mov?? ?ah, 0Eh?? ?; ┃ 每讀一個扇區就在 "Booting? " 后面打一個點, 形成這樣的效果:
?? ?mov?? ?al, '.'?? ??? ?; ┃
?? ?mov?? ?bl, 0Fh?? ?; ┃ Booting ......
?? ?int?? ?10h?? ??? ??? ??? ?; ┃ 10號中斷是專門用來顯示字符用的,其中AH表示要顯示字符的格式
?? ?pop?? ?bx?? ??? ??? ??? ?; ┃ AL表示要顯示的字符,所以顯示一個字符占2個字節
?? ?pop?? ?ax?? ??? ??? ??? ?; ┛
?? ?mov?? ?cl, 1
?? ?call?? ?ReadSector
?? ?pop?? ?ax?? ??? ??? ?; 取出此 Sector 在 FAT 中的序號
?? ?call?? ?GetFATEntry
?? ?cmp?? ?ax, 0FFFh
?? ?jz?? ?LABEL_FILE_LOADED
?? ?push?? ?ax?? ??? ??? ?; 保存 Sector 在 FAT 中的序號
?? ?mov?? ?dx, RootDirSectors
?? ?add?? ?ax, dx
?? ?add?? ?ax, DeltaSectorNo
?? ?add?? ?bx, [BPB_BytsPerSec]?? ?;BPB_BytsPerSec表示每個扇區的字節數,即512字節
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?;將其賦給bx,說明將bx后移512個字節,Sector->es:bx
?? ?jmp?? ?LABEL_GOON_LOADING_FILE
LABEL_FILE_LOADED:
?? ?mov?? ?dh, 1?? ??? ??? ?; "Ready."
?? ?call?? ?DispStr?? ??? ??? ?; 顯示字符串
; *****************************************************************************************************
?? ?jmp?? ?BaseOfLoader:OffsetOfLoader?? ?; 這一句正式跳轉到已加載到內存中的 LOADER.BIN 的開始處
?? ??? ??? ??? ??? ??? ?; 開始執行 LOADER.BIN 的代碼
?? ??? ??? ??? ??? ??? ?; Boot Sector 的使命到此結束
; *****************************************************************************************************
;============================================================================
;變量
;----------------------------------------------------------------------------
wRootDirSizeForLoop?? ?dw?? ?RootDirSectors?? ?; Root Directory 占用的扇區數, 在循環中會遞減至零.
wSectorNo?? ??? ?dw?? ?0?? ??? ?; 要讀取的扇區號
bOdd?? ??? ??? ?db?? ?0?? ??? ?; 奇數還是偶數
;============================================================================
;字符串
;----------------------------------------------------------------------------
LoaderFileName?? ??? ?db?? ?"LOADER? BIN", 0?? ?; LOADER.BIN 之文件名
; 為簡化代碼, 下面每個字符串的長度均為 MessageLength
MessageLength?? ??? ?equ?? ?9
BootMessage:?? ??? ?db?? ?"Booting? "; 9字節, 不夠則用空格補齊. 序號 0
Message1?? ??? ?db?? ?"Ready.?? "; 9字節, 不夠則用空格補齊. 序號 1
Message2?? ??? ?db?? ?"No LOADER"; 9字節, 不夠則用空格補齊. 序號 2
;============================================================================
;----------------------------------------------------------------------------
; 函數名: DispStr
;----------------------------------------------------------------------------
; 作用:
;?? ?顯示一個字符串, 函數開始時 dh 中應該是字符串序號(0-based)
DispStr:
?? ?mov?? ?ax, MessageLength
?? ?mul?? ?dh
?? ?add?? ?ax, BootMessage
?? ?mov?? ?bp, ax?? ??? ??? ?; ┓
?? ?mov?? ?ax, ds?? ??? ??? ?; ┣ ES:BP = 串地址
?? ?mov?? ?es, ax?? ??? ??? ?; ┛
?? ?mov?? ?cx, MessageLength?? ?; CX = 串長度
?? ?mov?? ?ax, 01301h?? ??? ?; AH = 13,? AL = 01h
?? ?mov?? ?bx, 0007h?? ??? ?; 頁號為0(BH = 0) 黑底白字(BL = 07h)
?? ?mov?? ?dl, 0
?? ?int?? ?10h?? ??? ??? ?; 調用10號中斷顯示字符
?? ?ret
;----------------------------------------------------------------------------
; 函數名: ReadSector
;----------------------------------------------------------------------------
; 作用:
;?? ?從第 ax 個 Sector 開始, 將 cl 個 Sector 讀入 es:bx 中
ReadSector:
?? ?; -----------------------------------------------------------------------
?? ?; 怎樣由扇區號求扇區在磁盤中的位置 (扇區號 -> 柱面號, 起始扇區, 磁頭號)
?? ?; -----------------------------------------------------------------------
?? ?; 設扇區號為 x
?? ?;????????????????????????????? ┌ 柱面號 = y >> 1
?? ?;?????? x?? ??? ??? ??? ??? ??? ┌ 商 y ┤
?? ?; -------------- => ┤????? └ 磁頭號 = y & 1
?? ?;? 每磁道扇區數???? │
?? ?;????????????????????????????? └ 余 z => 起始扇區號 = z + 1
?? ?push?? ?bp
?? ?mov?? ?bp, sp
?? ?sub?? ?esp, 2?? ??? ??? ?; 辟出兩個字節的堆棧區域保存要讀的扇區數: byte [bp-2]
?? ?mov?? ?byte [bp-2], cl
?? ?push?? ?bx?? ??? ??? ?; 保存 bx
?? ?mov?? ?bl, [BPB_SecPerTrk]?? ?; bl: 除數
?? ?div?? ?bl?? ??? ??? ?; y 在 al 中, z 在 ah 中
?? ?inc?? ?ah?? ??? ??? ?; z ++
?? ?mov?? ?cl, ah?? ??? ??? ?; cl <- 起始扇區號
?? ?mov?? ?dh, al?? ??? ??? ?; dh <- y
?? ?shr?? ?al, 1?? ??? ??? ?; y >> 1 (其實是 y/BPB_NumHeads, 這里BPB_NumHeads=2)
?? ?mov?? ?ch, al?? ??? ??? ?; ch <- 柱面號
?? ?and?? ?dh, 1?? ??? ??? ?; dh & 1 = 磁頭號
?? ?pop?? ?bx?? ??? ??? ?; 恢復 bx
?? ?; 至此, "柱面號, 起始扇區, 磁頭號" 全部得到 ^^^^^^^^^^^^^^^^^^^^^^^^
?? ?mov?? ?dl, [BS_DrvNum]?? ??? ?; 驅動器號 (0 表示 A 盤)
.GoOnReading:
?? ?mov?? ?ah, 2?? ??? ??? ?; 讀
?? ?mov?? ?al, byte [bp-2]?? ??? ?; 讀 al 個扇區
?? ?int?? ?13h
?? ?jc?? ?.GoOnReading?? ??? ?; 如果讀取錯誤 CF 會被置為 1, 這時就不停地讀, 直到正確為止
?? ?add?? ?esp, 2
?? ?pop?? ?bp
?? ?ret
;----------------------------------------------------------------------------
; 函數名: GetFATEntry
;----------------------------------------------------------------------------
; 作用:
;?? ?找到序號為 ax 的 Sector 在 FAT 中的條目, 結果放在 ax 中
;?? ?需要注意的是, 中間需要讀 FAT 的扇區到 es:bx 處, 所以函數一開始保存了 es 和 bx
GetFATEntry:
?? ?push?? ?es
?? ?push?? ?bx
?? ?push?? ?ax
?? ?mov?? ?ax, BaseOfLoader?? ?; ┓
?? ?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:;偶數
?? ?xor?? ?dx, dx?? ??? ??? ?; 現在 ax 中是 FATEntry 在 FAT 中的偏移量. 下面來計算 FATEntry 在哪個扇區中(FAT占用不止一個扇區)
?? ?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 = (BaseOfLoader - 100) * 10h
?? ?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
;----------------------------------------------------------------------------
times ?? ?510-($-$$)?? ?db?? ?0?? ?; 填充剩下的空間,使生成的二進制代碼恰好為512字節
dw ?? ?0xaa55?? ??? ??? ??? ?; 結束標志
;?????????????????????????????? boot.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;????????????????????????????????????????????????????? Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;???????????????????????????????????????????????????? Noted by Ethan_zhang, 2011
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;%define?? ?_BOOT_DEBUG_?? ?; 做 Boot Sector 時一定將此行注釋掉!將此行打開后用 nasm Boot.asm -o Boot.com 做成一個.COM文件易于調試
%ifdef?? ?_BOOT_DEBUG_
?? ?org? 0100h?? ??? ??? ?; 調試狀態, 做成 .COM 文件, 可調試
%else
?? ?org? 07c00h?? ??? ??? ?; Boot 狀態, Bios 將把 Boot Sector 加載到 0:7C00 處并開始執行
%endif
;================================================================================================
;因為堆棧是從高往底走的,而程序是從0100h或07c00h的位置開始往高地址走的,所以定義堆棧的棧頂為程序的加載地址
%ifdef?? ?_BOOT_DEBUG_
BaseOfStack?? ??? ?equ?? ?0100h?? ?; 調試狀態下堆?;刂?棧底, 從這個位置向低地址生長)
%else
BaseOfStack?? ??? ?equ?? ?07c00h?? ?; Boot狀態下堆?;刂?棧底, 從這個位置向低地址生長)
%endif
%include?? ?"load.inc"
;================================================================================================
;=================================Ethan_zhang========================================
;jmp short 段內短轉移,以當前ip的相對跳轉地址的偏依量作為轉移量,但偏移量只允許在-128 ~ +127字節之間
;nop是fat12文件頭格式中的BS_jmpBoot固定格式
;=================================Ethan_zhang========================================
?? ?jmp short LABEL_START?? ??? ?; Start to boot.
?? ?nop?? ??? ??? ??? ?; 這個 nop 不可少
; 下面是 FAT12 磁盤的頭, 之所以包含它是因為下面用到了磁盤的一些信息
%include?? ?"fat12hdr.inc"
LABEL_START:?? ?
?? ?mov?? ?ax, cs
?? ?mov?? ?ds, ax
?? ?mov?? ?es, ax
?? ?mov?? ?ss, ax
?? ?mov?? ?sp, BaseOfStack
?? ?; 清屏
?? ?mov?? ?ax, 0600h?? ??? ?; AH = 6,? AL = 0h
?? ?mov?? ?bx, 0700h?? ??? ?; 黑底白字(BL = 07h)
?? ?mov?? ?cx, 0?? ??? ??? ?; 左上角: (0, 0)
?? ?mov?? ?dx, 0184fh?? ??? ?; 右下角: (80, 50)
?? ?int?? ?10h?? ??? ??? ?; int 10h
;=================================Ethan_zhang========================================
;在后面定義了一系列固定長度的字符串,所以這里只要用dh來表示要顯示第幾個固定長度的字符地址就可以顯示字符了
;=================================Ethan_zhang========================================
?? ?mov?? ?dh, 0?? ??? ??? ?; "Booting? "
?? ?call?? ?DispStr?? ??? ??? ?; 顯示字符串
?? ?
?? ?xor?? ?ah, ah?? ?; ┓
?? ?xor?? ?dl, dl?? ?; ┣ 軟驅復位
?? ?int?? ?13h?? ?; ┛
;=================================Ethan_zhang========================================
;尋找LOADER.BIN文件的大體思路為:
;LOADER.BIN文件存儲在A盤中,我們知道A盤的格式是FAT12格式,具體格式見書本P103,其主要是有引導扇區、
;FAT1區、FAT2區、根目錄區(長度不固定,需要計算)和 數據區組成。引導扇區放的就是我們寫的引導代碼boot.bin
;文件,我們的LOADER.BIN文件是放在數據區中的,而文件的文件名是放在根目錄中,因此,如果我們想查看該盤是否
;含有我們想要的文件時,我們應該先到根目錄中查看是否含有該文件名,如果有,說明該盤存在該文件,那么下面可以
;從盤中讀取該文件了,文件在盤中是按照簇來進行存儲的,而在FAT12盤中,一個簇中只含有一個扇區,故下面我們只以
;扇區來進行說明。所以文件在FAT12中是按照扇區(一個扇區512字節)來進行存儲的,所以一個文件一般會占多個扇區,
;而每個文件占的扇區數會記錄在FAT1區中,我們只要從文件根目錄中獲取該文件在FAT1區中的起始地址,只要該地址
;存儲的不是0xFFF說明該文件還占有其他扇區,我們繼續讀取該地址指向的扇區,直到FAT1項中的值為0xFFF,這表示文件
;結束,讀取完畢而根目錄也是按照扇區進行存儲的,所以我們得從根目錄起始扇區開始順序讀取每個扇區,直到根目錄區結束。
;而每個根目錄項是32個字節,因此一個扇區可以有16個根目錄項,我們挨個比較每個根目錄項中的文件名和我們期望查找的文件名
;是否相同,如果相同就表示已經找到,只要取出根目錄項中的DIR_FstClus,然后從FAT1項中取出相應的數據即可。
;如果沒有找到,那么就到下一個根目錄項中查找,如果當前扇區都沒有找到,那么讀取下一個扇區,知道這個根目錄區結束。
;=================================Ethan_zhang========================================
; 下面在 A 盤的根目錄尋找 LOADER.BIN
?? ?mov?? ?word [wSectorNo], SectorNoOfRootDirectory
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
?? ?cmp?? ?word [wRootDirSizeForLoop], 0?? ?; ┓
?? ?jz?? ?LABEL_NO_LOADERBIN?? ??? ??? ??? ??? ??? ??? ?; ┣ 判斷根目錄區是不是已經讀完
?? ?dec?? ?word [wRootDirSizeForLoop]?? ??? ???? ; ┛ 如果讀完表示沒有找到 LOADER.BIN
?? ?mov?? ?ax, BaseOfLoader
?? ?mov?? ?es, ax?? ??? ??? ?; es <- BaseOfLoader
?? ?mov?? ?bx, OffsetOfLoader?? ?; bx <- OffsetOfLoader?? ?于是, es:bx = BaseOfLoader:OffsetOfLoader
?? ?mov?? ?ax, [wSectorNo]?? ?; ax <- Root Directory 中的某 Sector 號
?? ?mov?? ?cl, 1?? ??? ??? ??? ?; 要讀取的扇區數目
?? ?call?? ?ReadSector?? ?;將cl個Sector中的數據讀到內存es:bx處
?? ?mov?? ?si, LoaderFileName?? ?; ds:si -> "LOADER? BIN"
?? ?mov?? ?di, OffsetOfLoader?? ?; es:di -> BaseOfLoader:0100 = BaseOfLoader*10h+100
?? ?cld?? ??? ??? ? ;清除方向標志,告訴程序si,di向前移動;std指令為設置方向,告訴程序si,di向后移動
?? ?mov?? ?dx, 10h?? ??? ??? ??? ??? ??? ?;10h表示的是16,因為一個扇區是512字節,而每個根目錄項是32字節,
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?;故每個扇區含有512/32=16個根目錄項
LABEL_SEARCH_FOR_LOADERBIN:
?? ?cmp?? ?dx, 0?? ??? ??? ??? ??? ?; ┓循環次數控制,
?? ?jz?? ?LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR?? ?; ┣如果已經讀完了一個 Sector,
?? ?dec?? ?dx?? ??? ??? ??? ??? ?; ┛就跳到下一個 Sector
?? ?mov?? ?cx, 11
LABEL_CMP_FILENAME:
?? ?cmp?? ?cx, 0
?? ?jz?? ?LABEL_FILENAME_FOUND?? ?; 如果比較了 11 個字符都相等, 表示找到
dec?? ?cx
?? ?lodsb?? ??? ??? ??? ?;將 ds:si 指向的地址內容加載到 al
?? ?cmp?? ?al, byte [es:di]
?? ?jz?? ?LABEL_GO_ON
?? ?jmp?? ?LABEL_DIFFERENT?? ??? ?; 只要發現不一樣的字符就表明本 DirectoryEntry 不是
; 我們要找的 LOADER.BIN
LABEL_GO_ON:
?? ?inc?? ?di
?? ?jmp?? ?LABEL_CMP_FILENAME?? ?;?? ?繼續循環
LABEL_DIFFERENT:
?? ?and?? ?di, 0FFE0h?? ??? ?;????? ┓di &= E0 為了讓它指向本條目開頭;因為E0的二進制為1110 0000,后面五位
?? ??? ??? ??? ??? ??? ??? ??? ??? ?;?? ??? ┃剛好是32個字節,因此di與上一個OFFE0h,可以回到本條目錄的開頭
?? ?add?? ?di, 20h?? ??? ??? ?;????? ┃讓di增加32個字節,即一個根目錄項的大小,從而進入下一個根目錄項
?? ?mov?? ?si, LoaderFileName?? ?;????? ┣ 讓si重新指向LoaderFileName的起始位置,因為在前面的比較過程中
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?;?? ??? ┃si移動了,要重新比較的話,還得重新回到起始點
?? ?jmp?? ?LABEL_SEARCH_FOR_LOADERBIN;??? ┛
LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
?? ?add?? ?word [wSectorNo], 1
?? ?jmp?? ?LABEL_SEARCH_IN_ROOT_DIR_BEGIN
LABEL_NO_LOADERBIN:
?? ?mov?? ?dh, 2?? ??? ??? ?; "No LOADER."
?? ?call?? ?DispStr?? ??? ??? ?; 顯示字符串
%ifdef?? ?_BOOT_DEBUG_
?? ?mov?? ?ax, 4c00h?? ??? ?; ┓
?? ?int?? ?21h?? ??? ??? ?; ┛沒有找到 LOADER.BIN, 回到 DOS,21號中斷是回到DOS中
%else
?? ?jmp?? ?$?? ??? ??? ?; 沒有找到 LOADER.BIN, 死循環在這里
%endif
LABEL_FILENAME_FOUND:?? ??? ??? ?; 找到 LOADER.BIN 后便來到這里繼續
?? ?mov?? ?ax, RootDirSectors
?? ?and?? ?di, 0FFE0h?? ??? ?; 同上面一樣,回到當前根目錄項的起始位置
?? ?add?? ?di, 01Ah?? ??? ?; 01Ah是DIR_FstClus 在根目錄項中的偏移地址,它表示該文件在FAT1區中的起始序號
?? ?mov?? ?cx, word [es:di]
?? ?push?? ?cx?? ??? ??? ?; 保存此 Sector 在 FAT 中的序號
?? ?add?? ?cx, ax
?? ?add?? ?cx, DeltaSectorNo?? ?; 這句完成時 cl 里面變成 LOADER.BIN 的起始扇區號 (從 0 開始數的序號)
?? ?mov?? ?ax, BaseOfLoader
?? ?mov?? ?es, ax?? ??? ??? ?; es <- BaseOfLoader
?? ?mov?? ?bx, OffsetOfLoader?? ?; bx <- OffsetOfLoader?? ?于是, es:bx = BaseOfLoader:OffsetOfLoader = BaseOfLoader * 10h + OffsetOfLoader
?? ?mov?? ?ax, cx?? ??? ??? ?; ax <- Sector 號
LABEL_GOON_LOADING_FILE:
?? ?push?? ?ax?? ??? ??? ?; ┓
?? ?push?? ?bx?? ??? ??? ?; ┃
?? ?mov?? ?ah, 0Eh?? ?; ┃ 每讀一個扇區就在 "Booting? " 后面打一個點, 形成這樣的效果:
?? ?mov?? ?al, '.'?? ??? ?; ┃
?? ?mov?? ?bl, 0Fh?? ?; ┃ Booting ......
?? ?int?? ?10h?? ??? ??? ??? ?; ┃ 10號中斷是專門用來顯示字符用的,其中AH表示要顯示字符的格式
?? ?pop?? ?bx?? ??? ??? ??? ?; ┃ AL表示要顯示的字符,所以顯示一個字符占2個字節
?? ?pop?? ?ax?? ??? ??? ??? ?; ┛
?? ?mov?? ?cl, 1
?? ?call?? ?ReadSector
?? ?pop?? ?ax?? ??? ??? ?; 取出此 Sector 在 FAT 中的序號
?? ?call?? ?GetFATEntry
?? ?cmp?? ?ax, 0FFFh
?? ?jz?? ?LABEL_FILE_LOADED
?? ?push?? ?ax?? ??? ??? ?; 保存 Sector 在 FAT 中的序號
?? ?mov?? ?dx, RootDirSectors
?? ?add?? ?ax, dx
?? ?add?? ?ax, DeltaSectorNo
?? ?add?? ?bx, [BPB_BytsPerSec]?? ?;BPB_BytsPerSec表示每個扇區的字節數,即512字節
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?;將其賦給bx,說明將bx后移512個字節,Sector->es:bx
?? ?jmp?? ?LABEL_GOON_LOADING_FILE
LABEL_FILE_LOADED:
?? ?mov?? ?dh, 1?? ??? ??? ?; "Ready."
?? ?call?? ?DispStr?? ??? ??? ?; 顯示字符串
; *****************************************************************************************************
?? ?jmp?? ?BaseOfLoader:OffsetOfLoader?? ?; 這一句正式跳轉到已加載到內存中的 LOADER.BIN 的開始處
?? ??? ??? ??? ??? ??? ?; 開始執行 LOADER.BIN 的代碼
?? ??? ??? ??? ??? ??? ?; Boot Sector 的使命到此結束
; *****************************************************************************************************
;============================================================================
;變量
;----------------------------------------------------------------------------
wRootDirSizeForLoop?? ?dw?? ?RootDirSectors?? ?; Root Directory 占用的扇區數, 在循環中會遞減至零.
wSectorNo?? ??? ?dw?? ?0?? ??? ?; 要讀取的扇區號
bOdd?? ??? ??? ?db?? ?0?? ??? ?; 奇數還是偶數
;============================================================================
;字符串
;----------------------------------------------------------------------------
LoaderFileName?? ??? ?db?? ?"LOADER? BIN", 0?? ?; LOADER.BIN 之文件名
; 為簡化代碼, 下面每個字符串的長度均為 MessageLength
MessageLength?? ??? ?equ?? ?9
BootMessage:?? ??? ?db?? ?"Booting? "; 9字節, 不夠則用空格補齊. 序號 0
Message1?? ??? ?db?? ?"Ready.?? "; 9字節, 不夠則用空格補齊. 序號 1
Message2?? ??? ?db?? ?"No LOADER"; 9字節, 不夠則用空格補齊. 序號 2
;============================================================================
;----------------------------------------------------------------------------
; 函數名: DispStr
;----------------------------------------------------------------------------
; 作用:
;?? ?顯示一個字符串, 函數開始時 dh 中應該是字符串序號(0-based)
DispStr:
?? ?mov?? ?ax, MessageLength
?? ?mul?? ?dh
?? ?add?? ?ax, BootMessage
?? ?mov?? ?bp, ax?? ??? ??? ?; ┓
?? ?mov?? ?ax, ds?? ??? ??? ?; ┣ ES:BP = 串地址
?? ?mov?? ?es, ax?? ??? ??? ?; ┛
?? ?mov?? ?cx, MessageLength?? ?; CX = 串長度
?? ?mov?? ?ax, 01301h?? ??? ?; AH = 13,? AL = 01h
?? ?mov?? ?bx, 0007h?? ??? ?; 頁號為0(BH = 0) 黑底白字(BL = 07h)
?? ?mov?? ?dl, 0
?? ?int?? ?10h?? ??? ??? ?; 調用10號中斷顯示字符
?? ?ret
;----------------------------------------------------------------------------
; 函數名: ReadSector
;----------------------------------------------------------------------------
; 作用:
;?? ?從第 ax 個 Sector 開始, 將 cl 個 Sector 讀入 es:bx 中
ReadSector:
?? ?; -----------------------------------------------------------------------
?? ?; 怎樣由扇區號求扇區在磁盤中的位置 (扇區號 -> 柱面號, 起始扇區, 磁頭號)
?? ?; -----------------------------------------------------------------------
?? ?; 設扇區號為 x
?? ?;????????????????????????????? ┌ 柱面號 = y >> 1
?? ?;?????? x?? ??? ??? ??? ??? ??? ┌ 商 y ┤
?? ?; -------------- => ┤????? └ 磁頭號 = y & 1
?? ?;? 每磁道扇區數???? │
?? ?;????????????????????????????? └ 余 z => 起始扇區號 = z + 1
?? ?push?? ?bp
?? ?mov?? ?bp, sp
?? ?sub?? ?esp, 2?? ??? ??? ?; 辟出兩個字節的堆棧區域保存要讀的扇區數: byte [bp-2]
?? ?mov?? ?byte [bp-2], cl
?? ?push?? ?bx?? ??? ??? ?; 保存 bx
?? ?mov?? ?bl, [BPB_SecPerTrk]?? ?; bl: 除數
?? ?div?? ?bl?? ??? ??? ?; y 在 al 中, z 在 ah 中
?? ?inc?? ?ah?? ??? ??? ?; z ++
?? ?mov?? ?cl, ah?? ??? ??? ?; cl <- 起始扇區號
?? ?mov?? ?dh, al?? ??? ??? ?; dh <- y
?? ?shr?? ?al, 1?? ??? ??? ?; y >> 1 (其實是 y/BPB_NumHeads, 這里BPB_NumHeads=2)
?? ?mov?? ?ch, al?? ??? ??? ?; ch <- 柱面號
?? ?and?? ?dh, 1?? ??? ??? ?; dh & 1 = 磁頭號
?? ?pop?? ?bx?? ??? ??? ?; 恢復 bx
?? ?; 至此, "柱面號, 起始扇區, 磁頭號" 全部得到 ^^^^^^^^^^^^^^^^^^^^^^^^
?? ?mov?? ?dl, [BS_DrvNum]?? ??? ?; 驅動器號 (0 表示 A 盤)
.GoOnReading:
?? ?mov?? ?ah, 2?? ??? ??? ?; 讀
?? ?mov?? ?al, byte [bp-2]?? ??? ?; 讀 al 個扇區
?? ?int?? ?13h
?? ?jc?? ?.GoOnReading?? ??? ?; 如果讀取錯誤 CF 會被置為 1, 這時就不停地讀, 直到正確為止
?? ?add?? ?esp, 2
?? ?pop?? ?bp
?? ?ret
;----------------------------------------------------------------------------
; 函數名: GetFATEntry
;----------------------------------------------------------------------------
; 作用:
;?? ?找到序號為 ax 的 Sector 在 FAT 中的條目, 結果放在 ax 中
;?? ?需要注意的是, 中間需要讀 FAT 的扇區到 es:bx 處, 所以函數一開始保存了 es 和 bx
GetFATEntry:
?? ?push?? ?es
?? ?push?? ?bx
?? ?push?? ?ax
?? ?mov?? ?ax, BaseOfLoader?? ?; ┓
?? ?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:;偶數
?? ?xor?? ?dx, dx?? ??? ??? ?; 現在 ax 中是 FATEntry 在 FAT 中的偏移量. 下面來計算 FATEntry 在哪個扇區中(FAT占用不止一個扇區)
?? ?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 = (BaseOfLoader - 100) * 10h
?? ?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
;----------------------------------------------------------------------------
times ?? ?510-($-$$)?? ?db?? ?0?? ?; 填充剩下的空間,使生成的二進制代碼恰好為512字節
dw ?? ?0xaa55?? ??? ??? ??? ?; 結束標志
總結
以上是生活随笔為你收集整理的boot.asm文件注释的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 8086/8088 存储器分段概念
- 下一篇: Makefile文件的使用