From 79dbeb367cc7b39e965c052ebb62076a2118c54c Mon Sep 17 00:00:00 2001 From: dzwdz Date: Fri, 9 Jul 2021 16:13:38 +0200 Subject: basic interrupt support --- kernel/idt.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/idt.h | 3 +++ kernel/isr.c | 9 ++++++++ kernel/isr.h | 6 +++++ kernel/main.c | 2 ++ 5 files changed, 91 insertions(+) create mode 100644 kernel/idt.c create mode 100644 kernel/idt.h create mode 100644 kernel/isr.c create mode 100644 kernel/isr.h (limited to 'kernel') diff --git a/kernel/idt.c b/kernel/idt.c new file mode 100644 index 0000000..e1d45b9 --- /dev/null +++ b/kernel/idt.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include + +struct idt_entry { + uint16_t offset_low ; + uint16_t code_seg ; + uint8_t zero ; // unused, has to be 0 + uint8_t type : 4; // 16/32 bit, task/interrupt/task gate + uint8_t storage : 1; // 0 for interrupt/trap gates + uint8_t ring : 2; + uint8_t present : 1; + uint16_t offset_high ; +} __attribute__((packed)); + +// is exactly the same as lgdt_arg, i should combine them into a single struct +// later +struct lidt_arg { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); + + +static struct idt_entry IDT[256]; +static struct lidt_arg lidt_arg; + +static inline void idt_add(uint8_t num, bool user, void (*isr)); +static void idt_prepare(); +static void idt_load(); +static void idt_test(); + + +static inline void idt_add(uint8_t num, bool user, void (*isr)) { + uintptr_t offset = (uintptr_t) isr; + + IDT[num] = (struct idt_entry) { + .offset_low = offset, + .offset_high = offset >> 16, + .code_seg = SEG_r0code << 3, + .zero = 0, + .present = 1, + .ring = user ? 3 : 0, + .storage = 0, + .type = 0xE, // 32-bit interrupt gate + }; +} + +static void idt_prepare() { + for (int i = 0; i < 256; i++) + IDT[i].present = 0; + + idt_add(0x8, false, isr_double_fault); +} + +static void idt_load() { + lidt_arg.limit = sizeof(IDT) - 1; + lidt_arg.base = (uintptr_t) &IDT; + asm("lidt (%0)" : : "r" (&lidt_arg) : "memory"); +} + +static void idt_test() { + asm("int $0x34" : : : "memory"); +} + +void idt_init() { + idt_prepare(); + idt_load(); + idt_test(); +} diff --git a/kernel/idt.h b/kernel/idt.h new file mode 100644 index 0000000..5627657 --- /dev/null +++ b/kernel/idt.h @@ -0,0 +1,3 @@ +#pragma once + +void idt_init(); diff --git a/kernel/isr.c b/kernel/isr.c new file mode 100644 index 0000000..69c688b --- /dev/null +++ b/kernel/isr.c @@ -0,0 +1,9 @@ +#include +#include +#include + +__attribute__((interrupt)) +void isr_double_fault(struct interrupt_frame *frame) { + tty_const("#DF"); + for(;;); +} diff --git a/kernel/isr.h b/kernel/isr.h new file mode 100644 index 0000000..7230986 --- /dev/null +++ b/kernel/isr.h @@ -0,0 +1,6 @@ +#pragma once + +struct interrupt_frame; + +__attribute__((interrupt)) +void isr_double_fault(struct interrupt_frame *frame); diff --git a/kernel/main.c b/kernel/main.c index 5c2c5e8..bc1e0d3 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -10,6 +11,7 @@ void kmain() { tty_clear(); gdt_init(); + idt_init(); sysenter_setup(); mem_init(); -- cgit v1.2.3