用匯編編寫DOS下的內存駐留程序(3)

字號:

三 中斷矢量
    3.1 IBM PC提供的中斷
     IBM PC有兩種基本形態(tài)的中斷.如果是由外圍設備所產生的中斷就叫做硬件中斷(Hardware interrupt),譬如:鍵盤,磁盤機和時鐘等外圍設備都可以產生硬件中斷.外圍設備所產生的中斷信號都連接到中斷控制器,中斷控制器可以根據它們之間的重要性來安排優(yōu)先順序,以便使CPU有效地處理這些硬件信號.另一種中斷是軟件中斷(Software interrupt),軟件中斷也叫做陷井(Trap),它是由執(zhí)行中的軟件所產生.雖然軟件包中斷的處理方式和硬件中斷完全相同,但是通常軟件中斷是希望執(zhí)行操作系統(tǒng)所提供的服務.
       表3.1是IBM PC所提供的中斷,這些中斷是根據中斷號碼和中斷矢量(Interrupt vector)排列.
       IBM PC的用戶或是編寫應用程序的程序人員很少會直接接觸到硬件中斷,除非是使用某些特殊的硬件,或是需要較嚴格的要求時,最常被修改的硬件中斷是敲鍵盤所產生的中斷(9H),尤其是文本編輯的程序.大體而言,只有硬件設計者基是系統(tǒng)程序人員才會注意到所有在硬件中斷;編寫內存駐留程序的設計人員則只使用到部分硬件中斷而已,尤其是:鍵盤中斷和計時器(Timer)的中斷.
       反之,軟件中斷對于任何編寫匯編程序的人,甚至對編寫高級語言程序的人都相當的重要.軟件中斷是應用程序進入到IBM PC操作系統(tǒng)的接口,經由這些接口應用程序才可以執(zhí)行所要求的系統(tǒng)服務.
       其中軟件中斷中最重要,同時也是最常被匯編語言程序設計師所用到是DOS INT 21H.這個中斷是執(zhí)行DOS系統(tǒng)調用的軟件中斷,它可以讓應用程序執(zhí)行任何DOS的操作.
       接下來最有用的軟件中斷是ROM-BIOS(基本輸入輸出系統(tǒng))所提供的中斷.這些軟件中斷是IBM PC所提供的的低層次服務,譬如:鍵盤輸入,顯示器輸出和磁盤機的輸入與輸出等.
    3.2 鍵盤輸入的方法
       以下就以IBM PC從鍵盤讀取字符為例子,來說明中斷的工作方式.IBM PC從鍵盤讀取字符時,使用了兩種不同形式中斷,亦即:硬件中斷和軟件中斷.當使用者從鍵盤敲下一個鍵時,鍵盤的線路就會送出一個信號.這個信號會造成硬件中斷發(fā)生,從而觸發(fā)低層次的鍵盤中斷處理程序開始執(zhí)行.這個中斷處理程序馬上從鍵盤的硬件讀取使用者所敲入的字符,然后把它放到一個隊列中,如果這個隊列填滿時,鍵盤中斷處理程序會使IBM PC發(fā)出一聲響.鍵盤中斷處理程序做完這些事情之后,它就把控制權交還給原先被中斷的程序.如果有一個程序希望從鍵盤讀取一個字符時,它就發(fā)出適當的軟件中斷信號,這時候就由相對應的中斷處理程序去檢查鍵盤隊列,并且傳回隊列中的第一個字符.
       上面所介紹的鍵盤輸入工作方式,在中斷驅動系統(tǒng)中很普遍地采用.這和做法可以把實際上需要輸入的應用程序和實際上執(zhí)行輸入的處理部分分開來.這種做法也可以用在其它不同形式的輸入和輸出外圍設備.
    3.3 改變輸入矢量
       中斷矢量儲存在IBM PC最前面的400H個字節(jié)中.每一個矢量的長度是四個字節(jié)組成,這四個字節(jié)內所存放的是中斷處理程序執(zhí)行的地址值.其中前兩個字節(jié)包含地址值的位移(Offset)部分,后面的兩個字節(jié)則包含了段(Segment)部分.
       中斷矢量有兩種修改方法.可以直接地設置中斷矢量的地址值,或是使用DOS所提供的系統(tǒng)調用設置中斷矢量的地址值.
       3.3.1 直接設置中斷矢量
        因為中斷矢量只是存放地址值的存儲位置,因此我們可以直接地把地址存放到存儲位置中.以下是一個小例子:
        mov ax,0
        mov es,ax
        mov word ptr es:24,offset Keyboard
        mov word ptr es:26,seg Keyboard
       在許多情況下,上面的程序都可以正確地執(zhí)行.但是如果上面的程序正在執(zhí)行時突然敲下一個鍵的話,就可能會問題;而最糟的情 況是發(fā)生:第三個MOV已經執(zhí)行完畢,而第四個MOV尚未執(zhí)行時.如果在此時敲下任何鍵的話,鍵盤中斷矢量都沒有任何意義,而造成整個系 統(tǒng)死機.因此我們可以在設置中斷矢量時,讓中斷無效,譬如:
        mov ax,0
        mov es,ax
        cli
        mov word ptr es:24,offset Keyboard
        mov word ptr es:26,seg Keyboard
       上面的做法在大部分的情況下都可以正確地執(zhí)行.但是CLI這個指令無法停止NMI中斷(不可屏蔽中斷),因此如果發(fā)生NMI中斷時就 沒用辦法.  下面的這一種做法雖然比較復雜,但是對于所有的中斷都有效,這包括了NMI中斷在內:
        mov word ptr kbd-ptr[0],offset Keyboard
        mov word ptr kbd-ptr[2],seg Keyboard
        mov di,0 ;Use Di to Set ES to zero
        mov es,di ;Set ES to destination segment
        mov di,24 ;Set DI to destination offset
        mov si,offset kbdptr ;set SI to source offset
        mov cx,2 ;Set word count to 2
        cld ;Set direction to forward
        cli ;Disable interrupts
        rep movsw ;Copy the new vector
        sti ;Enable interrupts
       kbdptr dd ?
        上面的程序中,kbdptr是兩個字節(jié)(WORD)的指針(Pointer),其中包含了鍵盤 中斷處理程序的起始志趣值.REP這個指令將根據寄存 器CX所設置的次數來重復執(zhí)行MOVSW,而整個指令就如同單一的指令一樣.NMI中斷不能夠發(fā)生在一個完整的指令中.因為地址值搬移的操 作都能包含在一個單一指令中,因此可以免除任何中斷的干擾.
       3.3.2 使用DOS來設置中斷矢量
        因為要想安全地設置中斷矢量需要一些技巧,因此DOS提供了一項特殊的服務,以幫助程序人員安全地設置中斷矢量,如果只使用 DOS所提供的這項服務來設定中斷矢量的話,那么就不必擔心會發(fā)生前面所敘述的差錯.DOS同時也提供了:讀取中斷矢量的服務.因為讀 取中斷矢量的內容不會修改系統(tǒng)的狀態(tài);因此若直接寫程序讀取,也很安全.但是如果你要自己直接讀取中斷矢量的內容時,就必須計算 出中斷矢量的位置.而DOS已經提供了這項服務.
        使用DOS所提供的系統(tǒng)調用,來讀取中斷矢量的內容時,必須利用INT 21H中的函數35H(讀取中斷矢量),這個函數熱氣矢量號碼來 計算中斷矢量的地址,然后返回其中的內容.以下就是一個例子:
        Old_Keyboard_IO dd ?
        mov al,16h
        mov ah,35h
        int 21h
        mov word ptr Old_Keyboard_IO,bx ;Offset of interrupt handler
        mov word ptr Old_Keyboard_IO,es ;Segment of interrupt handler
       用DOS來設置中斷矢量例子:
        New_Keyboard_IO dd ?
        mov word ptr New_Keyboard_IO,bx ;Offset of interrupt handler
        mov word ptr New_Keyboard_IO,es ;Segment of interrupt handler
        mov al,16h
        mov ah,25h
        int 21h