diff --git a/lib/libc/CMakeLists.txt b/lib/libc/CMakeLists.txt index a7249a0..89e6c99 100644 --- a/lib/libc/CMakeLists.txt +++ b/lib/libc/CMakeLists.txt @@ -1,6 +1,5 @@ add_library(c STATIC - src/malloc.cpp src/string.cpp ) diff --git a/lib/libc/include/stdlib.h b/lib/libc/include/stdlib.h deleted file mode 100644 index 3634d1f..0000000 --- a/lib/libc/include/stdlib.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "stddef.h" - -void* malloc(size_t size); diff --git a/lib/libc/src/malloc.cpp b/lib/libc/src/malloc.cpp deleted file mode 100644 index 5165ce5..0000000 --- a/lib/libc/src/malloc.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -#include "stdlib.h" - -namespace { -class NaiveAllocator { - public: - constexpr static uint64_t kSize = 0x10000; - NaiveAllocator() {} - bool is_init() { return next_addr_ != 0; } - void Init() { - uint64_t vmmo_cap; - uint64_t err = ZMemoryObjectCreate(kSize, &vmmo_cap); - if (err != 0) { - (void)ZProcessExit(err); - } - err = ZAddressSpaceMap(gSelfVmasCap, 0, vmmo_cap, 0, &next_addr_); - max_addr_ = next_addr_ + kSize; - } - - void* Allocate(size_t size) { - uint64_t addr = next_addr_; - next_addr_ += size; - if (next_addr_ >= max_addr_) { - (void)ZProcessExit(0xBEEF); - return 0; - } - return reinterpret_cast(addr); - } - - private: - uint64_t next_addr_ = 0; - uint64_t max_addr_ = 0; -}; - -NaiveAllocator gAlloc; - -} // namespace - -void* malloc(size_t size) { - if (!gAlloc.is_init()) { - gAlloc.Init(); - } - return gAlloc.Allocate(size); -} diff --git a/lib/mammoth/util/new.cpp b/lib/mammoth/util/new.cpp index e63f9a4..008633c 100644 --- a/lib/mammoth/util/new.cpp +++ b/lib/mammoth/util/new.cpp @@ -1,8 +1,166 @@ +#include +#include #include -#include +#include +#include -[[nodiscard]] void* operator new(uint64_t size) { return malloc(size); } -[[nodiscard]] void* operator new[](uint64_t size) { return malloc(size); } +#include "util/debug.h" + +namespace { + +class PageAllocator { + public: + static uint64_t AllocatePagePair() { + uint64_t mem_cap; + check(ZMemoryObjectCreate(0x2000, &mem_cap)); + + uint64_t vaddr; + check(ZAddressSpaceMap(gSelfVmasCap, 0, mem_cap, /* align= */ 0x2000, + &vaddr)); + + // The address space mapping will keep this memory capability alive. + check(ZCapRelease(mem_cap)); + + return vaddr; + } +}; + +struct BuddySlot { + BuddySlot* next; + BuddySlot* prev; + uint64_t size; +}; + +uint64_t NeededSize(uint64_t size) { + uint64_t needed = size + sizeof(BuddySlot); + // Start at 32 because sizeof(BuddySlot) is already 24; + uint64_t pow2 = 32; + + while (pow2 < needed) { + pow2 <<= 1; + } + + return pow2; +} + +class BuddyAllocator { + public: + BuddyAllocator() {} + + void Init() { + free_front_ = nullptr; + AddPage(); + check(ZMutexCreate(&mutex_cap_)); + } + + void* Allocate(uint64_t size) { + check(ZMutexLock(mutex_cap_)); + if (size > (0x2000 - sizeof(BuddySlot))) { + crash("Can't allocate greater than one page", glcr::UNIMPLEMENTED); + } + if (free_front_ == nullptr) { + AddPage(); + } + BuddySlot* slot = free_front_; + uint64_t needed = NeededSize(size); + BuddySlot* best_fit = nullptr; + + while (slot != nullptr) { + bool fits = slot->size >= needed; + bool better = best_fit == nullptr || slot->size < best_fit->size; + if (fits && better) { + best_fit = slot; + } + slot = slot->next; + } + + if (best_fit == nullptr) { + AddPage(); + best_fit = free_front_; + } + + while (best_fit->size > needed) { + best_fit = Split(best_fit); + } + + Remove(best_fit); + // TODO: We may need to align the pointer here. + void* ptr = reinterpret_cast(best_fit) + sizeof(BuddySlot); + check(ZMutexRelease(mutex_cap_)); + return ptr; + } + + private: + BuddySlot* free_front_ = nullptr; + z_cap_t mutex_cap_ = 0; + + void AddPage() { + uint64_t vaddr = PageAllocator::AllocatePagePair(); + BuddySlot* slot = reinterpret_cast(vaddr); + slot->prev = nullptr; + slot->next = free_front_; + free_front_ = slot; + slot->size = 0x2000; + } + + BuddySlot* Split(BuddySlot* slot) { + if (slot->size <= 32) { + crash("Splitting smallest buddy chunk", glcr::INTERNAL); + } + + slot->size /= 2; + BuddySlot* new_slot = reinterpret_cast( + reinterpret_cast(slot) ^ slot->size); + new_slot->size = slot->size; + new_slot->next = slot->next; + new_slot->prev = slot; + if (slot->next) { + slot->next->prev = new_slot; + } + slot->next = new_slot; + return slot; + } + + void Remove(BuddySlot* slot) { + if (slot->prev) { + slot->prev->next = slot->next; + } + if (slot->next) { + slot->next->prev = slot->prev; + } + + if (free_front_ == slot) { + free_front_ = slot->next; + } + + slot->next = nullptr; + slot->prev = nullptr; + } +}; + +BuddyAllocator gAllocator; +bool gHasInit = false; + +// FIXME: Race condition. +void* Allocate(uint64_t size) { + if (!gHasInit) { + // Call Init since we don't call global constructors yet. + gAllocator.Init(); + gHasInit = true; + } + void* ptr = gAllocator.Allocate(size); + + char buffer[64]; + // glcr::FixedStringBuilder builder(buffer, 64); + // glcr::StrFormatIntoBuffer(builder, "Allocated {x}", (uint64_t)ptr); + // dbgln(builder.operator glcr::StringView()); + return ptr; +} + +} // namespace + +[[nodiscard]] void* operator new(uint64_t size) { return Allocate(size); } +[[nodiscard]] void* operator new[](uint64_t size) { return Allocate(size); } void operator delete(void*, uint64_t) {} void operator delete[](void*) {} diff --git a/sys/yellowstone/yellowstone_server.cpp b/sys/yellowstone/yellowstone_server.cpp index ab352a0..1b4fcae 100644 --- a/sys/yellowstone/yellowstone_server.cpp +++ b/sys/yellowstone/yellowstone_server.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include "hw/gpt.h"