一、中斷和異常
中斷何和異常是指明系統、處理器或當前執行程序(或任務)的某處出現一個事件,該事件需要處理器進行處理。通常,這種事情會導致執行控制器被強迫從當前運行程序轉移到被稱為終端處理程序或異常處理程序的特殊軟件函數或任務中。處理器響應中斷或異常所采取的行動稱為中斷/異常服務(處理)。
通常中斷發生在程序執行的隨機時刻,以響應硬件發出的信號。系統硬件使用中斷來處理外部事件,例如要求為外部設備提供服務。當然,軟件也能通過執行 INT n 指令產生中斷。
異常發生在處理器執行一條指令時,檢測到一個出錯條件時發生,例如被0除出錯條件。處理器可以檢測到各種出錯條件,包括違反保護機制。頁錯誤以及機器內部錯誤。對應用程序來說,80x86的中斷和異常處理機制可以透明地處理發生的異常和中斷事件。當收到一個中斷或檢測到一個異常時,處理器會自動把當前正在正在執行的程序或任務掛起,並開始運行中斷或異常處理程序。當處理程序執行完畢,處理器就會恢復並繼續執行被中斷的程序或任務。被中斷程序的恢復過程並不會失去程序執行的連貫性,除非從異常中恢復是不可能的或者中斷異常導致當前運行程序被終止。
二、異常和中斷向量
為了有助於處理異常和中斷,每個需要被處理器進行特殊處理的處理器定義的異常和中斷條件都被賦予了一個標識號,稱為向量。處理器把賦予異常或中斷的向量用作中斷描述符表IDT中的一個索引號,來定位一個異常或中斷的處理程序入口點位置。
允許的向量號范圍是0到255.其中0到31保留用作80x86處理器定義的異常和中斷,不過目前該范圍內的向量號並非每個都已定義了功能,未定義功能的向量號將留在以后使用。
范圍在32到255的向量號用於用戶定義的中斷。這些中斷通常用於外部I/O設備,使得這些設備可以通過外部硬件中斷機制向處理器發送中斷。
三、中斷源和異常源
(一)、中斷源
處理器從兩種地方接收終端:
- 外部(硬件產生)的中斷。
- 軟件產生的中斷。
外部中斷通過處理器芯片上兩個引腳(INTR 和 NMI)接收。當引腳接收到外部發生的中斷信號時,處理器就會從系統總線上讀取外部中斷控制器提供的中斷向量號。當引腳 NMI 接收到信號時,就產生一個非屏蔽中斷。它使用固定的中斷向量號2。 任何通過處理器 INTR 引腳接收的外部中斷都被稱為可屏蔽硬件中斷,包括中斷向量號0到255。標志寄存器 EFLAGS 的 IF 標志可用來屏蔽所有這些硬件中斷。
通過在指令操作數中提供中斷向量號, INT n 指令可用於從軟件中產生中斷。例如,指令 INT 0x80 會執行Linux的系統系統中斷調用中斷0x80。向量0到255中的任何一個都可以用作INT指令的中斷號。如果使用了處理器預先定義的 NMI向量,那么處理器對它的響應將與普通方式產生的該NMI中斷不同,如果NMI的向量號2用於該INT指令,就會調用NMI的中斷處理程序,但此時並不會激活處理器的NMI處理硬件(???)。
注意,EFLAGS中的IF標志位不能屏蔽使用INT執行從軟件產生的中斷。
(二)、異常源
處理器接收的異常也有兩個來源:
- 處理器檢測到的程序錯誤異常。
- 軟件產生的異常。
在應用程序或操作系統執行期間,如果處理器檢測到程序錯誤,就會產生一個或多個異常。80x86處理器為其檢測到的每一個異常定義了一個向量。異常可以被細分為故障
、陷阱
和中止
。
指令INTO、INT 3 和 BOUND 指令可以用來從軟件中產生異常。這些指令可對指令流中指定點執行的特殊異常條件進行檢查。例如,INT 3 指令會產生一個斷點異常。
INT n 指令可用於在軟件中模擬指定的異常,但有一個限制。如果INT指令中的操作數n是80x86異常的向量號之一,那么處理器將為該向量號產生一個中斷,該中斷就會去執行與該向量有關的異常處理程序。但是,因為實際上是一個中斷,因此處理器並不會把一個錯誤號壓入棧,即使硬件產生的該向量相關的中斷通常會產生一個錯誤碼。對於那些會產生錯誤碼的異常,異常的處理程序會試圖從棧上彈出錯誤碼。因此,如果使用INT指令來模擬產生一個異常,處理程序則會把EIP(正好處於缺少的錯誤碼位置處)彈出棧 ,從而會造成返回位置錯誤。
四、異常的分類
根據異常被報告的方式以及導致異常的指令是否能夠被重新執行,異常可被細分為故障(Fault)、陷阱(Trap)和中止(Abort)。
- Fault 是一種通常可以被糾正的異常,並且一旦被糾正程序就可以繼續運行。當出現一個Fault,處理器會把機器的狀態恢復到產生Fault的指令之前的狀態。因此異常處理程序的返回地址會指向產生Fault的指令,而不是其后面一條指令。因此在返回后產生Fault的指令將被重新執行。
- Trap 是一個引起陷阱的指令被執行后立刻會報告的異常。Trap也能夠讓程序或任務連貫地執行。Trap處理程序的返回地址指向引起陷阱指令的隨后一條指令,因此在返回后會執行下一條指令。
- Abort 是一種不會總是報告導致異常的指令的精確位置的異常,並且不允許導致異常的程序重新繼續執行。Abort用於報告嚴重錯誤,例如硬件錯誤以及系統表中存在不一致性或非法值。
五、程序或任務的重新執行
為了讓程序或任務在一個異常或中斷處理完之后能重新恢復執行,除了中止之外的所有異常都能報告精確的指令位置,並且所有中斷保證是在指令邊界上發生。
- 對於故障類異常,處理器產生異常時保存的返回指針指向出錯指令。因為,當程序或任務在故障處理程序返回后重新開始執行時,原出錯指令會被重新執行。重新執行引發出錯的指令通常用於處理訪問指令操作數受阻止的情況。Fault最常見的一個例子是頁面故障(Page-Fault)異常。當程序引用不在內存中頁面上的一個操作數時就會出現這種異常。當頁故障異常發生時,異常處理程序可以把該頁面加載到內存中並通過重新執行出錯指令來恢復程序運行。為了確保重新執行對於當前執行程序具有透明性,處理器會保存必要的寄存器和堆棧指針信息,以使得自己能夠返回到執行出錯指令之前的狀態。
- 對於陷阱Trap類異常,處理器產生異常時保存的返回指針指向引起陷阱操作的后一條指令。如果在一條執行控制轉移的指令執行期間檢測到一個Trap,則返回指令指針會反映出控制的轉移情況。例如,如果在執行JMP指令時檢測到一個Trap異常,那么返回指令指針會指向JMP指令的目標位置,而非指向JMP指令隨后的一條指令。
- 中止Abort類異常不支持可靠地重新執行程序或任務。中止異常的處理程序通常用來收集異常發生時有關處理器狀態的診斷信息,並且盡可能恰當地關閉程序和系統。
中斷會嚴格地支持被中斷程序的重新執行而不會失去任何連貫性。中斷所保存的返回指令指針指向處理器獲取中斷時將要執行的下一條指令的邊界處。如果剛執行的指令有一個重復前綴,則中斷會在當前重復結束並且寄存器已為下一次重復操作設置好時發生。
六、開啟和禁止中斷
標志寄存器EFLAGS的中斷允許標志IT能夠禁止為處理器INTR引腳上收到的可屏蔽硬件中斷提供服務。當IF=0時,處理器禁止發送INTR引腳的中斷;當IF=1時,則發送到INTR引腳的中斷信號會被處理器進行處理。
IF標志並不影響發送到NMI引腳的非屏蔽中斷,也不影響處理器產生的異常。如同EFLAGS中的其它標志一樣,處理器在相應硬件復位操作時會清楚IF標志(IF=0)。
IF標志可以使用指令STI和CLI來設置或清除。只有當程序的CPL<=IOPL 時才可執行這兩條指令,否則將引發一般保護性異常。IF標志也會受以下操作影響:
- PUSHF 指令會把EFLAGS內容存到棧中,並且可以在那里被修改。而POPF指令可用於把已經被修改過的標志內容放入EFLAGS寄存器中。
- 任務切換、POPF 和 IRET 指令會加載EFLAGS寄存器。因此,它們可用來修改IF標志。
- 當通過中斷門處理一個中斷時,IF標志會被自動清除(復位),從而會禁止可屏蔽硬件中斷。但如果是通過陷阱門來處理一個中斷,則IF標志不會被復位。
七、異常和中斷的優先級
如果在一條指令邊界有多個異常或中斷等待處理時,處理器會按規定的次序躲他們進行處理。處理器會首先處理最高優先級類的異常或中斷。低優先的異常會被丟棄,而低優先級的中斷則會保持等待。當中斷處理程序返回到產生異常和/或中斷的程序或任務時,被丟棄的異常會重新發生。
優先級 | 說明 |
---|---|
1(最高) | 硬件復位: RESET |
2 | 任務切換陷阱: TSS中設置了T標志 |
3 | 外部硬件介入 |
4 | 前一指令陷阱: 斷點、調試陷阱異常 |
5 | 外部中斷: NMI中斷、可屏蔽硬件中斷 |
6 | 代碼斷點錯誤 |
7 | 取下一條指令錯誤: 違反代碼段限長、代碼頁錯誤 |
8 | 下一條指令譯碼錯誤: 指令長度>15字節、無效操作碼、協處理器不存在 |
9(最低) | 執行指令錯誤: 溢出、邊界檢查、無效TSS、段不存在、堆棧錯誤、一般保護、數據頁、對其檢查、浮點異常。 |