本文呈現一款純組合語言編寫的磁碟工具 prw.asm,功能對標 DOS 7.1 FDISK.EXE 與 PowerQuest PQMAGIC.EXE。程式在 486DX2 平台上運行,支援雙 IDE 控制器(Primary/Secondary,IRQ 14/15)、Master/Slave 雙通道、多種定址模式(CHS/LBA/LARGE),能完整掃描硬碟分區表、遞迴解析擴展分區邏輯鏈、依照 FDISK/PQMAGIC 規則分配邏輯磁碟機代號(C:~Z:,超出以 ^ 代替),並提供扇區級讀寫/備份功能。
DOS/Win98 依序掃描 Primary Master(80h)、Primary Slave(81h)、Secondary Master(82h)、Secondary Slave(83h),跳過空通道。啟動序由 BIOS Boot Sequence 決定。
| 暫存器 | 含義 | 範圍/編碼 |
|---|---|---|
| AH | 02h=讀 / 03h=寫 | |
| AL | 扇區數 | 低 6 位有效 (1~63) |
| ES:BX | 緩衝區實模式位址 | |
| CH | 柱面號低 8 位 | 0~1023 |
| CL | 位 0~5:扇區號(1起);位 6~7:柱面號高 2 位 | |
| DH | 磁頭號 | 0~15/254 |
| DL | 磁碟號 | 00h/01h=軟碟;80h~=硬碟 |
使用 16 位元組擴展參數塊 extblk:
extblk db 16, 0 ; 區塊大小、保留
sec_tot dw 1 ; 扇區數
buf_off dw offset buf ; 緩衝區偏移
buf_seg dw seg buf ; 緩衝區段值
lbal dw 0 ; LBA 低雙字低字
lbah dw 0 ; LBA 低雙字高字
dd 0 ; LBA 高雙字 (共 64 位)
CHS↔LBA 互轉公式:
LBA = C × SPC + H × SPT + (S-1)
C = LBA / SPC; H = (LBA % SPC) / SPT; S = (LBA % SPT) + 1
其中 SPC=每柱面扇區數、SPT=每磁道扇區數。
每顆硬碟 0 磁柱 0 磁頭 1 扇區 (CHS) 為 MBR,偏移 1BEh 起連續 4×16 位元組分區表項:
| 偏移 | 大小 | 欄位 | 說明 |
|---|---|---|---|
| 00h | 1 | BootInd | 80h=啟動/作用中,00h=非啟動 |
| 01h | 3 | Start CHS | 起始磁頭/扇區/柱面 (編碼同 Int 13h) |
| 04h | 1 | PartType | 分區類型代碼 (見下表) |
| 05h | 3 | End CHS | 結束 CHS |
| 08h | 4 | StartLBA | 分區前隱藏扇區數 (相對磁碟起始) |
| 0Ch | 4 | NumSecs | 分區總扇區數 |
擴展分區內部以單向鏈結串列組織邏輯分區:
StartLBA 指向第一個邏輯分區的 EBR (Extended Boot Record)。程式 chain 子程式實現遞迴走訪:讀取 EBR → 顯示/記錄當前邏輯分區 → 取 1CEh 項的 StartLBA 加上擴展分區基址 → 循環至類型 00h。
掃描順序固定為磁碟 80h→83h,每磁碟三階段:
BootInd=80h → 分配下一代號 (首個作用主分區得 C:)代號超過 Z: 時,FDISK 繼續分配,PQMAGIC 停止,prw.asm 採用 ^ 符號標記。
| 模組/子程式 | 功能 | 關鍵技術點 |
|---|---|---|
dospri | 掃描主分區、分配代號、記錄佔用表項 | Int 13h AH=201h 驗證磁碟存在;primk 表比對類型;fcbsz 記錄佔用項索引 |
dosext | 掃描擴展分區、啟動鏈遞迴 | 檢測 extmk(05h/0Fh);取基址 entrydi:entryes;呼叫 chain |
chain | 遞迴走訪 EBR 鏈 | 讀 EBR (AH=201h) → pri_non 顯示/分配 → 累加基址跳轉下一 EBR |
nondos | 處理剩餘主分區與非 DOS | 略過已佔用表項 (fcbsz) 與擴展類型 |
h_geo | 取得硬碟幾何參數 | 優先 Int 13h AH=48h (擴展);失敗退回 AH=08h (傳統);計算 SPC/SPT |
f_geo | 軟碟幾何參數 | 讀 BPB (偏移 19h/24h/26h) 反推柱面/磁頭/扇區 |
chs2lba/lba2chs | CHS↔LBA 雙向轉換 | 64 位運算 (DX:AX);SPC/SPT 為除數 |
rw1by1 | 單扇區讀/寫 (傳統/擴展/VxD) | 模式旗標 drv_p;VxD 路徑檢測緩衝區跨 4KB 頁、自動映射/釋放 |
INnib | 十六進位鍵盤輸入 (長度可配) | 轉換至 stk1 堆疊陣列;低字回傳 BX |
Show | 格式化輸出分區資訊 | from80/logidrv/Boot/volume/Front/In 字串模板 |
Windows 9x V86 監控器攔截 Int 13h,DOS 程式無法直接存取硬碟。prw 採用動態載入 VxD方案:
INT 2Fh/AX=1684h, BX=3180h 取得 VxD V86_API_Entry 入口 (ES:DI)。CLIENT_STRUCT,VxD 內部執行 Exec_Int(0x13) 實體中斷。BP 修正值:BP < 4096 → 偏移量;BP = 4096 → 緩衝區已在 V86 可見區;BP = 0x1010 → 成功映射至 V86 第 0x10 頁;BP = 0x1110 → 映射失敗。BP 調整 ES:BX 重試,完成後釋放映射頁面。配套 C++ 載入器 (CreateFile("\\\\.\\C.VXD", FILE_FLAG_DELETE_ON_CLOSE)) 實現按需動態載入/卸載。
雙硬碟環境 (ST32140A 2.0 GB + QUANTUM 514 MB) 掃描結果:
80,C:,Boot:80,FAT:06,Front:0000003F,In:00101661 ; 1299 MB FAT16B 作用主分區 80,^,Boot:00,FAT:17,Front:001016A0,In:00047A00 ; Hidden NTFS 574 MB (^符號) 80,E:,Boot:00,FAT:0B,Front:001490A0,In:00046A00 ; FAT32 邏輯分區 81,D:,Boot:80,FAT:06,Front:0000003F,In:000E8A00 ; 472 MB 作用主分區 81,H:,Boot:00,FAT:01,Front:000E8A40,In:00011A00 ; FAT12 邏輯分區 ...
與 FDISK/PQMAGIC 代號分配完全一致,驗證演算法正確性。
prw.asm 以不足 2 KB 核心代碼,完整實現了從 BIOS 幾何參數獲取、CHS/LBA 雙模式存取、MBR/EBR 遞迴解析、三階段代號分配、V86 環境下的 VxD 突破五大核心難題。代碼結構清晰、模組解耦,是學習底層磁碟編程、BIOS 介面、實模式/V86 交互、VxD 開發的極佳教案與實用工具。