kernel/x86_64: Add a way to register IRQ handlers from other kernel subsystems

This commit is contained in:
apio 2023-05-10 19:14:23 +02:00
parent d589834eb7
commit f0caf010bf
Signed by: apio
GPG Key ID: B8A7D06E42258954
3 changed files with 57 additions and 11 deletions

View File

@ -29,5 +29,7 @@ namespace CPU
u16 get_processor_id();
bool register_interrupt(u8 interrupt, void (*handler)(Registers*));
void pause();
}

View File

@ -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

View File

@ -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