From 8bff2ee0f54d0fb5b8fc364d212d58639eeb5f50 Mon Sep 17 00:00:00 2001 From: apio Date: Tue, 6 Sep 2022 13:21:54 +0200 Subject: [PATCH] Add a RangeAllocator which serves as a physical memory allocator --- kernel/include/memory/RangeAllocator.h | 38 +++++++ kernel/src/init/Init.cpp | 3 + kernel/src/main.cpp | 22 ++++- kernel/src/memory/RangeAllocator.cpp | 131 +++++++++++++++++++++++++ 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 kernel/include/memory/RangeAllocator.h create mode 100644 kernel/src/memory/RangeAllocator.cpp diff --git a/kernel/include/memory/RangeAllocator.h b/kernel/include/memory/RangeAllocator.h new file mode 100644 index 00000000..eb4feb0e --- /dev/null +++ b/kernel/include/memory/RangeAllocator.h @@ -0,0 +1,38 @@ +#pragma once +#include + +class RangeAllocator +{ + public: + void init(void* start_address, uint64_t count); + void init_from_mmap(); + + void* request_page(); + void free_page(void* address); + void free_pages(void* address, uint64_t count); + + void lock_page(void* address); + void lock_pages(void* address, uint64_t count); + + uint64_t get_free(); + uint64_t get_used(); + uint64_t get_reserved(); + + private: + void reserve_page(void* address); + void reserve_pages(void* address, uint64_t count); + + bool bitmap_read(uint64_t index); + void bitmap_set(uint64_t index, bool value); + + uint64_t free_mem = 0; + uint64_t used_mem = 0; + uint64_t reserved_mem = 0; + + char* bitmap_addr; + uint64_t bitmap_size; + + uint64_t start_index = 0; +}; + +extern RangeAllocator physical_allocator; \ No newline at end of file diff --git a/kernel/src/init/Init.cpp b/kernel/src/init/Init.cpp index 11009e44..1b2782db 100644 --- a/kernel/src/init/Init.cpp +++ b/kernel/src/init/Init.cpp @@ -4,6 +4,7 @@ #include "cpu/CPU.h" #include "interrupts/Interrupts.h" #include "io/Serial.h" +#include "memory/RangeAllocator.h" #include "panic/hang.h" #include "render/Draw.h" #include "render/TextRenderer.h" @@ -29,4 +30,6 @@ void Init::early_init() ASSERT(Draw::try_initialize()); // ASSERT(TextRenderer::try_initialize()); + + physical_allocator.init_from_mmap(); } \ No newline at end of file diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index f1fcbbdc..b23fbebb 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -14,6 +14,7 @@ #include "log/Log.h" #include "memory/KernelHeap.h" #include "memory/Memory.h" +#include "memory/RangeAllocator.h" #include "panic/hang.h" #include "power/shutdown.h" #include "render/BBRenderer.h" @@ -73,7 +74,26 @@ extern "C" void _start() kinfoln("Interrupts enabled"); - printf("%d KB of system memory, %d KB available\n", Memory::get_system() / 1024, Memory::get_usable() / 1024); + printf("%d KB of system memory\n%d KB free\n%d KB used\n%d KB reserved\n", Memory::get_system() / 1024, + physical_allocator.get_free() / 1024, physical_allocator.get_used() / 1024, + physical_allocator.get_reserved() / 1024); + + void* address = physical_allocator.request_page(); + printf("Allocated page at address 0x%zx\n", address); + + void* address2 = physical_allocator.request_page(); + printf("Allocated page at address 0x%zx\n", address2); + + printf("%d KB of system memory\n%d KB free\n%d KB used\n%d KB reserved\n", Memory::get_system() / 1024, + physical_allocator.get_free() / 1024, physical_allocator.get_used() / 1024, + physical_allocator.get_reserved() / 1024); + + physical_allocator.free_page(address); + printf("Freed page\n"); + + printf("%d KB of system memory\n%d KB free\n%d KB used\n%d KB reserved\n", Memory::get_system() / 1024, + physical_allocator.get_free() / 1024, physical_allocator.get_used() / 1024, + physical_allocator.get_reserved() / 1024); Debug::DebugStatus::the()->StartBootStage(Color{0x33, 0x33, 0x00, 0xFF}); ACPI::SDTHeader* rootSDT = ACPI::GetRSDTOrXSDT(); diff --git a/kernel/src/memory/RangeAllocator.cpp b/kernel/src/memory/RangeAllocator.cpp new file mode 100644 index 00000000..ab25349e --- /dev/null +++ b/kernel/src/memory/RangeAllocator.cpp @@ -0,0 +1,131 @@ +#include "memory/RangeAllocator.h" +#include "assert.h" +#include "bootboot.h" +#include "memory/Memory.h" +#include "std/string.h" + +extern BOOTBOOT bootboot; + +RangeAllocator physical_allocator; + +void RangeAllocator::init_from_mmap() +{ + uint64_t total_mem = Memory::get_system(); + + void* biggest_chunk = nullptr; + uint64_t biggest_chunk_size = 0; + + MMapEnt* ptr = &bootboot.mmap; + uint64_t mmap_entries = (bootboot.size - 128) / 16; + for (uint64_t i = 0; i < mmap_entries; i++) + { + if (MMapEnt_Size(ptr) > biggest_chunk_size) + { + biggest_chunk = (void*)MMapEnt_Ptr(ptr); + biggest_chunk_size = MMapEnt_Size(ptr); + } + ptr++; + } + + bitmap_addr = (char*)biggest_chunk; + ASSERT((total_mem / 4096 / 8) < biggest_chunk_size); + bitmap_size = total_mem / 4096 / 8 + 1; + memset(bitmap_addr, 0, bitmap_size); + + free_mem = total_mem; + + lock_pages(bitmap_addr, bitmap_size / 4096 + 1); + + ptr = &bootboot.mmap; + for (uint64_t i = 0; i < mmap_entries; i++) + { + if (!MMapEnt_IsFree(ptr)) { reserve_pages((void*)MMapEnt_Ptr(ptr), MMapEnt_Size(ptr) / 4096); } + ptr++; + } +} + +bool RangeAllocator::bitmap_read(uint64_t index) +{ + return (bitmap_addr[index / 8] & (0b10000000 >> (index % 8))) > 0; +} + +void RangeAllocator::bitmap_set(uint64_t index, bool value) +{ + uint64_t byteIndex = index / 8; + uint8_t bitIndexer = 0b10000000 >> (index % 8); + bitmap_addr[byteIndex] &= ~bitIndexer; + if (value) { bitmap_addr[byteIndex] |= bitIndexer; } +} + +void* RangeAllocator::request_page() +{ + for (uint64_t index = start_index; index < (bitmap_size * 8); index++) + { + if (bitmap_read(index)) continue; + bitmap_set(index, true); + start_index = index + 1; + free_mem -= 4096; + used_mem += 4096; + return (void*)(index * 4096); + } + + return 0; +} + +void RangeAllocator::free_page(void* address) +{ + uint64_t index = (uint64_t)address / 4096; + if (!bitmap_read(index)) return; + bitmap_set(index, false); + used_mem -= 4096; + free_mem += 4096; + if (start_index > index) start_index = index; +} + +void RangeAllocator::free_pages(void* address, uint64_t count) +{ + for (uint64_t index = 0; index < count; index++) { free_page((void*)((uint64_t)address + index)); } +} + +void RangeAllocator::lock_page(void* address) +{ + uint64_t index = (uint64_t)address / 4096; + if (bitmap_read(index)) return; + bitmap_set(index, true); + used_mem += 4096; + free_mem -= 4096; +} + +void RangeAllocator::reserve_page(void* address) +{ + uint64_t index = (uint64_t)address / 4096; + if (bitmap_read(index)) return; + bitmap_set(index, true); + reserved_mem += 4096; + free_mem -= 4096; +} + +void RangeAllocator::lock_pages(void* address, uint64_t count) +{ + for (uint64_t index = 0; index < count; index++) { lock_page((void*)((uint64_t)address + index)); } +} + +void RangeAllocator::reserve_pages(void* address, uint64_t count) +{ + for (uint64_t index = 0; index < count; index++) { reserve_page((void*)((uint64_t)address + index)); } +} + +uint64_t RangeAllocator::get_free() +{ + return free_mem; +} + +uint64_t RangeAllocator::get_used() +{ + return used_mem; +} + +uint64_t RangeAllocator::get_reserved() +{ + return reserved_mem; +} \ No newline at end of file