首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

DSKWATCH:磁碟錯誤即時監控與螢幕顯示 TSR

     編輯:組合語言

前言:硬體錯誤可視化 — 攔截 BIOS 磁碟中斷

在無系統日誌、無事件檢視器的 DOS 年代,磁碟讀寫錯誤 (扇區損壞、磁頭定位失敗、CRC 錯誤) 往往只會導致程式掛起或回傳錯誤碼,使用者難以即時感知。DSKWATCH.ASM (Steve Holzner, PC Magazine 1985) 實作一個 TSR:攔截 INT 13h (BIOS 磁碟服務) 向量,在原始處理常式返回後檢查 Carry Flag (CF=1 表示錯誤),若發生錯誤則在螢幕固定位置 (右上角) 顯示錯誤類型 (無回應、定位失敗、NEC 錯誤、CRC 錯誤、DMA 溢位、扇區未找到、位址標記遺失、寫保護、未知錯誤)。程式展示了中斷鏈結、螢幕直接寫入 (文字/圖形模式自動偵測)、錯誤碼解碼、TSR 常駐等實用技術。

程式架構

  1. 初始化 load_watch:
    • 讀取 IVT INT 13h*4 保存原始向量至 old_disk_int
    • 設定新向量指向 disk_watch
    • 呼叫 INT 10h, AH=15h 取得當前視訊模式,計算螢幕右上角起始位置 (first_position)
    • 偵測單色/彩色模式,設定顯存段基址 (screen_seg_offset = 0 或 8000h)
    • INT 27h 常駐 (保留初始化碼前所有區塊)
  2. 攔截常式 disk_watch:
    • PUSHF / CALL old_disk_int 執行原始 BIOS 磁碟服務
    • 保存旗標至 flags,檢查 CF
    • 若 CF=0 → 直接恢復旗標、返回
    • 若 CF=1 → 保存暫存器、解碼 AH 錯誤碼、顯示訊息、恢復暫存器/旗標、返回

關鍵技術細節

1. 錯誤碼解碼與訊息表

msg_part_1 db 'Disk error: '
msg_part_2 db 'No response Failed Seek NEC Error '
 db 'Bad CRC SeenDMA Overrun Impos Sector'
 db 'No Addr MarkW. ProtectedErr Unknown '

msg_part_2 為 12 字元寬度固定欄位訊息表,對應錯誤碼 (AH) 的位元權重:

Bit錯誤碼 (AH)訊息
001hNo response
102hFailed Seek
204hNEC Error
308hBad CRC
410hDMA Overrun
520hImpos Sector
640hNo Addr Mark
780hW. Protected

解碼迴圈:MOV DX, 80h / MOV CX, 7 / CMP AH, DH / JE FOUND / ADD SI, 12 / SHR DH, 1 / LOOP — 從最高位 (80h) 向下測試,匹配則顯示對應 12 字元訊息。若無匹配 (AH=03h 等非單一位錯誤碼) 顯示 "Unknown "。

2. 直接寫入顯存

write_to_screen proc near
 mov cx, 12
w_loop:
 movs es:byte ptr[di], cs:[si]  ; 複製字元
 mov al, 7
 mov es:[di], al                ; 屬性 = 白底黑字? (07h)
 inc di
 loop w_loop
 ret

使用 MOVS 字串指令高效複製字元+屬性。屬性 `07h` (白字黑底) 在單色/彩色文字模式通用。

3. 旗標與堆疊精細恢復

fin:
 pop ret_addr_word       ; 彈出原 CALL 返回位址 (IP)
 pop ret_addr_word[2]    ; 彈出原 CALL 返回位址 (CS)
 add sp, 2               ; 跳過原 PUSHF 推入的旗標
 push flags              ; 推入我們保存的旗標
 popf                    ; 恢復旗標 (含 CF=1)
 jmp ret_addr            ; 遠端跳轉返回原呼叫者

關鍵技巧:原始 `CALL old_disk_int` 推入 `CS:IP`,`PUSHF` 推入旗標。我們需保持原呼叫者看到 CF=1 (錯誤),故在返回前移除原旗標、推入保存的旗標、再 `JMP` 返回。此過程不破壞任何暫存器 (已全部 push/pop)。

4. 視訊模式偵測與顯存基址

mov ah, 15
int 10h                 ; AL=模式, AH=列數, BH=頁面
sub ah, 25              ; 從右邊倒數 25 字元
shl ah, 1               ; *2 (字元+屬性)
mov byte ptr first_position, ah
test al, 4              ; Bit 2=1 表示單色模式 (Mode 7)
jnz exit
mov screen_seg_offset, 8000h  ; 彩色文字模式基址 B800h - B000h = 8000h

單色模式 (Mode 7) 顯存位於 B000:0000,彩色文字模式 (Mode 2/3) 位於 B800:0000。程式以 `ES` 固定為 `B000h` (screen segment),`screen_seg_offset` 作為額外偏移 (0 或 8000h) 加至 `DI`。

完整原始碼

interrupts segment at 0h org 13h*4 disk_int label dword interrupts ends screen segment at 0B000h screen ends code_seg segment assume cs:code_seg org 0100h first: jmp load_watch msg_part_1 db 'Disk error: ' msg_part_2 db 'No response Failed Seek NEC Error ' db 'Bad CRC SeenDMA Overrun Impos Sector' db 'No Addr MarkW. ProtectedErr Unknown ' first_position dw ? flags dw ? screen_seg_offset dw 0 old_disk_int dd ? ret_addr label dword ret_addr_word dw 2 dup(?) disk_watch proc far assume cs:code_seg pushf call old_disk_int pushf pop flags jc error jmp fin error: push ax, cx, dx, di, si, es lea si, msg_part_1 assume es:screen mov dx, screen mov es, dx mov di, screen_seg_offset add di, first_position call write_to_screen mov dx, 80h mov cx, 7 e_loop: cmp ah, dh je e_found add si, 12 shr dh, 1 loop e_loop cmp ah, 3 je e_found add si, 12 e_found: call write_to_screen pop es, si, di, dx, cx, ax fin: pop ret_addr_word pop ret_addr_word[2] add sp, 2 push flags popf jmp ret_addr disk_watch endp write_to_screen proc near ... endp load_watch proc near assume ds:interrupts mov ax, interrupts mov ds, ax mov ax, disk_int mov old_disk_int, ax mov ax, disk_int[2] mov old_disk_int[2], ax mov disk_int, offset disk_watch mov disk_int[2], cs mov ah, 15 int 10h sub ah, 25 shl ah, 1 mov byte ptr first_position, ah test al, 4 jnz exit mov screen_seg_offset, 8000h exit: mov dx, offset load_watch int 27h load_watch endp code_seg ends end first

教學價值與現代映照

  • BIOS 中斷攔截:`INT 13h` 為磁碟服務核心入口,攔截點低於 DOS 檔案系統,可捕捉所有磁碟活動 (含開機載入器、分區工具、絕對扇區讀寫)。
  • 硬體錯誤碼標準化:IBM PC BIOS 定義的磁碟錯誤碼 (AH 位元掩碼) 成為行業標準,現代 SCSI Sense Key / ATA Error Register / NVMe Status Field 同樣採用位元掩碼編碼錯誤類型。
  • 即時視覺化監控:在無作業系統支援下,直接寫入顯存實現「系統級通知」 — 現代 Windows ETW/Event Log、Linux kernel `printk`/dmesg、UEFI Boot Services `ConOut` 同樣解決「早期/底層錯誤可視化」問題。
  • TSR 共存技巧:鏈結原始向量、最小化常駐體積、精細堆疊/旗標管理 — 現代內核模組/驅動程式同樣需處理中斷鏈結、上下文保存、併發安全。

DSKWATCH 以約 150 行程式碼,實作了專業級磁碟健康監控工具,其「攔截 → 執行原操作 → 檢查結果 → 解碼錯誤 → 即時顯示 → 透明返回」閉環邏輯,是理解底層錯誤處理、硬體抽象層設計、系統監控代理開發的經典範例。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved