From 880638202faa87a11049aaf89a690aa99ac835d2 Mon Sep 17 00:00:00 2001 From: keyboard-slayer Date: Sun, 10 Dec 2023 23:29:10 +0100 Subject: [PATCH] feat: idt --- src/kernel/archs/hal.h | 6 +- src/kernel/archs/x86_64/asm.h | 8 +++ src/kernel/archs/x86_64/handler.c | 112 ++++++++++++++++++++++++++++++ src/kernel/archs/x86_64/helper.s | 93 ++++++++++++++++++++++++- src/kernel/archs/x86_64/idt.c | 37 ++++++++++ src/kernel/archs/x86_64/idt.h | 41 +++++++++++ src/kernel/archs/x86_64/mod.c | 2 + src/kernel/archs/x86_64/regs.h | 31 +++++++++ src/kernel/core/main.c | 1 + 9 files changed, 329 insertions(+), 2 deletions(-) create mode 100644 src/kernel/archs/x86_64/asm.h create mode 100644 src/kernel/archs/x86_64/handler.c create mode 100644 src/kernel/archs/x86_64/idt.c create mode 100644 src/kernel/archs/x86_64/idt.h create mode 100644 src/kernel/archs/x86_64/regs.h diff --git a/src/kernel/archs/hal.h b/src/kernel/archs/hal.h index af009cb..ed0e21f 100644 --- a/src/kernel/archs/hal.h +++ b/src/kernel/archs/hal.h @@ -4,6 +4,10 @@ Res hal_setup(void); +/* --- Structs ------------------------------------------------------------ */ + +typedef struct _HalRegs HalRegs; + /* --- Assembly function --------------------------------------------------- */ void hal_disable_interrupts(void); @@ -16,4 +20,4 @@ void hal_panic(void); /* --- I/O ---------------------------------------------------------------- */ -Stream hal_dbg_stream(void); \ No newline at end of file +Stream hal_dbg_stream(void); diff --git a/src/kernel/archs/x86_64/asm.h b/src/kernel/archs/x86_64/asm.h new file mode 100644 index 0000000..bfc77bb --- /dev/null +++ b/src/kernel/archs/x86_64/asm.h @@ -0,0 +1,8 @@ +#pragma once + +#define asm_read_cr(n, reg) asm volatile("mov %%cr" #n ", %0" \ + : "=r"(reg)) + +#define asm_write_cr(n, reg) asm volatile("mov %0, %%cr" #n \ + : \ + : "r"(reg)) \ No newline at end of file diff --git a/src/kernel/archs/x86_64/handler.c b/src/kernel/archs/x86_64/handler.c new file mode 100644 index 0000000..9d8052f --- /dev/null +++ b/src/kernel/archs/x86_64/handler.c @@ -0,0 +1,112 @@ +#include +#include +#include + +#include "asm.h" +#include "regs.h" + +enum +{ + IRQ0 = 32, +}; + +static Spinlock lock = SPINLOCK_INIT; +static char *exception_messages[32] = { + "Division By Zero", + "Debug", + "Non Maskable Interrupt", + "Breakpoint", + "Detected Overflow", + "Out Of Bounds", + "Invalid Opcode", + "No Coprocessor", + "Double Fault", + "Coprocessor Segment Overrun", + "Bad Tss", + "Segment Not Present", + "StackFault", + "General Protection Fault", + "Page Fault", + "Unknown Interrupt", + "Coprocessor Fault", + "Alignment Check", + "Machine Check", + "SIMD Floating-Point Exception", + "Virtualization Exception", + "Control Protection Exception", + "Reserved", + "Hypervisor Injection Exception", + "VMM Communication Exception", + "Security Exception", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", +}; + +static void dump_backtrace(uintptr_t rbp) +{ + struct _StackFrame + { + struct _StackFrame *rbp; + uint64_t rip; + } *stackframe = (void *)rbp; + + for (;;) + { + if (stackframe->rip == 0) + { + break; + } + print$(" * %p\n", stackframe->rip); + stackframe = stackframe->rbp; + } +} + +static void kpanic(HalRegs const regs[static 1]) +{ + spinlock_acquire(&lock); + uint64_t cr0, cr2, cr3, cr4; + + asm_read_cr(0, cr0); + asm_read_cr(2, cr2); + asm_read_cr(3, cr3); + asm_read_cr(4, cr4); + + print$("\n!!! ---------------------------------------------------------------------------------------------------\n\n"); + print$(" KERNEL PANIC\n"); + print$(" %s was raised\n\n", exception_messages[regs->intno]); + print$(" Registers:\n"); + print$(" interrupt: %x, err: %x \n", regs->intno, regs->err); + print$(" RAX %p RBX %p RCX %p RDX %p\n", regs->rax, regs->rbx, regs->rcx, regs->rdx); + print$(" RSI %p RDI %p RBP %p RSP %p\n", regs->rsi, regs->rdi, regs->rbp, regs->rsp); + print$(" R8 %p R9 %p R10 %p R11 %p\n", regs->r8, regs->r9, regs->r10, regs->r11); + print$(" R12 %p R13 %p R14 %p R15 %p\n", regs->r12, regs->r13, regs->r14, regs->r15); + print$(" CR0 %p CR2 %p CR3 %p CR4 %p\n", cr0, cr2, cr3, cr4); + print$(" CS %p SS %p FLG %p\n", regs->cs, regs->ss, regs->rflags); + print$(" RIP \033[7m%p\033[0m\n\n", regs->rip); + print$(" Backtrace:\n"); + dump_backtrace(regs->rbp); + print$("--------------------------------------------------------------------------------------------------- !!!\n\n"); + spinlock_release(&lock); +} + +uintptr_t interrupt_handler(uintptr_t rsp) +{ + HalRegs *regs = (HalRegs *)rsp; + + if (regs->intno < IRQ0) + { + kpanic(regs); + + for (;;) + { + hal_disable_interrupts(); + hal_pause(); + } + } + + return rsp; +} \ No newline at end of file diff --git a/src/kernel/archs/x86_64/helper.s b/src/kernel/archs/x86_64/helper.s index 34f8df3..7b4a5f2 100644 --- a/src/kernel/archs/x86_64/helper.s +++ b/src/kernel/archs/x86_64/helper.s @@ -15,8 +15,99 @@ gdt_flush: push %rdi lretq - tss_flush: mov $0x28, %ax ltr %ax + ret + +.altmacro +.globl idt_flush +.globl __interrupts_vector +.extern interrupt_handler + +.macro INTERRUPT_NAME intno + .quad __interrupt\intno +.endm + +.macro INTERRUPT_ERR intno +__interrupt\intno: + pushq $\intno + jmp __interrupt_common +.endm + +.macro INTERRUPT_NOERR intno +__interrupt\intno: + pushq $0 + pushq $\intno + jmp __interrupt_common +.endm + +.macro __pusha + push %rax + push %rbx + push %rcx + push %rdx + push %rsi + push %rdi + push %rbp + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 +.endm + +.macro __popa + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rbp + pop %rdi + pop %rsi + pop %rdx + pop %rcx + pop %rbx + pop %rax +.endm + +__interrupt_common: + cld + __pusha + + movq %rsp, %rdi + call interrupt_handler + movq %rax, %rsp + + __popa + add $16, %rsp + iretq + +.set i,0 +.rept 48 + .if i != 8 && i != 10 && i != 11 && i != 12 && i != 13 && i != 14 && i != 17 && i != 30 + INTERRUPT_NOERR %i + .else + INTERRUPT_ERR %i + .endif + .set i,i+1 +.endr + +.align 8 +__interrupts_vector: +.set i,0 +.rept 48 + INTERRUPT_NAME %i + .set i,i+1 +.endr + +idt_flush: + lidt (%rdi) ret \ No newline at end of file diff --git a/src/kernel/archs/x86_64/idt.c b/src/kernel/archs/x86_64/idt.c new file mode 100644 index 0000000..be87667 --- /dev/null +++ b/src/kernel/archs/x86_64/idt.c @@ -0,0 +1,37 @@ +#include + +#include "gdt.h" +#include "idt.h" + +static Idt idt; +static IdtDescriptor idt_desc = { + .size = sizeof(idt) - 1, + .offset = (uintptr_t)&idt, +}; + +static void idt_init_entry(IdtEntry *self, uint64_t base, uint8_t type) +{ + self->offset_low = base & 0xFFFF; + self->offset_mid = (base >> 16) & 0xFFFF; + self->offset_high = (base >> 32) & 0xFFFFFFFF; + self->ist = 0; + self->selector = GDT_KERNEL_CODE * 8; + self->type_attr = IDT_INT_PRESENT | type; + self->zero = 0; +} + +uintptr_t idt_descriptor(void) +{ + return (uintptr_t)&idt_desc; +} + +void idt_init(void) +{ + for (size_t i = 0; i < IDT_ENTRY_COUNT; i++) + { + idt_init_entry(&idt.entries[i], __interrupts_vector[i], IDT_INT_GATE); + } + + idt_flush(idt_descriptor()); + log$("IDT lodaded"); +} \ No newline at end of file diff --git a/src/kernel/archs/x86_64/idt.h b/src/kernel/archs/x86_64/idt.h new file mode 100644 index 0000000..a271a08 --- /dev/null +++ b/src/kernel/archs/x86_64/idt.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#define IDT_ENTRY_COUNT (256) + +enum +{ + IDT_INT_PRESENT = (1 << 7), + IDT_INT_GATE = (0xe), +}; + +typedef struct [[gnu::packed]] +{ + uint16_t size; + uintptr_t offset; +} IdtDescriptor; + +typedef struct packed +{ + uint16_t offset_low; + uint16_t selector; + uint8_t ist; + uint8_t type_attr; + uint16_t offset_mid; + uint32_t offset_high; + uint32_t zero; +} IdtEntry; + +typedef struct [[gnu::packed]] +{ + IdtEntry entries[IDT_ENTRY_COUNT]; +} Idt; + +void idt_init(void); + +uintptr_t idt_descriptor(void); + +extern uintptr_t __interrupts_vector[]; + +extern void idt_flush(uintptr_t); \ No newline at end of file diff --git a/src/kernel/archs/x86_64/mod.c b/src/kernel/archs/x86_64/mod.c index 01d21a3..52349f7 100644 --- a/src/kernel/archs/x86_64/mod.c +++ b/src/kernel/archs/x86_64/mod.c @@ -4,6 +4,7 @@ #include "e9.h" #include "gdt.h" +#include "idt.h" Stream hal_dbg_stream(void) { @@ -15,5 +16,6 @@ Stream hal_dbg_stream(void) Res hal_setup(void) { gdt_init(); + idt_init(); return ok$(); } \ No newline at end of file diff --git a/src/kernel/archs/x86_64/regs.h b/src/kernel/archs/x86_64/regs.h new file mode 100644 index 0000000..b14e1e7 --- /dev/null +++ b/src/kernel/archs/x86_64/regs.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +struct [[gnu::packed]] _HalRegs +{ + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rbp; + uint64_t rdi; + uint64_t rsi; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t rax; + + uint64_t intno; + uint64_t err; + + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +}; \ No newline at end of file diff --git a/src/kernel/core/main.c b/src/kernel/core/main.c index eaea023..d1ab528 100644 --- a/src/kernel/core/main.c +++ b/src/kernel/core/main.c @@ -5,6 +5,7 @@ _Noreturn int _start() { log$("Hello, world!"); hal_setup(); + for (;;) ; } \ No newline at end of file