2009年3月19日 星期四

●Fast A20 和92H,及8042到底是什麼關係

以下是從DOS编程技术這ㄍ大陸博客寫ㄉ資料放ㄌ上來,它裡面還有介紹一些好東西。您可以慢慢參考、品嘗。
早期的PC,控制鍵盤有一個單獨的單片機8042,現如今這個晶片已經給集成到了其它大片子中,但其功能和使用 方法還是一樣,當PC機剛剛出現A20 Gate的時候,估計實在找不到控制它的地方了,同時為這點小事也不值得增加晶片,於是工程師使用這個8042鍵盤控制器來控制A20 Gate,但A20 Gate真的和鍵盤一點關係也沒有,我們先從軟體的角度簡單介紹一下8042這個晶片。
8042有4個寄存器
• 1個8-bit長的Input buffer;Write-Only;
• 1個8-bit長的Output buffer; Read-Only;
• 1個8-bit長的Status Register;Read-Only;
• 1個8-bit長的Control Register;Read/Write。
有兩個埠位址:60h和64h。
• 讀60h埠,讀output buffer
• 寫60h埠,寫input buffer
• 讀64h埠,讀Status Register
對Control Register的操作相對要複雜一些,首先要向64h埠寫一個命令(20h為讀命令,60h為寫命令),然後根據命令從60h埠讀出Control Register的資料或者向60h埠寫入Control Register的資料(64h埠還可以接受許多其它的命令)。
先來看看Status Register的定義,我們後面要用bit 0和bit 1:
bit meaning
-----------------------------------------------------------------------
0 output register (60h) 中有數據
1 input register (60h/64h) 有數據
2 系統標誌(上電重定後被置為0)
3 data in input register is command (1) or data (0)
4 1=keyboard enabled, 0=keyboard disabled (via switch)
5 1=transmit timeout (data transmit not complete)
6 1=receive timeout (data transmit not complete)
7 1=even parity rec'd, 0=odd parity rec'd (should be odd)
除了這些資源外,8042還有3個內部埠:Input Port、Outport Port和Test Port,這三個埠的操作都是通過向64h發送命令,然後在60h進行讀寫的方式完成,其中本文要操作的A20 Gate被定義在Output Port的bit 1上,所以我們有必要對Outport Port的操作及埠定義做一個說明。
• 讀Output Port
向64h發送0d0h命令,然後從60h讀取Output Port的內容
• 寫Output Port
向64h發送0d1h命令,然後向60h寫入Output Port的資料
另外我們還應該介紹兩個命令:
• 禁止鍵盤操作命令
向64h發送0adh
• 打開鍵盤操作命令
向64h發送0aeh
有了這些命令和知識,我們可以考慮操作A20 Gate了,有關8042晶片更詳細的資料,請參考該晶片的Data Sheet。
如何打開和關閉A20 Gate。
理論上講,我們只要操作8042晶片的輸出埠(64h)的bit 1,就可以控制A20 Gate,但實際上,當你準備向8042的輸入緩衝區裡寫資料時,可能裡面還有其它資料沒有處理,所以,我們要首先禁止鍵盤操作,同時等待資料緩衝區中沒 有資料以後,才能真正地去操作8042打開或者關閉A20 Gate。打開A20 Gate的具體步驟大致如下:
1.關閉中斷;
2.等待8042 Input buffer為空;
3.發送禁止鍵盤操作命令;
4.等待8042 Input buffer為空;
5.發送讀取8042 Output Port命令;
6.等待8042 Output buffer有數據;
7.讀取8042 Output buffer,並保存得到的位元組;
8.等待8042 Input buffer為空;
9.發送Write 8042 Output Port命令到8042 Input buffer;
10.等待8042 Input buffer為空;
11.將從8042 Output Port得到的位元組的第2位置1(或清0),然後寫入8042 Input buffer;
12.等待,直到8042 Input buffer為空為止;
13.發送允許鍵盤操作命令到8042 Input buffer;
14. 打開中斷。
下面是完成打開A20 Gate的代碼:
A20Enable:
cli ;1.關閉中斷
call WaitInbufEmpty ;2.等待8042 Input buffer為空;
mov al, 0adh
mov dx, 64h
out dx, al ;3.發送禁止鍵盤操作命令
call WaitInbufEmpty ;4.等待8042 Input buffer為空;
mov al, 0d0h
mov dx, 64h
out dx, al ;5.發送讀取8042 Output Port命令;
call WaitOutbufFull ;6.等待8042 Output buffer有數據;
mov dx, 60h
in al, dx ;7.讀取8042 Output buffer
push ax ;保存讀取的資料
call WaitInbufEmpty ;8.等待8042 Input buffer為空;
mov al, 0d1h
mov dx, 64h
out dx, al ;9.發送寫 8042 Output Port命令
call WaitInbufEmpty ;10.等待8042 Input buffer為空
pop ax
or al, 02h ;11.將從8042 Output Port得到的位元組的bit 1置1
mov dx, 60h
out dx, al ;寫入Output Port
call WaitInbufEmpty ;12.等待8042 Input buffer為空
mov al, 0aeh
mov dx, 64h
out dx, al ;13.發送允許鍵盤操作命令
sti ;開中斷
ret

WaitInbufEmpty:
mov dx, 64h
in al, dx ;讀取Status Register
test al, 02h
jnz WaitInbufEmpty
ret

WaitOutbufFull:
mov dx, 64h
in al, dx
test al, 01 ;讀取Status Register
jz WaitOutbufFull
ret
後來,由於感覺使用8042控制A20運行太慢了(確實,那麼長的代碼,中間還要若干次的wait),所以後來又出現了所謂的Fast A20,實際上,現在的大多數機器都是Fast A20,Fast A20使用92h埠控制A20,同時BIOS裡提供了一個軟中斷來控制A20:
入口:ah=24h
al=0 關閉A20
1 打開A20
2 讀取A20狀態
int 15h
返回:如果BIOS支援此功能,CF=0,否則CF=1
CF=0時,AX返回當前A20狀態,1=打開,0=關閉
像8042中的Output Port中的定義一樣,92h埠的bit 1控制著A20,為1時打開,為0時關閉,從92h中讀一個byte可以看a20的當前狀態,所以對92h的操作如下:
• 讀A20狀態
mov dx, 92h
in al, dx
如果al的bit 1為1表示a20打開,否則為0
• 打開A20
mov dx, 92h
mov al, 02
out dx, al
• 關閉A20
mov dx, 92h
mov al, 0
out dx, al
特別要注意的是,大家從這篇文章的文字中可能也能感覺到,A20 Gate的設計本身就讓人感覺很彆扭,不是那麼流暢,所以和A20有關的事情就難免也會有相同的感覺,很奇怪的是,上面介紹的三種方法並不是在每台機器上 都適用,所以如果你要做一個商務軟體其中要操作A20,那一定要三種方式聯合使用才比較穩妥,否則會有意想不到的結果,LINUX公開的啟動代碼中就是這 麼做的
在DOS下有時我們會在config.sys中寫上一句:dos=high,這句就會把駐留的DOS放到高端記憶體區域去,怎麼放的呢?關鍵點就是打開 A20,然後把DOS從常設記憶體搬到100000h起始的區域去,並把在常設記憶體中佔用的記憶體釋放掉,當然說起來容易,實際做的時候還有很多細節要處理。
說到DOS=HIGH,就不得不提醒大家另一件事,如果在config.sys中有dos=high這一句,那麼恐怕92h的方法和BIOS的方法都會不 完全靈驗(至於操作8042的方法靈不靈我沒有試),這是DOS做了手腳,因為DOS被放到了高端記憶體中,為了保證DOS能正常運行,它不允許你把A20 給關掉,遇到這種情況不要驚慌,不是我寫得不對,確實是DOS太狡猾了。
還有最後一點要特別注意,92h的bit 0是給機器發重定信號的(8042 Output Port的bit 0也是),所以在向92h寫資料時,千萬不要讓bit 0為1,否則機器會重新啟動,如果你的應用程式需要重新開機機器,這也是方法之一,比jmp 0ffffh:0來的還要乾脆。
在其它我們介紹保護模式的文章中,我們會用到上面提到的打開A20的方法,屆時可能就不會做更多的解釋了。
另外,涉及操作A20的資料其實很少,有些資料我手裡也很缺乏,比如92h除bit 0和bit 1以外的定義是什麼我至今也不知道。

更多參考:Gate A20與保護模式

沒有留言:

張貼留言