feat: Various improvements
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
@@ -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();
|
||||||
|
};
|
||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user