From 1bf5e324005ce7122a195af106cec656960648dc Mon Sep 17 00:00:00 2001 From: dzwdz Date: Sat, 10 Jul 2021 17:41:32 +0200 Subject: a sensible source structure The idea is that src/kernel/ is only allowed to interface with the hardware using whatever's defined in src/arch/generic.h. I'll probably write a small script for checking this later on. This is a giant commit so I've probably fucked something up. It boots fine on Bochs and QEMU, so at least there's that. --- src/arch/i386/interrupts/idt.c | 75 ++++++++++++++++++++++++++++++++++++++++++ src/arch/i386/interrupts/idt.h | 3 ++ src/arch/i386/interrupts/isr.c | 24 ++++++++++++++ src/arch/i386/interrupts/isr.h | 15 +++++++++ 4 files changed, 117 insertions(+) create mode 100644 src/arch/i386/interrupts/idt.c create mode 100644 src/arch/i386/interrupts/idt.h create mode 100644 src/arch/i386/interrupts/isr.c create mode 100644 src/arch/i386/interrupts/isr.h (limited to 'src/arch/i386/interrupts') diff --git a/src/arch/i386/interrupts/idt.c b/src/arch/i386/interrupts/idt.c new file mode 100644 index 0000000..4e23118 --- /dev/null +++ b/src/arch/i386/interrupts/idt.c @@ -0,0 +1,75 @@ +#include +#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(0x08, false, isr_double_fault); + idt_add(0x0d, false, isr_general_protection_fault); + idt_add(0x34, false, isr_test_interrupt); +} + +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"); + if (!isr_test_interrupt_called) panic(); +} + +void idt_init() { + idt_prepare(); + idt_load(); + idt_test(); +} diff --git a/src/arch/i386/interrupts/idt.h b/src/arch/i386/interrupts/idt.h new file mode 100644 index 0000000..5627657 --- /dev/null +++ b/src/arch/i386/interrupts/idt.h @@ -0,0 +1,3 @@ +#pragma once + +void idt_init(); diff --git a/src/arch/i386/interrupts/isr.c b/src/arch/i386/interrupts/isr.c new file mode 100644 index 0000000..03399ea --- /dev/null +++ b/src/arch/i386/interrupts/isr.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#include + +bool isr_test_interrupt_called = false; + +__attribute__((interrupt)) +void isr_double_fault(struct interrupt_frame *frame) { + tty_const("#DF"); + panic(); +} + +__attribute__((interrupt)) +void isr_general_protection_fault(struct interrupt_frame *frame) { + tty_const("#GP"); + panic(); +} + +__attribute__((interrupt)) +void isr_test_interrupt(struct interrupt_frame *frame) { + isr_test_interrupt_called = true; +} diff --git a/src/arch/i386/interrupts/isr.h b/src/arch/i386/interrupts/isr.h new file mode 100644 index 0000000..150fc46 --- /dev/null +++ b/src/arch/i386/interrupts/isr.h @@ -0,0 +1,15 @@ +#pragma once +#include + +struct interrupt_frame; + +extern bool isr_test_interrupt_called; // used in the self-test in idt.c + +__attribute__((interrupt)) +void isr_double_fault(struct interrupt_frame *frame); + +__attribute__((interrupt)) +void isr_general_protection_fault(struct interrupt_frame *frame); + +__attribute__((interrupt)) +void isr_test_interrupt(struct interrupt_frame *frame); -- cgit v1.2.3