diff options
author | dzwdz | 2021-07-09 16:13:38 +0200 |
---|---|---|
committer | dzwdz | 2021-07-09 16:13:38 +0200 |
commit | 79dbeb367cc7b39e965c052ebb62076a2118c54c (patch) | |
tree | 23651a0ea6abbe9d9cbc4968a35e0ab317911185 | |
parent | 9b851331995c84f9548eba05e51b47656cb83deb (diff) |
basic interrupt support
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | kernel/idt.c | 71 | ||||
-rw-r--r-- | kernel/idt.h | 3 | ||||
-rw-r--r-- | kernel/isr.c | 9 | ||||
-rw-r--r-- | kernel/isr.h | 6 | ||||
-rw-r--r-- | kernel/main.c | 2 |
6 files changed, 92 insertions, 0 deletions
@@ -1,6 +1,7 @@ AS = i686-elf-as CC = i686-elf-gcc CFLAGS = -std=gnu99 -ffreestanding -O2 -Wall -Wextra +CFLAGS += -mgeneral-regs-only CFLAGS += -I. LFLAGS = -ffreestanding -O2 -nostdlib -lgcc QFLAGS = -no-reboot -d guest_errors,int,pcall,cpu_reset 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 <kernel/gdt.h> +#include <kernel/idt.h> +#include <kernel/isr.h> +#include <stdbool.h> +#include <stdint.h> + +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 <kernel/isr.h> +#include <kernel/tty.h> +#include <stdint.h> + +__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 <kernel/gdt.h> +#include <kernel/idt.h> #include <kernel/mem.h> #include <kernel/proc.h> #include <kernel/tty.h> @@ -10,6 +11,7 @@ void kmain() { tty_clear(); gdt_init(); + idt_init(); sysenter_setup(); mem_init(); |