Reputation: 189
I have problem with 09h interrupt. I'm hooking int vector and set my handler for 09h and it works properly. But when I return basic handler to int vector and terminate program DOS prints full keyboard buffer and then any key pressing doesn't work.
My simple program prints scan codes for pressed/unpressed keys.
model tiny
.code
.386
org 100h
main:
xor ax, ax
push ax
pop es
jmp start
handler:
push bx cx ax dx
in al, 60h
cmp al, 81h
je hand_end
call tohex
lea dx, nl
mov ah, 09h
int 21h
in al,61H ;get value of keyboard control lines
mov ah,al ; save it
or al,80h ;set the "enable kbd" bit
out 61H,al ; and write it out the control port
xchg ah,al ;fetch the original control port value
out 61H,al ; and write it back
mov al, 20h ;send End-Of-Interrupt signal
out 20h, al ; to the 8259 Interrupt Controller
pop dx ax cx bx
jmp dword ptr cs:[vec]
hand_end:
pop dx ax cx bx
jmp exit
start:
cli
mov ax, 3509h
int 21h
mov word ptr [vec], bx
mov word ptr [vec + 2], es
mov ax, 2509h
lea dx, handler
int 21h
sti
lp:
jmp lp
exit:
; returning iVector
cli
push ds
mov ax, 2509h
mov ds, word ptr [vec + 2]
mov dx, word ptr [vec]
int 21h
pop ds
sti
mov ax, 4c00h
int 21h
proc tohex
pusha
push es
mov ah, al
mov cx, 2
push ds
pop es
lea di, hex
hxlp:
shr al, 4
lea bx, hx_table
xlat
stosb
shl ah, 4
mov al, ah
loop hxlp
lea dx, hex
mov ah, 09h
int 21h
pop es
popa
ret
endp tohex
nl db 13,10,'$'
vec dd ?,'$'
hex db ?,?,'$'
hx_table db '0123456789ABCDEF'
end main
Here is DOS Box screenshoot https://www.dropbox.com/s/v1olsalhzgnyyfv/int09h_problem.png
Upvotes: 1
Views: 3103
Reputation: 11018
Your source code has a number of things that made me frown; I don't know how forgiving DOS Box is, but on a real IBM-PC compatible machine with MS-DOS installed, I would expect this program to hang.
exit
branch doesn't pop dx ax cx bx
and ends in ret
(should be iret
); upon return it might jump anywhere.tohex
) without restoring their original value: es
, si
, di
.ds
and the direction flag (which affects stosb
); that's a dangerous assumption.tohex
into the keyboard buffer, instead of printing them yourself. Let the main thread call DOS interrupt 01h so that the contents of the keyboard buffer are echoed to the screen. Restore the interrupt vector there; this is not something the interrupt handler itself should be doing.EDIT: Thanks for the edit. It seems there are two separate issues remaining.
Funny thing is, the problem did not occur on an original Win95 machine; only on DOSBox! One might consider this to be a bug in DOSBox, but when nobody complained before, it typically means you are doing something out of the ordinary.
Solution: do not call the original interrupt handler at the end of your own handler; just iret
instead.
This problem occurs both on Win95 and on DOSBos; there are two bugs in the code that is called when the user presses Esc.
The following two instructions are in the wrong order; loading ds
will displace the address of the operand of the next instruction.
mov ds, word ptr [vec + 2]
mov dx, word ptr [vec]
I did some refactoring, and came up with the following; works in DOSBox and Win95.
However, the approach is still far from ideal; calling DOS function 09h to print a string from within the interrupt handler seems pretty harmful. If the main thread would call DOS functions itself (not uncommon in a real-life application), the whole program could crash and burn due to DOS being not re-entrant.
Sorry for the subtle syntax differences in addressing modes; I used an old Borland assembler.
IDEAL
MODEL tiny
CODESEG
ORG 100h
main:
cli
mov ax,3509h
int 21h
mov [WORD LOW vec],bx
mov [WORD HIGH vec],es
mov ax,2509h
mov dx,OFFSET handler
int 21h
sti
lp:
;mov ah,01h
;int 21h ; uncomment this and the program will crash
mov al,[scancode]
cmp al,81h
jne lp
push ds
mov ax,2509h
mov dx,[WORD LOW vec]
mov ds,[WORD HIGH vec]
int 21h
pop ds
mov ax,4C00h
int 21h
handler:
push ax
push bx
push cx
push dx
push ds
mov ax,cs
mov ds,ax
in al,60h
mov [scancode],al
in al,61h
or al,80h
out 61h,al
and al,7Fh
out 61h,al
mov al,20h
out 20h,al
call tohex
pop ds
pop dx
pop cx
pop bx
pop ax
iret
tohex:
mov bx,OFFSET hx_table
mov al,[scancode]
and al,0Fh
xlat
mov ah,al
mov al,[scancode]
shr al,4
xlat
mov [WORD PTR hex],ax
mov dx,OFFSET hex
mov ah,09h
int 21h
ret
DATASEG
hex db ?,?,13,10,'$'
hx_table db '0123456789ABCDEF'
scancode db 0
UDATASEG
vec dd ?
END main
Upvotes: 3
Reputation: 732
Pressed keys still remain in buffer. You need to call original int 09h to check whether there are keys awaiting and fetch them using the same original int 09h (GetKey).
Other possibility is to end interrupt call without calling original int 09h. But this solution needs to cancel itself on one of the keys (or it will hang computer/DOSbox) and support port 20h handling (as I remember this port needs to know that app/BIOS fetched the key).
You can make app that fetches keys and prints scancodes without changing interrupt address to your handler. But it should exit itself on one of the keys (to avoid printing endlessly - as you made checking for 81h key).
Also, you can watch 60h port for scancodes and get more (Ctrl, Alt, Shift) even with distinction left-right (other port, as I remember 64h). Don't write to these ports! You may want to look to old TechHelp app (there was 4.1 version).
More info is available here.
Upvotes: 1