From 3542affaeda7df7b886cd8a9681b65d7a0b4a737 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Duje=20Mihanovi=C4=87?= Date: Mon, 13 Jun 2022 11:41:50 +0200 Subject: [PATCH] Rework interrupt handling This new system should, among other things, allow for more flexibility than the previous one. TODO: Define interrupt stack frame --- Makefile | 2 +- kernel/arch/x86/irq/idt.c | 6 +-- kernel/arch/x86/irq/interrupt.c | 36 ++++++++++++++ kernel/arch/x86/irq/sample_handler.c | 63 ------------------------- kernel/arch/x86/irq/stub.s | 41 ++++++++++++++++ kernel/include/arch/x86/irq/idt.h | 2 +- kernel/include/arch/x86/irq/interrupt.h | 6 +++ kernel/kernel.c | 21 ++++----- 8 files changed, 96 insertions(+), 81 deletions(-) create mode 100644 kernel/arch/x86/irq/interrupt.c delete mode 100644 kernel/arch/x86/irq/sample_handler.c create mode 100644 kernel/arch/x86/irq/stub.s create mode 100644 kernel/include/arch/x86/irq/interrupt.h diff --git a/Makefile b/Makefile index f254d0c..c351093 100644 --- 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 diff --git a/kernel/arch/x86/irq/idt.c b/kernel/arch/x86/irq/idt.c index 54e8612..3871751 100644 --- a/kernel/arch/x86/irq/idt.c +++ b/kernel/arch/x86/irq/idt.c @@ -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 index 0000000..b2abef9 --- /dev/null +++ b/kernel/arch/x86/irq/interrupt.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include + +/* 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 index 5b0e2d4..0000000 --- a/kernel/arch/x86/irq/sample_handler.c +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include -#include -#include -#include -#include - -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 index 0000000..c15969a --- /dev/null +++ b/kernel/arch/x86/irq/stub.s @@ -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 diff --git a/kernel/include/arch/x86/irq/idt.h b/kernel/include/arch/x86/irq/idt.h index daf586f..501e5cd 100644 --- a/kernel/include/arch/x86/irq/idt.h +++ b/kernel/include/arch/x86/irq/idt.h @@ -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 index 0000000..fbecdd8 --- /dev/null +++ b/kernel/include/arch/x86/irq/interrupt.h @@ -0,0 +1,6 @@ +#ifndef X86_INTERRUPT_H +#define X86_INTERRUPT_H + +extern int register_interrupt(int irq, int (*handler)(void)); + +#endif diff --git a/kernel/kernel.c b/kernel/kernel.c index 9257a0e..5a6a82d 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -1,18 +1,14 @@ #include #include #include +#include #include #include #include -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); -- 2.39.5