По принцип казано, освен ако не извикате манипулатора по подразбиране, след като сте свършили работата си, ще трябва да кажете на 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 (клавиатура). Функцията за регистрация просто копира отместването на функцията в таблица (interrupt_handlers
) с 32-битови адреси. Аз съм в режим на плоска памет (4GB адресируеми, ES вече държи селектора на сегменти за записваем сегмент от данни. 0xB8000 + 79*2 просто сочи към знака в горния десен ъгъл на текстов екран 80x25 mode3)
; 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
АКТУАЛИЗАЦИЯ: Ето 16-битов ISR, който функционира в DosBox.
;-----------------------------------------------------
; 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
person
enhzflep
schedule
14.10.2015