?? boot.asm
字號(hào):
;%define _BOOT_DEBUG_ ; 做 Boot Sector 時(shí)一定將此行注釋掉!將此行打開后用 nasm Boot.asm -o Boot.com 做成一個(gè).COM文件易于調(diào)試
%ifdef _BOOT_DEBUG_
org 0100h ; 調(diào)試狀態(tài), 做成 .COM 文件, 可調(diào)試
%else
org 07c00h ; Boot 狀態(tài), Bios 將把 Boot Sector 加載到 0:7C00 處并開始執(zhí)行
%endif
;================================================================================================
%ifdef _BOOT_DEBUG_
BaseOfStack equ 0100h ; 調(diào)試狀態(tài)下堆?;刂?棧底, 從這個(gè)位置向低地址生長(zhǎng))
%else
BaseOfStack equ 07c00h ; Boot狀態(tài)下堆棧基地址(棧底, 從這個(gè)位置向低地址生長(zhǎng))
%endif
BaseOfLoader equ 09000h ; LOADER.BIN 被加載到的位置 ---- 段地址
OffsetOfLoader equ 0100h ; LOADER.BIN 被加載到的位置 ---- 偏移地址
RootDirSectors equ 14 ; 根目錄占用空間
SectorNoOfRootDirectory equ 19 ; Root Directory 的第一個(gè)扇區(qū)號(hào)
;================================================================================================
jmp short LABEL_START ; Start to boot.
nop ; 這個(gè) nop 不可少
; 下面是 FAT12 磁盤的頭
BS_OEMName DB 'ForrestY' ; OEM String, 必須 8 個(gè)字節(jié)
BPB_BytsPerSec DW 512 ; 每扇區(qū)字節(jié)數(shù)
BPB_SecPerClus DB 1 ; 每簇多少扇區(qū)
BPB_RsvdSecCnt DW 1 ; Boot 記錄占用多少扇區(qū)
BPB_NumFATs DB 2 ; 共有多少 FAT 表
BPB_RootEntCnt DW 224 ; 根目錄文件數(shù)最大值
BPB_TotSec16 DW 2880 ; 邏輯扇區(qū)總數(shù)
BPB_Media DB 0xF0 ; 媒體描述符
BPB_FATSz16 DW 9 ; 每FAT扇區(qū)數(shù)
BPB_SecPerTrk DW 18 ; 每磁道扇區(qū)數(shù)
BPB_NumHeads DW 2 ; 磁頭數(shù)(面數(shù))
BPB_HiddSec DD 0 ; 隱藏扇區(qū)數(shù)
BPB_TotSec32 DD 0 ; 如果 wTotalSectorCount 是 0 由這個(gè)值記錄扇區(qū)數(shù)
BS_DrvNum DB 0 ; 中斷 13 的驅(qū)動(dòng)器號(hào)
BS_Reserved1 DB 0 ; 未使用
BS_BootSig DB 29h ; 擴(kuò)展引導(dǎo)標(biāo)記 (29h)
BS_VolID DD 0 ; 卷序列號(hào)
BS_VolLab DB 'Tinix0.01 '; 卷標(biāo), 必須 11 個(gè)字節(jié)
BS_FileSysType DB 'FAT12 ' ; 文件系統(tǒng)類型, 必須 8個(gè)字節(jié)
LABEL_START:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack
xor ah, ah ; ┓
xor dl, dl ; ┣ 軟驅(qū)復(fù)位
int 13h ; ┛
; 下面在 A 盤的根目錄尋找 LOADER.BIN
mov word [wSectorNo], SectorNoOfRootDirectory
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
cmp word [wRootDirSizeForLoop], 0 ; ┓
jz LABEL_NO_LOADERBIN ; ┣ 判斷根目錄區(qū)是不是已經(jīng)讀完
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 號(hào)
mov cl, 1
call ReadSector
mov si, LoaderFileName ; ds:si -> "LOADER BIN"
mov di, OffsetOfLoader ; es:di -> BaseOfLoader:0100 = BaseOfLoader*10h+100
cld
mov dx, 10h
LABEL_SEARCH_FOR_LOADERBIN:
cmp dx, 0 ; ┓循環(huán)次數(shù)控制,
jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR ; ┣如果已經(jīng)讀完了一個(gè) Sector,
dec dx ; ┛就跳到下一個(gè) Sector
mov cx, 11
LABEL_CMP_FILENAME:
cmp cx, 0
jz LABEL_FILENAME_FOUND ; 如果比較了 11 個(gè)字符都相等, 表示找到
dec cx
lodsb ; ds:si -> al
cmp al, byte [es:di]
jz LABEL_GO_ON
jmp LABEL_DIFFERENT ; 只要發(fā)現(xiàn)不一樣的字符就表明本 DirectoryEntry 不是
; 我們要找的 LOADER.BIN
LABEL_GO_ON:
inc di
jmp LABEL_CMP_FILENAME ; 繼續(xù)循環(huán)
LABEL_DIFFERENT:
and di, 0FFE0h ; else ┓ di &= E0 為了讓它指向本條目開頭
add di, 20h ; ┃
mov si, LoaderFileName ; ┣ di += 20h 下一個(gè)目錄條目
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
%else
jmp $ ; 沒有找到 LOADER.BIN, 死循環(huán)在這里
%endif
LABEL_FILENAME_FOUND: ; 找到 LOADER.BIN 后便來(lái)到這里繼續(xù)
jmp $ ; 代碼暫時(shí)停在這里
;============================================================================
;變量
;----------------------------------------------------------------------------
wRootDirSizeForLoop dw RootDirSectors ; Root Directory 占用的扇區(qū)數(shù), 在循環(huán)中會(huì)遞減至零.
wSectorNo dw 0 ; 要讀取的扇區(qū)號(hào)
bOdd db 0 ; 奇數(shù)還是偶數(shù)
;============================================================================
;字符串
;----------------------------------------------------------------------------
LoaderFileName db "LOADER BIN", 0 ; LOADER.BIN 之文件名
; 為簡(jiǎn)化代碼, 下面每個(gè)字符串的長(zhǎng)度均為 MessageLength
MessageLength equ 9
BootMessage: db "Booting "; 9字節(jié), 不夠則用空格補(bǔ)齊. 序號(hào) 0
Message1 db "Ready. "; 9字節(jié), 不夠則用空格補(bǔ)齊. 序號(hào) 1
Message2 db "No LOADER"; 9字節(jié), 不夠則用空格補(bǔ)齊. 序號(hào) 2
;============================================================================
;----------------------------------------------------------------------------
; 函數(shù)名: DispStr
;----------------------------------------------------------------------------
; 作用:
; 顯示一個(gè)字符串, 函數(shù)開始時(shí) dh 中應(yīng)該是字符串序號(hào)(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 = 串長(zhǎng)度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 0007h ; 頁(yè)號(hào)為0(BH = 0) 黑底白字(BL = 07h)
mov dl, 0
int 10h ; int 10h
ret
;----------------------------------------------------------------------------
; 函數(shù)名: ReadSector
;----------------------------------------------------------------------------
; 作用:
; 從第 ax 個(gè) Sector 開始, 將 cl 個(gè) Sector 讀入 es:bx 中
ReadSector:
; -----------------------------------------------------------------------
; 怎樣由扇區(qū)號(hào)求扇區(qū)在磁盤中的位置 (扇區(qū)號(hào) -> 柱面號(hào), 起始扇區(qū), 磁頭號(hào))
; -----------------------------------------------------------------------
; 設(shè)扇區(qū)號(hào)為 x
; ┌ 柱面號(hào) = y >> 1
; x ┌ 商 y ┤
; -------------- => ┤ └ 磁頭號(hào) = y & 1
; 每磁道扇區(qū)數(shù) │
; └ 余 z => 起始扇區(qū)號(hào) = z + 1
push bp
mov bp, sp
sub esp, 2 ; 辟出兩個(gè)字節(jié)的堆棧區(qū)域保存要讀的扇區(qū)數(shù): byte [bp-2]
mov byte [bp-2], cl
push bx ; 保存 bx
mov bl, [BPB_SecPerTrk] ; bl: 除數(shù)
div bl ; y 在 al 中, z 在 ah 中
inc ah ; z ++
mov cl, ah ; cl <- 起始扇區(qū)號(hào)
mov dh, al ; dh <- y
shr al, 1 ; y >> 1 (其實(shí)是 y/BPB_NumHeads, 這里BPB_NumHeads=2)
mov ch, al ; ch <- 柱面號(hào)
and dh, 1 ; dh & 1 = 磁頭號(hào)
pop bx ; 恢復(fù) bx
; 至此, "柱面號(hào), 起始扇區(qū), 磁頭號(hào)" 全部得到 ^^^^^^^^^^^^^^^^^^^^^^^^
mov dl, [BS_DrvNum] ; 驅(qū)動(dòng)器號(hào) (0 表示 A 盤)
.GoOnReading:
mov ah, 2 ; 讀
mov al, byte [bp-2] ; 讀 al 個(gè)扇區(qū)
int 13h
jc .GoOnReading ; 如果讀取錯(cuò)誤 CF 會(huì)被置為 1, 這時(shí)就不停地讀, 直到正確為止
add esp, 2
pop bp
ret
times 510-($-$$) db 0 ; 填充剩下的空間,使生成的二進(jìn)制代碼恰好為512字節(jié)
dw 0xaa55 ; 結(jié)束標(biāo)志
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -