基本上,除非您在完成工作后调用默认处理程序,否则您必须告诉 PIC(可编程中断控制器)您已完成 - 默认处理程序会为您执行此操作 - 发送EOI(中断信号结束)到 PIC。 PIC 不会再次触发中断,直到你告诉它你已经完成了当前的中断。
在 32 位保护模式下执行此操作的代码如下所示。请注意,我对所有 IRQ 使用通用处理程序,只是将其交给适当注册的用户回调函数。我都包括了。
首先,通用 IRQ 处理程序
irq_handler:
push ebp
mov ebp, esp
add ebp, 8
mov eax, [ebp +registers_t.int_no]
cmp eax, IRQ7 ; this just dumps spurious IRQ7 interrupts
je .irqHandlerDone
cmp eax, IRQ8 ; if it's IRQ0 - IRQ7, the first controller fired the int, otherwise the slave controller did
jb .slaveResetDone
.resetSlave:
mov al,20H ; send End-Of-Interrupt signal
out 0xA0,al ; to the 8259 _slave_ Programmable Interrupt Controller
.slaveResetDone:
.resetMaster:
mov al, 0x20 ; send End-Of-Interrupt signal
out 0x20, al ; to the 8259 master Programmable Interrupt Controller
mov eax, [ebp + registers_t.int_no]
shl eax, 2 ; x4
mov esi, interrupt_handlers
add esi, eax ; esi --> interrupt_handlers[int_no]
cmp dword [esi], 0
je .irqHandlerDone
call [esi]
.irqHandlerDone:
pop ebp
ret
接下来,IRQ1(键盘)处理程序。注册函数只是简单地将函数的偏移量复制到一个 32 位地址的表 (interrupt_handlers) 中。
我处于平面内存模式(4GB 可寻址,ES 已经拥有可写数据段的段选择器。0xB8000 + 79*2 只是指向 80x25 模式3 文本屏幕右上角的字符)
; keyboard IRQ handler
irq1Handler:
push ebp
mov ebp, esp
add ebp, 8+4
in al, 0x60
mov bl, al
mov byte [port60], al
in al, 0x61
mov ah, al
or al, 0x80
out 0x61, al
xchg ah, al
out 0x61, al
and bl, 0x80
jnz .done
pusha
;mov al, [port60]
;call outputChar
mov edi, 0xB8000 + 79*2
mov al, [port60]
mov [es:edi], al
popa
.done:
pop ebp
ret
port60 db 0
代码来自 James M 的教程,这里:http://www.jamesmolloy.co.uk/tutorial_html/5.-IRQs%20and%20the%20PIT.html
在 OSDev.org - http://wiki.osdev.org/Main_Page 上可以阅读很多关于硬件接口的信息
更新:
这是一个在 DosBox 中运行的 16 位 ISR。
;-----------------------------------------------------
; handles int 0x09
;-----------------------------------------------------
keyhandler:
cli
pusha
in al, 0x60 ; get key data
mov bl, al ; save it
mov byte [port60], al
in al, 0x61 ; keybrd control
mov ah, al
or al, 0x80 ; disable bit 7
out 0x61, al ; send it back
xchg ah, al ; get original
out 0x61, al ; send that back
mov al, 0x20 ; End of Interrupt
out 0x20, al ;
and bl, 0x80 ; key released
jnz done ; don't repeat
mov al, [port60]
;
; do something with the scan-code here
;
done:
popa
iret
port60 db 0 ; where we'll store the scan-code