第四章:LABEL_FILENAME_FOUND,LABEL_GOON_LOADING_FILE,GetFATEntry ,ReadSector四段代码一起详细解释

LABEL_FILENAME_FOUND:   ; 找到 LOADER.BIN 后便来到这里继续
 mov ax, RootDirSectors      ;mov ax,14
 and di, 0FFE0h  ; di -> 当前条目的开始
 add di, 01Ah  ; di -> 首 Sector
 mov cx, word [es:di] ;mov cx,3 通过bochs调试本例中是3
 push cx   ; 保存此 Sector 在 FAT 中的序号
 add cx, ax          ; 3+14
 add cx, DeltaSectorNo ; cx <- LOADER.BIN的起始扇区号3+14+17=34,34是loader.bin的起始扇区
 mov ax, BaseOfLoader 
 mov es, ax   ; es <- BaseOfLoader
 mov bx, OffsetOfLoader ; bx <- OffsetOfLoader
 mov ax, cx   ; ax <- Sector 号                 ax=34

LABEL_GOON_LOADING_FILE:
 push ax   ; `.
 push bx   ;  |  bx=0100h
 mov ah, 0Eh   ;  | 每读一个扇区就在 "Booting  " 后面
 mov al, '.'   ;  | 打一个点, 形成这样的效果:
 mov bl, 0Fh   ;  | Booting ......
 int 10h   ;  |
 pop bx   ;  |
 pop ax   ; /

 mov cl, 1 ;ax=0022h=34,cx=0001h=1,dx=000eh=14,bx=0100h
 call ReadSector
 pop ax   ; 取出此 Sector 在 FAT 中的序号     ax=0003h, 把ss:0x00007bfe的值0003赋给ax
 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]
 jmp LABEL_GOON_LOADING_FILE
LABEL_FILE_LOADED:

 mov dh, 1   ; "Ready."
 call DispStr   ; 显示字符串

; *****************************************************************************************************
 jmp BaseOfLoader:OffsetOfLoader ; 这一句正式跳转到已加载到内
      ; 存中的 LOADER.BIN 的开始处,
      ; 开始执行 LOADER.BIN 的代码。
      ; Boot Sector 的使命到此结束。
; *****************************************************************************************************

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

;----------------------------------------------------------------------------
; 函数名: 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                                ax=3
 mov byte [bOdd], 0
 mov bx, 3
 mul bx   ; dx:ax = ax * 3      ax=9
 mov bx, 2
 div bx   ; dx:ax / 2  ==>  ax <- 商, dx <- 余数     ax=4,dx=1
 cmp dx, 0
 jz LABEL_EVEN                       ;dx=1,条件不成立
 mov byte [bOdd], 1                 ;[bodd]=1表示为奇数,继续向下执行,xor dx,dx
LABEL_EVEN:;偶数
 ; 现在 ax 中是 FATEntry 在 FAT 中的偏移量,下面来
 ; 计算 FATEntry 在哪个扇区中(FAT占用不止一个扇区)
 xor dx, dx   
 mov bx, [BPB_BytsPerSec]                   bx=512;dx=00h
 div bx ; dx:ax / BPB_BytsPerSec           ax=4
     ;  ax <- 商 (FATEntry 所在的扇区相对于 FAT 的扇区号)             ax=0
     ;  dx <- 余数 (FATEntry 在扇区内的偏移)。                             dx=4
 push dx
 mov bx, 0 ; bx <- 0 于是, es:bx = (BaseOfLoader - 100):00
 add ax, SectorNoOfFAT1 ; 此句之后的 ax 就是 FATEntry 所在的扇区号     add ax,1
 mov cl, 2                         ;把FAT1,FAT2读到es:bx的地方
 call ReadSector ; 读取 FATEntry 所在的扇区, 一次读两个, 避免在边界
      ; 发生错误, 因为一个 FATEntry 可能跨越两个扇区
 pop dx                                             dx=4,bx=0
 add bx, dx                                        bx=4
 mov ax, [es:bx]                                 eax=0x0000fff0      ;根据偏移量,读取FATEntry
 cmp byte [bOdd], 1
 jnz LABEL_EVEN_2
 shr ax, 4                                           eax=0x00000fff       ;如果是奇数就要右移4位,如上eax多了一个0
LABEL_EVEN_2:
 and ax, 0FFFh                                   and之后 eax=ox00000fff ;如果是偶数就要去掉高4位,剩下低12位

LABEL_GET_FAT_ENRY_OK:

 pop bx
 pop es
 ret
;-----------------------------------------------------------------------------------------------------------------------------

由开始扇区号(相对与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

posted on 2011-05-12 21:51  wanghj_dz  阅读(388)  评论(0编辑  收藏  举报

导航