Windows 3.x/9x 採用非搶佔式協同多工,訊息驅動架構導致外部硬體事件必須經過系統訊息佇列 → 應用程式訊息佇列 → 視窗程序的漫長路徑,無法滿足工業控制、資料擷取等即時應用的硬性延遲需求。雖可購買即時核心 (如 FLX、iRMX),但中小專案成本過高。本文展示如何利用 DPMI (DOS Protected Mode Interface) 在 Windows 增強模式下直接掛接硬體中斷向量,繞過訊息機制實現微秒級回應。
IRET 返回DPMI 由 INT 31h 與部分 INT 2Fh 服務組成,Windows 作為 DPMI Host 提供服務。關鍵中斷管理功能:
INT 31h AH=0204h - 取得保護模式中斷向量輸入: AX=0204h, BL=中斷號
輸出: CF=0 成功, CX:DX = 選擇子:偏移量
CF=1 失敗
INT 31h AH=0205h - 設定保護模式中斷向量輸入: AX=0205h, BL=中斷號, CX:DX = 處理程式選擇子:偏移量
輸出: CF=0 成功, CF=1 失敗
WM_CREATE 訊息處理中 (最早安全時機)WM_DESTROY 訊息處理中 (必須恢復,否則 Windows 崩潰)0204h 保存原向量,退出時用 0205h 還原void interrupt far DataReceive() {
static int i = 0;
char ch = inportb(0x3F8); // 讀取接收緩衝器
if (!inFlag) {
if (ch != 's' && i == 0) goto ExitISR; // 等待起始字元 's'
dataCom_r[i++] = ch;
if (ch == 'e') { inFlag = 1; i = 0; } // 結束字元 'e'
}
ExitISR:
outportb(0x20, 0x20); // 發送 EOI 給主 8259A
}
void InitCom(void) {
// 1. 保存原中斷向量 (IRQ4 = INT 0Ch)
_asm {
cli
mov ax, 0204h
mov bl, 0Ch
int 31h
sti
}
old_vector = MK_FP(_CX, _DX);
// 2. 設定新中斷向量指向 DataReceive
_asm {
cli
mov ax, 0205h
mov bl, 0Ch
mov cx, seg DataReceive
mov dx, offset DataReceive
int 31h
sti
}
// 3. 硬體初始化:8250 UART + 8259A PIC
unsigned char s8259 = inportb(0x21); // 保存主 PIC IMR
outportb(0x21, s8259 & 0xE8); // 開啟 IRQ4 (bit 3=0)
outportb(0x3FB, 0x83); // DLAB=1
outportb(0x3F8, 0x0C); // 鮑率 9600: 除數低位
outportb(0x3F9, 0x00); // 除數高位
outportb(0x3FB, 0x03); // DLAB=0, 8N1
outportb(0x3FC, 0x08); // 啟用接收中斷 (IER bit 0)
outportb(0x3F9, 0x01); // 輔助控制
}
void RestoreComm(void) {
outportb(0x21, s8259); // 恢復 PIC IMR
_asm {
cli
mov ax, 0205h
mov bl, 0Ch
mov cx, seg old_vector
mov dx, offset old_vector
int 31h
sti
}
}
// WM_CREATE
case WM_CREATE:
InitCom();
break;
// WM_DESTROY
case WM_DESTROY:
RestoreComm();
PostQuitMessage(0);
break;
// 主迴圈中檢查全域旗標 inFlag,讀取 dataCom_r 緩衝區處理資料
| IRQ | 中斷號 | 裝置 |
|---|---|---|
| IRQ0 | 08h | 定時器 |
| IRQ1 | 09h | 鍵盤 |
| IRQ3 | 0Bh | COM2/COM4 |
| IRQ4 | 0Ch | COM1/COM3 |
| IRQ5 | 0Dh | LPT2/聲卡 |
| IRQ7 | 0Fh | LPT1 |
IMR (0x21):中斷屏蔽暫存器,對應 bit 置 1 為屏蔽EOI (0x20):結束中斷命令,非特定 EOI 為 0x20| 埠位址 | 功能 (DLAB=0) | 功能 (DLAB=1) |
|---|---|---|
| Base+0 (0x3F8) | 接收/發送緩衝器 (RBR/THR) | 除數鎖存器低位 (DLL) |
| Base+1 (0x3F9) | 中斷啟用 (IER) | 除數鎖存器高位 (DLH) |
| Base+2 (0x3FA) | 中斷識別 (IIR, 唯讀) | - |
| Base+3 (0x3FB) | 線路控制 (LCR) | - |
| Base+4 (0x3FC) | 調制解調器控制 (MCR) | - |
| Base+5 (0x3FD) | 線路狀態 (LSR) | - |
| Base+6 (0x3FE) | 調制解調器狀態 (MSR) | - |
| Base+7 (0x3FF) | 暫存器 (SCR) | - |
在修改中斷向量、操作 PIC/UART 暫存器時,必須 cli 關閉中斷,操作完成後 sti 開啟,防止競態條件。
interrupt 關鍵字函式)在 Windows 3.1 上同時運行:
結果:系統穩定運行,串口中斷回應延遲在微秒級,明顯優於訊息機制。遷移至 Windows 95 同樣正常運作。
CLI/STI、存取 I/O 埠。必須編寫核心模式驅動程式 (KMDF/WDM)。本文展示的 DPMI 中斷掛接技術,是 Windows 3.x/9x 時代實現硬體即時回應的經典方案。透過 INT 31h AH=0204h/0205h 管理保護模式中斷向量、CLI/STI 保護關鍵區段、正確程式化 8259A PIC 與 8250 UART、在 WM_CREATE/WM_DESTROY 管理生命週期,可在視窗應用程式中獲得微秒級硬體中斷回應。雖然現代 Windows 架構已使此技術失效,但其核心思想——繞過 OS 排程器直接處理硬體事件——仍是理解即時系統、驅動程式開發、嵌入式韌體設計的基礎知識。