]> git.dujemihanovic.xyz Git - nameless-os.git/commitdiff
Rework interrupt handling
authorDuje Mihanović <duje.mihanovic@skole.hr>
Mon, 13 Jun 2022 09:41:50 +0000 (11:41 +0200)
committerDuje Mihanović <duje.mihanovic@skole.hr>
Mon, 27 Jun 2022 19:58:17 +0000 (21:58 +0200)
This new system should, among other things, allow for more flexibility than the
previous one.

TODO: Define interrupt stack frame

Makefile
kernel/arch/x86/irq/idt.c
kernel/arch/x86/irq/interrupt.c [new file with mode: 0644]
kernel/arch/x86/irq/sample_handler.c [deleted file]
kernel/arch/x86/irq/stub.s [new file with mode: 0644]
kernel/include/arch/x86/irq/idt.h
kernel/include/arch/x86/irq/interrupt.h [new file with mode: 0644]
kernel/kernel.c

index f254d0c8ed42952a44a7d1cd42ad6c699b727b63..c3510938c72abeee53245b818c089643614c2dad 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,7 @@ export GIT_REV = $(shell git describe --long HEAD)
 
 CFLAGS = -g -fgnu89-inline -Ikernel/include -Ikernel/include/arch/x86 -ffreestanding -DGIT_COMMIT=\"$(GIT_REV)\"
 
-KERNEL_OBJ = kernel/entry.o kernel/arch/x86/halt.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/sample_handler.o kernel/kernel.o
+KERNEL_OBJ = kernel/entry.o kernel/arch/x86/halt.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/interrupt.o kernel/arch/x86/irq/stub.o kernel/kernel.o
 
 BOOTLOADER_OBJ = boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN boot/x86/stage3/loader.elf
 
index 54e8612934ffd9f08751d84cebb59ae5ec1d2227..3871751061001c62d71091d3b24eea1fedf0e880 100644 (file)
@@ -7,17 +7,17 @@ inline void load_idt(struct idtr idtr)
        asm volatile ("lidt %0": : "m" (idtr));
 }
 
-void idt_set_descriptor(struct idt_descriptor *idt, uint8_t vector, uint16_t segment, uint32_t offset, uint8_t type, uint8_t dpl)
+void idt_set_descriptor(struct idt_descriptor *idt, uint8_t vector, uint16_t segment, void (*offset)(void), uint8_t type, uint8_t dpl)
 {
        struct idt_descriptor *descriptor = &idt[vector];
 
-       descriptor->offset_1 = offset & 0xFFFF;
+       descriptor->offset_1 = (uint32_t) offset & 0xFFFF;
        descriptor->segsel = segment;
        descriptor->unused = 0;
        descriptor->type = type;
        descriptor->dpl = dpl;
        descriptor->present = 1;
-       descriptor->offset_2 = offset >> 16;
+       descriptor->offset_2 = (uint32_t) offset >> 16;
 }
 
 inline void populate_idtr(struct idtr *idtr, struct idt_descriptor *idt)
diff --git a/kernel/arch/x86/irq/interrupt.c b/kernel/arch/x86/irq/interrupt.c
new file mode 100644 (file)
index 0000000..b2abef9
--- /dev/null
@@ -0,0 +1,36 @@
+#include <irq/idt.h>
+#include <irq/interrupt.h>
+#include <tty.h>
+#include <stddef.h>
+#include <irq/i8259a.h>
+
+/* This table will hold pointers to our interrupt handlers. */
+static int (*int_handler_table[256])(void);
+
+void int_handler(int interrupt)
+{
+       if (int_handler_table[interrupt] == NULL) {
+               kprint("WARNING: Unhandled interrupt ", 0);
+               kprintb(interrupt);
+               kprint(" occurred!\n", 0);
+       } else {
+               int ret = (*int_handler_table[interrupt])();
+               if (ret) {
+                       kprint("WARNING: Error while handling interrupt ", 0);
+                       kprintb(interrupt);
+                       kprint("!\n", 0);
+               }
+       }
+       if (interrupt >= 0x20) {
+               pic_send_eoi(interrupt - 0x20);
+       }
+}
+
+int register_interrupt(int irq, int (*handler)(void))
+{
+       int_handler_table[irq] = handler;
+       if (irq >= 32 && irq < 48) {
+               pic_unmask(irq-32);
+       }
+       return 0;
+}
diff --git a/kernel/arch/x86/irq/sample_handler.c b/kernel/arch/x86/irq/sample_handler.c
deleted file mode 100644 (file)
index 5b0e2d4..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#include <tty.h>
-#include <irq/i8259a.h>
-#include <io.h>
-#include <stdint.h>
-#include <mm/paging.h>
-#include <panic.h>
-
-typedef uint32_t uword_t;
-
-struct interrupt_frame {
-       uword_t ip;
-       uword_t cs;
-       uword_t flags;
-};
-
-struct fault_frame {
-       struct pf_errcode error_code;
-       uintptr_t eip;
-       uint16_t cs;
-       uint32_t eflags;
-};
-
-struct abort_frame;
-
-__attribute__((interrupt))
-void keyb_handler(struct interrupt_frame *frame)
-{
-       pic_send_eoi(1);
-       kprint("Got a keyboard interrupt!\n", 0);
-       inb(0x60);
-       int a = *(int *) (0xa0000000);
-}
-
-__attribute__((interrupt))
-void pf_handler(struct fault_frame *frame)
-{
-       int address;
-       struct pf_errcode errcode = frame->error_code;
-       asm ("mov %%cr2, %0": "=a" (address));
-       kprint("A page fault occurred!\n", VGA_COLOR_BRIGHT_RED);
-       kprint("Faulting address: ", 0);
-       kprintd(address);
-       kprint("\n", 0);
-       if (!errcode.p) {
-               kprint("Address points to non-mapped page\n", 0);
-       }
-       if (errcode.wr) {
-               kprint("Fault occurred while writing to memory\n", 0);
-       } else {
-               kprint("Fault occurred while reading from memory\n", 0);
-       }
-       if (errcode.id) {
-               kprint("Fault occurred while fetching instruction\n", 0);
-       }
-       PANIC("page fault");
-}
-
-__attribute__((interrupt))
-void double_fault(struct abort_frame *frame)
-{
-       PANIC("double fault");
-}
-
diff --git a/kernel/arch/x86/irq/stub.s b/kernel/arch/x86/irq/stub.s
new file mode 100644 (file)
index 0000000..c15969a
--- /dev/null
@@ -0,0 +1,41 @@
+; Stubs for interrupt handlers
+
+bits 32
+section .text
+
+extern int_handler
+
+int_common:
+       cld
+       call int_handler
+       add esp, 4
+       popad
+       iretd
+
+%macro INTERRUPT 1
+global int%1
+int_%1:
+       pushad
+       push dword %1
+       jmp int_common
+%endmacro
+
+%assign i 0
+%rep 48
+INTERRUPT i
+%assign i i+1
+%endrep
+
+; Define flat table containing addresses of handlers
+section .rodata
+global _int_handler_table
+_int_handler_table:
+       %macro INT 1
+               dd int_%1
+       %endmacro
+
+       %assign i 0
+       %rep 48
+       INT i
+       %assign i i+1
+       %endrep
index daf586f2d5aefe44c723d5f38cb84290f0967472..501e5cd52034b544cbb085f5c71be4784186a599 100644 (file)
@@ -21,7 +21,7 @@ struct idtr {
        uint32_t base; /* starting address of IDT */
 } __attribute__((packed));
 
-extern void idt_set_descriptor(struct idt_descriptor *idt, uint8_t vector, uint16_t segment, uint32_t offset, uint8_t type, uint8_t dpl);
+extern void idt_set_descriptor(struct idt_descriptor *idt, uint8_t vector, uint16_t segment, void (*offset)(void), uint8_t type, uint8_t dpl);
 extern inline void load_idt(struct idtr idtr);
 extern inline void populate_idtr(struct idtr *idtr, struct idt_descriptor *idt);
 
diff --git a/kernel/include/arch/x86/irq/interrupt.h b/kernel/include/arch/x86/irq/interrupt.h
new file mode 100644 (file)
index 0000000..fbecdd8
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef X86_INTERRUPT_H
+#define X86_INTERRUPT_H
+
+extern int register_interrupt(int irq, int (*handler)(void));
+
+#endif
index 9257a0e9cdedc7a251d84912414f5591c9c87976..5a6a82d1d75b816e9efdee7eb3c7d3e151d4bdcf 100644 (file)
@@ -1,18 +1,14 @@
 #include <tty.h>
 #include <io.h>
 #include <irq/idt.h>
+#include <irq/interrupt.h>
 #include <irq/i8259a.h>
 #include <stdint.h>
 #include <mm/paging.h>
 
-struct abort_frame;
-struct interrupt_frame;
-struct fault_frame;
-extern void double_fault(struct abort_frame *frame);
-extern void keyb_handler(struct interrupt_frame *frame);
-extern void pf_handler(struct fault_frame *frame);
-static struct idt_descriptor idt[256] __attribute__((aligned(0x10)));
-static struct idtr idtr __attribute__((aligned(0x10)));
+struct idt_descriptor idt[256] __attribute__((aligned(0x10)));
+struct idtr idtr __attribute__((aligned(0x10)));
+extern void (*_int_handler_table[48])(void);
 
 struct e820_map {
        uint64_t base;
@@ -47,16 +43,15 @@ void kmain(struct e820_map *mmap, int mmap_size)
        kprint("BIOS memory map:\n", 0);
        print_e820(mmap, mmap_size);
        kprint("Preparing IDT...\n", 0);
-       idt_set_descriptor(idt, 8, 0x8, (uint32_t) double_fault, IDT_INTERRUPT_GATE, 0x0);
-       idt_set_descriptor(idt, 14, 0x8, (uint32_t) pf_handler, IDT_INTERRUPT_GATE, 0x0);
-       idt_set_descriptor(idt, 33, 0x8, (uint32_t) keyb_handler, IDT_INTERRUPT_GATE, 0x0);
+       for (int i=0; i<48; i++) {
+               idt_set_descriptor(idt, i, 0x8, _int_handler_table[i], IDT_INTERRUPT_GATE, 0);
+       }
        kprint("IDT prepared, loading...\n", 0);
        populate_idtr(&idtr, idt);
        load_idt(idtr);
-       kprint("IDT loaded, enabling interrupts...\n", 0);
+       kprint("Setting up interrupts...\n", 0);
        pic_init(0x20, 0x28);
        pic_mask_all();
-       pic_unmask(1);
        asm volatile ("sti");
        kprint("All done\n", 0);
        while(1);