这里有很多问题与覆盖默认的int 9 ISR有关,我已经仔细阅读了它们。我的问题似乎是独一无二的。编写键盘中断处理程序有许多好的例子,但它们涉及将原始ISR链接到
上。我想完全替换原始的INT 9 ISR。我不使用INT 16H BIOS键盘服务,也不介意是否没有管理键盘数据区域。实际上,替换ISR将通过两种方式对我有益。
我自己的ISR可能会更快。我可以快速对传入的制作/中断代码做出反应,决定应以指定我的需求的方式做什么,然后立即恢复我的程序。
我不再需要在我的主循环中包含代码来清除类型的缓冲区。
这是我编写的程序,该程序安装了键盘(INT 9(和计时器(INT 1CH(ISRS。该程序通过将像素写入屏幕来响应击键。在此示例中,键盘ISR被链接到原始的INT 9 ISR上,并且在两个DOSBOX和硬件(Pentium笔记本电脑运行DOS(中效果很好。计时器ISR每55毫秒在缓冲区中更新Pixel 0。它用作程序的当前状态(是否崩溃(的指标。由于我用键盘ISR弄乱了,因此我不能总是知道该机器是否已锁定,例如,按下盖子锁定并查看LED指示灯是否亮起。
;----------------------------------------------------------------------------|
theStack SEGMENT STACK ;|
;____________________________________________________________________________|
db 64 dup ('THESTACK')
;----------------------------------------------------------------------------|
theStack ENDS ;|
;____________________________________________________________________________|
;----------------------------------------------------------------------------|
varData SEGMENT ;|
;____________________________________________________________________________|
pixCol db ? ;current color index
pixPos dw ? ;current position in VGA pixel buffer
;----------------------------------------------------------------------------|
varData ENDS ;|
;____________________________________________________________________________|
;----------------------------------------------------------------------------|
code SEGMENT
assume cs:code,ds:varData
oldInt9 dd 0 ;original int 9 target
oldInt1c dd 0 ;original int 1c target
main PROC
start:
mov ax, varData
mov ds, ax ;Load the variable segment into ds
;____________________________________________________________________________|
call SET_VGA_256 ;set video mode 13h
call INSTALL_ISR ;install the ISRs
mov ax, 40h
mov es, ax ;access keyboard data area via segment 40h
loop0:
;clr type-ahead buff, prevents PC spkr beep
;(has to occur at some point if you don't
;use int 16h BIOS keyboard services, and
;the original int 9 ISR is still handling
;keystrokes)
mov WORD PTR es:[1ah], 1eh ;set the kbd buff head to start of buff
mov WORD PTR es:[1ch], 1eh ;set the kbd buff tail to same as buff head
inc pixCol ;increment the current pixel color
inc pixPos ;increment the current pixel position
cmp pixPos, 63999d ;Is pixPos < pixel area
jb loop0 ;If so, loop back
mov pixPos, 0 ;If not, reinit pixPos
in al, 60h ;al <- last key press
cmp al, 1 ;Was the key Esc
jne loop0 ;If not, loop back
call EXIT2DOS ;Uninstall ISRs, restore text mode, exit.
SET_VGA_256 PROC
;SETS VIDEO MODE TO 13H (VGA 320x200 256 COLORS)
push ax
mov ax, 13h ;320x200 256 colors
int 10h ;video mode set
pop ax
ret
SET_VGA_256 ENDP
INSTALL_ISR PROC
;PATCHES NEW VECTOR ENTRIES INTO THE INTERRUPT VECTOR TABLE.
;THE DEFAULT INPUT (INT 9H) ISR IS REPLACED WITH MY OWN INPUT HANDLING ISR.
;Int 1C TIMER ISR IS CHAINED FOR DEBUGGING PURPOSES.
;THE OLD VECTOR ENTRIES ARE BACKED UP. THEY WILL BE RESTORED BEFORE PROGRAM
;TERMINATION.
push es
;// BACKUP THE OLD IVT ENTRIES //
cli ;disable hardware interrupts
xor ax, ax
mov es, ax ;es <- 0
mov ax, WORD PTR es:[9*4] ;ax <- offset part of IVT entry
mov WORD PTR cs:oldInt9, ax ;store it in MSW of oldInt9
mov ax, WORD PTR es:[9*4+2] ;si <- segment part of IVT entry
mov WORD PTR cs:oldInt9+2, ax ;store it in LSW of oldInt9
mov ax, WORD PTR es:[1ch*4]
mov WORD PTR cs:oldInt1c, ax
mov ax, WORD PTR es:[1ch*4+2]
mov WORD PTR cs:oldInt1c+2, ax ;store INT 1C IVT entry
;// INSTALL THE NEW INTERRUPT HANDLERS //
mov WORD PTR es:[9*4], OFFSET INPUT_ISR ;copy my new ISR offset to IVT
mov WORD PTR es:[9*4+2], cs ;copy my code segment to IVT
mov WORD PTR es:[1ch*4], OFFSET TIMER_ISR
mov WORD PTR es:[1ch*4+2], cs ;do the same for int 1c entry
sti ;enable hardware interrupts
pop es
ret
INSTALL_ISR ENDP
INPUT_ISR PROC
;PRINTS A PIXEL OF SOME COLOR INDEX TO SOME LOCATION IN THE PIXEL BUFFER
;WHEN A KEYSTROKE OCCURS. ONE KEYSTROKE GENERATES TWO INTERRUPTS, ONE FOR
;KEY-DOWN, AND ONE FOR KEY-UP.
pushf
cli ;disable hardware interrupts
;(disabled anyway upon entry)
push ds
push es
push bx
push ax
mov bx, varData
mov ds, bx ;ds <- data segment
mov bx, 0a000h
mov es, bx ;es <- VGA pixel buffer
mov bx, pixPos ;bx <- current pixel position
mov ah, pixCol ;ah <- current pixel color
mov BYTE PTR es:[bx], ah ;write the pixel to the buffer
pop ax
pop bx
pop es
pop ds
popf
jmp cs:oldInt9 ;now execute original ISR
INPUT_ISR ENDP
TIMER_ISR PROC
;USED FOR DEBUGGING. IF THE COLOR OF PIXEL POSITION 0 STOPS UPDATING, THINGS
;HAVE GONE VERY WRONG.
pushf
cli ;disable hardware interrupts
;(disabled anyway upon entry)
push ds
push es
push bx
push ax
mov bx, varData
mov ds, bx ;ds <- data segment
mov bx, 0a000h
mov es, bx ;es <- VGA pixel buffer
mov ah, pixCol ;ah <- current pixel color
xor bx, bx ;bx <- pixel position 0
mov BYTE PTR es:[bx], ah ;write the pixel to the buffer
pop ax
pop bx
pop es
pop ds
popf
jmp cs:oldInt1c ;now execute original ISR
TIMER_ISR ENDP
EXIT2DOS PROC
;UNINSTALL ISR, CLEAR THE TYPE-AHEAD BUFFER, RESTORE TEXT MODE, AND EXIT.
cli ;disable hardware interrupts
xor ax, ax
mov es, ax
mov ax, WORD PTR cs:oldInt9
mov WORD PTR es:[9*4], ax
mov ax, WORD PTR cs:oldInt9+2
mov WORD PTR es:[9*4+2], ax ;Original int 9 ISR restored to IVT
mov ax, WORD PTR cs:oldInt1c
mov WORD PTR es:[1ch*4], ax
mov ax, WORD PTR cs:oldInt1c+2
mov WORD PTR es:[1ch*4+2], ax ;Original int 1c ISR restored to IVT
sti ;enable hardware interrupts
;clear type-ahead buffer just before exit
;to prevent dumping garbage characters
;to DOS prompt.
mov ax, 40h
mov es, ax ;access kbd data area via segment 40h
mov WORD PTR es:[1ah], 1eh ;set the kbd buff head to start of buff
mov WORD PTR es:[1ch], 1eh ;set kbd buff tail to same as buff head
;now the keyboard buffer is cleared.
xor ah, ah ;select video mode function
mov al, 3 ;select 80x25 16 colors
int 10h ;restore VIDEO back to text mode
mov ax, 4c00h ;Terminate process DOS service
int 21h ;Control returns to DOS
EXIT2DOS ENDP
;----------------------------------------------------------------------------|
main ENDP ;|
;|
code ENDS ;|
;|
END start ;|
;____________________________________________________________________________|
如果我稍微更改input_isr过程,以便它将EOI发送到PIC并执行IRET,原始INT 9 ISR将永远不会执行。
INPUT_ISR PROC
pushf
cli ;disable hardware interrupts
;(disabled anyway upon entry)
push ds
push es
push bx
push ax
mov bx, varData
mov ds, bx ;ds <- data segment
mov bx, 0a000h
mov es, bx ;es <- VGA pixel buffer
mov bx, pixPos ;bx <- current pixel position
mov ah, pixCol ;ah <- current pixel color
mov BYTE PTR es:[bx], ah ;write the pixel to the buffer
mov al, 20h
out 20h, al ;EOI
pop ax
pop bx
pop es
pop ds
popf
iret
INPUT_ISR ENDP
但是,这会在DOSBOX和硬件上引起问题。在DOSBOX中,它不会崩溃,但行为不稳定。像素通常会在窗户的右上角彼此串在一起,并且像素迟缓出现在屏幕上。计时器ISR仍执行,并且可以正常终止程序。在硬件中发生即时崩溃。计时器ISR停止更新其像素,并且必须重新启动机器。
替换INT 9 ISR甚至安全吗?我知道从机器到机器的特定方面的幕后影响是特定的,但是它经常做系统至关重要的事情吗?据我所知,它只是管理键盘数据区域,对吗?
正如迈克尔·皮奇(Michael Petch(在上述评论链中提到的,必须在结束ISR之前阅读端口60h,否则不会发生其他键盘中断。
更正的INPUT_ISR
过程:
INPUT_ISR PROC
;PRINTS A PIXEL OF SOME COLOR INDEX TO SOME LOCATION IN THE PIXEL BUFFER
;WHEN A KEYSTROKE OCCURS. ONE KEYSTROKE GENERATES TWO INTERRUPTS, ONE FOR
;KEY-DOWN, AND ONE FOR KEY-UP.
pushf
cli ;disable hardware interrupts
;(disabled anyway upon entry)
push ds
push es
push bx
push ax
mov bx, varData
mov ds, bx ;ds <- data segment
mov bx, 0a000h
mov es, bx ;es <- VGA pixel buffer
mov bx, pixPos ;bx <- current pixel position
mov ah, pixCol ;ah <- current pixel color
mov BYTE PTR es:[bx], ah ;write the pixel to the buffer
in al, 60h ;read port 60h, must always be done before
;terminating an int 9 ISR, or else no
;keyboard interrupts will occur
mov al, 20h
out 20h, al ;EOI
pop ax
pop bx
pop es
pop ds
popf
iret
INPUT_ISR ENDP