精華區beta Programming 關於我們 聯絡資訊
※ [本文轉錄自 ric 信箱] 發信人: dv.bbs@csie.nctu (皮皮), 信區: programming 標 題: 優良信件轉載 發信站: 交大資工鳳凰城資訊站 (Sat Mar 18 16:18:40 1995) 轉信站: bridge!bbsroute!phoenix 以下信件, 原載於 90-assembly, 是關於 PC 鍵盤, 並非我寫的, 我作的只有轉載的工作. 希望對您有幫助. --------------------------------------------------------------- 90-ASSEMBLY - Msg : 63 of 72 From : Chi'u I-Nan 90:1013/622 16 Mar 95 19:56:00 To : All Subj : 關於鍵盤 ----------------------------------------------------------------------------- 近來看了看許多網友討論鍵盤的控制,並不是非常熟悉, 故將我寫好關於鍵盤方面的資料上傳給諸位參考, 希望對各位有所助益. 這些資料原是我準備寫"軟體保護技術研究" 一書中的文章,但因工作忙碌,一直無法順利寫完 (寫了半年多才寫 這麼一點...). 除了鍵盤資料外,我也將一些硬體控制方面的資料 一併上傳,其中關於146818 (CMOS控制)以前已上傳過,因此不再重 複上傳. 8237 (DMA控制) 尚未完全寫完,以後再說. 所有上傳的資料都是我參考多本書籍,並親自寫程式測試過的, 正確性應極高. 當然,若文中有錯誤的地方,也請指正一下,免得 我繼續"誤"人. 如果有進一步興趣的話,以下是一些參考書籍, 可供進一步研究. 7.PC系統程式設計, 吳宗穎&賴明宏譯, 格致, 1990. 8.DOS技術手冊(二)徹底研究篇, 施威銘著, 旗標, 1987. 9.BIOS系統呼叫, 林鴻明編譯, 格致, 1989. 10.IBM PC介面技術與週邊設備實習, 謝聿婷編著, 全欣, 1989. 11.IBM PC BIOS程式剖析, 林書華著, 儒林, 1985. 12.IBM PC/XT硬體線路精解, 劉紹漢編著, 全華, 1991. 13.IBM PC/AT硬體技術手冊, 趙健雄譯, 儒林, 1986. 14.386/AT硬體徹底剖析, 陳柏村編著, 全華, 1991. 15.Intel Total Solution Component & Development Tool Handbook, Intel, 1987. 16.Microsystem Components Handbook, Microprocessors and Peripherals, Volume I, II, Intel, 1985. 17.The TTL Data Book, Volume I,II,III, TEXAS Instruments, 1984. [7,8,9]為介紹PC系統的相關書籍,[7]的內容幾乎涵蓋了所有的PC系統相 關知識,但介紹並不是很深入,頗適合技術參考使用。[8]及[9]則分別對 於DOS及BIOS有更詳細的介紹,較適合初學者閱讀。[10,11,12,13,14,15, 16,17]則是介紹PC硬體控制的書籍,[10]的介紹頗詳細,但硬體的種類也 較少,頗適合初學者閱讀;[11]為解析BIOS的書籍,所涵蓋的硬體較多, 但介紹也較不深入;[12]則對PC的線路設計加以說明,以上三本都是針對 PC/XT的架構做說明的。[13,14]則以PC/AT為主做說明,[13]主要是針對 286/AT的硬體線路及控制部份加以說明,其中還附有完整的AT BIOS程式, 頗適合程式設計師閱讀。[14]則是針對386/AT的元件加以詳細說明,主要 的內容為電路的設計,對純學軟體的人來說,看來會比較吃力些,但是其 中一些關於軟體控制方式仍頗具參考價值。至於[15,16,17]則是以零件的 觀點說明該零件的控制方式,頗適合搭配上述的書籍參考使用。[15,16] 均為INTEL的80系列零件,其中[16]較偏重於AT的機器,[17]則為TTL零件 的參考手冊。 * 青衫詩客 -- 小邱 * -+- Via 中文銀版快信 V2.28C + Origin: 檔案貨櫃, 歡迎您來挖寶, 28800 BPS, 04-230-2080; (90:1013/622) --------------------------------------------------------------- 90-ASSEMBLY - Msg : 64 of 72 From : Chi'u I-Nan 90:1013/622 16 Mar 95 19:46:00 To : All Subj : 鍵盤1 ----------------------------------------------------------------------------- 一.鍵盤 想要中斷鍵盤與追蹤者的連繫,首先我們必須完全了解鍵盤的輸入到 追蹤者取得的整個過程,如此我們才能從這個過程中找到中斷的地方。在 早期的XT上,鍵盤控制器是使用8048,當鍵盤有任何按鍵按下時,首先由 8048取得該按鍵的掃描碼(Scan Code)後,將掃描碼傳給8255(8255同 時也控制著是否允許鍵盤工作),然後送出岔斷訊號給8259,由8259發出 IRQ1岔斷訊號給CPU,然後跳入INT 9h的岔斷處理程式執行。而在AT上, 鍵盤控制器改用了功能較強的8042,同時也取消了8255這個週邊界面元件, 因此掃描碼便不經由8255傳送,而直接由8042傳送。雖然XT和AT有這些差 異,但事實上各I/O Port的功能大致上仍頗相容,因此大部份的XT程式還 是可以在AT上正確的執行。 INT 9h的岔斷處理程式主要是從8255取得Scan Code,然後將之換算 成ASCII碼,最後再將兩者放到鍵盤緩衝區內(鍵盤緩衝區的位址由BIOS 的一些參數決定)。這之中當然還處理了一些特殊的按鍵,如Ctrl-Alt-Del、 Caps Lock等等。而電腦的執行程式便經由岔斷INT 16h來偵測及取得在鍵 盤緩衝區內的按鍵資料,最後依照所得到的按鍵資料進行指定的工作。整 個連繫的過程大致是這樣子。如果你對於前面所說的過程中,關於硬體部 份如8255、8042、8259等不是很了解的話,請你隨時參閱附錄一中的說明 後再繼續往下閱讀。 由這個連繫的過程,我們大概可推出下類幾種截斷鍵盤輸入的方式: 1.控制8042,使得鍵盤無法輸入或不可輸入。 2.控制8255,阻止鍵盤的輸入。 3.控制8259,阻止鍵盤岔斷的產生或進入鍵盤岔斷處理程式。 4.破壞或截斷鍵盤岔斷處理程式。 5.破壞、改變或檢查鍵盤緩衝區內的資料及其輸入指標值。 6.破壞或截斷鍵盤資料輸入岔斷處理程式。 以下我們便仔細說明這些截斷鍵盤輸入的方法。 技術一 利用8042控制命令將鍵盤禁能 在說明如何利用8042控制命令將鍵盤禁能之前,我們先說明8042控制 命令的下達方式: ; ; ======================================================== ; 以下為8042界面函數之內部呼叫函數 ; ======================================================== ; Flush8042 PROC ; 清除所有的輸出緩衝器資料 push ax FlushOBF: in al,64h test al,1 jz NotOBF in al,60h jmp short FlushOBF NotOBF: pop ax retn Flush8042 ENDP ; WaitIBF PROC ; 等待8042輸入緩衝器有空 WaitIBFLoop: push ax in al,64h test al,2 pop ax jnz WaitIBFLoop retn WaitIBF ENDP ; WaitOBF PROC ; 等待8042輸出緩衝器有資料送來 WaitOBFLoop: push ax in al,64h test al,1 pop ax jz WaitOBFLoop retn WaitOBF ENDP ; Read8042Data PROC ; 讀取8042回應資料 ; 傳回: AL = 回應資料 call WaitOBF ; 等待資料回庄 in al,60h retn Read8042Data ENDP ; Write8042Data PROC ; 送出資料給8042 ; 參數: AL = 8042系統命令或資料 ; 備註: 本函數亦為送出系統命令或資料的函數 call WaitIBF ; 等待輸入緩衝區有空 out 60h,al ; 送出資料 call WaitIBF ; 確認8042收到 retn Write8042Data ENDP ; RealSend8042Cmd PROC ; 送出一般命令碼給8042 ; 參數: AL = 8042一般控制命令 ; 備註: 8042命令之參數或傳回值由外界處理 call WaitIBF ; 等待輸入緩衝區有空 out 64h,al ; 送出命令 call WaitIBF ; 確認8042收到 retn RealSend8042Cmd ENDP ; RealSend8042Sys PROC ; 送出系統命令碼或參數給8042 ; 參數: AL = 8042系統控制命令或參數 ; 傳回: AL = 8042回應值 ; 備註: 除回音外,其餘命令或參數應檢查是否傳回ACK call Flush8042 call Write8042Data call Read8042Data retn RealSend8042Sys ENDP ; ; ======================================================== ; 以下為8042界面函數,使用前必須使用CLI將岔斷禁能 ; ======================================================== ; Send8042Cmd PROC ; 送出一般命令碼給8042 ; 參數: AL = 8042一般控制命令 call RealSend8042Cmd retn Send8042Cmd ENDP ; Read8042Cmd PROC ; 送出讀取命令給8042 ; 參數: AL = 8042讀取命令 ; 傳回: AL = 讀取值 call Flush8042 call RealSend8042Cmd call Read8042Data retn Read8042Cmd ENDP ; Write8042Cmd PROC ; 送出寫入命令給8042 ; 參數: AL = 8042寫入命令 ; AH = 寫入資料 ; 備註: AX值會被破壞 call RealSend8042Cmd xchg al,ah call Write8042Data retn Write8042Cmd ENDP ; Echo8042 PROC ; 送出8042回音命令 ; 傳回: AL = EEh mov al,0EEh ; 回音命令 call RealSend8042Sys retn Echo8042 ENDP ; Send8042Sys PROC ; 送出系統命令碼或參數給8042 ; 參數: AL = 8042系統控制命令或參數 ; 備註: 本函數會自動一直傳送,直到8042回應ACK RetrySysCmd: push ax call RealSend8042Sys cmp al,0FAh ; ACK訊號? pop ax jne RetrySysCmd retn Send8042Sys ENDP ; Write8042Sys PROC ; 送出系統寫入命令給8042 ; 參數: AL = 8042系統寫入命令 ; AH = 寫入資料 ; 備註: AX值會被破壞 call Send8042Sys xchg al,ah call Send8042Sys retn Write8042Sys ENDP ; Read8042Sys PROC ; 送出系統讀取命令給8042 ; 參數: AL = 8042系統讀取命令 ; AH = 寫入資料 ; 備註: AX值會被破壞 call Send8042Sys call Read8042Data retn Read8042Sys ENDP * 青衫詩客 -- 小邱 * -+- Via 中文銀版快信 V2.28C + Origin: 檔案貨櫃, 歡迎您來挖寶, 28800 BPS, 04-230-2080; (90:1013/622) --------------------------------------------------------------- 90-ASSEMBLY - Msg : 65 of 72 From : Chi'u I-Nan 90:1013/622 16 Mar 95 19:47:00 To : All Subj : 鍵盤2 ----------------------------------------------------------------------------- 以上8042界面函數的使用方式可區分如下: 1.一般控制命令 Read8042Cmd = 8042讀取命令(有回送值者)使用。 Write8042Cmd = 8042寫入命令(有參數者)使用。 Send8042Cmd = 其他無回送值或參數者使用。 2.系統命令 Echo8042 = 回音命令專用。 Read8042Sys = 8042讀取命令(有回送值者)使用。 Write8042Sys = 8042寫入命令(有參數者)使用。 Send8042Sys = 其他無參數者使用。 記得這些函數在使用前一定要使用CLI指令將岔斷禁能,否則會無法 正常執行。現在我們正式開始探討利用8042控制命令將鍵盤禁能的技術: 1.改變8042命令位元組位元4的值以抑制鍵盤。一般的寫法如下: mov al,20h ; 讀取8042命令位元組 call Read8042Cmd or al,10h ; 將位元4設成1以抑制鍵盤 mov ah,al mov al,60h ; 將8042命令位元組寫回 call Write8042Cmd 還原的方式便是: mov al,20h ; 讀取8042命令位元組 call Read8042Cmd and al,0EFh ; 將位元4設成0以啟動鍵盤 mov ah,al mov al,60h ; 將8042命令位元組寫回 call Write8042Cmd 由於我們已知8042命令位元組之初值大都使用45h,因此上面的抑制的 程式也可以直接寫成: mov ax,5560h call Write8042Cmd 還原的方式為: mov ax,4560h call Write8042Cmd 另外亦可直接使用控制命令還原命令位元組位元4的值,請參見第三點 的說明。 2.改變8042命令位元組位元0的值以抑制岔斷訊號的產生。寫法和第一點 類似,因此不再多做說明: mov al,20h ; 讀取8042命令位元組 call Read8042Cmd and al,0FEh ; 將位元0設成0以抑制岔斷 mov ah,al mov al,60h ; 將8042命令位元組寫回 call Write8042Cmd 還原的方式為: mov al,20h ; 讀取8042命令位元組 call Read8042Cmd or al,01h ; 將位元0設成1以啟動岔斷 mov ah,al mov al,60h ; 將8042命令位元組寫回 call Write8042Cmd 另一種寫法: mov ax,4460h call Write8042Cmd 還原方式: mov ax,4560h call Write8042Cmd 3.使用鍵盤失效命令抑制鍵盤,該命令會自動將8042位元組之位元4設成0。 寫法如下: mov al,0ADh call Send8042Cmd 還原方式為: mov al,0AEh call Send8042Cmd 亦可直接更動8042命令位元組的值,請參見第一點的說明。 4.使用系統預設失效命令,暫停鍵盤功能。寫法如下: mov al,0F5h call Send8042Sys 還原方式為: mov al,0F4h call Send8042Sys 但是這個命令會影響到鍵盤的延遲與重複率(回復到預設值),對於已 將鍵盤的延遲與重複率設成最快的使用者會覺得很不方便,可以下列方 式重新設回: mov ax,00F3h call Write8042Sys 技術二 改變8042之模式狀態 將可程式化硬體的執行模式改變,使之無法與外部線路或處理程式相 配合,如此也可以達到保護的效果。當然這項改變必須是可以回復,而且 不損及原系統之正常運作為前提才行的。以下為8042可改變的模式: 1.改變命令位元組位元6的斷開碼格式。藉由將這個位元設定成0使之成為 雙斷開碼格式(PC上為使用單斷開碼),原PC之鍵盤岔斷INT 9h將無法 再正常地處理8042所送入之鍵盤資料,但是在還原之前必須將岔斷禁能, 以避免出現一大堆原INT 9h解出的錯誤鍵盤資料。改變斷開碼的寫法如 下: mov al,20h ; 讀取8042命令位元組 call Read8042Cmd and al,0BEh ; 將位元6設成0以使用雙斷開碼 mov ah,al mov al,60h ; 將8042命令位元組寫回 call Write8042Cmd 還原的方式為: mov al,20h ; 讀取8042命令位元組 call Read8042Cmd or al,40h ; 將位元6設成1以使用單斷開碼 mov ah,al mov al,60h ; 將8042命令位元組寫回 call Write8042Cmd 另一種寫法: mov ax,0460h call Write8042Cmd 還原方式: mov ax,4560h call Write8042Cmd 這個技術特別適合自行撰寫的鍵盤岔斷處理程式,以做為密碼等資料輸 入使用。即使在密碼輸入中途被岔斷欲破解,只要自行撰寫的鍵盤岔斷 處理程式不和原INT 9h的鍵盤岔斷處理程式相容的話,追蹤者將再也無 法藉由鍵盤對電腦下命令,從而達到保護的效果。當然使用這種方式還 要考慮到其他的輸入裝置,如滑鼠的INT 33h等,這方面不在本書的討 論範圍內。以下為一個雙斷開碼轉單斷開碼之鍵盤岔斷處理程式: NewInt9h PROC ; 處理雙斷開碼轉單斷開碼的鍵盤岔斷處理程式 push ax in al,60h ; 讀取鍵盤送來資料 cmp al,0F0h ; 雙斷開碼第一位元組? jne NormalInt9h WaitSecond: in al,64h ; 等待第二個斷開碼過來 test al,1 jz WaitSecond in al,60h or al,80h NormalInt9h: ; 自己寫的單斷開碼處理程式放在此處 ; 該程式可參考AT BIOS的書籍 ; 但要注意暫存器值的保存 ; AL = 鍵盤讀出的資料 (單斷開碼格式) mov al,20h ; 送出EOI給第一個8259 out 20h,al pop ax iret NewInt9h ENDP 2.將命令位元組位元0改成值1,使用Polling處理方式。這個位元的設定 與還原方式,請參見技術一的第二點。不使用岔斷而使用Polling的處 理方式,也適合用在輸入密碼上,以下為鍵盤資料輸入的Polling處理 方式: Poll8042 PROC ; 使用Polling方式取得鍵盤資料 ; 傳回: Carry On = 鍵盤沒有資料輸入 ; Carry Off時, AL = 鍵盤資料 in al,64h test al,1 jz NoKBData in al,60h clc retn NoKBData: stc retn Poll8042 ENDP 上面這個函數所讀取到的資料仍會受斷開碼格式的影響。使用Polling 處理方式時,要特別注意因處理不及導致的資料覆蓋問題,因此這種處 理方式通常不適於組合鍵的處理(如Ctrl-A)。如果沒有組合鍵,一般 都可以不管資料覆蓋的問題。 * 青衫詩客 -- 小邱 * -+- Via 中文銀版快信 V2.28C + Origin: 檔案貨櫃, 歡迎您來挖寶, 28800 BPS, 04-230-2080; (90:1013/622) --------------------------------------------------------------- 90-ASSEMBLY - Msg : 66 of 72 From : Chi'u I-Nan 90:1013/622 16 Mar 95 19:48:00 To : All Subj : 鍵盤3 ----------------------------------------------------------------------------- 技術三 利用8042存取重要指令或資料 8042的命令位元組是一個可以完全讀寫的暫存器,而這個位元組的值 與鍵盤的作用是息息相關的,因此若要完全隔絕使用者對鍵盤的控制,又 要避免使用者跳過對此位元組的讀寫,最有效的方法便是將一些重要資料 或指令暫存在這個暫存器內,而在稍後再讀回使用。若大量使用此一方法, 勢必造成追蹤者在破解過程中極大的困擾,必須時時記錄該值並跳過讀寫 的程式。若再混用技術二不可跳略的鍵盤輸入處理方式,要破解便要費上 極大的功夫。但是在設回原值前,記得必須要將岔斷禁能。以下為寫入的 方式: mov ah,<資料> mov al,60h call Write8042Cmd 讀取方式為: mov al,20h call Read8042Cmd 如此AL便傳回原寫入的資料。最後還原的方式便是: mov ax,4560h call Write8042Cmd 讀寫的資料可以是指令、位址、資料、密碼、鍵值等等。另外,某些會輸 出固定值的8042命令,其回送值也可以當成上述資料運算使用,只不過這 些命令較死,效果不若命令位元組來得好。以下為會傳送固定值的8042命 令: AAh(一般命令) -> 55h ABh(一般命令) -> 00h EEh(系統命令) -> EEh FFh(系統命令) -> AAh(會影響鍵盤延遲與重複率) 技術四 控制8255將鍵盤禁能 8255之Port B位元7用來控制鍵盤的啟用與否,因此藉由改變這個位 元值便能達到使鍵盤禁能的目的。以下為使鍵盤禁能的方式: in al,61h or al,80h out 61h,al 還原的方式為: in al,61h and al,7Fh out 61h,al 由於AT並不使用8255,因此這個技術只對XT有效,對於AT並無效。但 因為AT Port 61h高四位元為僅讀位元,因此這項技術即使用在AT上也不 會造成其他不良的影響。 技術五 改變8259的岔斷位址 由於8259可以更改岔斷的起始位址,因此如果我們將8259重新初始化, 改變它的岔斷起始位址,則鍵盤插斷便不會再呼叫INT 9h,如此再配合其 他技術便可達到鍵盤禁用的目的。例如: 1.將INT 08h~INT 0Fh岔斷位址複製到INT 00h~INT 07h,然後改變 8259的岔斷起始位址為00h,則鍵盤岔斷將改在INT 1h,這個岔斷 剛好就是追蹤程式常用的單步岔斷。如此便可使得追蹤者一但使用 單步追蹤便無法使用鍵盤,要使用鍵盤便無法使用單步追蹤。這個 方式特別適合自己寫的鍵盤岔斷處理程式和資料輸入程式,使得在 輸入密碼過程中不易被岔斷破解。 2.將8259的岔斷起始位址隨便改到一個位址,並將岔斷禁能。由於追 蹤者在追蹤過程中一定要用到岔斷,因此一但他將岔斷允能,便會 因鍵盤岔斷跳入不名的程式位址而導致當機或其他結果。 重新初始化8259以改變岔斷起始位址的方式如下: (一)PC/XT in al,21h ; 先取得並記錄原來的IMR值 push ax mov al,13h ; 送出ICW1 out 20h,al jmp short $+2 ; 延遲 mov al,<起始位址> ; 送出ICW2 (原值08h) out 21h,al jmp short $+2 mov al,09h ; 送出ICW4 out 21h,al jmp short $+2 pop ax out 21h,al ; 設回原來的IMR值 (二)AT第一個8259 in al,21h ; 先取得並記錄原來的IMR值 push ax mov al,11h ; 送出ICW1 out 20h,al jmp short $+2 ; 延遲 mov al,<起始位址> ; 送出ICW2 (原值08h) out 21h,al jmp short $+2 mov al,04h ; 送出ICW3 out 21h,al jmp short $+2 mov al,01h ; 送出ICW4 out 21h,al jmp short $+2 pop ax out 21h,al ; 設回原來的IMR值 (三)AT第二個8259 in al,0A1h ; 先取得並記錄原來的IMR值 push ax mov al,11h ; 送出ICW1 out 0A0h,al jmp short $+2 ; 延遲 mov al,<起始位址> ; 送出ICW2 (原值70h) out 0A1h,al jmp short $+2 mov al,02h ; 送出ICW3 out 0A1h,al jmp short $+2 mov al,01h ; 送出ICW4 out 0A1h,al jmp short $+2 pop ax out 0A1h,al ; 設回原來的IMR值 在改變8259岔斷起始位址的初始化過程中,必須記得使用CLI命令將 岔斷關掉,而在一切均妥當或復原後再用STI命令啟用岔斷。注意程式結 束前(指轉交給受保護程式前)必須設回原來的岔斷起始位址,該值可以 參見上面的ICW2後面的註解。 由於一般的I/O Port命令較容易被解開,因此建議所有有關I/O Port 動作的命令,最好將之分散到保護程式各處。例如上面的8259初始化命令, 最好能再與其他命令(特別是其他I/O Port的命令)交叉相混合,如此不 但中間JMP SHORT $+2的延遲命令可以省略,也較不容易被追蹤者解析出 來。若再使用下一章會提到指令隱藏技術,則保護的成效將會更好。 技術六 利用8259 IMR值遮斷鍵盤岔斷 利用8259 IMR值來遮斷鍵盤岔斷是一種相當普遍的作法,已不具保護 的作用了。但它能確實有效地防止鍵盤岔斷的發生,因此運用也很廣。以 下遮斷鍵盤岔斷的方式: in al,21h or al,02h out 21h,al 還原的方式為: in al,21h and al,0FDh out 21h,al * 青衫詩客 -- 小邱 * -+- Via 中文銀版快信 V2.28C + Origin: 檔案貨櫃, 歡迎您來挖寶, 28800 BPS, 04-230-2080; (90:1013/622) -------------------------------------------------------------- 90-ASSEMBLY - Msg : 67 of 72 From : Chi'u I-Nan 90:1013/622 16 Mar 95 19:49:00 To : All Subj : 鍵盤4 ----------------------------------------------------------------------------- 技術七 不送出EOI以停止鍵盤岔斷 PC的鍵盤岔斷處理程式結束前,必須以下列方式送出一個EOI命令給 第一個8259,否則下個鍵盤岔斷將無法產生: mov al,20h out 20h,al 如果我們改掉鍵盤岔斷處理程式,使之在結束前不送出EOI命令,如此亦 有禁止鍵盤岔斷的功用。以下為該鍵盤岔斷處理程式: NoEOIInt9h PROC ; 不送出EOI的鍵盤岔斷處理程式 push ax in al,60h ; 讀取鍵盤送來資料 pop ax iret NoEOIInt9h ENDP 但是如何使鍵盤自動產生一岔斷,使得這個岔斷處理程式被執行呢?只要 隨便下個鍵盤會回送資料的命令即可,例如8042回音命令: cli <<取得並暫存原鍵盤岔斷處理程式位址>> <<設定新的鍵盤岔斷處理程式>> call Echo8042 ; 送出回音命令,其他有回送資料之命令亦可 sti <<保護程式其他處理,途中會產生一鍵盤岔斷>> mov al,20h ; 送出EOI結束鍵盤岔斷 out 20h,al 以上是AT的作法。XT上並非使用8042,因此必須利用8255來處理。以下為 XT不送出EOI的鍵盤岔斷處理程式(註:下述兩程式係直接延用XT BIOS之 部份程式): NoEOIInt9h PROC ; XT不送出EOI的鍵盤岔斷處理程式 push ax in al,60h ; 讀取鍵盤送來資料 push ax in al,61h ; 清除本次送來之鍵盤資料 mov ah,al ; (同時亦禁能) or al,80h out 61h,al xchg al,ah ; 再度啟用鍵盤 out 61h,al pop ax iret NoEOIInt9h ENDP 至於使XT鍵盤自動產生一岔斷的方式為: in al,61h ; 將鍵盤時基降為低電位 and al,0BFh out 61h,al mov cx,10582 ; 延遲20ms (8088 CPU下) WaitInt9h: loop WaitInt9h or al,40h ; 恢復鍵盤時基 out 61h,al ; (此時將產生鍵盤重置訊號) 技術八 破壞或截斷鍵盤岔斷處理程式或輸入程式 鍵盤的岔斷程式包括INT 9h的硬體岔斷處理程式,和INT 16h的資料 輸入程式。藉由對這兩種岔斷程式的破壞或截斷,均有助於中斷鍵盤與使 用者之間的連繫。以下為幾種破壞或截斷岔斷處理程式的方法,這些方法 也適用於其他的岔斷處理程式。 1.直接破壞岔斷向量表,這是一種相當簡單卻又頗實用的方法。你可以單 純地破壞岔斷向量表,而在稍後再將之還原回來,或是拿岔斷向量表做 為變數存放資料,甚至將岔斷向量表做為程式執行的地方。愈是有意義、 混亂、且不斷地更動岔斷向量表的值,保護程式愈難以破解(註:以後 所提的資料或程式破壞,均指此一方式,將不再多做說明)。鍵盤硬體 岔斷INT 9h的岔斷向量在位址0:24h處,而鍵盤資料輸入岔斷INT 16h的 岔斷向量則在位址0:58h處。 2.取得原岔斷處理程式的向量位址後,破壞原岔斷處理程式碼。破壞的方 式可參考前項之說明,但必須先測試該位址的程式內容是否為僅讀,因 為該岔斷處理程式很有可能是在ROM區。如此,即使有任何其他除錯程 式或常駐程式將被破壞的岔斷向量還原,也會因原岔斷處理程式已遭受 破壞而無法正常執行,進而達到反追蹤的目的。 3.改寫鍵盤岔斷處理程式及鍵盤輸入岔斷處理程式。這種方式較適合於需 要輸入密碼,而又想避免被岔斷追蹤的情況。由於這類程式,大部份的 BIOS程式討論的書籍中均有列出,因此在此處便不多做說明。但記得在 改寫時,必須考慮執行密碼輸入時可能被岔斷追蹤的狀況,以便加以反 制。例如採用非正規的鍵盤雙斷開碼格式、破壞追蹤環境等,讓追蹤程 式即使岔斷成功,亦無法正常執行。 技術九 破壞、修改或檢查鍵盤緩衝區的指標與資料 當鍵盤有資料輸入時,均會更動鍵盤緩衝區的指標值,以及緩衝區內 的資料。因此在岔斷禁能的情況下,若這部份的內容有所更動,我們便可 判定有其他追蹤程式的執行。當然,我們也可以破壞這些指標值內容,以 防止追蹤程式岔斷後的正常執行。 1.檢查鍵盤緩衝區內容或輸入指標值是否更動。鍵盤緩衝區輸入指標在位 址0:41Ah~041Dh處,鍵盤緩衝區則在0:41Eh~0:43Dh處(由鍵盤緩衝 區位置指標決定),共32 byte。 2.破壞鍵盤資料緩衝區之輸入資料指標。 3.更改或破壞鍵盤資料緩衝區位置指標。鍵盤資料緩衝區位置指標在0:480h ~0:483h處,初值分別為1Eh和3Eh。 關於鍵盤資料緩衝區和各指標的關係,請參閱其他相關書籍。 * 青衫詩客 -- 小邱 * -+- Via 中文銀版快信 V2.28C + Origin: 檔案貨櫃, 歡迎您來挖寶, 28800 BPS, 04-230-2080; (90:1013/622) --------------------------------------------------------------- 90-ASSEMBLY - Msg : 68 of 72 From : Chi'u I-Nan 90:1013/622 16 Mar 95 19:49:00 To : All Subj : 8042資料 ----------------------------------------------------------------------------- (二)8042 8042為AT使用的鍵盤控制器,內部有一個狀態暫存器,供外界檢測鍵 盤狀態;一個輸出埠和一個輸入埠,用來做為與外界的控制訊號使用;一 個輸入緩衝器和一個輸出緩衝器,用來存放與外界的界面資料,包括命令 和資料等。以下為這些元件的意義。 1.狀態暫存器 位元7 = 同位錯誤 位元6 = 接收逾時錯誤 位元5 = 傳送逾時錯誤 位元4 = 鍵盤啟用開關,0表禁能,1表允能 位元3 = 命令/資料指示位元,0表資料,1表命令 位元2 = 系統旗標,由外界設定 位元1 = 輸入緩衝器已滿,但尚未被8042讀走 位元0 = 輸出緩衝器已滿,但尚未被外界讀走 說明:狀態暫存器為一僅讀暫存器,各位元反應了鍵盤的某項狀態。例如 8042所使用的同位位元為奇同位,因此如果取得的鍵盤資料偵測為 偶同位的話,位元7的值便會設立成1,以便反應出同位錯誤。位元 3的值由線路所控制,反應出輸入緩衝器內的資料型態(即命令或 資料),以供8042決定處理的方式。在AT上,命令的寫入是經由I/O Port 64h,而資料的寫入則經由I/O Port 60h。因此若輸入緩衝器 內的資料是經前者(Port 64h)寫入者,位元3的值便會設立成1, 若是經由後者(Port 60h)寫入者,則位元3的值便會設立成0。位 元2的值由外界所送入的命令所控制,請參閱後面所述之命令。位 元1和位元0是用來指示外界是否可對8042的緩衝器寫入或讀取資料。 當位元1為0時,外界才能再將資料送到8042的輸入緩衝器;當位元 0為1時,外界才能從8042的輸出緩衝器讀取資料。當不是上述的情 況時,外界程式便必須一直等待到上述的情況成立,否則不能對8042 的緩衝器進行I/O動作。 備註:位元4的值根據其他書籍所言為用來反應鍵盤抑制開關的狀態,但 經作者試用所有抑制鍵盤的命令均無法使之變成0。猜想可能這個 位元值係接至輸入埠位元7,但由於無法找到8042內部線路圖,因 此作者也無法確定。 2.輸入埠 位元7 = 鍵盤抑制開關,0為抑制,1為開啟 位元6 = 顯示器型態選擇,0為彩色,1為單色 位元5 = 0表已裝設製造時跳線 位元4 = 1表啟動系統電路板上的第二個256KB RAM 位元3~0 = 保留 說明:輸入埠的資料僅能讀取,且必須透過命令方式讀取。輸入埠各位元 的資訊均來自外界,其值因機器而異,因此便略而不提。位元7接 至一個5支腳的Jumper的第4腳,這支腳的訊號同時也控制著外界 RESET訊號的進入,若能改變這支腳的值成為0(也就是低電位), 則不但鍵盤不能作用,外界RESET也無法重新啟動電腦,必須整個 關機重開,只可惜這個Jumper是做死的,無法利用軟體來控制(作 者曾在某本書中看到這個位元值可以用軟體改變,但該書中所寫的 I/O Port為64h,似乎不太可能,再查閱各相關書籍及AT線路,已 確認該書內容是錯誤的)。 備註:由於8042輸入埠的值均依連接線路而定,並無法由軟體控制或改變, 因此大都無實用價值。作者曾在不同廠牌PC上讀取輸入埠的值(均 使用彩色螢幕),結果所得到的值由FFh、FBh、FCh、E7h等不定, 其中位元6的值並不正確,但查閱線路圖和各參考書籍均指出位元6 為接地時為彩色顯示器,再由AT BIOS程式追蹤發現顯示器單彩色 的判斷並非由這個位元來決定,因此這個輸入埠的值並不是很可靠, 最好不要使用。 3.輸出埠 位元7 = 鍵盤資料線 位元6 = 鍵盤時脈 位元5 = 輸入緩衝器已滿 位元4 = 輸出緩衝器已滿 位元3~2 = 保留 位元1 = A20位址線控制 位元0 = 系統重置 說明:輸出埠的資料是可以讀寫的,但必須透過命令方式讀寫(註:請參 閱D1h輸出埠寫入命令的說明)。鍵盤資料線傳送的便是由8042送 出的資料,如掃描碼或回應資料等,其傳送的數據結構和RS232相 似: 第1位元 = 開始位元 第2~9 = 資料,由低位元先送 第10 = 奇同位位元 第11 = 停止位元 而鍵盤時脈便是用來分辨鍵盤資料線各位元的時序的。因此這兩個 位元的值並不固定,端視讀取時的狀態而定。位元1是用來控制CPU 的A20位址線輸出,當其值為0時,將強迫A20位址線輸出為0,此時 系統將無法讀寫HMA上的資料,也就是位址FFFF:10h將存取到0000:0 位址。當其值為1時,A20位址線才由CPU的輸出決定。位元0用來重 置系統,當其值為0時,整個系統將會重置(也就是重新開機)。 由於位元0和位元1關係到整個系統的運作,因此最好不要加以隨意 更動。 4.輸出緩衝器 用來供外界讀取按鍵的掃描碼,或是鍵盤送出的回應資料。這個緩衝 器必須在狀態暫存器位元0值為1時才可以讀取。 5.輸入緩衝器 用來供外界輸入命令或資料使用,必須在狀態暫存器位元1值為0時才 可以寫入。 在AT上,8042狀態暫存器的讀取,必須經由I/O Port 64h,輸出緩衝 器的讀取,則經由I/O Port 60h。輸入緩衝器則分成60h和64h兩個Port, 分別用來輸入資料和命令。至於8042的輸入埠和輸出埠的值,則必須籍由 命令來取得或設定。送出命令給8042的方式,是先將命令寫入Port 64h, 再依需要將資料寫入Port 60h,如此命令便算送出完畢。之後8042根據命 令的處理結果,可能會回送一些資料回來,此時由Port 60h便可讀回這些 回應資料。以下為一些8042常用的命令: 20h = 讀取8042命令位元組。 60h = 寫入8042命令位元組,各位元意義如下: 位元7 = 保留 位元6 = 0表雙斷開碼,1表單斷開碼 位元5 = 1表不做同位檢查 位元4 = 1表抑制鍵盤 位元3 = 1表不理會鍵盤抑制 位元2 = 系統旗標 位元1 = 保留 位元0 = 啟用岔斷輸入(IRQ1) 位元6用來控制斷開碼的格式,也就是按鍵在放開時8042所送 出的資料格式。當值為0時,表示採用雙斷開碼格式,首先送 出F0h,然後後面跟著放開鍵的掃描碼。當值為1時,則採用單 斷開碼格式,也就是將掃描碼的位元7設成1,用以表示這是個 斷開碼。由於PC的BIOS程式均採用單斷開碼方式解譯8042送來 的資料,因此這個位元大都設成1。位元5的值較有爭議,在有 些書上寫明必須設成1,做為IBM PC的相容模式,但有的書上 則只說明這是用來檢查同位位元的而已。經作者實際在多種PC 上測試,結果這個位元的初值有的為0,有的為1,而且不管這 個位元的值設成0或1,系統均仍正常運作。因此作者建議還是 將之設成0,啟用同位檢查比較好些(原某書上標明IBM PC相 容模式應為錯誤的)。位元4用來抑制鍵盤,當值設成1時,將 使得時脈線路成為低電位,使得鍵盤界面失效。位元3根據各 相關書籍所述為使鍵盤的抑制功能失效,但經作者試過,即使 將這個位元設成1,各種鍵盤抑制命令仍然會抑制鍵盤的功能, 因此它的實際用途不明。位元2用來設定狀態暫存器位元2,也 就是系統旗標的值,這個旗標並沒什麼作用,一般在PC均設成 1。位元0用來控制是否採用岔斷輸入,一般均設成1。若將之 設成0,則必須使用Poll方式處理,較為麻煩。位元7和位元1 為保留值,可任意寫入0或1。 AAh = 自我測試,OK時輸出55h。注意這個命令會重設8042命令位元 組的值,因此在命令之後應重設8042命令位元組的值,否則鍵 盤功能將會被抑制而失去作用。 ABh = 介面測試,傳回結果: 00 = 正常 01 = 鍵盤時脈保持在低電位 02 = 鍵盤時脈保持在高電位 03 = 鍵盤資料線保持在低電位 04 = 鍵盤資料線保持在高電位 ACh = 診斷傾印(diagonstic dump),將16位元組的控制器記憶體、 輸入埠目前狀態、輸出埠目前狀態、以及控制器的程式狀態字 組送至系統。事實上,經作者在各種PC上測試的結果發現,實 際送出的資料差異性很大,有的完全不送資料,有的只送一個 byte,而有的一送便是十幾個byte。其資料的意義找遍各書籍 均未說明,因此此部份的說明也只好省略了。 ADh = 鍵盤失效(即將8042命令位元組之位元4設成1)。 AEh = 啟用鍵盤(即將8042命令位元組之位元4設成0)。 C0h = 讀取輸入埠,必須輸出緩衝器有空的時才可使用。 D0h = 讀取輸出埠,必須輸出緩衝器有空的時才可使用。 D1h = 寫入輸出埠。但是這個命令經作者實際測試過,並不會將給定 的資料寫入輸出埠。因此若要改變輸出埠的輸出值,應使用後 面會提到的Fxh命令,但這個命令只能改變輸出埠位元3~0的 值。 E0h = 讀取測試輸入埠,各位元值意義如下: 位元7~2 = 固定為0 位元1 = 鍵盤資料線 位元0 = 鍵盤時脈 其中位元0~1係由輸出埠位元7~6所回送的輸入資料,以做為 鍵盤自我測試時使用。同樣的,這個命令所讀出的值也因輸出 埠的狀態而異,請參閱輸出埠中的說明。 Fxh = 脈波輸出,x中4個位元分別對應到輸出埠的位元3~0,命令中 被選到的位元(以0選定)會有6us的低電位脈衝(也就是邏輯 值0)。請參閱輸出埠中的說明。 以下則為8042的系統命令。系統命令和一般命令的送出方式不同,必須經 由資料埠,也就是I/O Port 60h送出。8042收到後,除了EEh回音命令以 外,均會回送ACK訊號FAh(收到命令或資料均會回送)。以下為各系統命 令的意義: EDh = 設定模式指示器,輸入值意義為: 位元7~3 = 固定為0 位元2 = Caps Lock指示器 位元1 = Numeric Lock指示器 位元0 = Scroll Lock指示器 設定之後,鍵盤上對應的LED便會亮起來。 EEh = 回音,鍵盤以EEh回應。 F3h = 設定鍵重複率及延遲,送入值意義為: 位元7 = 固定為0。 位元6~5 = 延遲參數,延遲(1+x)*250ms。 位元4~0 = 重複參數,假設位元2~0值為A,位元4~3值 為B,則重複週期為(8+A)*2^B*4.17ms。 F4h = 系統啟用,並清除輸出緩衝器。 F5h = 使用鍵盤預設值、清除輸出緩衝器,最後將系統失效,等待進 一步指令。若要再啟用必須使用系統命令F4h。 F6h = 使用鍵盤預設值設定重複率及延遲率,並清除輸出緩衝器。 FEh = 重送命令,鍵盤回送上次的輸出。 FFh = 重置命令,鍵盤接收後清除輸出緩衝器,並使用預設值,最後 開始自我測試,完畢回送AAh表正常,其他值表有誤(注意, 此命令會先送出ACK後再送出AAh)。 EFh~F2h、F7h~FDh = 保留命令,不運作(NOP)。但事實上經作者 測試之後,發現其中有些命令在某些機器上似乎有作用,有些 會使鍵盤失效,有些則會回送一些額外的值。由於這部份的資 訊無法確定,因此只能建議讀者不要隨便使用這些保留命令。 以下為一些鍵盤可能回送的資料或命令: 00h = 覆蓋(Overrun),當輸出緩衝器已滿而且又有輸出時,便會 送出此一資料。 AAh = 基本測試完成碼。 EEh = 回音回應。 F0h = 斷開碼第一位元組,用來指示某個鍵已被放開。斷開碼由兩個 位元組組成,第一位元組便是F0h,第二位元組則為鍵盤掃描 碼。 FAh = ACK訊號,用以回應系統命令使用。 FEh = 重送命令,當鍵盤接到一個無效或錯誤的輸入時,均會發出此 命令要求外界重送。 FDh = 診斷錯誤,當鍵盤週期性自我診斷時發現錯誤,便發出此資料。 注意在對8042進行命令控制時,必須將岔斷禁能,以免外界鍵盤輸入 岔斷影響正常之鍵盤命令傳送。 * 青衫詩客 -- 小邱 * -+- Via 中文銀版快信 V2.28C + Origin: 檔案貨櫃, 歡迎您來挖寶, 28800 BPS, 04-230-2080; (90:1013/622) --------------------------------------------------------------- 90-ASSEMBLY - Msg : 69 of 72 From : Chi'u I-Nan 90:1013/622 16 Mar 95 19:51:00 To : All Subj : 8255資料 ----------------------------------------------------------------------------- (五)8255 8255為可程式化的週邊界面,只用在XT上,AT則已取消使用這個元件, 因此對於8255,我們只說明和XT相關且較重要的內容,至於詳細的內容, 請參閱其他相關書籍。8255具有24位元的I/O線,並區分為兩組:Group A 和Group B,分別佔用12位元。而這24位元的I/O線又可區分為三個輸出入 埠,其中Port A和Port B係由Group A和Group B中的8個位元I/O線所組成, Port C則分為高四位元和低四位元,分別由Group A和Group B剩下的四位 元所組成。因此在規劃上,Port C可針對高四位元和低四位元分別程式化 成不同的輸出入方式和處理模式,Port A和Port B則不行。8255對於這24 位元I/O線的規劃方式,係經由其內部控制字組來完成的,這個控制字組 的意義如下: 1.模式定義格式 位元7 = 必須固定為1 位元6~5 = Group A模式,當位元6為1時,一律為模式2 位元4 = Port A輸出入方式,0表輸出,1表輸入 位元3 = Port C高四位元輸出入方式,0表輸出,1表輸入 位元2 = Group B模式 位元1 = Port B輸出入方式,0表輸出,1表輸入 位元0 = Port C低四位元輸出入方式,0表輸出,1表輸入 說明:XT的設定值為99h,即Port A、Port C為輸入,Port B為輸出,採 用的模式均為模式0。至於8255可規劃的三種模式名稱分別為: 模式0 = Basic Input/Output 模式1 = Strobed Input/Output 模式2 = Bi-Directional Bus 2.位元重置格式 位元7 = 必須固定為0 位元6~4 = 不使用 位元3~1 = 選擇的位元 位元0 = 設定值 說明:位元重置格式只用在模式1和模式2上,用來控制岔斷訊號產生的禁 能和允能。 在XT上,控制字組是在I/O Port 63h,而Port A、Port B、Port C則 分別在I/O Port 60h、61h、62h。其中Port A除了用來做為鍵盤資料的輸 入外,亦可做為DIP開關1的輸入值,這項差別由Port B位元7來控制。Port B 、Port C各位元的意義如下: 1.Port B 位元7 = 0表啟用鍵盤,允許鍵盤岔斷的發生,Port A將讀取鍵盤掃 描碼;1表鍵盤禁能,並清除鍵盤的輸入,Port A將讀取DIP 關閉1的值。 位元6 = 0表強迫鍵盤時基於低電位,1表鍵盤時基正常作用 位元5 = 0表啟用I/O通道檢查 位元4 = 0表啟用RAM同位檢查 位元3 = 控制錄音機馬達,0表運轉 位元2 = 值1表PC0讀取DIP開關2的位元0,0表讀取位元4 位元1 = 喇叭資料輸入控制 位元0 = 計時器Gate 2控制 說明:喇叭的資料輸入係接至計時器2,而計時器2的輸出與否由Gate 2控 制。在輸至喇叭前還有一個AND閘控制,因此欲使喇叭發聲,必須 使得位元1和位元0均成為1,此時喇叭便會以計時器2的輸出頻率發 聲。關於計時器的部份,請參閱8237的說明。 2.Port C 位元7 = 1表RAM同位檢查錯誤 位元6 = 1表I/O通道檢查錯誤 位元5 = 計時器2輸出訊號 位元4 = 錄音機資料輸入 位元3~0 = DIP開關2讀取值。 在AT上,8255已不再使用。原Port 60h改接至8042鍵盤控制器,仍做 為鍵盤資料讀取使用。Port 61h則改用ALS175來取代,並集結了Port B和 Port C中幾個較重要的位元。至於Port 62h和63h,則均捨棄不用了。以 下為AT中Port 61h各位元的意義,其中高4位元為僅讀位元: 位元7 = 1表RAM同位檢查錯誤 位元6 = 1表I/O通道檢查錯誤 位元5 = 計時器2輸出訊號 位元4 = RAM Reflesh訊號 位元3 = 1表啟用I/O通道檢查 位元2 = 1表啟用RAM同位檢查 位元1 = 喇叭資料輸入控制 位元0 = 計時器Gate 2控制 備註:以上關於8255各I/O位元在XT上的作用,作者參閱多本XT書籍後, 發現所著內容均有所出入。雖然作者針對相異的部份,儘量和BIOS 程式及線路圖搭配來做判斷,但因找不到XT機器做實際測試,因此 不敢保證內容完全正確,但至少錯誤的機會應已較少。 * 青衫詩客 -- 小邱 * -+- Via 中文銀版快信 V2.28C + Origin: 檔案貨櫃, 歡迎您來挖寶, 28800 BPS, 04-230-2080; (90:1013/622) --------------------------------------------------------------- 90-ASSEMBLY - Msg : 70 of 72 From : Chi'u I-Nan 90:1013/622 16 Mar 95 19:52:00 To : All Subj : 8259資料 ----------------------------------------------------------------------------- (六)8259 8259為一種可程式化的優先序岔斷控制器,所有PC週邊硬體的岔斷均 必須透過這個元件來觸發所對應的岔斷處理程式。以下我們先說明8259的 硬體特性。8259共分成四個啟始命令字組ICW和三個操作命令字組OCW,前 者做為初始化時使用,後者則可供程式自行使用。8259初始化的過程為: 送出ICW1 送出ICW2 if 串接模式 then 送出ICW3 if 需要ICW4 then 送出ICW4 各啟始命令字組的意義為: 1.ICW1 位元7~5 = 岔斷向量位址(只用在MCS-80模式) 位元4 = 固定為1 位元3 = 0為邊緣觸發(edge trigger) 1為位準觸發(level trigger) 位元2 = 呼叫位址間隔(只用在MCS-80模式) 0為呼叫位址間隔8 1為呼叫位址間隔4 位元1 = 0為串接模式(cascade mode) 1為單一模式(single mode) 位元0 = 0不需要ICW4 1需要ICW4 說明:8259除了可供8088系列使用外,也可供MSC-80系列使用,因此當任 何位元若標明只使用在MSC-80模式時,PC上均不需使用。另外,由 於PC上使用的是8088系列的CPU,必須利用ICW4指定為8088模式, 因此本啟始命令的位元4、1均必須固定為1,位元7~5、2則可為0 可為1。至於採用何種觸發方式,則依電路特性而定,PC上通常採 用邊緣觸發,因此位元3也大致固定為0。比較有爭議的是位元1的 值。在舊型的PC/XT上,由於只使用一個8259做為岔斷控制用,因 此必須使用單一模式,故它的初值為13h。但到了PC/AT時,由於系 統功能加強,原來的一個8259已不敷使用,於是便擴增為兩個8259 串接在一起,因此這兩個8259便都必須使用初值11h。 2.ICW2 (1) MCS-80模式 位元7~0 = 岔斷向量位址 (2) 8088模式 位元7~3 = 岔斷向量位址 位元2~0 = 固定為0 說明:這個命令是用來設定硬體岔斷時,所要執行的岔斷向量啟始值。 PC/AT的第一個8259觸發的岔斷在08h~0Fh,因此初值為08h;第二 個8259觸發的岔斷在70h~77h,因此初值為70h。這些初值若在不 影響系統的岔斷功能下,是可以隨意改變的。 3.ICW3 (1) 主控制器(master device) 位元7~0 = 各位元分別表示IRQx是否有串接另一個8259控制器, 0表示沒有,1表示有。 (2) 次控制器(slave device) 位元7~3 = 固定為0 位元2~0 = 次控制器的識別碼。 說明:這個初始命令必須有兩個以上的8259串接在一起時才使用的,因此 PC/XT並不使用這個初始命令。至於PC/AT上的兩個8259,由於是串 接在IRQ2上的,因此主控制器(也就是第一個8259)的初值便必須 為04h。至於次控制器,由於必須配合所串接的IRQ來做編號,因此 次控制器的初值便必須為02h,否則無法正常工作。 4.ICW4 位元7~5 = 固定為0 位元4 = 0為非特別全巢狀模式 1為特別全巢狀模式 位元3~2 = 0x 不帶緩衝模式 10 主控制器帶緩衝模式 11 次控制器帶緩衝模式 位元1 = 0表非自動結束岔斷(EOI) 1表自動結束岔斷 位元0 = 0表MSC-80模式 1表8088模式 說明:特別全巢狀模式(special fully nested mode),主要用在大系 統中使用多個8259串接模式時,以便規劃不同的岔斷權限,詳細資 料請參閱相關書籍。通常我們均使用非特別全巢狀模式,也就是初 始化時以IRQ0優先權最高,IRQ7最低(這個優先權是可以改變的)。 而在某個岔斷發生處理時,優先權更高的岔斷允許再發生,以岔斷 目前正在處理的岔斷,而相同或較低優先權的岔斷則不允許發生。 至於是否要規劃成緩衝模式,必須視所連接系統之Data Bus線路而 定。對於是否使用自動結束岔斷,則由作業系統或岔斷處理程式的 設置程式來決定。一般使用自動結束岔斷對於岔斷處理程式會比較 方便些,不會因忘了送出EOI命令(參閱OCW2命令)而使得系統功 能停止或當機。但是它最大的缺點是,如果相同的IRQ岔斷一再發 生,而該岔斷程式又使用了STI命令允許岔斷發生時(為了讓更高 優先權的岔斷產生),則可能造成岔斷程式再被岔斷,導致重入問 題,以及岔斷順序更動等問題。因此在絕大部份的情況下,大都會 採用非自動岔斷結束,在PC上亦然。不過若使用非自動EOI的結束 方式時,岔斷處理程式在處理完岔斷後必須送出一個EOI命令給8259, 表示岔斷已處理完,否則8259便視為該岔斷未結束而不再產生下個 岔斷了。 備註:關於本初始命令的初值,由XT的BIOS查得為09h,由286 AT的BIOS 查得為01h,也就是前者採用緩衝模式,後者並不採用緩衝模式。 經查閱有關8259零件的手冊,其中說明緩衝模式主要用在具有BUS 驅動緩衝區的Data Bus,由8259的SP/EN訊號來控制緩衝區。當不 是緩衝模式時,這個訊號接腳在主控制器上必須接Vcc,而在次控 制器上則必須接地。再查閱86 XT和286、386 AT的線路圖,發現確 實XT的設計電路是使用緩衝模式,而286、386 AT的設計電路則為 非緩衝模式。因此在初始化時,必須依PC的種類而有不同的初始化 值(事實上,XT只有一個8259,在初始化過程方面便一定會有不太 一樣的地方,必須與AT分別處理),如果未與設計的電路做好匹配 的規劃,則有當機之虞(但並不一定會當機。據作者實際測試過, 在某些AT上將8259規劃成緩衝模式會當機,而在某些AT上則不管是 否規劃成緩衝模式卻仍都正常工作,這和主機電路板的線路設計有 關)。 以下為各操作命令字組的意義: 1.OCW1 位元7~0 = 分別表示IRQx是否啟動,0表示允能(enable),1表示 禁能(disable)。 說明:本命令也就是設定岔斷的罩遮值(IMR,Interrupt Mask Register)。 在使用時,通常先讀取原值後,再設置所要處理的岔斷所對應的位 元,以避免影響到其他岔斷。 2.OCW2 位元7~5 = 000 取消自動EOI時旋轉優先權模式 001 不特別指定IRQx方式結束岔斷 010 無作用 011 指定IRQx方式結束岔斷 100 設定自動EOI時旋轉優先權模式 101 不特別指定IRQx結束岔斷時旋轉優先權 110 設定優先權 111 指定IRQx結束岔斷時旋轉優先權 位元4~3 = 固定為0 位元2~0 = 指定的IRQx 說明:本命令是用來指定岔斷優先權的處理方式(請參閱相關書籍),以 及指示岔斷是否處理完畢。一般在PC上大都使用20h做不特別指定 IRQx方式來結束8259的岔斷。所謂不特別指定IRQx方式,指的是要 處理的IRQ編號並不由位元2~0來指定,而以目前已發生且優先權 最高的岔斷為準。 3.OCW3 位元7 = 固定為0 位元6~5 = 0x 無作用 10 取消特殊罩值(reset special mask) 11 設定特殊罩值(set special mask) 位元4 = 固定為0 位元3 = 固定為1 位元2 = 0表使用岔斷方式服務 1表不使用岔斷方式服務(poll command) 位元1~0 = 0x 無作用 10 讀取岔斷需求暫存器(IRR) 11 讀取內部服務暫存器(ISR) 說明:特殊罩值功能,主要是提供給需要任意改變岔斷的禁能、允能,而 又不希望因未送出EOI命令,而導致其他較低優先權的岔斷無法發 生的程式使用。當設定了特殊罩值後,則每次在OCW1重設罩值時, 均會將所有未被罩遮掉的IRQ重新啟用。IRR及ISR這兩個暫存器的 值可用來辨別各岔斷的產生與否。IRR(Interrupt Request Register)記錄了硬體已產生岔斷需求,但8259尚未發出岔斷訊號 或CPU尚未回應確認訊號的岔斷;ISR(Interrupt Service Register) 則記錄了CPU已接收到岔斷訊號但處理程式尚未回應EOI命令的岔斷。 當要讀取這兩個暫存器值時,首先必須送出OCW3指定所要讀取的暫 存器,然後再由相同的輸出入埠將之讀取。 備註:不使用岔斷服務的方式(poll command),依8259之零件說明為RD 訊號會讀取Priority Level值,其值意義如下: 位元7 = 1表有岔斷發生 位元6~3 = 保留 位元2~0 = 岔斷發生的編號 又說明Poll Command是使用在8259的岔斷輸出訊號不使用,或CPU 線路已將岔斷訊號輸入禁能的情況。據作者實際測試結果,在PC上 將OCW3修改成Poll Command形態,並不影響到原岔斷的執行,讀取 而得的值也並非Priority Level的值。至於為何如此,作者遍尋相 關書籍,也問過許多硬體設計從業人員,竟找不到答案。作者猜測 可能是因PC CPU仍然接收並使用8259的岔斷輸出訊號,使得8259的 岔斷確認訊號並非由Poll Command的RD訊號確認所致,至於真正原 因,則不得而知了。 當8259重新初始化後,IMR的值均會重設為00h(也就是允許所有的岔 斷產生),並取消特殊罩值功能。因此當我們要重新初始化8259時,必須 記錄原來的IMR值,並在初始化後將之設回,以免初始化後某些原已被禁 能的岔斷再次產生而發生問題。當然,初始化後視情況也必須重新設定 OCW3的值。 上述所有命令字組在PC上均透過I/O Port 20h、21h(第一個8259) 和A0h、A1h(第二個8259)來讀寫。I/O Port 20h和A0h做為ICW1、OCW2 和OCW3命令的輸入,以及IRR、ISR暫存器值的輸出。I/O Port 21h和A1h 則做為ICW2、ICW3、ICW4和OCW1命令的輸入,以及IMR暫存器值的輸出。 至於8259是如何去分辨送來的是那個命令字組,這倒不必我們費心,因為 這些命令字組中大都已安排好某些位元均固定為0或1。由這些固定位元, 8259便能輕易地辨別出所輸入的命令種類。以下是目前在PC/AT中兩個8259 所處理的16個硬體岔斷內容: ┌ IRQ0 計時岔斷 │ IRQ1 鍵盤岔斷 │ IRQ2 串接第二個8259 第一個8259 ─┤ IRQ3 次串列通訊埠(COM2) │ IRQ4 主串列通訊埠(COM1) │ IRQ5 印表機岔斷(LPT2) │ IRQ6 軟碟岔斷 └ IRQ7 印表機岔斷(LPT1) ┌ IRQ0 即時時脈岔斷 │ IRQ1 保留 │ IRQ2 保留 第二個8259 ─┤ IRQ3 保留 │ IRQ4 保留 │ IRQ5 數學處理單元岔斷 │ IRQ6 硬碟岔斷 └ IRQ7 保留 以下為各岔斷在本附錄中所對應的硬體說明: 計時岔斷 = 8253、8254 鍵盤岔斷 = 8042、8255 即時時脈岔斷 = 146818 其餘之硬體岔斷由於和本書內容無關,因此不予列入。 * 青衫詩客 -- 小邱 * -+- Via 中文銀版快信 V2.28C + Origin: 檔案貨櫃, 歡迎您來挖寶, 28800 BPS, 04-230-2080; (90:1013/622) --------------------------------------------------------------- 90-ASSEMBLY - Msg : 71 of 72 From : Chi'u I-Nan 90:1013/622 16 Mar 95 20:00:00 To : All Subj : 8253/8254資料 ----------------------------------------------------------------------------- (四)8253與8254 8253和8254均為PC使用之計時器,兩者除了外接的頻率限制不同外( 前者最多只能接2MHz,後者可接至8MHz,8254-2更可接至10MHz),其餘 部份均相容。但以PC計時器外接頻率才1.19MHz來看,兩者在使用上並沒 有什麼差別,因此以下之計時器,我們均以8253來稱呼。 8253具有三個16位元的計數器,可分別加以規劃。每個計數器均具有 一個輸入的頻率、一個控制閘(GATE)和一個輸出端,其中控制閘便是用 來控制輸出端是否輸出結果。以下為PC對於這三個16位元計數器的佈線方 式及作用: 計數器0 作用 = 系統計時器 輸入頻率 = 1,193,180Hz GATE0 = 接至+5V 輸出 = 第一個8259之IRQ0 計數器1 作用 = DRAM更新要求產生器 輸入頻率 = 1,193,180Hz GATE1 = 接至+5V 輸出 = 更新要求週期 計數器2 作用 = 喇叭音調頻率 輸入頻率 = 1,193,180Hz GATE2 = 接至Port 61h位元0 輸出 = 喇叭 由上面的資料我們可以知道,在PC上,除了GATE2(也就是Port 61h 的位元0)可以控制計數器2是否有輸出外(控制喇叭是否發聲),其餘兩 個計數器我們均無法禁止其計數結果的輸出,頂多是更改其輸出頻率和輸 出波形而已。對於三個計數器的輸出規劃及計數值讀寫,首先必須寫出控 制字組到控制暫存器中,這個暫存器在PC上是經由Port 43h寫入的,之後 再分別由Port 40h~42h讀寫計數器0~2的值。控制字組的格式為: 位元7~6 = 計數器選擇(0~2) 位元5~4 = 操作方式 00 = Latch住目前的計數值 01 = 讀寫計數值的高位元組 10 = 讀寫計數值的低位元組 11 = 依次讀寫計數值的低、高位元組 位元3~1 = 模式,各值意義為 000 - 模式0 001 - 模式1 x10 - 模式2 x11 - 模式3 100 - 模式4 101 - 模式5 位元0 = 0表二進制計數,1表BCD制計數 以下為各輸出模式的意義: 1.模式0(Interrupt on Terminal Count) 計數時輸出為Low,當計數完畢後,輸出昇至High,然後重新計數, 並將輸出再還原為Low。 2.模式1(Programmable One-Shot) 當GATE由Low昇成High時開始計數,計數時輸出為Low,當計數完畢後, 輸出昇至High並結束計數。 3.模式2(Rate Generator) 當GATE為High時開始計數,計數時輸出為High,當計數完畢後,輸出 降為Low一個Clock後升為High,然後繼續重新計數。 4.模式3(Square Wave Generator) 當GATE為High時開始計數,且以2遞減,當計數完畢後,輸出高低互 變,並繼續重新計數。 5.模式4(Software Triggerd Strobe) 計數時輸出為High,當計數完畢後,輸出降為Low一個Clock後升為 High,並停止計數。若GATE為Low時停止計數。 6.模式5(Hardware Triggerd Strobe) 當GATE由Low昇成High時開始計數,計數時輸出為High,當計數完畢 後,輸出降為Low一個Clock後升為High,並停止計數。 由於在PC上,各計數器之用途及外接線路均已定死,因此計數器0必 須採用模式3;計數器1必須採用模式2;計數器2則必須採用模式3,否則 輸出之波形將無法與線路配合,而產生奇怪的現象。以下,作者再進一步 介紹各計數器的計數值在PC上的規劃方式: 1.計數器0 計數器0在PC上是做為時序之控制,以18.2Hz定頻觸發INT 8h。其初 值為0,也就是每計數65536岔斷一次INT 8h,因此1,193,180/65536= 18.2Hz。通常這個計數值是不加以更動的,以免影響到系統時間的運 作,但是若欲做為短時間定頻岔斷之特殊運用時,更動也是允許的。 不過相同功能也可以運用146818(INT 70h)來完成,因此更改計數 器0的計數值便不是那麼的需要。以下為本計數器的計數值寫入方式: out 43h,36h out 40h,計數值低位元組 out 40h,計數值高位元組 2.計數器1 計數器1在PC上是做為DRAM定時更新使用,在XT上是接到8237 DMA通 道0上,但在AT上已不再使用DMA式更新了。這個計數器的初值為18, 也就是每隔15us更新DRAM一次。由於DRAM的更新頻率對於程式運用上 較無關,因此這個計數器的計數值通常我們不會加以改變。以下為本 計數器的計數值寫入方式: out 43h,74h out 41h,計數值低位元組 out 41h,計數值高位元組 3.計數器2 計數器2在PC上是用來控制喇叭發聲的頻率,應寫入的計數值為 1,193,180/頻率。以下為本計數器的計數值寫入方式: out 43h,0B6h out 42h,計數值低位元組 out 42h,計數值高位元組 * 青衫詩客 -- 小邱 * -+- Via 中文銀版快信 V2.28C + Origin: 檔案貨櫃, 歡迎您來挖寶, 28800 BPS, 04-230-2080; (90:1013/622) -------------------------------------------------------------- 90-ASSEMBLY - Msg : 72 of 72 From : Chi'u I-Nan 90:1013/622 16 Mar 95 20:17:00 To : All Subj : 鍵盤補遺 ---------------------------------------------------------------------------- 列完了一堆資料後,順便講講前述資料的運用方式. 在90-C區中曾有人問到如何產生某個按鍵,而回信 的內容大都指明使用int 16h的功能來完成. 雖然 大部份的情況下,這種作法是可以滿足的,但對於 那些特殊的按鍵(指不輸入到鍵盤緩衝區的按鍵), 或是截取int 9h程式的熱鍵,int 16h便無法完成此 一需求,只能控制8042來完成. 作法如下: 1.首先要知道按鍵的掃描碼,假設為a. 2.執行cli,避免岔斷產生 3.讀取8042命令位元組值並暫存. 4.設定8042命令位元組的值為a. 5.再次讀取8042命令位元組值. 6.設回原8042命令位元組值 7.使用8042系統重送命令,但不要讀取回送值. 8.執行sti,稍延遲一下. 此時因8042會送出值a,因此 會岔斷int 9h,於是便相當於按下了掃描碼a的按鍵. 9.重複步驟2-8,但送出的掃描碼改成 a or 80h,表示這個 鍵放開. 利用上述的方式可以產生任何你要的按鍵. 如果是組合 鍵,例如左Shift+右Shift,則分別產生按下鍵,最後再分別送出 兩個鍵的放開鍵便可以了. 道理很簡單,因為int 9h判斷按 鍵是以port 60h的值(也就是鍵盤掃描碼)為準, 利用更改 port 60h回傳值,並產生int 9h的岔斷,自然便能夠模擬鍵盤 按鍵的發生. 至於實作方式,就看你自己了... * 青衫詩客 -- 小邱 * -+- Via 中文銀版快信 V2.28C + Origin: 檔案貨櫃, 歡迎您來挖寶, 28800 BPS, 04-230-2080; (90:1013/622) --- Via Offline Auto BBS Email Post -- 自由的風,吹得心醉......... -- ※ 發信站: 批踢踢實業坊(ptt.twbbs.org) ◆ From: Rick.m5.ntu.edu