x86保護模式-七中斷和異常
386相比較之前的cpu 增強了中斷處理能力 並且引入了 異常概念
一 80386的中斷和異常
為了支持多任務和虛擬存儲器等功能,3
86把外部中斷稱為中斷 把內部中斷稱為異常
最多支持256中斷或異常
1.中斷
中斷是由異步的外部事件引起的。外部事件及中斷響應與正執行的指令沒有關系。
通常中斷對應i/o操作的完成,cpu中intr引腳接受外部的可屏蔽的中斷請求,NMI引腳接受外部不可屏蔽的中斷請求。
EFLAGS標志寄存器中的IF標志決定是否屏蔽可屏蔽的中斷請求
intr發出中斷請求的同時還有一個8位的中斷向量。cpu根據向量號來決定下一步的操作。
8059a能夠設置向cpu提供向量號,處理中斷請求的優先級。
8259級聯,最多可用 1片主帖+8片從片, 每片從片有8個外部中斷請求IR0~IR7,
主片的IR0~IR7引腳分別連接8個從片的INT引腳。最多可有 8x8=64個外部中斷請求。

cpu不屏蔽來自NMI的中斷請求,響應NMI中斷時,
不從外部硬件接收中斷向量號。固定的向量號為2 。為了不可屏蔽的嵌套,每當接受一個NMI中斷,
cpu就在內部屏蔽了再次響應NMI,這一屏蔽過程直到執行中斷返回指令IRET后才結束。
所以NMI處理程序應該以IRET指令結束。
2.異常
異常時80386在執行指令期間檢測到不正常的或非法的條件所引起的。與正在執行的指令有直接的聯系。
例如 除法指令 除數等於0時。特權級不正確,指令不能成功完成。
軟中斷指令“INT n”和“INTO”也歸類於異常而不稱為中斷,是因為執行這些指令產生異常事件。
386識別多種不同類別的異常,並且賦予每一種類別以不同的中斷向量號。異常發生后,cpu響應異常,根據向量號轉到相應的異常處理程序。
根據引起異常的程序是否可被恢復和恢復點不同,把異常分類為故障fault,陷阱trap和中止abort。我們把對應的異常處理程序分別稱為故障處理程序、陷阱處理程序和中止處理程序。
故障是在引起異常的指
令之前,把異常情況通知給系統的一種異常。故障是可以排除的。當控制轉移到故障處理程序時,所保存的斷
點cs及eip的值指向引起故障的指令。這樣,在故障處理程序把故障排除后,執行IRET返回到引起故障的程序繼續執行時,剛才引起故障的指令可重新得到執行。
這種重新執行,不需要操作系統軟件的額外參與。故障的發先可能在指令執行之前,也可能在指令執行期間。
如果在指令執行期間檢測到故障,那么中止故障指令,並把
指令的操作數恢復為指令開始執行之前的值。這可保證故障指令的重新執行得到正確的結果。
例如,一條指令執行期間,發現段不存在,那么就停止該指令的執行,並通知系統產生段故障,對應的段故障處理程序可通過加載該段的方法來排除故障,之后,原指令就可以成功執行,至少不再發生段不存在的故障。
陷阱是在引起異常的指令后,把異常情況通知給系統的一種異常。當控制轉移到異常處理程序時,所保存的斷點cs及eip的值指向引起陷阱的指令的下一條要執行的指令。
下一條要執行的指令,不一定就是下一條指令(例如call 指令)。因此陷阱處理程序並不能總根據保存的斷點,反推確定出產生異常的指令。在轉入陷阱處理程序時,引起陷阱的指令應正常完成,它有可能改變了寄存器或存儲單元。
軟中斷指令、單步異常是陷阱的例子。
中止是在系統出現嚴重情況時,通知系統的一種異常。引起中止的指令是無法確定的。產生中止時,正執行的程序不能被恢復執行。
系統接收中止后,處理程序要重新建立各種系統表格,並可能重新啟動操作系統。硬件故障和系統表中出現非法值或不一致的值是中止的例子
3.優先級
在一條指令執行期間,入檢測到不只一個中斷或異常,那么按下邊所列優先級通知系統。把優先級最高的中斷或異常通知系統,其他優先級較低的異常被廢棄,而優先級較高的中斷則保持懸掛

二 異常的類型
中斷和異常一樣都分為多種類型
1.386識別的異常
多種不同類別的異常及賦予的對應中斷向量號如下表所示。
某些異常還可以出錯碼的形式提供一些附加信息傳遞給異常處理程序,出錯代碼列表中的“無”表示沒有出錯代碼,“有”表示有出錯代碼。

保護模式下的某些中斷向量號的分配與實模式的中斷向量號發生沖突。實模式下的中斷向量號的分配基於pc微機系統的8086/8088cpu,上表中的中斷向量號的分配是80386所規定的。實際上8086/8088 保留了這些發生沖突的中斷向量號。盡管有沖突,80386需要向下兼容,原因是80386的實模式下,幾乎不發生哪些中斷向量號與外部硬件中斷請求時所提供的中斷向量號存在沖突的異常。需要注意的是, 在保護模式下必須重新設置8259a中斷控制器,以產生不予異常相沖突的硬件中斷向量。
2.故障類異常
當發生故障,控制轉移到故障處理程序時,所保存的斷點cs及eip的值指向引起故障的指令,以便在排除故障后恢復執行
a 除法出錯故障 異常0
除法出錯時一種故障。當執行DIV指令或IDIV指令時,如果除數等於0或者商太大,以至於存放商的操作數容納不下
此故障沒有出錯碼
b 邊界檢查故障 異常5
如果BOUND指令發現被測試的值超過了指令中給定的范圍,那么就發生邊界檢查故障。無出錯碼
c 非法操作碼故障 異常6
如果386不能把
cs和eip所指向存儲單元的
位模式
識別為某條指令的部分,那么就發生非法操作碼故障。當出現如下情況時 發生這樣的故障 cs:ip指向的位置不是指令
(1)操作碼字段的內容不是一個合法的386指令代碼
(2)要求使用存儲器操作數的場合,使用了寄存器操作數
(3)不能被加鎖的指令前使用了LOCK前綴。
非法操作碼故障不提供錯誤碼
d 設備不可用故障(異常7)
不支持387協處理器,
可用該異常的處理程序代替協處理器的軟件模擬器。發生任務切換時,使得只有在新任務使用浮點指令時,才進行387寄存器狀態的切換。設備不可用故障不提供出錯碼。
(1)執行浮點指令時,cr0中em位或ts位為1。
(2)執行wait指令時,cr0中的ts位及em位都為1。
(3)
異常的處理程序必須是一個程序而不是任務,否則當處理程序發布一條IRET指令時,80386就設置ts位。然后協處理器再次執行這個發生故障的指令,發現ts是置位的。因此再次發生異常7,結果就是死循環。處理程序能通過陷阱門被調用,因為執行期間可以允許中斷
e 無效tss故障 (異常0ah)
當正從任務狀態段tss裝入選擇子時,如果發生了除了段不存在外的段異常時,就發生此故障。
1進入故障處理程序時,保存的cs及eip指向發生故障的指令
2或者該故障作為任務切換的一部分發生時,指向任務的第一條指令
3提供出錯碼

其中選擇子部分指向引起故障的tss的選擇子。16位的出錯碼的主要成分是選擇子,指向引起故障的tss的選擇子。高13位是選擇子的索引部分,TI位是描述符表指示位。
上圖為異常出錯碼的一般格式。從途中可見出錯碼不含選擇子的rpl 而由IDT位和EXT位代替。當處理某一異常或外部中斷時,又發生了某種異常,那么EXT位置1.當從中斷描述符表IDT中讀出表項並產生異常時,IDT位置1,這只在中斷或異常的處理期間才會發生。當沒有選擇子時,構成出錯碼選擇子部分的值為0。
4.引起無效tss故障的原因如下
a tss描述符中的段限長小於103
b 無效的LDT描述符,或者LDT未出現
c 堆棧段不是一個可寫段
d 堆棧段選擇子索引的描述符超出描述符表界限
e 堆棧段DPL與新的cpl不匹配;
f 堆棧段選擇子的rpl不等於cpl
g 代碼段選擇子索引的描述符超出描述符表界限
h 代碼段選擇子不指向代碼段
i 非一致代碼段的dpl不等於新的cpl
j 一致代碼段的dpl大於新的cpl
k 對應ds es fs 或gs的選擇子指向一個不可讀的段,例如系統段
l 對應ds es fs 或gs的選擇子索引的描述符超出描述符表的界限
f 段不存在的故障(異常0bh)
處理器在把描述符裝入非ss寄存器的高速緩沖時,如果發現描述符其他方面有效,而p位為0表示(對應段不存在),那么在引用此描述符時就發生段不存在故障。有關ss段的情形納入堆棧段故障。在進入故障處理程序時,
保存的cs及eip執行發生故障的指令;或者該故障作為任務切換的一部分發生時,指向任務的第一條指令。
段不存在故障提供了一個包含引起該故障的段選擇子的出錯代碼。出錯碼的格式如上圖所示。選擇子索引部分為引起段不存在故障的段描述符選擇子的索引。
g 堆棧段故障(異常0ch)
cpu檢測到用ss寄存器進行尋址的段有關的某種問題時,就發生堆棧段故障。在進入故障處理程序時,保存的cs級eip指向發生故障的指令;或者該故障作為任務切換的一部分發生時,指向任務的第一條指令。堆棧段故障提供一個出錯碼,出錯碼的格式也如上如所示
引起堆棧段故障的原因
(1)堆棧操作時,偏移超出段界限所規定的范圍。這種情況下的出錯碼是0.例如PUSH操作時,堆棧溢出。
(2)在由特權級變換所引起的對內層堆棧操作時,偏移超出段界限所規定的范圍。這種情況下的出錯碼包含有內層堆棧的選擇子。
(3)裝入到ss寄存器(高速緩沖寄存器)的描述符中的存在位為0.這種情況下的出錯碼包含有對應的選擇子。
第一中情況容易辨別。第2和3中情況的辨別需要通過判斷出錯碼所含的選擇子所指示的描述符中的存在位進行,如果存在位為1,那么是第二種情況,否則是第三種情況。
h 通用保護故障(異常0dh)
除了明確列出的段異常外,其他的段異常都被視為通用保護故障。在進入故障處理程序時,保存的cs及eip指向發生故障的指令;或者該故障作為任務切換的一部分發生時,指向任務的第一條指令。通用保護故障提供一個出錯碼,出錯碼的格式也如上圖所示。
根據處理程序可能作出的響應,通用保護故障可分為如下兩類:
(1)違反保護方式,但程序無須中止的異常。此類故障的出錯碼為0.這種異常在應用程序執行特權指令或I/O訪問呢時發生,支持虛擬8086程序的系統或支持虛擬i/o訪問的系統需要模擬這些指令,並在模擬完成產生故障的指令后,重新執行被中斷的程序。
(2)違反保護方式,並導致程序終止的異常。這類故障提供的出錯碼可能為0 ,也可能不是0(能確定選擇子時)。引起此類的故障原因
a 向某個只讀數據段或代碼段寫;
b 從某個智能執行的代碼段讀出;
c 將某個系統段描述符裝入到數據段寄存器ds、es、fs、gs或ss;
d 將控制轉移到一個不可執行的段;
e 在通過段寄存器cs、ds、es、fs或gs訪問內存時,偏移超出段界限
f 當訪問某個描述符表時,超過描述符表段界限;
把pg位為1但pe位為0的控制信息裝入到cr0寄存器;
切換到一個正忙的任務。
對上述兩類通用保護故障的辨別,可通過檢查引起故障的指令和出錯碼進行。如果出錯碼非0,那么肯定是第二類通用保護故障。如果
出錯碼是0,那么需要進一步檢查引起故障的指令,以確定它是否是系統支持的可以模擬的指令。
i 頁故障 異常0eh 略
j 協處理器出錯 異常10h
協處理器出錯故障指示協處理器發生了未被屏蔽的數字錯誤,如上溢或下溢。在引起故障的浮點指令之后的下一條浮點指令
或WAIT指令,把協處理器出錯作為一個故障通知給系統。協處理器出錯故障不提供出錯碼。
3.陷阱類異常
a 調試陷阱 異常1
調試異常有故障類型,也有陷阱類型。調試程序可以訪問調試寄存器dr6 以確定調試異常的原因和類型。調試異常不提供出錯碼。
b 單字節 INT3 異常3
INT3是一條特別的單字節 INT n 指令 ,調試程序可利用該指令支持程序斷點。INT3指令被看成是一種陷阱。而不是一個中斷。當由於執行INT3指令進入異常3處理程序時,被保存的cs和eip指向緊跟INT3的指令,即INT3后面的字節。INT3陷阱不提供出錯碼。
c 溢出 異常4
INTO指令提供條件陷阱。如果OF標志為1,那么INTO指令產生陷阱;否則不產生陷阱,繼續執行INTO后面的指令。在進入溢出處理程序時,被保存的cs和eip指向INTO指令的下一條指令。溢出陷阱不提供出錯碼。
4.中止類異常
a 雙重故障異常 異常8
當系統正在處理一個異常時,如果又檢測到一個異常,處理器試圖向系統通知一個雙重故障,而不是通知第二個異常。雙重故障屬於中止類異常,所以在轉入雙重故障處理程序時,被保存的cs和eip可能不指向引起雙重故障的指令,而且指令的重新啟動不支持雙重故障。 出錯碼為0
當正處理一個段故障異常時,有可能又產生一個頁故障。在這種情況下,通知給系統的是一個頁故障異常而不是雙重故障異常。但是,如果正處理一個段故障或頁故障時,又一個段故障被檢測到;或者如果正處理一個頁故障時,又一個頁故障被檢測到,那么就引起雙重故障。
當正處理一個頁故障時,又一個段或頁故障被檢測到,那么處理器暫停執行指令,並進入關機方式。關機方式類似於處理器指令一條HLT指令后的狀態:處理器空轉,並維持到處理器接收到一個NMI中斷請求或者被重新啟動為止。在關機方式下,處理器不響應INTR中斷請求。
雙重故障通常指示系統表出現嚴重的問題,例如段描述符表、頁表或中斷描述符表出現問題。雙重故障處理程序在重建系統表后,可能不得不重新啟動操作系統。
b 協處理器段越界 異常9
協處理器段越界異常屬於中止類異常,這是因為引起該異常的指令不能被重新啟動。但更浮點指令操作數超出段界限時,產生該中止異常。協處理器段越界異常不提供出錯碼。在異常處理程序入口保存的cs及eip指向被中止的指令。這種中止不是系統的中止,而是只影響到這種異常時正執行的指令所在的程序。
三 中斷和異常的轉移方法