標籤:hot .com 實模式 並且 清除 stat 通過 檢測 情況
電腦群組成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 中斷的處理過程