1. 程式人生 > >9.6 基於中斷的功能調用

9.6 基於中斷的功能調用

img 技術 判斷 操作 主程序 顯示器 調用 輸入輸出 向量

計算機組成

9 中斷和異常

9.6 基於中斷的功能調用

技術分享圖片

那現在,我在執行這些運算之後,也就是執行這些程序的過程中呢,又遇到了一個奇怪的現象。這裏突然有一個地方寫著,請查看緊急操作手冊的第二百項,那我就翻到這個地方去了。翻到前面,然後找第二百項,然後找到了對應的操作——是讓我在本子的某一個地方寫一個數。這是怎麽回事呢?一般來說,剛才我們學到的都是我在運算當中遇到了異常的情況,然後我主動去查找前面的對應的異常處理的方法,查找中斷向量表。那麽現在在這個程序當中,居然主動的寫到了讓我去查找相關的中斷項量表。這個是怎麽回事情呢?我們就來看看這個問題。

技術分享圖片

在x86指令系統當中,其實還提供了一條中斷指令,它的格式是INT,加上一個操作數n。用這條指令,就可以直接調用對應的中斷服務程序。這個n是0到255當中的一個數,對應的中斷類型碼。當CPU執行到指令時,首先會將標誌寄存器壓棧,然後清除IF和TF兩個標誌位,也就是關中斷。再將CS和IP兩個寄存器的內容壓棧,然後根據指令中提供的類型碼,也就是這個n,去查找中斷向量表,找到對應的中斷服務程序的入口地址。再將入口地址裝到CS和IP寄存器當中去,這樣下一步CPU就會到中斷服務程序的入口取出下一條指令繼續執行。

那麽看到這一個步驟和我們之前介紹的,CPU處理中斷的過程是一樣的。但是區別在於,這是由運行指令主動觸發的。

技術分享圖片

比如,之前CPU當中,如果發生的1號中斷,CPU就會來中斷向量表當中取出1號中斷向量。然後,轉向對應的中斷服務程序開始執行。但如果當前CPU執行程序的過程當中,並沒有滿足觸發1號中斷的條件,而是直接寫了一條指令 int 1,CPU也會到中斷向量表當中,取出1號中斷向量,裝入CS,IP寄存器,再轉到1號中斷服務程序開始執行。

那這樣做有什麽意義呢?明明沒有發生中斷,我們為什麽要調用這個中斷服務程序。這種中斷指令的使用場景其實有兩類。一類就是CPU的一些專用的中斷,就是需要通過調用指令的方式來實現的。比如說3號中斷,那就得寫 int 3

這樣的指令才可以產生。這種情況我們在之前已經介紹過了,現在我們來看另外一種情況。

技術分享圖片

技術分享圖片

比如說有一類,我們稱為BIOS中斷。BIOS就是基本輸入輸出系統,這是一套不大但是還挺復雜的程序,存放在ROM當中。寄存器在剛通電或者復位時,CPU就會從BIOS ROM當中取出第一條指令開始執行。所以,在BIOS當中會提供系統加電自檢和主要的輸入輸出設備處理程序等功能模塊。所謂的功能模塊,也就是一個一個具有獨立功能的程序,比如從鍵盤接收一個字符,或是在顯示器上顯示一個字符,這些工作不但在系統初始化時需要使用,在後來用戶使用計算機的過程中,其實也會用到。而如果要用戶自己去編寫處理這些輸入輸出設備的程序,那就太麻煩了。所以,BIOS的設計者就將其中的這些功能各個包裝起來,形成了很多個獨立的功能模塊。然後將這些獨立功能模塊的入口地址,放在中斷的向量表當中,那如果我們想使用這些功能,比如說就像在顯示器上顯示一個字符,用戶就不用去關心到底用的是什麽顯示器,要占用多少個像素,等等。只需要使用BOIS提供的功能模塊,用INT指令調用對應的中斷服務程序就可以了。而且我們可能希望向這些功能模塊傳遞一些參數,那就可以通過寄存器進行傳遞。

我們不妨來看一個例子。

技術分享圖片

這個表是BIOS中斷的一個片段。想使用BOIS中斷,首先就得查找BIOS中斷的手冊,這個手冊一般會提供這樣一個表格,列出了BIOS這些功能模塊所在用的中斷號,比如說10H,就是用於在顯示器上進行顯示的一個中斷服務程序;而1AH,則是設置系統時鐘的一個中斷服務程序。

我們以1AH為例。如果我們想要改變現在的系統時鐘,當然我們可以去分析時鐘管理芯片的功能,通過查找它的手冊來分析如何去改變系統時鐘的設置,這可能要花很多個步驟。那BIOS的設計者就幫我們封裝好了這個功能,我們只要這樣寫代碼就可以了(紅色匯編代碼)。因為我們通過這個表可以看到,如果要設置時鐘,我們需要提供一個功能號為1,因為1AH這個中斷裏頭,其實有多種功能,我們可能想讀出當前時鐘的值;也可能要改變當前時鐘的值。這個中斷服務程序怎麽識別呢?

它就要求你在AH寄存器當中放入一個數,那麽在中斷服務程序的開始,會先檢查AH寄存器。如果裏面是0,那它就按照讀時鐘的操作運行後續的代碼;如果AH裏面的值是1,它就按照設置時鐘的操作執行後續的代碼。

現在我們要設置時鐘。所以,在AH裏面先放上1。然後我們查這張表,知道我們要設置的時間是放在這幾個寄存器當中,CH放在要設置的小時數,CL放要上要設的分鐘數,DH是秒,DL是百分之一秒。而CL和CH組成的寄存器是CX,DL和DH組成的寄存器是DX。所以,我們直接可以通過對CX和DX賦值,來設置這個時間。那麽現在為了簡單,我們就設成0點0分0秒,這些參數準備好以後,我們最後寫 INT 1AH

接下來就像是之前介紹過發生中斷的時候一樣,CPU會去中斷向量表當中找到1AH對應的中斷向量,然後轉移到對應的中斷服務程序開始執行,而這段中斷服務程序就是位於BIOS所在的存儲區域。那在這個中斷服務程序當中,就會去操作管理系統時鐘的芯片或者部件完成時鐘的更改,然後再返回到這個主程序當中繼續執行下面的代碼。

這樣就把一個和底層硬件細節非常相關的操作給封裝起來,讓編程人員可以比較輕松的完成這樣的工作。BIOS中斷其實提供了很多種類型,可以完成相當豐富的功能,有興趣的話,可以查找相關BIOS的手冊。但是因為BIOS容量有限,因此我們還是可以利用這個方法,在上層的軟件當中,提供更為豐富的功能。

技術分享圖片

那我們來介紹一個例子,就是DOS中斷。

DOS是早期的一種操作系統。它占用了一個中斷類型號,21H。和BIOS占據了多個中斷類型號不同,DOS中斷只有這一個類型號。但它的功能非常的豐富,常用的文件管理、 存儲管理等很復雜的功能,都可以用這個中斷服務程序來解決。那它怎麽區分我們到底想使用哪個功能呢?其實剛才BOIS中斷給我們提供了這樣的思路。我們可以通過一個寄存器,傳入一個參數,來告訴中斷服務程序,我們到底想調用哪樣的功能。所以,所有的DOS中斷都只使用這一個中斷入口。而且DOS是一個操作系統,它所提供的中斷功能比BIOS中斷更為齊全、完整,而且進一步屏蔽了設備的物理特性,讓編程的使用變得更加的方便。

技術分享圖片

我們也來看一個例子。如果我們想在屏幕上輸出一個字符,那我們可以查找DOS中斷所提供的表格,DOS中斷都是21H。所以,這個表裏面只需要列出功能號。那麽發現,6號功能是在進行輸入輸出的操作。所以,我們現在AH寄存器當中存入6。然後我們進一步發現,如果我們想輸出一個字符,就在DL寄存器當中,放入我們想顯示的這個字符;而如果我們想通過鍵盤輸入這個字符,則只需要在DL寄存器當中,存入FF。而最後輸入的字符,會放在AL寄存器當中。那我們現在還是來看輸出,所以我們在DL寄存器當中存上這個字符,然後調用 INT 21H, 這樣CPU就會轉向21H號中斷所對應的中斷服務程序。在這個服務程序當中,首先會檢查AH裏面的值,確定功能號,然後就進入到這個功能對應的程序代碼段,再根據DL寄存器的內容,判斷出這是一次輸出。那這個服務程序接下來就會對顯示器進行操作,讓對應的字符顯示在屏幕的合適的位置。

這些繁瑣的工作,都不需要用戶來關心了,只要簡單的調用這個DOS中斷就可以了。當然前提是這些操作都已經由其它的程序員幫你寫好,並且封裝起來還安裝在了你這個電腦上,這樣你才可以使用。歸根到底,這些操作都還是要有人來寫出程序,只不過一次寫好之後,其他的用戶就可以直接調用了,這樣會很方便。所以說,無論是BIOS中斷,還是DOS中斷,或者是其它類似的中斷方式,其本質並不是計算機運行當中發生了異常的情況,而是利用了現有的中斷這種機制來實現一些系統函數,代碼的調用,以便向高層的軟件屏蔽底層硬件的細節,從而提高編程的便利性,正確性和可移植性。

技術分享圖片

那現在,我們的機制已經講的很清除了。在程序執行的過程中遇到的任何異常情況,我們都可以自如的處理,而且還可以利用這個機制,完成更加豐富的功能。所以,可以說我們對任何情況,都已經是能夠應對自如了。

9.6 基於中斷的功能調用