1. 程式人生 > >9.4 中斷的處理過程

9.4 中斷的處理過程

發出 表格 設置 成了 出現 來源 壓棧 四種 內部

計算機組成

9 中斷和異常

9.4 中斷的處理過程

技術分享圖片

那我們現在可以放心大膽地進行運算了。算,算,算,一旦遇到了一個異常情況,我們就根據這個異常情況的類型,去查找這個手冊最前面的表格。假如我們遇到的可能是第四種類型,我們找到第四條,上面寫著操作方法在第十二頁。翻到第十二頁,好,找到了。那麽按照這個操作方法一步一步往下執行,就把這問題給解決了。然後呢,我們就可以繼續剛才的運算了,對不對?可是我剛才是在哪一頁進行的運算?這在哪兒呢?我怎麽回到剛才的運算呢?

技術分享圖片

我們先來看一看在CPU內部是如何檢測中斷的。我們就以x86的實模式為例。在CPU內部,會有中斷的處理電路。如果在運算時發生了異常的情況,比如出現除法錯誤,運算器就會產生相應的中斷信號。如果遇到其他指令產生的中斷,就會產生其他對應的控制信號。那這些中斷都是和正在運行的程序本身有關的,所以我們叫它軟件中斷,或者是內部中斷。

那還有來自CPU外部的中斷。這些外設有可能是鍵盤、網絡、打印機,等等。當鍵盤按鍵,或者有收發網絡包的情況,這些外設的芯片或者板卡就會通過主板上的物理連線,發出中斷請求信號。這些信號最終都會連接到CPU內部。不管來源是哪裏,CPU檢測到了中斷請求信號,就會進行處理。

技術分享圖片

中斷處理的過程是這樣的。首先,CPU會關閉中斷響應,也就是不再接受後面其他的外部中斷請求了。註意,只是不接收外部中斷請求。然後將發生中斷處的這個指令的地址保存到棧中,也就是內存當中的一個區域,這個信息必須要保存好,以便於處理完中斷後可以正確地返回當前的程序繼續執行。那究竟是保存發生中斷的這條指令的地址,還是發生中斷的這條指令之後的一條指令的地址,這和這個中斷具體的類型會有關系。第三步則由CPU識別中斷的來源,確定中斷類型號,從而能夠找到相應的中斷服務程序的入口地址。

這三步一般都是由硬件自動完成的。

技術分享圖片

第四步是保存現場,也就將中斷服務程序中可能會改變的寄存器先壓棧,也就是放到內存中保存起來。為什麽要這麽做呢?我們來看一個例子。

技術分享圖片

在這個主程序片段中,我們假設執行到這條除法指令的時候發生了中斷。這時就會調用中斷服務程序。我們假設在這中斷服務程序當中,有 add cx,dx 這麽一條指令,它會改寫CX寄存器的值。

如果我們沒有對CX寄存器進行保護的話,在中斷返回之後,CX寄存器的內容就已經改變了。然後回到主程序繼續往下執行時,這個CX寄存器的內容,就不再是主程序中之前傳到CX寄存器中的內容了。這樣就會導致主程序的錯誤。所以,在中斷服務程序中,如果要用到CX寄存器,就應該先進行壓棧,把當前CX寄存器的值保存到存儲器中,然後在中斷返回之前,再執行彈棧的操作。這樣中斷返回之後,CX寄存器的內容就沒有變化,不會影響主程序的運行。

技術分享圖片

然後第五步,就是執行這個中斷服務程序的主體內容。而且在中斷服務程序中,可以在適當的時候重新開放中斷,以便響應其他高優先級的外部中斷。以免中斷服務程序本身要執行比較長的時間,造成有高優先級的外部中斷長時間無法得到響應。

那如何在中斷服務程序當中,重新開放中斷呢?

技術分享圖片

那這就涉及到對標誌寄存器的操作。在標誌寄存器當中有一些標誌位是狀態標誌,狀態標誌一般情況下,是由硬件設置,然後由軟件讀取。例如進位標誌,就是在運算器產生進位時,由硬件自動設置,然後由軟件的指令讀取出來,可能會進行相關的累加操作。而另一類標誌稱為控制標誌,這些標誌通常是由軟件進行設置,然後硬件電路根據這些標誌設置的不同,而執行不同的功能。

標誌寄存器的第九位就是中斷標誌。

技術分享圖片

IF這個標誌控制對可屏蔽中斷的響應。

外部中斷分為兩大類,一類是可屏蔽中斷,一類是非屏蔽中斷。IF標誌只對外部中斷當中的可屏蔽中斷起作用。如果IF等於1,那就允許CPU響應可屏蔽中斷請求;如果IF等於0,那就不允許CPU響應可屏蔽中斷請求。那怎麽設置IF標誌位的值呢?

有兩條指令。STI指令就是把IF位置為1,而CLI指令就是把IF標誌位清零。這兩條指令都是沒有操作數的指令。當然,IF指令對非屏蔽中斷和內部中斷都是不起作用的。

技術分享圖片

然後我們來看中斷處理過程的最後一步,那就是恢復現場並且返回主程序繼續運行。

技術分享圖片

返回主程序就需要執行中斷返回指令。中斷返回指令它可以不帶操作數,那麽IRET這條指令的操作,就是從當前的棧頂彈出三個字,分別送到IP、CS和FLAGS寄存器當中去。IRET這條指令是放在中斷服務程序的末尾,在中斷調用時,CPU中的硬件電路會將這三個寄存器的值壓入棧中。所以,在執行中斷返回指令時,也會由硬件從棧頂彈出這三個字,再放回到這三個寄存器當中,當CS和IP寄存器改變之後,下一條指令就會回到程序發生中斷的地方繼續執行了。

當然我們也註意到,IRET這條中斷返回指令操作的是CS和IP寄存器。在32位和64位的x86中,指令指針寄存器,又被擴展為EIP和RIP寄存器,它們的寬度都是不一樣的。所以,後來又有了不同的對應的指令。

技術分享圖片

我們再用一個圖示來看一看剛才介紹的中斷處理的過程。我們就以內部中斷為例。

當CPU執行到某條指令,例如就是這條指令,如果此時發生中斷,CPU內部就會產生中斷信號,相關的中斷處理電路會判斷中斷的來源,並產生中斷類型號。CPU的硬件電路會將CS和IP寄存器壓棧,這樣就保存好了處理完中斷後要返回的地址。同時硬件上還會將FLAGS寄存器壓棧,以便保存好當前的各項標誌,以免中斷處理程序當中,有些指令會改變程序的標誌位。在硬件上還會清除IF標誌位,以起到關中斷的作用。然後根據中斷類型號,找到對應的中斷向量,也就是新的CS和IP的值,並以此更新CPU當中的CS和IP寄存器。當完成這個操作後,CPU就會轉到中斷服務程序開始執行。那麽在中斷服務程序中,也可以執行STI指令,以開放中斷。當完成了中斷服務程序之後,最後一條就是執行中斷返回指令(IRET)。這條指令會從存儲器當中將剛才壓棧的三個字彈出來,並按照對應的順序存到CS、IP和FLAGS寄存器當中去,這樣就完成了返回主程序的動作。

註:PSW即程序狀態字(有些教材也叫程序狀態寄存器),Program Status Word。

技術分享圖片

這就是中斷處理過程的六個主要的步驟。通常情況下,前三步都是由處理中斷的硬件電路來完成,後三部則是由軟件,也就是中斷服務程序來完成。

技術分享圖片

但這只是一個大體的分工,在真的要涉及中斷服務程序的時候,必須要針對具體的系統,弄清楚軟硬件的分工究竟是怎麽樣的。例如在保存現場這件事情上,剛才我們介紹的標誌寄存器是由硬件來負責保存的,但是在另外的一些系統上,可能硬件就不會自動地保存標誌寄存器,就需要由中斷服務程序的軟件來進行保存。

那麽在設計中斷服務程序時,必須要搞清楚這些問題,不然就有可能發生錯誤。

技術分享圖片

現在,我們不但有了這張表,而且有了一個規範的操作流程。我們知道運算中出現異常情況,怎麽查到這張表,怎麽找到異常的操作的步驟。然後,應該事先做哪些記錄,以免丟失信息。最後我們還知道怎麽回到我們剛才運算的那個地方,繼續進行下一步的操作。

這就是一個完整的中斷的處理過程。

9.4 中斷的處理過程