2010年02月28日

时间:2023-02-14 11:44:59

;%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 ;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  ;要读取的扇区号
bOdd   db  ;奇数还是偶数

;字符串
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