summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanny Holman <dholman@gymli.org>2024-06-25 12:49:40 -0500
committerDanny Holman <dholman@gymli.org>2024-06-25 12:49:40 -0500
commit0dc4d97e70c17df56a260d31a1cb44881cf64520 (patch)
tree8fc93c709d334be836e3b896e2ed5f5320292169
parent3851af792ca7b4bb7fc998337c4aec05627cfa8f (diff)
kernel: interrupt: create a generic interrupt API
Create a generic interface for drivers to make use of interrupt vectors. This API should be platform-agnostic enough to allow any driver to make use of virtually any interrupt vector on any CPU. On x86, the first 32 interrupts are set aside for CPU exceptions, and interrupt 128 is set aside for system calls. Signed-off-by: Danny Holman <dholman@gymli.org>
-rw-r--r--arch/i386/include/kernel/asm.h4
-rw-r--r--arch/i386/include/kernel/syscall.h2
-rw-r--r--arch/i386/kernel/idt.c27
-rw-r--r--arch/i386/kernel/syscall.c2
-rw-r--r--include/kernel/interrupt.h13
-rw-r--r--kernel/interrupt.c20
6 files changed, 50 insertions, 18 deletions
diff --git a/arch/i386/include/kernel/asm.h b/arch/i386/include/kernel/asm.h
index d692917..cc570c5 100644
--- a/arch/i386/include/kernel/asm.h
+++ b/arch/i386/include/kernel/asm.h
@@ -9,6 +9,8 @@
#define COM_PORT 0x3F8
+#define MAX_ISR 256
+
struct regs {
uint32_t eax;
uint32_t ebx;
@@ -95,7 +97,7 @@ void irq_stub_13(void);
void irq_stub_14(void);
void irq_stub_15(void);
-void syscall_stub(void);
+void isr_stub_128(void);
void aquire_lock(int *lock);
void release_lock(int *lock);
diff --git a/arch/i386/include/kernel/syscall.h b/arch/i386/include/kernel/syscall.h
index a689183..a657527 100644
--- a/arch/i386/include/kernel/syscall.h
+++ b/arch/i386/include/kernel/syscall.h
@@ -29,6 +29,6 @@
#define SYS_HALT 87
#define SYS_REBOOT 88
-int handle_syscall(struct isr_frame *frame);
+void handle_syscall(struct isr_frame *frame);
#endif
diff --git a/arch/i386/kernel/idt.c b/arch/i386/kernel/idt.c
index 1a06631..a178801 100644
--- a/arch/i386/kernel/idt.c
+++ b/arch/i386/kernel/idt.c
@@ -1,4 +1,5 @@
#include <kernel/idt.h>
+#include <kernel/interrupt.h>
#include <kernel/syscall.h>
#include <kernel/panic.h>
#include <kernel/gdt.h>
@@ -67,20 +68,10 @@ void exception_handler(struct isr_frame *frame) {
}
}
-void interrupt_handler(struct isr_frame frame) {
- if (frame.isr_vector < 32) {
- exception_handler(&frame);
- } else if (frame.isr_vector < 48) {
- irq_dispatch(&frame);
- } else {
- switch (frame.isr_vector) {
- case 0x80:
- handle_syscall(&frame);
- break;
- default:
- panic("Unmapped interrupt");
- }
- }
+void generic_handler(struct isr_frame *frame) {
+ kprintf("No handler registered for IRQ %d\n", frame->isr_vector);
+ if (frame->isr_vector > 32 && frame->isr_vector < 48)
+ pic_eoi(frame->isr_vector-32);
}
void idt_set_gate(uint8_t num, void (*handler)(void), uint16_t cs, uint8_t flags) {
@@ -96,6 +87,12 @@ void idt_install(void) {
idtr.limit = (uint16_t)sizeof(struct idt_entry) * 256 - 1;
idtr.base = (uint32_t)idt;
+ for (int i = 0; i < 32; i++)
+ register_isr_handler(i, exception_handler);
+ for (int i = 32; i < 224; i++)
+ register_isr_handler(i, generic_handler);
+ register_isr_handler(0x80, handle_syscall);
+
idt_set_gate(0x0, isr_stub_0, 0x08, IDT_EXCEPTION);
idt_set_gate(0x1, isr_stub_1, 0x08, IDT_EXCEPTION);
idt_set_gate(0x2, isr_stub_2, 0x08, IDT_EXCEPTION);
@@ -146,7 +143,7 @@ void idt_install(void) {
idt_set_gate(0x2E, irq_stub_14, 0x08, IDT_INTERRUPT);
idt_set_gate(0x2F, irq_stub_15, 0x08, IDT_INTERRUPT);
- idt_set_gate(0x80, syscall_stub, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x80, isr_stub_128, 0x08, IDT_INTERRUPT);
__asm__ volatile("lidt %0" : : "memory"(idtr));
}
diff --git a/arch/i386/kernel/syscall.c b/arch/i386/kernel/syscall.c
index e8b69a2..200af4f 100644
--- a/arch/i386/kernel/syscall.c
+++ b/arch/i386/kernel/syscall.c
@@ -10,7 +10,7 @@ void sys_read(struct isr_frame *frame) {
void sys_write(struct isr_frame *frame) {
}
-int handle_syscall(struct isr_frame *frame) {
+void handle_syscall(struct isr_frame *frame) {
switch (frame->eax) {
case SYS_READ:
sys_read(frame);
diff --git a/include/kernel/interrupt.h b/include/kernel/interrupt.h
new file mode 100644
index 0000000..b707fe7
--- /dev/null
+++ b/include/kernel/interrupt.h
@@ -0,0 +1,13 @@
+#ifndef KERNEL_INTERRUPT_H
+#define KERNEL_INTERRUPT_H
+
+#include <kernel/asm.h>
+#include <stdint.h>
+#include <stddef.h>
+
+void register_isr_handler(unsigned int isr, void (*handler)(struct isr_frame *frame));
+void clear_isr_handler(unsigned int isr);
+
+void isr_dispatch(struct isr_frame frame);
+
+#endif
diff --git a/kernel/interrupt.c b/kernel/interrupt.c
new file mode 100644
index 0000000..9639aea
--- /dev/null
+++ b/kernel/interrupt.c
@@ -0,0 +1,20 @@
+#include <kernel/interrupt.h>
+#include <kernel/asm.h>
+
+static void (*isr_handlers[MAX_ISR])(struct isr_frame *frame);
+
+void register_isr_handler(unsigned int isr, void (*handler)(struct isr_frame *frame)) {
+ if (isr > MAX_ISR)
+ panic("Attempted to set non-existant interrupt vector");
+ isr_handlers[isr] = handler;
+}
+
+void clear_isr_handler(unsigned int isr) {
+ if (isr > MAX_ISR)
+ panic("Attempted to clear non-existant interrupt vector");
+ isr_handlers[isr] = NULL;
+}
+
+void isr_dispatch(struct isr_frame frame) {
+ (*isr_handlers[frame.isr_vector])(&frame);
+}