feat: Various improvements

This commit is contained in:
Daniel Hammer
2025-04-16 10:32:11 +02:00
parent 35cf3f7c80
commit fcd81be1c5
14 changed files with 135 additions and 98 deletions
+2 -2
View File
@@ -15,7 +15,7 @@ namespace kcp {
vector<const char*> result; vector<const char*> result;
cstringstream current_stream = cstringstream(); cstringstream current_stream = cstringstream();
do { while (true) {
if (*str == delimiter || *str == '\0') { if (*str == delimiter || *str == '\0') {
auto cstr = current_stream.c_str(); auto cstr = current_stream.c_str();
auto cstr_len = Lib::strlen(cstr); auto cstr_len = Lib::strlen(cstr);
@@ -35,7 +35,7 @@ namespace kcp {
current_stream << (char)*str; current_stream << (char)*str;
str++; str++;
} while (*str != '\0'); };
return result; return result;
} }
+1 -1
View File
@@ -25,7 +25,7 @@ kcp::cstringstream& kcp::cstringstream::operator<<(char c) {
if (this->string == nullptr) 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; return *this;
} }
+7 -34
View File
@@ -1,12 +1,12 @@
/* /*
* gdt.hpp * gdt.hpp
* Intel Global Descriptor Table
* Copyright (c) 2025 Daniel Hammer
*/ */
#include "GDT.hpp" #include "GDT.hpp"
#include "../Terminal/Terminal.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 { namespace Hal {
using namespace Kt; using namespace Kt;
@@ -14,39 +14,14 @@ namespace Hal {
BasicGDT kernelGDT{}; BasicGDT kernelGDT{};
void PrepareGDT() { void PrepareGDT() {
kout << "HardwareAbstraction: GDT at " << base::hex << (uint64_t)&kernelGDT << "\n";
kernelGDT = { 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}, {0xFFFF, 0, 0, 0x00, 0x00, 0},
{0xFFFF, 0, 0, 0x9A, 0xA0, 0},
// Kernel code/data {0xFFFF, 0, 0, 0x92, 0xA0, 0},
{0xFFFF, 0, 0, 0x9A, 0xA0, 0}, {0xFFFF, 0, 0, 0x9A, 0xA0, 0},
{0xFFFF, 0, 0, 0x92, 0xA0, 0}, {0xFFFF, 0, 0, 0x92, 0xA0, 0},
// User code/data {0, 0, 0, 0xFA, 0x00, 0x0},
{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
}
}; };
gdtPointer = GDTPointer{ gdtPointer = GDTPointer{
@@ -60,11 +35,9 @@ namespace Hal {
extern "C" void ReloadSegments(); extern "C" void ReloadSegments();
void BridgeLoadGDT() { void BridgeLoadGDT() {
// Puts the GDT pointer structure into the GDTR
kout << "HardwareAbstraction: Setting GDTR" << Kt::newline;
LoadGDT(&gdtPointer); LoadGDT(&gdtPointer);
kout << "HardwareAbstraction: Reloading segments" << Kt::newline;
ReloadSegments(); ReloadSegments();
KernelLogStream(DEBUG, "HardwareAbstraction") << "Set new GDT (0x" << base::hex << (uint64_t)&kernelGDT << ")";
} }
}; };
+1 -22
View File
@@ -1,5 +1,6 @@
/* /*
* gdt.hpp * gdt.hpp
* Intel Global Descriptor Table
* Copyright (c) 2025 Daniel Hammer * Copyright (c) 2025 Daniel Hammer
*/ */
@@ -8,50 +9,28 @@
using namespace std; 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 { namespace Hal {
class GDTEntry { class GDTEntry {
public: 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 LimitLow;
uint16_t BaseLow; uint16_t BaseLow;
uint8_t BaseMiddle; uint8_t BaseMiddle;
// Determine which processor rings this segment can be used in
uint8_t AccessByte; uint8_t AccessByte;
// Lower 4 bits are the higher 4 bits of limit
uint8_t GranularityByte; uint8_t GranularityByte;
uint8_t BaseHigh; uint8_t BaseHigh;
// 16 + 16 + 8 + 8 = 48 bits
}__attribute__((packed)); }__attribute__((packed));
struct BasicGDT { struct BasicGDT {
// Conventionally the first entry of the GDT has all values zeroed out.
GDTEntry Null; GDTEntry Null;
// Kernel code segment descriptor
GDTEntry KernelCode; GDTEntry KernelCode;
// Kernel data segment descriptor
GDTEntry KernelData; GDTEntry KernelData;
// UM code segment descriptor
GDTEntry UserCode; GDTEntry UserCode;
// UM data segment descriptor
GDTEntry UserData; GDTEntry UserData;
// Task State Segment // Task State Segment
GDTEntry TSS; GDTEntry TSS;
}__attribute__((packed)); }__attribute__((packed));
// Simple structure that tells the CPU the size of the GDT, and it's address
struct GDTPointer { struct GDTPointer {
uint16_t Size; uint16_t Size;
uint64_t GDTAddress; uint64_t GDTAddress;
+2 -6
View File
@@ -56,11 +56,7 @@ namespace Hal {
template<size_t i> template<size_t i>
__attribute__((interrupt)) void ExceptionHandler(System::PanicFrame* frame) __attribute__((interrupt)) void ExceptionHandler(System::PanicFrame* frame)
{ {
// kcp::cstringstream stream;
// stream << "Caught " << base::hex << "0x" << i << " " << ExceptionStrings[i] << " in kernel";
frame->InterruptVector = i; frame->InterruptVector = i;
Panic(ExceptionStrings[i], frame); Panic(ExceptionStrings[i], frame);
} }
@@ -119,10 +115,10 @@ namespace Hal {
SetHandler<0, 31>::run(); SetHandler<0, 31>::run();
kout << "HardwareAbstraction: Created exception interrupt vectors" << "\n"; Kt::KernelLogStream(Kt::OK, "HardwareAbstraction") << "Created exception interrupt vectors";
LoadIDT(IDTR); LoadIDT(IDTR);
kout << "HardwareAbstraction: Loaded new IDT" << "\n"; Kt::KernelLogStream(Kt::OK, "HardwareAbstraction") << "Loaded new IDT";
} }
}; };
+6 -4
View File
@@ -29,6 +29,7 @@
#include <Hal/IDT.hpp> #include <Hal/IDT.hpp>
#include <Memory/PageFrameAllocator.hpp> #include <Memory/PageFrameAllocator.hpp>
#include <Memory/HHDM.hpp>
using namespace Kt; using namespace Kt;
@@ -47,7 +48,7 @@ extern void (*__init_array_end[])();
extern "C" void kmain() { extern "C" void kmain() {
if (LIMINE_BASE_REVISION_SUPPORTED == false) { if (LIMINE_BASE_REVISION_SUPPORTED == false) {
hcf(); Hal::Halt();
} }
// Call global constructors. // Call global constructors.
@@ -57,7 +58,7 @@ extern "C" void kmain() {
if (framebuffer_request.response == nullptr if (framebuffer_request.response == nullptr
|| framebuffer_request.response->framebuffer_count < 1) { || framebuffer_request.response->framebuffer_count < 1) {
hcf(); Hal::Halt();
} }
limine_framebuffer *framebuffer{framebuffer_request.response->framebuffers[0]}; limine_framebuffer *framebuffer{framebuffer_request.response->framebuffers[0]};
@@ -84,11 +85,12 @@ extern "C" void kmain() {
Memory::HHDMBase = hhdm_offset; Memory::HHDMBase = hhdm_offset;
if (memmap_request.response != nullptr) { 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::PageFrameAllocator pmm(Memory::Scan(memmap_request.response));
Memory::g_pfa = &pmm; Memory::g_pfa = &pmm;
Kt::KernelLogStream(OK, "MemoryManagement") << "Creating HeapAllocator";
Memory::HeapAllocator heap{}; Memory::HeapAllocator heap{};
Memory::g_heap = &heap; Memory::g_heap = &heap;
@@ -102,5 +104,5 @@ extern "C" void kmain() {
Hal::IDTInitialize(); Hal::IDTInitialize();
#endif #endif
hcf(); Hal::Halt();
} }
+11 -2
View File
@@ -51,10 +51,12 @@ namespace Memory
HeapAllocator::HeapAllocator() HeapAllocator::HeapAllocator()
{ {
InsertPagesToFreelist(8); InsertPagesToFreelist(0x32);
} }
void* HeapAllocator::Request(size_t size) { void* HeapAllocator::Request(size_t size) {
Lock.Acquire();
Node* current = head.next; Node* current = head.next;
Node* prev = &head; Node* prev = &head;
@@ -80,11 +82,14 @@ namespace Memory
InsertToFreelist(rest, newBlockSize); InsertToFreelist(rest, newBlockSize);
} }
Lock.Release();
return block; return block;
} }
prev = current; prev = current;
current = current->next; current = current->next;
Lock.Release();
} }
// First pass allocation failed // First pass allocation failed
@@ -106,6 +111,8 @@ namespace Memory
} }
void HeapAllocator::Free(void* ptr) { void HeapAllocator::Free(void* ptr) {
Lock.Acquire();
Header* header = GetHeader(ptr); Header* header = GetHeader(ptr);
auto size = header->size; auto size = header->size;
@@ -118,6 +125,8 @@ namespace Memory
void* actualBlock = (void*)header; void* actualBlock = (void*)header;
InsertToFreelist(actualBlock, size); InsertToFreelist(actualBlock, size);
Lock.Release();
} }
// Traverses the Allocator's linked list for debugging // Traverses the Allocator's linked list for debugging
@@ -126,7 +135,7 @@ namespace Memory
size_t i{0}; size_t i{0};
while (current != nullptr) { 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; current = current->next;
i++; i++;
} }
+2
View File
@@ -1,9 +1,11 @@
#pragma once #pragma once
#include "Memmap.hpp" #include "Memmap.hpp"
#include <CppLib/Spinlock.hpp>
namespace Memory { namespace Memory {
class HeapAllocator { class HeapAllocator {
static constexpr std::size_t headerMagic = 0x6CEF9AB4; static constexpr std::size_t headerMagic = 0x6CEF9AB4;
kcp::Spinlock Lock;
struct Node { struct Node {
size_t size; size_t size;
-2
View File
@@ -18,8 +18,6 @@ namespace Memory {
} }
if (entry->type == LIMINE_MEMMAP_USABLE) { 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) { if (entry->length > currentLargestSection.size) {
currentLargestSection = { currentLargestSection = {
.address = (uint64_t)entry->base, .address = (uint64_t)entry->base,
+2
View File
@@ -22,6 +22,8 @@ namespace Memory {
head.next = (Page*)g_section.address; head.next = (Page*)g_section.address;
head.next->size = section.size; head.next->size = section.size;
head.next->next = nullptr; head.next->next = nullptr;
Kt::KernelLogStream(Kt::DEBUG, "PageFrameAllocator") << "New pool size: " << section.size;
} }
void* PageFrameAllocator::Allocate() { void* PageFrameAllocator::Allocate() {
+1 -1
View File
@@ -12,6 +12,6 @@
// but should not be removed, unless you know what you are doing. // but should not be removed, unless you know what you are doing.
extern "C" { extern "C" {
int __cxa_atexit(void (*)(void *), void *, void *) { return 0; } int __cxa_atexit(void (*)(void *), void *, void *) { return 0; }
void __cxa_pure_virtual() { hcf(); } void __cxa_pure_virtual() { Hal::Halt(); }
void *__dso_handle; void *__dso_handle;
} }
+3 -1
View File
@@ -5,7 +5,8 @@
*/ */
// Halt and catch fire function. // Halt and catch fire function.
void hcf() namespace Hal {
__attribute__((noreturn)) void Halt()
{ {
for (;;) for (;;)
{ {
@@ -18,3 +19,4 @@ void hcf()
#endif #endif
} }
} }
};
+3 -1
View File
@@ -7,4 +7,6 @@
#pragma once #pragma once
// Halt and catch fire function. // Halt and catch fire function.
void hcf(); namespace Hal {
__attribute__((noreturn)) void Halt();
};
+73 -1
View File
@@ -15,6 +15,18 @@ namespace Kt
{ {
constexpr const char *clear = "\033[2J"; constexpr const char *clear = "\033[2J";
constexpr const char *cursor_reset = "\033[H"; 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, void Initialize(std::uint32_t *framebuffer, std::size_t width, std::size_t height, std::size_t pitch,
@@ -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<typename T>
KernelLogStream &operator<<(T item) {
localStream << item;
return *this;
}
};
}; };
extern Kt::KernelOutStream kout; extern Kt::KernelOutStream kout;