diff --git a/kernel/src/arch/CPU.h b/kernel/src/arch/CPU.h index 4e994339..3d9a2849 100644 --- a/kernel/src/arch/CPU.h +++ b/kernel/src/arch/CPU.h @@ -29,5 +29,7 @@ namespace CPU u16 get_processor_id(); + bool register_interrupt(u8 interrupt, void (*handler)(Registers*)); + void pause(); } diff --git a/kernel/src/arch/x86_64/CPU.asm b/kernel/src/arch/x86_64/CPU.asm index f7989b4e..b8b433d2 100644 --- a/kernel/src/arch/x86_64/CPU.asm +++ b/kernel/src/arch/x86_64/CPU.asm @@ -188,4 +188,18 @@ ISR_ERROR 21 ; control-protection exception (#CP) ; ISR 22-31 reserved IRQ 32, 0 ; timer interrupt IRQ 33, 1 ; keyboard interrupt +IRQ 34, 2 +IRQ 35, 3 +IRQ 36, 4 +IRQ 37, 5 +IRQ 38, 6 +IRQ 39, 7 +IRQ 40, 8 +IRQ 41, 9 +IRQ 42, 10 +IRQ 43, 11 +IRQ 44, 12 +IRQ 45, 13 +IRQ 46, 14 +IRQ 47, 15 ISR 66 ; system call diff --git a/kernel/src/arch/x86_64/CPU.cpp b/kernel/src/arch/x86_64/CPU.cpp index 5b8e957d..ab3e213c 100644 --- a/kernel/src/arch/x86_64/CPU.cpp +++ b/kernel/src/arch/x86_64/CPU.cpp @@ -28,6 +28,10 @@ extern void setup_idt(); static Thread* g_io_thread; +typedef void (*interrupt_handler_t)(Registers*); + +static interrupt_handler_t irq_handlers[16]; + void FPData::save() { asm volatile("fxsave (%0)" : : "r"(m_data)); @@ -150,21 +154,34 @@ void io_thread() } } +static void timer_interrupt(Registers* regs) +{ + Timer::tick(); + if (should_invoke_scheduler()) Scheduler::invoke(regs); +} + +static void keyboard_interrupt(Registers*) +{ + u8 scancode = IO::inb(0x60); + scancode_queue.try_push(scancode); + g_io_thread->wake_up(); +} + // Called from _asm_interrupt_entry extern "C" void arch_interrupt_entry(Registers* regs) { if (regs->isr < 32) handle_x86_exception(regs); - else if (regs->isr == 32) // Timer interrupt + else if (regs->isr >= 32 && regs->isr < 48) // IRQ from the PIC { - Timer::tick(); - if (should_invoke_scheduler()) Scheduler::invoke(regs); - pic_eoi(regs); - } - else if (regs->isr == 33) // Keyboard interrupt - { - u8 scancode = IO::inb(0x60); - scancode_queue.try_push(scancode); - g_io_thread->wake_up(); + u64 irq = regs->error; + interrupt_handler_t handler = irq_handlers[irq]; + if (!handler) + { + kwarnln("Unhandled IRQ catched! Halting."); + CPU::efficient_halt(); + } + + handler(regs); pic_eoi(regs); } else if (regs->isr == 66) // System call @@ -174,7 +191,7 @@ extern "C" void arch_interrupt_entry(Registers* regs) } else { - kwarnln("IRQ catched! Halting."); + kwarnln("Unhandled interrupt catched! Halting."); CPU::efficient_halt(); } } @@ -233,6 +250,10 @@ namespace CPU kwarnln("not setting the NX bit as it is unsupported"); setup_gdt(); setup_idt(); + + memset(irq_handlers, 0, sizeof(irq_handlers)); + register_interrupt(0, timer_interrupt); + register_interrupt(1, keyboard_interrupt); } void platform_finish_init() @@ -353,6 +374,15 @@ namespace CPU __get_cpuid(1, &unused, &ebx, &unused, &unused); return (u16)(ebx >> 24); } + + bool register_interrupt(u8 interrupt, interrupt_handler_t handler) + { + if (irq_handlers[interrupt]) return false; + + irq_handlers[interrupt] = handler; + + return true; + } } // called by kernel_yield