From 942adef65f4bdf5de78e7c01b9a8a45abf9cbf19 Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Sat, 8 Mar 2025 10:40:12 +0100 Subject: [PATCH] feat(IDT): IDT and exception handling support --- kernel/src/Common/Panic.cpp | 37 ++++++++- kernel/src/Common/Panic.hpp | 2 +- kernel/src/CppLib/Stream.cpp | 7 ++ kernel/src/CppLib/Stream.hpp | 1 + kernel/src/Hal/IDT.cpp | 129 ++++++++++++++++++++++++++++++ kernel/src/Hal/IDT.hpp | 27 +++++++ kernel/src/Memory/Memmap.cpp | 2 +- kernel/src/Platform/Registers.hpp | 37 ++++++++- kernel/src/main.cpp | 12 ++- 9 files changed, 245 insertions(+), 9 deletions(-) create mode 100644 kernel/src/Hal/IDT.cpp create mode 100644 kernel/src/Hal/IDT.hpp diff --git a/kernel/src/Common/Panic.cpp b/kernel/src/Common/Panic.cpp index 882e5b4..f122dd2 100644 --- a/kernel/src/Common/Panic.cpp +++ b/kernel/src/Common/Panic.cpp @@ -1,9 +1,40 @@ #include "Panic.hpp" -void Panic(const char *meditationString, System::Registers) { - kerr << "=========== Kernel panic ===========" << Kt::newline; - kerr << meditationString << Kt::newline; +void Panic(const char *meditationString, System::PanicFrame* frame) { + kerr << "\nGuru Meditation" << "\n" << "\n"; + + kerr << "\t" << "MeditationString: " << meditationString << Kt::newline; +#if defined (__x86_64__) + if (frame != nullptr) { + if (frame->InterruptVector == 0xE) { // In case of #PF the CPU pushes some other data to the frame + auto pf_frame = (System::PageFaultPanicFrame*)frame; + frame = (System::PanicFrame*)&pf_frame->IP; + + kerr << "\t" << "InterruptVector: " << "0x" << base::hex << 0xE << "\n"; + + /* Page fault error details */ + kerr << "\t" << "PageFaultPresent: " << base::dec << pf_frame->PageFaultError.Present << "\n"; + kerr << "\t" << "PageFaultWrite: " << base::dec << pf_frame->PageFaultError.Write << "\n"; + kerr << "\t" << "PageFaultUser: " << base::dec << pf_frame->PageFaultError.User << "\n"; + kerr << "\t" << "PageFaultReservedWrite: " << base::dec << pf_frame->PageFaultError.ReservedWrite << "\n"; + kerr << "\t" << "PageFaultInstructionFetch: " << base::dec << pf_frame->PageFaultError.InstructionFetch << "\n"; + kerr << "\t" << "PageFaultProtectionKey: " << base::dec << pf_frame->PageFaultError.ProtectionKey << "\n"; + kerr << "\t" << "PageFaultShadowStack: " << base::dec << pf_frame->PageFaultError.ShadowStack << "\n"; + kerr << "\t" << "PageFaultSGX: " << base::dec << pf_frame->PageFaultError.ShadowStack << "\n"; + } + else + { + kerr << "\t" << "InterruptVector: " << "0x" << base::hex << frame->InterruptVector << "\n"; + } + + kerr << "\t" << "InstructionPointer: " << "0x" << base::hex << frame->IP << "\n"; + kerr << "\t" << "CodeSegment: " << "0x" << base::hex << frame->CS << "\n"; + kerr << "\t" << "Flags: " << "0x" << base::hex << frame->Flags << "\n"; + kerr << "\t" << "StackPointer: " << "0x" << base::hex << frame->SP << "\n"; + kerr << "\t" << "StackSegment: " << "0x" << base::hex << frame->SS << "\n"; + } +#endif while (true) { #if defined (__x86_64__) asm ("cli"); diff --git a/kernel/src/Common/Panic.hpp b/kernel/src/Common/Panic.hpp index 62182a5..a6c52fc 100644 --- a/kernel/src/Common/Panic.hpp +++ b/kernel/src/Common/Panic.hpp @@ -2,4 +2,4 @@ #include #include -void Panic(const char *meditationString, System::Registers registers); \ No newline at end of file +void Panic(const char *meditationString, System::PanicFrame* frame); \ No newline at end of file diff --git a/kernel/src/CppLib/Stream.cpp b/kernel/src/CppLib/Stream.cpp index fc82737..d50e71c 100644 --- a/kernel/src/CppLib/Stream.cpp +++ b/kernel/src/CppLib/Stream.cpp @@ -50,6 +50,13 @@ kcp::cstringstream& kcp::cstringstream::operator<<(char* str) { return *this; } +kcp::cstringstream& kcp::cstringstream::operator<<(const char* str) { + *this << (char*)str; + + return *this; +} + + kcp::cstringstream& kcp::cstringstream::operator<<(int num) { char* out_str = Lib::int2basestr(num, current_base); diff --git a/kernel/src/CppLib/Stream.hpp b/kernel/src/CppLib/Stream.hpp index a1571e9..d54c143 100644 --- a/kernel/src/CppLib/Stream.hpp +++ b/kernel/src/CppLib/Stream.hpp @@ -31,6 +31,7 @@ namespace kcp { cstringstream& operator<<(char c); cstringstream& operator<<(char* str); + cstringstream& operator<<(const char* str); cstringstream& operator<<(int num); cstringstream& operator<<(uint32_t val); diff --git a/kernel/src/Hal/IDT.cpp b/kernel/src/Hal/IDT.cpp new file mode 100644 index 0000000..e073697 --- /dev/null +++ b/kernel/src/Hal/IDT.cpp @@ -0,0 +1,129 @@ +/* + * IDT.cpp + * Intel Interrupt Descriptor Table implementation + * Copyright (c) 2025 Daniel Hammer +*/ + +#include "IDT.hpp" + +#include +#include +#include +#include + +namespace Hal { + constexpr auto InterruptGate = 0x8E; + constexpr auto TrapGate = 0x8F; + + InterruptDescriptor* IDT; + IDTRStruct IDTR{}; + + const char* ExceptionStrings[] = { + "Division Error", + "Debug", + "Non-Maskable Interrupt", + "Breakpoint", + "Overflow", + "Bound Rage Exceeded", + "Invalid Opcode", + "Device Not Available", + "Double Fault", + "Coprocessor Segment Overrun", + "Invalid TSS", + "Segment Not Present", + "Stack-Segment Fault", + "General Protection Fault", + "Page Fault", + "Reserved", + "x87 Floating-Point Exception", + "Alignment Check", + "Machine Check", + "SMID Floating-Point Exception", + "Virtualization Exception", + "Control Protection Exception", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Hypervisor Injection Exception", + "VMM Communication Exception", + "Security Exception", + "Reserved" + }; + + template + __attribute__((interrupt)) void ExceptionHandler(System::PanicFrame* frame) + { + kcp::cstringstream stream; + stream << "Caught " << base::hex << "0x" << i << " " << ExceptionStrings[i] << " in kernel"; + + frame->InterruptVector = i; + + Panic(stream.cstr(), frame); + } + + void LoadIDT(IDTRStruct& idtr) { + asm("lidt %0" : : "m"(idtr)); + } + + InterruptDescriptor* GetInterruptDescriptor(size_t index) { + InterruptDescriptor* descriptor = (InterruptDescriptor*)(IDTR.Base + index * sizeof(InterruptDescriptor)); + return descriptor; + } + + uint64_t GetHandlerAddress(InterruptDescriptor* descriptor) { + uint64_t result{}; + + result |= (uint64_t)descriptor->Offset1; + result |= (uint64_t)descriptor->Offset2 << 16; + result |= (uint64_t)descriptor->Offset3 << 32; + + return result; + } + + void IDTEncodeInterrupt(size_t i, void* handler, uint8_t type_attr) { + uint64_t offset = (uint64_t)handler; + auto ptr = GetInterruptDescriptor(i); + + *ptr = InterruptDescriptor { + .Offset1 = (uint16_t)(offset & 0x000000000000ffff), + + .Selector = 0x08, + .IST = 0x00, + .TypeAttributes = type_attr, + + .Offset2 = (uint16_t)((offset & 0x00000000ffff0000) >> 16), + .Offset3 = (uint32_t)((offset & 0xffffffff00000000) >> 32), + + .Zero = 0x00 + }; + } + + template + struct SetHandler { + static void run() { + IDTEncodeInterrupt(I, (void*)&ExceptionHandler, TrapGate); + SetHandler::run(); + } + }; + + template + struct SetHandler {static void run() {}}; + + void IDTInitialize() { + IDT = (InterruptDescriptor*)Memory::g_heap->Request(4096); + IDTR.Limit = 0x0FF; + IDTR.Base = (uint64_t)&IDT; + + for (size_t i = 0; i < 32; i++) { + SetHandler<0, 31>::run(); + } + + kout << "[Hal] Created exception interrupt vectors" << "\n"; + + LoadIDT(IDTR); + + kout << "[Hal] Loaded new IDT" << "\n"; + } +}; \ No newline at end of file diff --git a/kernel/src/Hal/IDT.hpp b/kernel/src/Hal/IDT.hpp new file mode 100644 index 0000000..d54499a --- /dev/null +++ b/kernel/src/Hal/IDT.hpp @@ -0,0 +1,27 @@ +/* + * IDT.hpp + * Intel Interrupt Descriptor Table implementation + * Copyright (c) 2025 Daniel Hammer +*/ + +#pragma once +#include + +namespace Hal { + struct InterruptDescriptor { + uint16_t Offset1; + uint16_t Selector; + uint8_t IST; + uint8_t TypeAttributes; + uint16_t Offset2; + uint32_t Offset3; + uint32_t Zero; + }__attribute__((packed)); + + struct IDTRStruct { + uint16_t Limit; + uint64_t Base; + }__attribute__((packed)); + + void IDTInitialize(); +}; \ No newline at end of file diff --git a/kernel/src/Memory/Memmap.cpp b/kernel/src/Memory/Memmap.cpp index e1361a7..15937ff 100644 --- a/kernel/src/Memory/Memmap.cpp +++ b/kernel/src/Memory/Memmap.cpp @@ -30,7 +30,7 @@ namespace Memory { } [[unlikely]] if (currentLargestSection.address == 0) { - Panic("Couldn't find a usable memory section.", System::Registers{}); + Panic("Couldn't find a usable memory section.", nullptr); } return currentLargestSection; diff --git a/kernel/src/Platform/Registers.hpp b/kernel/src/Platform/Registers.hpp index d02e631..5da1bf1 100644 --- a/kernel/src/Platform/Registers.hpp +++ b/kernel/src/Platform/Registers.hpp @@ -5,8 +5,39 @@ using namespace std; #if defined (__x86_64__) namespace System { - struct Registers { - - }; + struct PanicFrame { + uint64_t IP; + uint64_t CS; + uint64_t Flags; + uint64_t SP; + uint64_t SS; + + uint8_t InterruptVector; + }__attribute__((packed)); + + struct PageFaultErrorCode { + uint8_t Present : 1; + uint8_t Write : 1; + uint8_t User : 1; + uint8_t ReservedWrite : 1; + uint8_t InstructionFetch : 1; + uint8_t ProtectionKey : 1; + uint8_t ShadowStack : 1; + uint8_t SGX : 1; + + uint64_t Reserved : 56; + }__attribute__((packed)); + + struct PageFaultPanicFrame { + PageFaultErrorCode PageFaultError; + uint64_t IP; + uint64_t CS; + uint64_t Flags; + uint64_t SP; + uint64_t SS; + + uint8_t InterruptVector; + }__attribute__((packed)); + }; #endif \ No newline at end of file diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 971b6f3..a63b5ec 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -22,6 +22,8 @@ #include #include +#include + using namespace Kt; namespace Memory { @@ -87,8 +89,16 @@ extern "C" void kmain() { Memory::g_heap = &allocator; } else { - Panic("Guru Meditation Error: System memory map missing!", System::Registers{}); + Panic("Guru Meditation Error: System memory map missing!", nullptr); } +#if defined (__x86_64__) + Hal::IDTInitialize(); +#endif + + int*x =(int*)0xffffffff; + + *x=0; + hcf(); }