2010年7月11日 星期日

如何在32bits保護模式下作debug

以下我所論及的主題並非是在os的保護模式底下的debug方式;而是當你有自己的執行系統,這個執行系統是從16bits模式執行後進入32bits保護模式,並且執行自己定義的ap。就類似memtest86這種從booting到run ap都能一手掌控的代碼。然而memtest在保護模式下都是C語言代碼,因此要debug相對容易,所以我們要討論的是以assembly為架構的debug方式。
首先我們知道frame buffer是以為址0xb8000~0xb8fff為vga顯示控制區域;當然其他模式mapping到的位址也不同;但我們討論的是前者。雖然在dos或16bits模式可以使用int 10h來讀寫螢幕,我們也知道int 10h的作法也是去控制frame buffer。然而進入保護模式下傳統的bios及dos中斷已不能調用。但是我們還是可以直接去存取frame buffer;所以我寫了比下代碼以assembly的方式來顯示一些除錯用途的資訊:
以下資訊為如何在保護模式下debug,並利用健盤做單步debug
;清除所有的輸出緩衝器資料
push ax
FlushOBF: in al,64h
test al,1
jz NotOBF
in al,60h
jmp short FlushOBF
NotOBF: pop ax


push ecx
push ebx
mov ecx,edi
POS_XY bx,20,23
call sub32_hexprint
pop ebx
pop ecx

;等待8042輸出緩衝器有資料送進來
push eax
WaitOBFLoop:
in al,64h
test al,1
jz WaitOBFLoop

pop eax
;以上這小段完成健盤單步執行判斷,做法是當無按鍵被按下時,便一直執行迴圈
;用法:
;先push ecx和ebx
;將要顯示的資料存到ecx
;POS_XY bx,__x,__y
;call sub32_hexprint
;pop ecx和ebx

sub32_hexprint proc
pushad
mov eax,160
mul bl
add eax,SCREEN_ADR
xchg eax,edx
mov eax,2
mul bh
add edx,eax
mov bx,8 ;count
xor edi,edi
NEXT:
call cl2digital
mov BPTR[edx+edi],al
shr ecx,4
add edi,2
dec bx
jnz NEXT
popad
ret
sub32_hexprint endp

cl2digital proc
xor eax,eax
push ecx
and ecx,0fh
cmp cl,10
jae isA2F
add cl,30h
jmp exit
isA2F:
sub cl,10
add cl,41h
exit:
mov al,cl
pop ecx
ret
cl2digital endp

下面是marco
SCREEN_ADR equ 0b8000h
POS_XY macro r_, x_, y_
mov r_, (((x_) SHL 8) + (y_))
endm


以下為鍵盤控制指令參考:
; ========================================================
; 以下為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
--> 閱讀更多...