diff --git a/kernel/src/CppLib/CString.cpp b/kernel/src/CppLib/CString.cpp index 91e1edd..0cec721 100644 --- a/kernel/src/CppLib/CString.cpp +++ b/kernel/src/CppLib/CString.cpp @@ -15,7 +15,7 @@ namespace kcp { vector result; cstringstream current_stream = cstringstream(); - do { + while (true) { if (*str == delimiter || *str == '\0') { auto cstr = current_stream.c_str(); auto cstr_len = Lib::strlen(cstr); @@ -35,7 +35,7 @@ namespace kcp { current_stream << (char)*str; str++; - } while (*str != '\0'); + }; return result; } diff --git a/kernel/src/CppLib/Stream.cpp b/kernel/src/CppLib/Stream.cpp index 5a76daf..59f0688 100644 --- a/kernel/src/CppLib/Stream.cpp +++ b/kernel/src/CppLib/Stream.cpp @@ -25,7 +25,7 @@ kcp::cstringstream& kcp::cstringstream::operator<<(char c) { if (this->string == nullptr) { - kerr << "kcp::cstringstream: Streaming failed due to failed allocation" << Kt::newline; + Kt::KernelLogStream(Kt::ERROR, "kcp::cstringstream") << "Character streaming failed due to failed allocation."; return *this; } diff --git a/kernel/src/Hal/GDT.cpp b/kernel/src/Hal/GDT.cpp index febd462..2028a41 100644 --- a/kernel/src/Hal/GDT.cpp +++ b/kernel/src/Hal/GDT.cpp @@ -1,12 +1,12 @@ /* * gdt.hpp + * Intel Global Descriptor Table + * Copyright (c) 2025 Daniel Hammer */ #include "GDT.hpp" #include "../Terminal/Terminal.hpp" -// Limine loads a GDT of course, (CS = 0x28) but we will need to make a TSS someday... therefore we load our own now - namespace Hal { using namespace Kt; @@ -14,39 +14,14 @@ namespace Hal { BasicGDT kernelGDT{}; void PrepareGDT() { - kout << "HardwareAbstraction: GDT at " << base::hex << (uint64_t)&kernelGDT << "\n"; kernelGDT = { - // Code segment offset 0x08 - // Data segment offset 0x10 - - // Not sure if having LimitLow set to 0xFFFF for the Null segment is kosher - {0xFFFF, 0, 0, 0x00, 0x00, 0}, - - // Kernel code/data + {0xFFFF, 0, 0, 0x00, 0x00, 0}, + {0xFFFF, 0, 0, 0x9A, 0xA0, 0}, + {0xFFFF, 0, 0, 0x92, 0xA0, 0}, {0xFFFF, 0, 0, 0x9A, 0xA0, 0}, {0xFFFF, 0, 0, 0x92, 0xA0, 0}, - - // User code/data - {0xFFFF, 0, 0, 0x9A, 0xA0, 0}, - {0xFFFF, 0, 0, 0x92, 0xA0, 0}, - - // One day this will point to our actual TSS - { - // Limit = sizeof(TSS) - 1 - 0, - - // Base = &TSS - 0, - 0, - - // Access byte = 0xFA - 0xFA, - - // Granularity = 0x00 - 0x00, - - 0x0 - } + + {0, 0, 0, 0xFA, 0x00, 0x0}, }; gdtPointer = GDTPointer{ @@ -60,11 +35,9 @@ namespace Hal { extern "C" void ReloadSegments(); void BridgeLoadGDT() { - // Puts the GDT pointer structure into the GDTR - kout << "HardwareAbstraction: Setting GDTR" << Kt::newline; LoadGDT(&gdtPointer); - - kout << "HardwareAbstraction: Reloading segments" << Kt::newline; ReloadSegments(); + + KernelLogStream(DEBUG, "HardwareAbstraction") << "Set new GDT (0x" << base::hex << (uint64_t)&kernelGDT << ")"; } }; \ No newline at end of file diff --git a/kernel/src/Hal/GDT.hpp b/kernel/src/Hal/GDT.hpp index 1531701..cdbd300 100644 --- a/kernel/src/Hal/GDT.hpp +++ b/kernel/src/Hal/GDT.hpp @@ -1,5 +1,6 @@ /* * gdt.hpp + * Intel Global Descriptor Table * Copyright (c) 2025 Daniel Hammer */ @@ -8,50 +9,28 @@ using namespace std; -// __attribute__((packed)) is the GCC extensions way of telling the compiler to ensure that it doesn't mess with these structures or add packing bytes -// for optimization because that would easily result in a triple fault. - namespace Hal { class GDTEntry { public: - // Base/Limit are obsolete in Long mode because segmentation is no longer used - // Sadly we must still build and load the GDT during kernel init - uint16_t LimitLow; uint16_t BaseLow; uint8_t BaseMiddle; - - // Determine which processor rings this segment can be used in uint8_t AccessByte; - // Lower 4 bits are the higher 4 bits of limit uint8_t GranularityByte; - - uint8_t BaseHigh; - - // 16 + 16 + 8 + 8 = 48 bits + uint8_t BaseHigh; }__attribute__((packed)); struct BasicGDT { - // Conventionally the first entry of the GDT has all values zeroed out. - GDTEntry Null; - - // Kernel code segment descriptor - GDTEntry KernelCode; - - // Kernel data segment descriptor - GDTEntry KernelData; - - // UM code segment descriptor - GDTEntry UserCode; - - // UM data segment descriptor + GDTEntry Null; + GDTEntry KernelCode; + GDTEntry KernelData; + GDTEntry UserCode; GDTEntry UserData; // Task State Segment GDTEntry TSS; }__attribute__((packed)); - // Simple structure that tells the CPU the size of the GDT, and it's address struct GDTPointer { uint16_t Size; uint64_t GDTAddress; diff --git a/kernel/src/Hal/IDT.cpp b/kernel/src/Hal/IDT.cpp index 4b58437..eccad21 100644 --- a/kernel/src/Hal/IDT.cpp +++ b/kernel/src/Hal/IDT.cpp @@ -56,11 +56,7 @@ namespace Hal { 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(ExceptionStrings[i], frame); } @@ -119,10 +115,10 @@ namespace Hal { SetHandler<0, 31>::run(); - kout << "HardwareAbstraction: Created exception interrupt vectors" << "\n"; + Kt::KernelLogStream(Kt::OK, "HardwareAbstraction") << "Created exception interrupt vectors"; LoadIDT(IDTR); - kout << "HardwareAbstraction: Loaded new IDT" << "\n"; + Kt::KernelLogStream(Kt::OK, "HardwareAbstraction") << "Loaded new IDT"; } }; \ No newline at end of file diff --git a/kernel/src/Main.cpp b/kernel/src/Main.cpp index 6d947e7..ee89697 100644 --- a/kernel/src/Main.cpp +++ b/kernel/src/Main.cpp @@ -29,6 +29,7 @@ #include #include +#include using namespace Kt; @@ -47,7 +48,7 @@ extern void (*__init_array_end[])(); extern "C" void kmain() { if (LIMINE_BASE_REVISION_SUPPORTED == false) { - hcf(); + Hal::Halt(); } // Call global constructors. @@ -57,7 +58,7 @@ extern "C" void kmain() { if (framebuffer_request.response == nullptr || framebuffer_request.response->framebuffer_count < 1) { - hcf(); + Hal::Halt(); } limine_framebuffer *framebuffer{framebuffer_request.response->framebuffers[0]}; @@ -84,11 +85,12 @@ extern "C" void kmain() { Memory::HHDMBase = hhdm_offset; if (memmap_request.response != nullptr) { - kout << "MemoryManagement: Creating global PageFrameAllocator" << newline; + Kt::KernelLogStream(OK, "MemoryManagement") << "Creating PageFrameAllocator"; Memory::PageFrameAllocator pmm(Memory::Scan(memmap_request.response)); Memory::g_pfa = &pmm; + Kt::KernelLogStream(OK, "MemoryManagement") << "Creating HeapAllocator"; Memory::HeapAllocator heap{}; Memory::g_heap = &heap; @@ -102,5 +104,5 @@ extern "C" void kmain() { Hal::IDTInitialize(); #endif - hcf(); + Hal::Halt(); } diff --git a/kernel/src/Memory/Heap.cpp b/kernel/src/Memory/Heap.cpp index 8b58744..935ecab 100644 --- a/kernel/src/Memory/Heap.cpp +++ b/kernel/src/Memory/Heap.cpp @@ -51,10 +51,12 @@ namespace Memory HeapAllocator::HeapAllocator() { - InsertPagesToFreelist(8); + InsertPagesToFreelist(0x32); } void* HeapAllocator::Request(size_t size) { + Lock.Acquire(); + Node* current = head.next; Node* prev = &head; @@ -79,12 +81,15 @@ namespace Memory InsertToFreelist(rest, newBlockSize); } - + + Lock.Release(); return block; } prev = current; current = current->next; + + Lock.Release(); } // First pass allocation failed @@ -106,6 +111,8 @@ namespace Memory } void HeapAllocator::Free(void* ptr) { + Lock.Acquire(); + Header* header = GetHeader(ptr); auto size = header->size; @@ -113,11 +120,13 @@ namespace Memory Panic("Bad magic in HeapAllocator header", nullptr); return; } - + auto actualSize = size + sizeof(Header); void* actualBlock = (void*)header; - InsertToFreelist(actualBlock, size); + InsertToFreelist(actualBlock, size); + + Lock.Release(); } // Traverses the Allocator's linked list for debugging @@ -126,7 +135,7 @@ namespace Memory size_t i{0}; while (current != nullptr) { - kout << "HeapAllocator: " << base::dec << i << " " << current->size << " bytes & address 0x" << base::hex << (uint64_t)current << Kt::newline; + Kt::KernelLogStream(Kt::DEBUG, "HeapAllocator") << base::dec << i << " " << current->size << " bytes & address 0x" << base::hex << (uint64_t)current; current = current->next; i++; } diff --git a/kernel/src/Memory/Heap.hpp b/kernel/src/Memory/Heap.hpp index 6db3278..f80fad0 100644 --- a/kernel/src/Memory/Heap.hpp +++ b/kernel/src/Memory/Heap.hpp @@ -1,9 +1,11 @@ #pragma once #include "Memmap.hpp" +#include namespace Memory { class HeapAllocator { static constexpr std::size_t headerMagic = 0x6CEF9AB4; + kcp::Spinlock Lock; struct Node { size_t size; diff --git a/kernel/src/Memory/Memmap.cpp b/kernel/src/Memory/Memmap.cpp index 5429c61..b015f25 100644 --- a/kernel/src/Memory/Memmap.cpp +++ b/kernel/src/Memory/Memmap.cpp @@ -18,8 +18,6 @@ namespace Memory { } if (entry->type == LIMINE_MEMMAP_USABLE) { - kout << "MemoryManagement: Found conventional memory section (size = " << base::dec << entry->length << " bytes, address = 0x" << base::hex << (uint64_t)entry->base << ")" << newline; - if (entry->length > currentLargestSection.size) { currentLargestSection = { .address = (uint64_t)entry->base, diff --git a/kernel/src/Memory/PageFrameAllocator.cpp b/kernel/src/Memory/PageFrameAllocator.cpp index 6815058..e323a83 100644 --- a/kernel/src/Memory/PageFrameAllocator.cpp +++ b/kernel/src/Memory/PageFrameAllocator.cpp @@ -22,6 +22,8 @@ namespace Memory { head.next = (Page*)g_section.address; head.next->size = section.size; head.next->next = nullptr; + + Kt::KernelLogStream(Kt::DEBUG, "PageFrameAllocator") << "New pool size: " << section.size; } void* PageFrameAllocator::Allocate() { diff --git a/kernel/src/Platform/ABI.cpp b/kernel/src/Platform/ABI.cpp index 9cee3f3..5f67128 100644 --- a/kernel/src/Platform/ABI.cpp +++ b/kernel/src/Platform/ABI.cpp @@ -12,6 +12,6 @@ // but should not be removed, unless you know what you are doing. extern "C" { int __cxa_atexit(void (*)(void *), void *, void *) { return 0; } - void __cxa_pure_virtual() { hcf(); } + void __cxa_pure_virtual() { Hal::Halt(); } void *__dso_handle; } diff --git a/kernel/src/Platform/Util.cpp b/kernel/src/Platform/Util.cpp index 87b1650..bb741b6 100644 --- a/kernel/src/Platform/Util.cpp +++ b/kernel/src/Platform/Util.cpp @@ -5,16 +5,18 @@ */ // Halt and catch fire function. -void hcf() -{ - for (;;) +namespace Hal { + __attribute__((noreturn)) void Halt() { -#if defined(__x86_64__) - asm("hlt"); -#elif defined(__aarch64__) || defined(__riscv) - asm("wfi"); -#elif defined(__loongarch64) - asm("idle 0"); -#endif + for (;;) + { + #if defined(__x86_64__) + asm("hlt"); + #elif defined(__aarch64__) || defined(__riscv) + asm("wfi"); + #elif defined(__loongarch64) + asm("idle 0"); + #endif + } } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/kernel/src/Platform/Util.hpp b/kernel/src/Platform/Util.hpp index 5dfe812..9aa9ca1 100644 --- a/kernel/src/Platform/Util.hpp +++ b/kernel/src/Platform/Util.hpp @@ -7,4 +7,6 @@ #pragma once // Halt and catch fire function. -void hcf(); \ No newline at end of file +namespace Hal { + __attribute__((noreturn)) void Halt(); +}; \ No newline at end of file diff --git a/kernel/src/Terminal/Terminal.hpp b/kernel/src/Terminal/Terminal.hpp index 4cfe8d9..8ab6d68 100644 --- a/kernel/src/Terminal/Terminal.hpp +++ b/kernel/src/Terminal/Terminal.hpp @@ -15,8 +15,20 @@ namespace Kt { constexpr const char *clear = "\033[2J"; constexpr const char *cursor_reset = "\033[H"; - }; + namespace colors { + constexpr const char* black = "\u001b[30m"; + constexpr const char* red = "\u001b[31m"; + constexpr const char* green = "\u001b[32m"; + constexpr const char* blue = "\u001b[34m"; + constexpr const char* cyan = "\u001b[36m"; + constexpr const char* yellow = "\u001b[33m"; + constexpr const char* magenta = "\u001b[35m"; + + constexpr const char* white = "\u001b[37m"; + }; + }; + void Initialize(std::uint32_t *framebuffer, std::size_t width, std::size_t height, std::size_t pitch, std::uint8_t red_mask_size, std::uint8_t red_mask_shift, std::uint8_t green_mask_size, std::uint8_t green_mask_shift, @@ -77,7 +89,67 @@ namespace Kt } }; - // This will be on the kernel entry point's stack. Which is totally fine since we don't ever exit from that function + enum KernelLogLevel { + INFO, + WARNING, + ERROR, + DEBUG, + OK + }; + + class KernelLogStream { + KernelOutStream localStream{}; + KernelLogLevel level; + + const char* componentName = ""; + +public: + KernelLogStream(KernelLogLevel desiredLevel, const char* desiredComponentName) { + level = desiredLevel; + componentName = desiredComponentName; + + switch (level) { + case INFO: { + localStream << screen::colors::cyan << "INFO " << screen::colors::white; + break; + } + + case WARNING: { + localStream << screen::colors::yellow << "WARNING " << screen::colors::white; + break; + } + + case ERROR: { + localStream << screen::colors::red << "ERROR " << screen::colors::white; + break; + } + + case DEBUG: { + localStream << screen::colors::magenta << "DEBUG " << screen::colors::white; + break; + } + + case OK: { + localStream << screen::colors::green << "OK " << screen::colors::white; + break ; + } + } + + localStream << componentName << ": "; + } + + ~KernelLogStream() { + localStream << newline; + } + + template + KernelLogStream &operator<<(T item) { + localStream << item; + + return *this; + } + }; + }; extern Kt::KernelOutStream kout;