我无法理解为什么我为我的程序编写的键盘中断服务程序(每次按键时都应该打印“hello world”)只在我执行dosbox上的.exe时出现一次。 这是代码:
while read -r i <&3; do
nexec -i "$i" hostname 2>>"errorlog.$i.txt" || {
echo "nexec for $i exited with status $?" >&2
continue
}
# check for case where it claimed success but actually failed
# if nexec is written correctly, you don't need any of this logic
# ...and can completely remove the rest of the loop.
if grep -q -e "$i" "errorlog.$i.txt"; then
echo "error accessing $i" >&2
else
echo "was able to connect to $i" >&2
fi
done 3<serverlist
# and combine all the individual logs into one file:
cat errorlog.*.txt >errorlog.txt && rm -f -- errorlog.*.txt
我尝试了一些东西,比如推送和弹出寄存器,使用另一个中断(系统时钟08h),但没有一个工作。 我知道ISR至少运行一次,因为屏幕上出现了“hello world”消息,但是每次按下一个键都会打印,我不知道它为什么没有。
我该如何解决这个问题?
答案 0 :(得分:1)
你必须做一些工作来免费&#34;键盘和中断。看看{{3}}。最简单的方法是跳转到自己的处理程序末尾的旧IRQ处理程序:
NAME keyb
PILE SEGMENT STACK
db 20 dup ('LA PILE ')
PILE ENDS
DONNEE SEGMENT
message db "Hello wolrd !$"
oldvec dw 0, 0
DONNEE ENDS
PROGRAMME SEGMENT
ASSUME CS:PROGRAMME , DS:DONNEE, ES:NOTHING, SS:PILE
debut:
mov ax,DONNEE
mov ds,ax
cli
xor ax,ax
mov es, ax ; load ES with segment address of interrupt pointer table
mov bx, 24h ; load BX with interrupt type
; Store the old IRQ vector
mov ax, es:[bx]
mov oldvec, ax
mov ax, es:[bx+2]
mov oldvec + 2, ax
mov word ptr es:[bx], OFFSET SUBR ; isr address
mov word ptr es:[bx]+2, SEG SUBR ; isr segment
mov ax, 01h
sti
BOUCLE: jmp BOUCLE
SUBR PROC NEAR
push ax
push dx
mov ah,9
mov dx,OFFSET message
int 21h
pop dx
pop ax
jmp dword ptr [oldvec]
SUBR ENDP
PROGRAMME ENDS
END debut
答案 1 :(得分:1)
基本上,除非你在完成工作后调用默认处理程序,否则你必须告诉PIC(可编程中断控制器)你已经完成了 - 默认处理程序会为你做这件事 - 发送到PIC的EOI(中断信号结束)。 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 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
<强>更新强> 这是一个在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