在《自己動手寫操作系統》中有個重要的彙編函數ReadSector,作用是通過中斷int 13,從驅動器中讀取開始地址(ax號扇區)後指定數量(cl個)扇區數據到目標地址(es:bp),具體代碼如下:
;----------------------------------------------------------------------------
; 函數名: ReadSector
;----------------------------------------------------------------------------
; 作用:
; 從第 ax 個 Sector 開始, 將 cl 個 Sector 讀入 es:bx 中
ReadSector:
; -----------------------------------------------------------------------
; 怎樣由扇區號求扇區在磁盤中的位置 (扇區號 -> 柱面號, 起始扇區, 磁頭號)
; -----------------------------------------------------------------------
; 設扇區號爲 x
; ┌ 柱面號 = y >> 1
; x ┌ 商 y ┤
; -------------- => ┤ └ 磁頭號 = y & 1
; 每磁道扇區數18 │
; └ 餘 z => 起始扇區號 = z + 1
push bp
mov bp, sp
sub esp, 2 ; 闢出兩個字節的堆棧區域保存要讀的扇區數: byte [bp-2]
mov byte [bp-2], cl
push bx ; 保存 bx
mov bl, [BPB_SecPerTrk] ; bl: 除數
div bl ; y 在 al 中, z 在 ah 中
inc ah ; z ++
mov cl, ah ; cl <- 起始扇區號
mov dh, al ; dh <- y
shr al, 1 ; y >> 1 (其實是 y/BPB_NumHeads, 這裏BPB_NumHeads=2)
mov ch, al ; ch <- 柱面號
and dh, 1 ; dh & 1 = 磁頭號
pop bx ; 恢復 bx
; 至此, "柱面號, 起始扇區, 磁頭號" 全部得到 ^^^^^^^^^^^^^^^^^^^^^^^^
mov dl, [BS_DrvNum] ; 驅動器號 (0 表示 A 盤)
.GoOnReading:
mov ah, 2 ; 讀
mov al, byte [bp-2] ; 讀 al 個扇區
int 13h
jc .GoOnReading ; 如果讀取錯誤 CF 會被置爲 1, 這時就不停地讀, 直到正確爲止
add esp, 2
pop bp
ret
其中最重要的是:
1、傳入的扇區起始號(ax)是邏輯編號(即從0開始),所以有了inc ah這行代碼。因爲軟盤的扇區號是從 0柱面0磁頭1扇區開始編號的。
2、商y的編碼方式爲 7位柱面號 + 1位磁頭號,2^7 = 128 > 80(每面的磁道數或柱面數)