From 9fc1aa15ef90dea6925271a184438d8c2a73f0dd Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 17 May 2023 22:54:37 -0700 Subject: [PATCH] Add an interrupt descriptor table. Set up a very basic handler for divide by zero and general protection faults. --- zion/CMakeLists.txt | 2 ++ zion/common/gdt.cpp | 2 +- zion/debug/debug.cpp | 8 +++++ zion/debug/debug.h | 3 +- zion/interrupt/interrupt.cpp | 55 +++++++++++++++++++++++++++++++ zion/interrupt/interrupt.h | 3 ++ zion/interrupt/interrupt_enter.s | 56 ++++++++++++++++++++++++++++++++ zion/zion.cpp | 5 +++ 8 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 zion/interrupt/interrupt.cpp create mode 100644 zion/interrupt/interrupt.h create mode 100644 zion/interrupt/interrupt_enter.s diff --git a/zion/CMakeLists.txt b/zion/CMakeLists.txt index 3c0c5da..3877f64 100644 --- a/zion/CMakeLists.txt +++ b/zion/CMakeLists.txt @@ -2,6 +2,8 @@ add_executable(zion common/gdt.cpp common/load_gdt.s debug/debug.cpp + interrupt/interrupt.cpp + interrupt/interrupt_enter.s zion.cpp) target_include_directories(zion diff --git a/zion/common/gdt.cpp b/zion/common/gdt.cpp index a280d3a..2e0f7cf 100644 --- a/zion/common/gdt.cpp +++ b/zion/common/gdt.cpp @@ -80,7 +80,7 @@ void InitGdt() { GdtPointer gdtp{ .size = sizeof(gGdtSegments) - 1, - .base = reinterpret_cast(&gGdtSegments), + .base = reinterpret_cast(gGdtSegments), }; asm volatile("lgdt %0" ::"m"(gdtp)); diff --git a/zion/debug/debug.cpp b/zion/debug/debug.cpp index 856765e..406594f 100644 --- a/zion/debug/debug.cpp +++ b/zion/debug/debug.cpp @@ -11,3 +11,11 @@ void dbgln(const char* str) { } outb(COM1, '\n'); } + +void panic(const char* str) { + asm volatile("cli"); + dbgln(str); + dbgln("PANIC"); + while (1) + ; +} diff --git a/zion/debug/debug.h b/zion/debug/debug.h index 634a3b7..77341da 100644 --- a/zion/debug/debug.h +++ b/zion/debug/debug.h @@ -1,3 +1,4 @@ #pragma once -void dbgln(const char *str); +void dbgln(const char* str); +void panic(const char* str); diff --git a/zion/interrupt/interrupt.cpp b/zion/interrupt/interrupt.cpp new file mode 100644 index 0000000..06cc771 --- /dev/null +++ b/zion/interrupt/interrupt.cpp @@ -0,0 +1,55 @@ +#include "interrupt/interrupt.h" + +#include + +#include "debug/debug.h" + +#define IDT_INTERRUPT_GATE 0x8E + +#define KERNEL_CS 0x8 + +struct InterruptDescriptorTablePointer { + uint16_t size; + uint64_t base; +} __attribute__((packed)); + +struct InterruptDescriptor { + uint16_t offset_low; + uint16_t selector; + uint8_t ist; + uint8_t flags; + uint16_t offset_medium; + uint32_t offset_high; + uint32_t zero; +} __attribute__((packed)); + +static InterruptDescriptor gIdt[256]; + +InterruptDescriptor CreateDescriptor(void isr(void)) { + uint64_t offset = reinterpret_cast(isr); + return InterruptDescriptor{ + .offset_low = static_cast(offset), + .selector = KERNEL_CS, + .ist = 0, + .flags = IDT_INTERRUPT_GATE, + .offset_medium = static_cast(offset >> 16), + .offset_high = static_cast(offset >> 32), + .zero = 0x0, + }; +} + +extern "C" void isr_divide_by_zero(); +extern "C" void interrupt_divide_by_zero(void* frame) { panic("DIV0"); } + +extern "C" void isr_protection_fault(); +extern "C" void interrupt_protection_fault(void* frame) { panic("GP"); } + +void InitIdt() { + gIdt[0] = CreateDescriptor(isr_divide_by_zero); + gIdt[13] = CreateDescriptor(isr_protection_fault); + InterruptDescriptorTablePointer idtp{ + .size = sizeof(gIdt), + .base = reinterpret_cast(gIdt), + }; + asm volatile("lidt %0" ::"m"(idtp)); +} diff --git a/zion/interrupt/interrupt.h b/zion/interrupt/interrupt.h new file mode 100644 index 0000000..d6225ab --- /dev/null +++ b/zion/interrupt/interrupt.h @@ -0,0 +1,3 @@ +#pragma once + +void InitIdt(); diff --git a/zion/interrupt/interrupt_enter.s b/zion/interrupt/interrupt_enter.s new file mode 100644 index 0000000..f2563e4 --- /dev/null +++ b/zion/interrupt/interrupt_enter.s @@ -0,0 +1,56 @@ +.macro interrupt_enter + push %rbp + push %r15 + push %r14 + push %r13 + push %r12 + push %r11 + push %r10 + push %r9 + push %r8 + push %rdi + push %rsi + push %rdx + push %rcx # (Return Address) + push %rbx + push %rax +.endm + +.macro interrupt_exit + pop %rax + pop %rbx + pop %rcx + pop %rdx + pop %rsi + pop %rdi + pop %r8 + pop %r9 + pop %r10 + pop %r10 + pop %r10 + pop %r10 + pop %r10 + pop %r10 + pop %rbp + + add $8, %rsp # Remove error code. +.endm + +.macro isr_handler name error_code=0 +.global isr_\name +isr_\name: + .if \error_code + .else + push $0 # if we don't have an error code, equalize the stack. + .endif + interrupt_enter + sti + mov %rsp, %rdi + call interrupt_\name + cli + interrupt_exit + iretq +.endm + +isr_handler divide_by_zero +isr_handler protection_fault,1 diff --git a/zion/zion.cpp b/zion/zion.cpp index 37cb331..fe44dfc 100644 --- a/zion/zion.cpp +++ b/zion/zion.cpp @@ -2,11 +2,16 @@ #include "common/gdt.h" #include "debug/debug.h" +#include "interrupt/interrupt.h" extern "C" void zion() { dbgln("Hello World!"); InitGdt(); dbgln("New GDT Loaded!"); + InitIdt(); + dbgln("IDT Loaded!"); + uint64_t a = 11 / 0; + dbgln("Recovered"); while (1) ;