这里有很多关于覆盖默认int 9 ISR的问题,我仔细阅读了它们。我的问题似乎很独特。有许多编写键盘中断处理程序的好例子,但它们涉及到原始ISR的链接。
我想完全取代原来的9 ISR。我没有使用int 16h BIOS键盘服务,如果键盘数据区域没有管理,我也不介意。事实上,取代ISR会对我有两个好处。
我自己的ISR可能会更快。我可以快速对传入的make / break代码作出反应,以一种特定于我需要的方式决定应该做什么,然后立即恢复我的程序。
我不再需要在主循环中包含代码来清除提前输入缓冲区。
这是我写的一个安装了键盘(int 9)和定时器(int 1ch)ISR的程序。程序通过向屏幕写入像素来响应击键。在这个例子中,键盘ISR被链接到原始的int 9 ISR,它在DOSBox和硬件(奔腾笔记本电脑运行DOS)中都能很好地工作。定时器ISR每隔55毫秒更新缓冲区中的像素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过程,以便它向PIC发送EOI并执行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是否安全?我知道它在机器之间的具体情况以及它在幕后的作用,但是它经常做一些对系统至关重要的事情吗?据我所知它只是管理键盘数据区,对吧?
答案 0 :(得分:1)
正如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