x86 彙編/可程式設計中斷控制器
最初的 IBM PC 包含一個名為 **可程式設計中斷控制器** 的晶片,用於處理來自系統的傳入中斷請求,並以有序的方式將它們傳送到 MPU 進行處理。最初的中斷控制器是 8259A 晶片,雖然現代計算機將使用更新的變體。最常見的替代品是 APIC (高階可程式設計中斷控制器),它本質上是舊 PIC 晶片的擴充套件版本,以保持向後相容性。本頁將介紹 8259A。

8259A 的功能實際上很簡單。每個 PIC 有 8 個輸入線,稱為中斷請求 (IRQ),編號從 0 到 7。當這些線之一變為高電平時,PIC 會提醒 CPU 併發送相應的中斷號。這個數字是透過將 IRQ 編號 (0 到 7) 加到內部 "向量偏移" 值來計算的。CPU 使用這個值來執行相應的中斷服務例程。(有關更多資訊,請參閱 高階中斷)。
當然,這並不像看起來那麼簡單,因為每個系統都有兩個 PIC,一個 "主" 和一個 "從"。所以,當從機發出中斷時,它實際上是傳送到主機的,主機再將它傳送到 CPU。這樣,中斷就會級聯,處理器可以有 16 個 IRQ 線。在這 16 個 IRQ 線中,有一個是用於兩個 PIC 晶片相互通訊的,因此可用 IRQ 的數量減少到 15 個。
雖然 cli 和 sti 可用於停用和啟用 *所有* 硬體中斷,但有時需要有選擇地停用來自某些裝置的中斷。為此,PIC 有一個內部 8 位暫存器,稱為中斷遮蔽暫存器 (IMR)。該暫存器中的位決定哪些 IRQ 傳遞到 CPU。如果一個 IRQ 被觸發,但 IMR 中的對應位被設定,則它會被忽略,不會發送任何內容到 CPU。
在 15 個可用的 IRQ 中,一些與一種型別的裝置普遍相關聯
- IRQ 0 ‒ 系統定時器
- IRQ 1 — 鍵盤控制器
- IRQ 3 — 序列埠 COM2
- IRQ 4 — 序列埠 COM1
- IRQ 5 — 行式列印終端 2
- IRQ 6 — 軟盤控制器
- IRQ 7 — 行式列印終端 1
- IRQ 8 — RTC 定時器
- IRQ 9 - X86_Assembly/ACPI
- IRQ 12 — 滑鼠控制器
- IRQ 13 — 數學協處理器
- IRQ 14 — ATA 通道 1
- IRQ 15 — ATA 通道 2
系統中的兩個 PIC 各自分配一個命令埠和一個數據埠
| PIC1 | PIC2 | |
|---|---|---|
| 命令 | 0x20 | 0xA0 |
| 資料 | 0x21 | 0xA1 |
通常,從資料埠讀取會返回 IMR 暫存器(見上文),寫入到它會設定該暫存器。我們可以利用這一點來設定哪些 IRQ 應該被忽略。例如,要停用 IRQ 6(軟盤控制器)觸發
in ax, 0x21
or ax, (1 << 6)
out 0x21, ax
同樣,要停用 IRQ 12(滑鼠控制器)
in ax, 0xA1
or ax, (1 << 4) ;IRQ 12 is actually IRQ 4 of PIC2
out 0xA1, ax
另一個常見任務,通常在作業系統初始化期間執行,是重對映 PIC。也就是說,改變它們的內部向量偏移量,從而改變它們傳送的中斷號。PIC1 的初始向量偏移量為 8,因此它會觸發中斷號 8 到 15。不幸的是,低 32 箇中斷中的一些被 CPU 用於異常(除零、頁面錯誤等),導致硬體中斷和軟體中斷之間發生衝突。對此的通常解決方案是將 PIC1 重對映到從 32 開始,並且通常將 PIC2 緊隨其後從 40 開始。這需要完全重新啟動 PIC,但實際上並不困難,只需八個 out 即可完成。
mov al, 0x11
out 0x20, al ;restart PIC1
out 0xA0, al ;restart PIC2
mov al, 0x20
out 0x21, al ;PIC1 now starts at 32
mov al, 0x28
out 0xA1, al ;PIC2 now starts at 40
mov al, 0x04
out 0x21, al ;setup cascading
mov al, 0x02
out 0xA1, al
mov al, 0x01
out 0x21, al
out 0xA1, al ;done!