Add an interrupt descriptor table.

Set up a very basic handler for divide by zero and
general protection faults.
This commit is contained in:
Drew Galbraith 2023-05-17 22:54:37 -07:00
parent 3e1a1f7485
commit 9fc1aa15ef
8 changed files with 132 additions and 2 deletions

View File

@ -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

View File

@ -80,7 +80,7 @@ void InitGdt() {
GdtPointer gdtp{
.size = sizeof(gGdtSegments) - 1,
.base = reinterpret_cast<uint64_t>(&gGdtSegments),
.base = reinterpret_cast<uint64_t>(gGdtSegments),
};
asm volatile("lgdt %0" ::"m"(gdtp));

View File

@ -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)
;
}

View File

@ -1,3 +1,4 @@
#pragma once
void dbgln(const char *str);
void dbgln(const char* str);
void panic(const char* str);

View File

@ -0,0 +1,55 @@
#include "interrupt/interrupt.h"
#include <stdint.h>
#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<uint64_t>(isr);
return InterruptDescriptor{
.offset_low = static_cast<uint16_t>(offset),
.selector = KERNEL_CS,
.ist = 0,
.flags = IDT_INTERRUPT_GATE,
.offset_medium = static_cast<uint16_t>(offset >> 16),
.offset_high = static_cast<uint32_t>(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<uint64_t>(gIdt),
};
asm volatile("lidt %0" ::"m"(idtp));
}

View File

@ -0,0 +1,3 @@
#pragma once
void InitIdt();

View File

@ -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

View File

@ -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)
;