;%define _BOOT_DEBUG_
%ifdef _BOOT_DEBUG
org 0100h
%else
org07c00h
%endif
;==================================================================
%ifdef _BOOT_DEBUG_
BaseOfStack equ 0100h ;调试状态下堆栈基地址(栈底,从这个位置向低地址生长0
%else
BaseOfStack equ 07c00h ;堆栈基地址
%endif
BaseOfLoader equ 09000h ;Loader.bin被加载到的段地址
OffsetOfLoader equ 0100h ;Loader.bin被加载到的偏移地址
RootDirSectors equ 14 ;根目录占用空间
SectorNoOfRootDirectoryequ 19 ;RootDirectory的第一个扇区号
SectorNoOfFAT1 equ 1 ;FAT的第一个扇区号= BPB_RsvSecCnt
DeltaSectorNo equ 17
jmp short LABEL_START
nop ;nop不能少,估计要初始化下面的BPB磁头
;下面是FAT12磁头
BS_OEMName DB'LZYSTART' ; OEM String, 必须 8 个字节
BPB_BytsPerSec DW512 ; 每扇区字节数
BPB_SecPerClus DB1 ; 每簇多少扇区
BPB_RsvdSecCnt DW1 ; Boot 记录占用多少扇区
BPB_NumFATs DB2 ; 共有多少 FAT 表
BPB_RootEntCnt DW224 ; 根目录文件数最大值
BPB_TotSec16 DW2880 ; 逻辑扇区总数
BPB_Media DB0xF0 ; 媒体描述符
BPB_FATSz16 DW9 ; 每FAT扇区数
BPB_SecPerTrk DW18 ; 每磁道扇区数
BPB_NumHeads DW2 ; 磁头数(面数)
BPB_HiddSec DD0 ; 隐藏扇区数
BPB_TotSec32 DD0 ; 如果 wTotalSectorCount 是 0由这个值记录扇区数
BS_DrvNum DB0 ; 中断 13 的驱动器号
BS_Reserved1 DB0 ; 未使用
BS_BootSig DB29h ; 扩展引导标记 (29h)
BS_VolID DD0 ; 卷序列号
BS_VolLab DB 'OrangeS0.02'; 卷标,必须 11 个字节
BS_FileSysType DB'FAT12 ' ;文件系统类型, 必须 8个字节
LABEL_START: mov ax,cx
movds,ax
moves,ax
movss,ax
movsp,BaseOfStack
;清屏
mov ax,0600h
mov bx,0700h
mov cx,0
mov dx,0184fh
int 10h
mov dh,0
call DispStr
xorah,ah ;软驱
xordl,dl ;复
int13h ;位
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;下面在A盘的根目录寻找LOADER.BIN
mov word[wSectorNo],SectorNoOfRootDirectory
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
cmp word[wRootDirSizeForLoop],0 ;判断根目录区是不是已经读完
jz LABEL_NO_LOADERBIN
dec word[wRootDirSizeForLoop]
mov ax,BaseOfLoader
mov es,ax ;es<- BaseOfLoader
mov bx,OffsetOfLoader ;bx<- OffsetOfLoader
mov ax,[wSectorNo] ;ax<-Root Directory 中的某Sector号
mov cl,1
call ReadSector
mov si,LoaderFileName ;ds:si->"LOADER BIN"
mov di,OffsetOfLoader ;es:do->BaseOfLoader : 0100
cld
mov dx,10h ;每扇区有16个条目,每条目有32个字节
LABEL_SEARCH_FOR_LOADERBIN:
cmp dx,0
jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR
dec dx
mov cx,11
LABEL_CMP_FILENAME:
cmp cx,0
jz LABEL_FILENAME_FOUND
dec cx
lodsb
cmp al,byte [es:di]
jz LABEL_GO_ON
jmp LABEL_DIFFERENT
LABEL_GO_ON:
inc di
jmp LABEL_CMP_FILENAME
LABEL_DIFFERENT:
and di,0FFE0H ;让di指向条目开头,即32的倍数
add di,20h ;指向下一个条目
mov si,LoaderFileName
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 ;"NoLoader."
call DispStr ;显示字符串
%ifdef _BOOT_DEBUG_
mov ax,4c00h
int 21h
%else
jmp $
%endif
LABEL_FILENAME_FOUND:
mov ax,RootDirSectors
and di,0ffe0h
add di,01Ah ;di->首Sector,即每条目的第26位后的一个字节写的是fat号
mov cx,word [es:di]
push cx
add cx,ax
add cx,DeltaSectorNo
mov ax,BaseOfLoader
mov es,ax
mov bx,OffsetOfLoader
mov ax,cx
LABEL_GOON_LOADING_FILE:
push ax
push bx
mov ah,0Eh
mov al,'.'
mov bl,0Fh
int 10h
pop bx
pop ax
mov cl,1
call ReadSector
pop ax
call GetFATEntry
cmp ax,0fffh
jz LABEL_FILE_LOADED
push ax
mov dx,RootDirSectors
add ax,dx
add ax,DeltaSectorNo
add bx,[BPB_BytsPerSec]
jmp LABEL_GOON_LOADING_FILE
LABEL_FILE_LOADED:
mov dh,1
call DispStr
jmp BaseOfLoader:OffsetOfLoader
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>..
;变量
wRootDirSizeForLoop dw RootDirSectors ;RootDirectory占用的扇区数
;在循环中会递减至0
wSectorNo dw 0 ;要读取的扇区号
bOdd db 0 ;奇数还是偶数
;字符串
LoaderFileName db "LOADER BIN",0 ;Loader.bin文件名
MessageLength equ 9
BootMessage: db "Booting "
Message1 db "Ready. "
Message2 db "NOLOADER"
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;显示字符串,函数开始时dh中应该是字符串序号(0-based)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DispStr:
mov ax,MessageLength
mul dh
add ax,BootMessage
mov bp,ax
mov ax,ds
mov es,ax
mov cx,MessageLength
mov ax,01301h
mov bx,0007h
mov dl,0
int 10h
ret
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.
;函数名:ReadSector ,从第ax个Sector开始,将cl个Sector读入 es:bx中
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ReadSector:
push bp
mov bp,sp
sub esp,2
mov byte [bp-2],cl
push bx
mov bl,[BPB_SecPerTrk]
div bl
inc ah ;z++为起始扇区号
mov cl,ah ;cl<-起始扇区号
mov dh,al ;dh<-y
shr al,1 ;y>>1
mov ch,al ;ch<-柱面号
and dh,1 ;磁头号
pop bx
;所需信息全部得到
mov dl,[BS_DrvNum] ;驱动器号
.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
mov bx,2
div bx
cmp dx,0
jz LABEL_EVEN
mov byte [bOdd],1
LABEL_EVEN: ;偶数
xor dx,dx
mov bx,[BPB_BytsPerSec]
div bx
push dx
mov bx,0
add ax,SectorNoOfFAT1
mov cl,2
call ReadSector
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
dw 0xaa55