第四章 boot.asm代码详解

第四章 boot.asm  代码详解

;%define _BOOT_DEBUG

   %ifdef   _BOOT_DEBUG

           org 0100h

    %else

            org 07c00h

     %endif

这段代码的意思是,如果定义了_BOOT_DEBUG 则 org 0100h,如果没有定义则 org 07c00h

如果把;%define _BOOT_DEBUG前面的;去掉则该语句执行,_BOOT_DEBUG定义了。如果加上;则被注释掉了,_BOOT_DEBUG没有定义。

-----------------------------------------------------------------------------------------------------------------------------------------

由开始扇区号(相对与0扇区号而言)推导出 磁头号、柱面号(磁道号),柱面开始扇区号

开始扇区号/18  得到的商Q,柱面号为 Q>>1,磁头号为Q&1

                     得到的余数R,柱面起始扇区为R+1

读软盘扇区的函数:

ReadSector:          ;从第ax个Sector开始读,将Cl个Sector读入es:bx中

push bp                 ;会用到bp,所以要先push bp

mov  bp,sp           ;准备用bp了

sub   esp ,2          ;辟出2个字节的堆栈区域保存要读的扇区数  ;byte [bp-2]

mov  byte[bp-2],cl   ;把要读的扇区数放在byte[bp-2]的堆栈空间

push bx                  ;保存bx,因为要用到bl作为除数,所以要先push保护起来

mov  bl,[BPB_SecPerTrk]  ;bl 除数为18

div    bl                            ;ax/bl ,商在al中,余数在ah中

inc    ah                           ;ah加1,相当于余数加1,得到柱面的开始扇区号

mov cl ,ah                      ;把起始扇区号赋给cl

mov dh ,al                      ;把商赋给dh

shr  al ,1                        ;把商右移1得到柱面号

mov ch,al                       ;把柱面号赋给ch

add dh,1                        ;商and1,得到磁头号,磁头号本来就要赋给dh

pop bx                            ;放出保存的bx

mov dl ,[BS_DrvNum]     ;驱动器号(0表示A盘)

;至此 cl 起始扇区号,ch 柱面号,dl 驱动器号,dh磁头号 就全部有值了,这样就把ax中的扇区数转化过来了,ax中的值也没用了。

;至此int 13中还有ah和al没有赋值,请看下面

.GoOnReading:
 mov ah, 2                           ; ah=2表示要读
 mov al, byte [bp-2]             ; 读 al 个扇区
 int 13h                               ;哈哈,所有的参数都有值了。
 jc .GoOnReading                 ; 如果读取错误 CF 会被置为 1, 
                                          ; 这时就不停地读, 直到正确为止
 add esp, 2
 pop bp

 ret

-------------------------------------------------------------------------------------------------------------------------------------------

xor ah,ah                         ; ah=0表示要复位

xor dl, dl                          ;dl表示要复位的驱动器号,0表示是软驱

int 13

--------------------------------------------------------------------------------------------------------------------------------------------

LABEL_START:
 mov ax, cs
 mov ds, ax
 mov es, ax
 mov ss, ax
 mov sp, BaseOfStack

 xor ah, ah ; `.
 xor dl, dl ;  |  软驱复位
 int 13h ; /
 
; 下面在 A 盘的根目录寻找 LOADER.BIN
 mov word [wSectorNo], SectorNoOfRootDirectory ;       SectorNoOfRootDirectory=19,根目录开始的扇区,初值等于19。

LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
 cmp word [wRootDirSizeForLoop], 0 ;  判断根目录区所有扇区是不是已经读完  ,初值等于14个扇区
 jz LABEL_NO_LOADERBIN               ;  如果读完表示没有找到 LOADER.BIN
 dec word [wRootDirSizeForLoop]      ; 根目录扇区总数减1
 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:di -> BaseOfLoader:0100,正好指向根目录项的文件名属性
 cld
 mov dx, 10h                                   ;因为一个扇区最多有512/32=16个根目录
LABEL_SEARCH_FOR_LOADERBIN:
 cmp dx, 0                                        ;  循环次数控制,
 jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR ;如果已经读完这个扇区的所有根目录,就跳到下一个扇区。
 dec dx                                             ; 就跳到这个扇区的下一个根目录
 mov cx, 11                                       ;因为根目录的DIR_Name有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 为了让它指向本条目开头
 add di, 20h                                             ;  di += 20h  下一个目录条目 20h=32个字节
 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   ; "No LOADER."                      ;DispStr会把2转换为message2这个地址
 call DispStr   ; 显示字符串
%ifdef _BOOT_DEBUG_
 mov ax, 4c00h  ; `.
 int 21h   ; /  没有找到 LOADER.BIN, 回到 DOS
%else
 jmp $   ; 没有找到 LOADER.BIN, 死循环在这里
%endif

LABEL_FILENAME_FOUND:   ; 找到 LOADER.BIN 后便来到这里继续
 jmp $   ; 代码暂时停在这里

 ;============================================================================
;变量
wRootDirSizeForLoop dw RootDirSectors ; Root Directory 占用的扇区数,RootDirSectors=14
      ; 在循环中会递减至零.
wSectorNo  dw 0  ; 要读取的扇区号,在循环中从19开始,不断加1,加13次
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
;============================================================================

posted on 2011-05-11 17:04  wanghj_dz  阅读(1958)  评论(0编辑  收藏  举报

导航