Windows NT 採用嚴格的處理器模式保護機制:應用程式運行於用戶模式,任何嘗試直接執行 I/O 指令(如 IN、OUT)的行為都會觸發保護性失敗(General Protection Fault)。這與 Windows 95/98 允許應用程式直接存取硬體形成鮮明對比。要在 NT 系統下合法操作硬體 I/O,必須編寫運行於核心模式的設備驅動程式,由驅動程式代為執行 I/O 操作。
Windows NT 設計目標是跨平台可移植性(支援 x86、MIPS、Alpha、PowerPC 等架構),因此引入硬體抽象層(HAL)隔離硬體差異。驅動程式開發者必須理解:
根據定義,I/O 寄存器/埠存取透過 I/O 週期 實現;但在某些系統中,外部總線的 I/O 空間可被映射到處理器記憶體空間(Memory-Mapped I/O),具體由 HAL 決定。
要存取特定 I/O 寄存器,驅動程式必須知道:
Isa、PCIBus 等| Offset | Size | 用途 |
|---|---|---|
| 0 | 1 Byte | 命令寄存器 |
| 1 | 1 Byte | 狀態寄存器 |
| 2 | 2 Bytes | 字資料寄存器 |
| 4 | 4 Bytes | 雙字資料寄存器 |
KIoRange DeviceIos;
NTSTATUS Status = DeviceIos.Initialize(
Isa, // 總線類型
0, // 總線編號
0xE700, // 總線位址
8, // 位址範圍大小 (8 bytes)
TRUE // 映射到系統空間 (若為記憶體映射 I/O)
);
if (NT_SUCCESS(Status)) {
// 映射成功,可進行 I/O 操作
}
// 定義寄存器偏移常數
#define COMMAND_REG 0
#define STATUS_REG 1
#define WORD_DATA_REG 2
#define DWORD_DATA_REG 3
// 讀取狀態寄存器 (1 byte)
UCHAR DeviceStatus = DeviceIos.inb(STATUS_REG);
// 寫入命令寄存器 (1 byte)
DeviceIos.outb(COMMAND_REG, CMD_RESET);
// 寫入 20 個字到資料埠 (2 bytes each)
DeviceIos.outw(WORD_DATA_REG, Buffer, 20);
若在同一函數中頻繁存取同一組寄存器,建立 KIoRegister 物件可減少函數呼叫開銷:
KIoRegister CommandReg = DeviceIos[COMMAND_REG];
KIoRegister StatusReg = DeviceIos[STATUS_REG];
// 寫入命令 (隱含轉型為 UCHAR)
CommandReg = (UCHAR)RESET_CMD;
// 讀取狀態 (隱含轉型為 UCHAR)
UCHAR Status = StatusReg;
UCHAR (8-bit)、USHORT (16-bit)、ULONG (32-bit) 必須與硬體規格完全對應KIoRegister 適合高頻存取場景;KIoRange 成員函數適合零星存取KIoRange 解構子會自動取消映射並釋放資源Windows NT 的安全模型強制將硬體存取封裝於核心模式驅動程式中。透過 HAL 抽象層與 DriverWorks 等工具包提供的 KIoRange/KIoRegister 類別,驅動程式開發者可跨平台、安全地實現 I/O 埠位址存取,同時保持程式碼可移植性與維護性。