Page 1 of 1
Mouse/Keyboard interrupt sometimes not fired?
Posted: Fri Jan 06, 2017 8:55 am
by szhou42
I am using the keyboard code in Bran's kernel development tutorial
I find that the keyboard and mouse interrupt only fires most of the time, sometimes i just don't receive any interrupts related to keyboard and mouse.
All my keyboard driver does is registering the keyboard interrupt and wait for interrupts to be fired.
Does anyone else following this tutorial have the same issue?
Re: Mouse/Keyboard interrupt sometimes not fired?
Posted: Fri Jan 06, 2017 4:31 pm
by hannah
My keyboard is based off his Tutorial and it is working fine. Please, send us your code.
Re: Mouse/Keyboard interrupt sometimes not fired?
Posted: Fri Jan 06, 2017 6:50 pm
by szhou42
Hi, here's my keyboard and interrupt code, which is almost identical to the tutorial.
Code: Select all
void keyboard_init() {
register_interrupt_handler(IRQ_BASE + 1, keyboard_handler);
}
Code: Select all
isr_t interrupt_handlers[256];
void register_interrupt_handler(int num, isr_t handler) {
if(num < 256)
interrupt_handlers[num] = handler;
}
void final_irq_handler(register_t reg) {
if(interrupt_handlers[reg.int_no] != NULL) {
isr_t handler = interrupt_handlers[reg.int_no];
handler(®);
}
irq_ack(reg.int_no);
}
i m trying to check my previous versions and find out which version cause the bug..
Re: Mouse/Keyboard interrupt sometimes not fired?
Posted: Sat Jan 07, 2017 12:14 am
by Nable
Code: Select all
void final_irq_handler(register_t reg) {
It looks like you are using famous buggy tutorial. There is a well-known problem that you should pass registers structure by pointer (not by value) as compiler may make unexpected changes in its arguments that are passed by value.
Re: Mouse/Keyboard interrupt sometimes not fired?
Posted: Sat Jan 07, 2017 3:35 am
by szhou42
Nable wrote:Code: Select all
void final_irq_handler(register_t reg) {
It looks like you are using famous buggy tutorial. There is a well-known problem that you should pass registers structure by pointer (not by value) as compiler may make unexpected changes in its arguments that are passed by value.
I just tried using pass structure by pointer, still not working.
However, my code always work in qemu without enabling kvm.
It looks like the problem is related to irq acknowledge, because in qemu with kvm enabled, sometimes all my other interrupts would stop firing after a few irq firings.
Re: Mouse/Keyboard interrupt sometimes not fired?
Posted: Sat Jan 07, 2017 3:38 am
by szhou42
szhou42 wrote:Nable wrote:Code: Select all
void final_irq_handler(register_t reg) {
It looks like you are using famous buggy tutorial. There is a well-known problem that you should pass registers structure by pointer (not by value) as compiler may make unexpected changes in its arguments that are passed by value.
I just tried using pass structure by pointer, still not working.
However, my code always work in qemu without enabling kvm.
It looks like the problem is related to irq acknowledge, because in qemu with kvm enabled, sometimes all my other interrupts would stop firing after a few irq firings.
Code: Select all
void irq_ack(uint8_t irq) {
if(irq >= 0x28)
outportb(PIC2, PIC_EOI); // output 0x20 to 0xA0
outportb(PIC1, PIC_EOI); // output 0x20 to 0x20
}
Re: Mouse/Keyboard interrupt sometimes not fired?
Posted: Sat Jan 07, 2017 4:27 am
by Octacone
szhou42 wrote:szhou42 wrote:Nable wrote:Code: Select all
void final_irq_handler(register_t reg) {
It looks like you are using famous buggy tutorial. There is a well-known problem that you should pass registers structure by pointer (not by value) as compiler may make unexpected changes in its arguments that are passed by value.
I just tried using pass structure by pointer, still not working.
However, my code always work in qemu without enabling kvm.
It looks like the problem is related to irq acknowledge, because in qemu with kvm enabled, sometimes all my other interrupts would stop firing after a few irq firings.
Code: Select all
void irq_ack(uint8_t irq) {
if(irq >= 0x28)
outportb(PIC2, PIC_EOI); // output 0x20 to 0xA0
outportb(PIC1, PIC_EOI); // output 0x20 to 0x20
}
For the reference, this is how my code looks like. It works just fine. Also 0x28 is 40 in decimal.
Code: Select all
void IRQ_Send_EOI(uint8_t irq_number)
{
if(irq_number >= 8)
{
Outportb(0xA0, 0x20);
}
Outportb(0x20, 0x20);
}
Re: Mouse/Keyboard interrupt sometimes not fired?
Posted: Sat Jan 07, 2017 7:22 pm
by szhou42
Sorry i just find out that it's not related to irq ack.
Instead, all interrupts stopped immediately after i enter real mode to set vesa mode and return back to protected mode.
Code: Select all
[bits 32]
global bios32_helper
global bios32_helper_end
global asm_gdt_ptr
global asm_gdt_entries
global asm_idt_ptr
global asm_in_reg_ptr
global asm_out_reg_ptr
global asm_intnum_ptr
extern gdt_init
extern idt_init
extern new_gdt_entries;
extern new_gdt_ptr;
extern new_idt_ptr;
extern new_reg_ptr;
extern new_intnum_ptr;
%define REBASE(x) (((x) - bios32_helper) + 0x7c00)
%define GDTENTRY(x) ((x) << 3)
%define CODE32 GDTENTRY(1) ; 0x08
%define DATA32 GDTENTRY(2) ; 0x10
%define CODE16 GDTENTRY(6) ; 0x30
%define DATA16 GDTENTRY(7) ; 0x38
PG_BIT_OFF equ 0x7fffffff
PG_BIT_ON equ 0x80000000
section .text
bios32_helper: use32
pusha
mov edx, esp
; Now in 32bit protected mode
; Disable interrupts
cli
; Turn off paging
mov ecx, cr0
and ecx, PG_BIT_OFF
mov cr0, ecx
; Zero cr3(save it in ebx before zeroing it)
xor ecx, ecx
mov ebx, cr3
mov cr3, ecx
; Load new gdt
lgdt [REBASE(asm_gdt_ptr)]
; Load idt
lidt [REBASE(asm_idt_ptr)]
jmp CODE16:REBASE(protected_mode_16)
protected_mode_16:use16
; Now in 16bit protected mode
; Update data segment selector
mov ax, DATA16
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Turn off protected mode
mov eax, cr0
and al, ~0x01
mov cr0, eax
jmp 0x0:REBASE(real_mode_16)
real_mode_16:use16
; 16 bit real mode data segment
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov sp, 0x8c00
sti
; ### Save current context ###
pusha
mov cx, ss
push cx
mov cx, gs
push cx
mov cx, fs
push cx
mov cx, es
push cx
mov cx, ds
push cx
pushf
mov ax, sp
mov edi, temp_esp
stosw
; ### Load the given context from asm_in_reg_ptr ###
; Temporaril change esp to asm_in_reg_ptr
mov esp, REBASE(asm_in_reg_ptr)
; only use some general register from the given context
popa
; set a new stack for bios interrupt
mov sp, 0x9c00
; opcode for int
db 0xCD
asm_intnum_ptr:
; put the actual interrupt number here
db 0x00
; ### Write current context to asm_out_reg_ptr ###
mov esp, REBASE(asm_out_reg_ptr)
add sp, 28
pushf
mov cx, ss
push cx
mov cx, gs
push cx
mov cx, fs
push cx
mov cx, es
push cx
mov cx, ds
push cx
pusha
; ### Restore current context ###
mov esi, temp_esp
lodsw
mov sp, ax
popf
pop cx
mov ds, cx
pop cx
mov es, cx
pop cx
mov fs, cx
pop cx
mov gs, cx
pop cx
mov ss, cx
popa
mov eax, cr0
inc eax
mov cr0, eax
jmp CODE32:REBASE(protected_mode_32)
protected_mode_32:use32
mov ax, DATA32
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; restore cr3
mov cr3, ebx
; Turn on paging
mov ecx, cr0
or ecx, PG_BIT_ON
mov cr0, ecx
; restore esp
mov esp, edx
sti
popa
ret
padding:
db 0x0
db 0x0
db 0x0
asm_gdt_entries:
; 8 gdt entries
resb 64
asm_gdt_ptr:
dd 0x00000000
dd 0x00000000
asm_idt_ptr:
dd 0x00000000
dd 0x00000000
asm_in_reg_ptr:
resw 14
asm_out_reg_ptr:
dd 0xaaaaaaaa
dd 0xaaaaaaaa
dd 0xaaaaaaaa
dd 0xaaaaaaaa
dd 0xaaaaaaaa
dd 0xaaaaaaaa
dd 0xaaaaaaaa
temp_esp:
dw 0x0000
bios32_helper_end:
Re: Mouse/Keyboard interrupt sometimes not fired?
Posted: Sat Jan 07, 2017 9:06 pm
by szhou42
...
Re: Mouse/Keyboard interrupt sometimes not fired?
Posted: Sat Jan 07, 2017 9:24 pm
by szhou42
This is super weird....
All I did is adding a line of code to to manually trigger an interrupt and see if interrupt works, interrupts start firing..
I think the reason is when I am returning to real mode to call bios, some interrupts is not being acknowledged so no more interrupts can be fired.
By manually triggering an interrupt, and acknowledging it, the PIC would start firing interrupts again.
So, directly acknowledging an irq would do the trick as well as manually trigger an interrupt. I tried it and it also works.