80386實模式下的中斷和異常的轉移方法與8086相同。這裡介紹的中斷和異常的轉移方法是指 80386在保護模式下響應中斷和處理異常時所采用的轉移方法。
由硬件自動實現的中斷響應和異常處理的步驟如下:
首先,判斷中斷向量號要索引的門描述符是否超出IDT的界限。若超出界限,就引起通用保護故障,出錯碼為中斷向量號乘8再加2。 其次,從IDT中取得對應的門描述符,分解出選擇子、偏移量和描述符屬性類型,並進行有關檢查。描述符只能是任務門、286中斷門、286陷阱門、386中斷門或386陷阱門,否則就引起通用保護故障,出錯碼是中斷向量號乘8再加2。如果是由INT n指令或INTO指令引起轉移,還要檢查中斷門、陷阱門或任務門描述符中的DPL是否滿足CPL<=DPL(對於其它的異常或中斷,門中的DPL被忽略)。這種檢查可以避免應用程序執行INT n指令時,使用分配給各種設備用的中斷向量號。如果檢查不通過,就引起通用保護故障,出錯碼是中斷向量號乘8再加2。門描述符中的P位必須是1,表示門描述符是一個有效項,否則就引起段不存在故障,出錯碼是中斷向量號乘8再加2。 最後,根據門描述符類型,分情況轉入中斷或異常處理程序。對於異常處理,在開始上述步驟之前,還要根據異常類型確定返回點;如果有出錯代碼,則形成符合出錯碼格式的出錯碼,並在實際執行異常處理程序之前把出錯碼壓入堆棧。為了保證棧的雙字邊界對齊,16位的出錯碼以32位的值壓入,其中高16位的值未作定義,對於16位段也是如此。
如果中斷向量號所指示的門描述符是386中斷門或386陷阱門,那麼控制轉移到當前任務的一個處理程序過程,並且可以變換特權級。與其它調用門的CALL指令一樣,從中斷門和陷阱門中獲取指向處理程序的48位全指針。其中16位選擇子是對應處理程序或代碼段的選擇子,它指示全局描述符表GDT或局部描述符表LDT中的代碼段描述符;32位偏移指示處理程序入口點在代碼段內的偏移量。通過中斷門或陷阱門的轉移過程如下所示,該過程由硬件自動進行。(1)若選擇子為空,則產生通用保護故障;(2)取對應的描述符;(3)若非存儲段描述符,則產生通用保護故障;(4)若非一致代碼段且DPL且段存在,則切換到內層堆棧;(5)調整RPL=0;(6)把描述符裝入CS;(7)若入口偏移越界,則產生通用保護故障;(8)EFLAGS壓入堆棧;(9)CS壓入堆棧;(10)EIP壓入堆棧;(11)使TF=0,NT=0;(12)若為中斷門,則使IF=0;(13)若有出錯碼,則把出錯碼壓入堆棧;(14)轉入處理程序。由上述轉移過程可見,中斷門或陷阱門中指示處理程序的選擇子必須指向描述一個可執行的代碼段的描述符。如果選擇子為空,就引起通用保護故障,出錯碼是0。如果描述符不是代碼段描述符,就引起通用保護故障,出錯碼含選擇子。中斷或異常可以轉移到同一特權級或內層特權級。上述指定處理程序代碼段的描述符中的類型及DPL字段,決定了這種同一任務內的轉移是否要發生特權級變換。如果是一個非一致代碼段,並且DPLCPL則產生通用保護異常。上述轉移過程中的第六步,也就是“把描述符裝入CS”,是指把上述指定處理程序段的描述符裝入CS的高速緩沖寄存器中,在這一步驟中要對描述符進行類似通過調用門進行轉移的其它檢查,包括是否代碼段描述符和代碼段描述符是否存在等,因此可能再發生異常。在對該描述符進行檢查時,通過調整門中選擇子的RPL=0(在處理器內部調整,而不影響存儲器中的選擇子的RPL字段)的方法,實現只考慮代碼段的DPL,而不考慮門中選擇子的RPL。把描述符裝入CS之後,還要檢查門描述符中給出的表示處理程序代碼段入口的偏移是否越界,即是否超出段界限。如果越界,就引起出錯碼為0的通用保護故障。從轉移過程還可以看出,把標志寄存器和斷點壓入堆棧的做法和順序與實模式是相同的,但這裡每一次堆棧操作是一個雙字,CS被擴展成32位。在16位段中亦是如此。把TF置成0,表示不允許處理程序單步執行。把NT置成0,表示處理程序在利用中斷返回指令IRET返回時,返回到同一任務而不是一個嵌套任務。需要注意的是,任何特權級的程序都可改變NT位,這樣可以利用中斷或陷阱處理程序完成任務切換。通過中斷門的轉移和通過陷阱門的轉移之間的差別只是對IF標志的處理。對於中斷門,在轉移過程中把IF置為0,使得在處理程序執行期間屏蔽掉INTR中斷(當然,在中斷處理程序中可以人為設置IF標志打開中斷,以使得在處理程序執行期間允許響應可屏蔽中斷);對於陷阱門,在轉移過程中保持IF位不變,即如果IF位原來是1,那麼通過陷阱門轉移到處理程序之後仍允許INTR中斷。因此,中斷門最適宜於處理中斷,而陷阱門適宜於處理異常。在有出錯碼的情況下,轉入處理程序之前還要把出錯碼壓入堆棧。只有異常處理才可能有出錯碼。下圖給出了通過中斷門或陷阱門轉移時的堆棧情況。(a)是沒有變換特權級和沒有出錯碼的情形;(b)是沒有變換特權級有出錯碼的情形;(c)是變換特權級和沒有出錯碼的內層堆棧的情形。(d)是變換特權級和有出錯碼的內層堆棧情形。注意圖中每一項為雙字。
如果中斷向量號所只是的門描述符是任務門描述符,那麼控制轉移到一個作為獨立的任務方式出現的處理程序。任務門中的選擇子是指向描述對應處理程序任務的TSS段的選擇子,即該選擇子指示一個可用的286TSS或386TSS。通過任務門的轉移與通過任務門到一個可用的386TSS的段間調用指令CALL的轉移很相似,主要的區別是,對於提供出錯碼的異常處理,在完成任務切換之後,把出錯碼壓入新任務的堆棧中(通過任務門進行轉移時,返回地址和外層棧指針不壓入新任務的堆棧)。 通過任務門的轉移,在進入中斷或異常處理程序時,標志寄存器EFLAGS中的NT位被置為1,表示是嵌套任務,則IRET指令返回時,沿TSS中的鏈接字段返回到最後一個被掛起的任務。
在響應中斷或處理異常時,使用任務門可提供一個處理程序任務的自動調度。這種任務調度由硬件直接執行,並且越過包含在操作系統中的軟件任務切換,這就為處理程序提供了一個快速的任務切換。
對中斷的響應和異常的處理,80386允許通過使用中斷門或陷阱門實現由當前任務之內的一個過程進行處理;也允許通過使用任務門實現由另一個任務進行處理。在當前任務之內的處理程序較為簡單,並可以很快地轉移到處理程序,但處理程序要負責保存及恢復處理器的寄存器等內容。轉到不同任務的處理程序要花費較長時間,保存及恢復處理器寄存器內容的開銷作為任務切換的一部分。使用當前任務內的處理程序的方法,在響應中斷或處理異常時,對正執行任務的狀態可直接進行訪問,但是這就要求每一個任務之內都包含一個處理程序。使用獨立任務的處理方法,使處理程序得到較好的隔離,但在響應中斷或處理異常時,對原任務狀態的訪問變得較為復雜。需要注意得是,有些異常必須由中斷門或陷阱門進行處理,如上面提到得異常7。
無效TSS異常必須使用任務門進行處理,以保證處理程序有一個有效得任務環境。其它得異常通常在任務環境之內進行處理。在任務內,異常被檢測並且不必屏蔽中斷,所以,所以使用陷阱門。由陷阱門指示的異常處理程序是一個由所有任務共享的過程,所以該處理程序最好置於全局地址空間之內。如果各個任務要求有不同的處理程序,那麼全局異常處理程序可保存一個各處理程序的入口表,並為引起異常的任務調用相應的處理程序。
中斷通常與正執行的任務沒有關系,並可能從使用任務門提供的隔離中獲得好處。要求較快響應的中斷,通過中斷門可以得到較好的處理。因為中斷隨時都可能發生,所以,通過中斷門訪問的中斷處理程序,必須置於全局地址空間中,以便對所有的任務都有效。還需強調的是,80386程序絕不能調用一個低特權級的過程,當處理器調用一個中斷或異常處理程序時,它實施相同的規則,所以,這樣一個過程必須至少具有與在其任務上下文中被調用的、由任務所執行的最高特權級的過程相同的特權級。因此,在使用中斷門時,中斷處理程序通常必須被安排在特權級0,否則若正在特權級0執行時發生中斷,則不能進入中斷處理程序,而會引起通用保護故障(中斷處理程序使用任務門時除外,因為任務切換可以從任何特權級切換到目標任務的任何特權級)。
中斷返回指令IRET用於從中斷或異常處理程序的返回。該指令的執行根據任務嵌套標志NT位是否為1分為兩種情形。
NT位為1,表示是嵌套任務的返回。當前TSS中的鏈接字段保存有前一任務的TSS的選擇子,取出該選擇子進行任務切換就完成了返回。這種情形在由通過任務門轉入的中斷或異常處理程序返回時出現,因為在由中斷門或陷阱門轉入處理程序時,NT位已被清0。
NT位為0,表示當前任務內的返回。這種情形在由通過中斷門或陷阱門轉入的中斷或異常處理程序返回時出現。具體進行的操作包括:從堆棧頂彈出返回指針EIP及CS,然後彈出EFLAGS值。彈出的CS選擇子的RPL字段,確定返回後的特權級。如果返回選擇子的RPL與CPL相同,則不進行特權級改變。若RPL規定了一個外層特權級,則需要特權級改變,從內層堆棧中彈出外層堆棧的指針ESP及SS的值。這些做法與RET指令相似。例如,使用CS選擇子的RPL,而不是由選擇子標識的段的DPL,是為了返回到不在DPL給定特權級的一致代碼段。若彈出的CS的選擇子的RPL規定了一個內層特權級,則產生通用保護故障。需要注意的是,對於IRET指令,保存在當前堆棧中的返回地址中的選擇子字段必須指向代碼段描述符。而不能是系統段或門描述符。否則將引起通用保護故障。
對於提供出錯代碼的異常處理程序,必須先人為地從堆棧中彈出出錯代碼,然後再執行IRET指令,及出錯代碼不會自動被處理器彈出或取消。
中斷返回指令IRET不僅能夠用於由中斷/異常引起的嵌套任務的返回,而且也適用於由段間調用指令CALL通過任務門引起的嵌套任務的返回,如前文所述,在執行通過任務門進行任務切換的段間調用指令CALL時,標志寄存器中的NT位被置為1,表示任務嵌套。而RET指令不能實現此功能。