User:Johnburger/Demo/Ints/Debug/Key
< User:Johnburger | Demo
Jump to navigation
Jump to search
The keyboard handler just has to test against the different keypresses that we want to heed, to affect the current display on the screen. From easiest to hardest:
- <Esc>
Just leave the debugger; - <Del>
Swap between displaying Bytes and DWords by changing theEBP
register (it holds the address of the function toCALL
). - <Up> or <Down> arrow
Subtract or Add (respectively)10h
toESI
(the current memory pointer) unless it's already outside the current Segment's limits. - <PgUp> or <PgDn>
Call the <Up> or <Down> (respectively) functionDebug.Show.Height - 1
times. Why- 1
? It allows a measure of overlap for the user to maintain synchronization with the scrolling. Note that there's no attempt to break out of the loop if the Segment limits have been reached: the code simply ignores the attempt, so it can ignore it repeatedly! - <Left> or <Right> arrow
These are the most complex functions. They Subtract or Add (respectively) the size of a Descriptor to the current value of the currently-displayed Selector, and then the result checked for readability with the CPU'sVERR
(VERify Read) instruction. (That hasn't had a lot of use in your code before, I'll bet!) If the new value is a readable Segment, it becomes the new current Segment. Otherwise, we loop around doing the Subtraction or Addition again. And if the ends of the Descriptor Table are reached, the Table Indicator bit inside the Selector is toggled to access the LDT or GDT, and the loop is continued.
The final keypresses above call the .Check
routine to determine if the Selector is readable, and to toggle the TI bit if necessary. If the new Selector isn't readable, it just returns. If it is, it establishes the new Minimum and Maximum values for the Segment, taking into account if the Descriptor is marked Expand Down.
Demo/Ints/Debug/Key.inc
;
; Ints/Debug/Key.inc
;
; This module handles the various keyboard actions.
Ints.Debug.Key:
HLT ; Wait for interrupt
MOV AL,0 ; Consume any keypress
XCHG [FS:Data.Key.Code],AL ; Avoid repeats
CMP AL,0 ; Anything there?
JE .End ; No, so leave
CMP AL,Debug.Key.Quit
JE .End ; Quit?
CMP AL,Debug.Key.Format
JE .Format
CMP AL,Debug.Key.Up
JE .Up
CMP AL,Debug.Key.Down
JE .Down
CMP AL,Debug.Key.PgUp
JE .PgUp
CMP AL,Debug.Key.PgDn
JE .PgDn
CMP AL,Debug.Key.Prev
JE Ints.Debug.Desc.Prev
CMP AL,Debug.Key.Next
JE Ints.Debug.Desc.Next
.End:
RET
;...............................................................................
Ints.Debug.Key.Format:
CMP EBP,Ints.Debug.Show.DWords
JE .Bytes
MOV EBP,Ints.Debug.Show.DWords
JMP .End
.Bytes:
MOV EBP,Ints.Debug.Show.Bytes
.End:
RET
;...............................................................................
Ints.Debug.Key.Up:
CMP ESI,EBX ; Reached Minimum?
JBE .End ; Yep! Do nothing.
SUB ESI,Debug.BytesPerRow ; Move earlier in memory
.End:
RET
;...............................................................................
Ints.Debug.Key.Down:
MOV EAX,ESI ; Try some calculations
ADD EAX,Debug.Show.Height*Debug.BytesPerRow ; Add in bottom of Screen
JO .End ; Overflow means too far!
DEC EAX ; Need to, since Limit has -1
CMP EAX,EDX ; Reached Maximum?
JAE .End ; Yep, so too far
ADD ESI,Debug.BytesPerRow ; Move later in memory
.End:
RET
;...............................................................................
Ints.Debug.Key.PgUp:
MOV CL,Debug.Show.Height-1 ; Leave one row the same
.Loop:
CALL Ints.Debug.Key.Up
LOOP .Loop
RET
;...............................................................................
Ints.Debug.Key.PgDn:
MOV CL,Debug.Show.Height-1 ; Leave one row the same
.Loop:
CALL Ints.Debug.Key.Down
LOOP .Loop
RET
;...............................................................................
Ints.Debug.Desc.Next:
MOV EAX,DS ; Get current Descriptor
.Loop:
ADD AX,x86.Desc_size ; Go to next Descriptor
CALL Ints.Debug.Desc.Check
JNE .Loop
RET
Ints.Debug.Desc.Prev:
MOV EAX,DS ; Get current Descriptor
.Loop:
SUB AX,x86.Desc_size ; Go to previous Descriptor
CALL Ints.Debug.Desc.Check
JNE .Loop
RET
Ints.Debug.Desc.Check:
; This checks the current Descriptor for readability. If not, it simply returns.
; If it is readable, it sets up the necessary registers; in particular the
; values for Minimum and Maximum.
; One step it does take is to check the result of the just-completed Next or
; Prev. If that over- or under-flowed, it swaps to the other Descriptor Table
; (GDT or LDT). Also note that since there's no easy way to determine the size
; of the current LDT, or even the GDT, it is easiest to simply check all the
; Descriptors.
JNC .Readable ; Didn't overflow: keep going
XOR EAX,x86.Seg.TI ; Use other Descriptor Table
.Readable:
VERR AX ; Can I read it?
JNZ .End ; Nope. Keep looking!
MOV DS,EAX ; Found!
LSL EDX,EAX ; Maximum address
XOR EBX,EBX ; Minimum address
MOV ESI,EBX ; Start at Minimum
LAR EAX,EAX ; One more thing...
TEST AH,x86.Desc.Mem.Type.Code ; Is it Code?
JNZ .Found ; OK, good
TEST AH,x86.Desc.Mem.Type.Stack ; No. Is it a Stack?
JZ .Found ; No! Phew!
XCHG EBX,EDX ; Yes, so everything's upside down!
INC EBX ; Or off-by-one
NOT EDX ; Or inverted!
; Start at "top" of Segment, less a screenful
MOV ESI,0-(Debug.Show.Height*Debug.BytesPerRow) ; Screenful
SHR EAX,16 ; Also need to check Gran byte
TEST AL,x86.Desc.Mem.Gran.Big ; 32-bit?
JNZ .Found ; Yes.
MOV AX,0FFFFh ; No. Need to mask off high word
AND EDX,EAX ; Maximum address
AND ESI,EAX ; Starting address
.Found:
XOR EAX,EAX ; Set Z flag - Found!
.End:
RET