From 512be884ed85a50a48e577fd41d3cfcb3c080764 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Mon, 8 May 2023 22:10:49 +0300 Subject: [PATCH] Kernel: Add barebones GeneralAllocator for >4096B --- kernel/CMakeLists.txt | 1 + kernel/arch/x86_64/MMU.cpp | 23 ++++++- .../include/kernel/Memory/GeneralAllocator.h | 34 ++++++++++ kernel/include/kernel/Memory/MMU.h | 8 +-- kernel/include/kernel/Process.h | 2 + kernel/kernel/Memory/GeneralAllocator.cpp | 64 +++++++++++++++++++ kernel/kernel/Process.cpp | 48 ++++++++++++-- userspace/test.c | 2 +- 8 files changed, 169 insertions(+), 13 deletions(-) create mode 100644 kernel/include/kernel/Memory/GeneralAllocator.h create mode 100644 kernel/kernel/Memory/GeneralAllocator.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 676f3935..893f71d8 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -26,6 +26,7 @@ set(KERNEL_SOURCES kernel/InterruptController.cpp kernel/kernel.cpp kernel/Memory/FixedWidthAllocator.cpp + kernel/Memory/GeneralAllocator.cpp kernel/Memory/Heap.cpp kernel/Memory/kmalloc.cpp kernel/Panic.cpp diff --git a/kernel/arch/x86_64/MMU.cpp b/kernel/arch/x86_64/MMU.cpp index 0d26bc8f..f8c309e4 100644 --- a/kernel/arch/x86_64/MMU.cpp +++ b/kernel/arch/x86_64/MMU.cpp @@ -312,7 +312,7 @@ namespace Kernel // Find any free page page (except for page 0) vaddr_t address = PAGE_SIZE; - while ((address << 48) == 0) + while ((address >> 48) == 0) { if (!(get_page_flags(address) & Flags::Present)) return address; @@ -322,6 +322,27 @@ namespace Kernel ASSERT_NOT_REACHED(); } + vaddr_t MMU::get_free_contiguous_pages(size_t page_count) const + { + for (vaddr_t address = PAGE_SIZE; !(address >> 48); address += PAGE_SIZE) + { + bool valid { true }; + for (size_t page = 0; page < page_count; page++) + { + if (get_page_flags(address + page * PAGE_SIZE) & Flags::Present) + { + address += page; + valid = false; + break; + } + } + if (valid) + return address; + } + + ASSERT_NOT_REACHED(); + } + bool MMU::is_page_free(vaddr_t page) const { ASSERT(page % PAGE_SIZE == 0); diff --git a/kernel/include/kernel/Memory/GeneralAllocator.h b/kernel/include/kernel/Memory/GeneralAllocator.h new file mode 100644 index 00000000..2c4dee55 --- /dev/null +++ b/kernel/include/kernel/Memory/GeneralAllocator.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +namespace Kernel +{ + + class GeneralAllocator + { + BAN_NON_COPYABLE(GeneralAllocator); + BAN_NON_MOVABLE(GeneralAllocator); + + public: + GeneralAllocator(MMU&); + ~GeneralAllocator(); + + vaddr_t allocate(size_t); + bool deallocate(vaddr_t); + + private: + struct Allocation + { + vaddr_t address { 0 }; + BAN::Vector pages; + }; + + private: + MMU& m_mmu; + BAN::LinkedList m_allocations; + }; + +} \ No newline at end of file diff --git a/kernel/include/kernel/Memory/MMU.h b/kernel/include/kernel/Memory/MMU.h index 8ddd3fc5..17728484 100644 --- a/kernel/include/kernel/Memory/MMU.h +++ b/kernel/include/kernel/Memory/MMU.h @@ -24,10 +24,10 @@ namespace Kernel ~MMU(); void identity_map_page(paddr_t, flags_t); - void identity_map_range(paddr_t, size_t, flags_t); + void identity_map_range(paddr_t, size_t bytes, flags_t); void unmap_page(vaddr_t); - void unmap_range(vaddr_t, size_t); + void unmap_range(vaddr_t, size_t bytes); void map_page_at(paddr_t, vaddr_t, flags_t); @@ -35,10 +35,10 @@ namespace Kernel flags_t get_page_flags(vaddr_t) const; bool is_page_free(vaddr_t) const; - bool is_range_free(vaddr_t, size_t) const; + bool is_range_free(vaddr_t, size_t bytes) const; vaddr_t get_free_page() const; - vaddr_t get_free_contiguous_pages(uint32_t) const; + vaddr_t get_free_contiguous_pages(size_t page_count) const; void load(); diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 803fa50e..6114aff9 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +96,7 @@ namespace Kernel BAN::Vector m_threads; BAN::LinkedList m_fixed_width_allocators; + GeneralAllocator* m_general_allocator; MMU* m_mmu { nullptr }; TTY* m_tty { nullptr }; diff --git a/kernel/kernel/Memory/GeneralAllocator.cpp b/kernel/kernel/Memory/GeneralAllocator.cpp new file mode 100644 index 00000000..076a28d6 --- /dev/null +++ b/kernel/kernel/Memory/GeneralAllocator.cpp @@ -0,0 +1,64 @@ +#include +#include + +namespace Kernel +{ + + GeneralAllocator::GeneralAllocator(MMU& mmu) + : m_mmu(mmu) + { } + + GeneralAllocator::~GeneralAllocator() + { + while (!m_allocations.empty()) + deallocate(m_allocations.front().address); + } + + vaddr_t GeneralAllocator::allocate(size_t bytes) + { + size_t needed_pages = BAN::Math::div_round_up(bytes, PAGE_SIZE); + + Allocation allocation; + if (allocation.pages.resize(needed_pages, 0).is_error()) + return 0; + + for (size_t i = 0; i < needed_pages; i++) + { + paddr_t paddr = Heap::get().take_free_page(); + if (paddr == 0) + { + for (size_t j = 0; j < i; j++) + Heap::get().release_page(allocation.pages[j]); + return 0; + } + allocation.pages[i] = paddr; + } + + allocation.address = m_mmu.get_free_contiguous_pages(needed_pages); + for (size_t i = 0; i < needed_pages; i++) + m_mmu.map_page_at(allocation.pages[i], allocation.address + i * PAGE_SIZE, MMU::Flags::UserSupervisor | MMU::Flags::ReadWrite | MMU::Flags::Present); + + MUST(m_allocations.push_back(BAN::move(allocation))); + return allocation.address; + } + + bool GeneralAllocator::deallocate(vaddr_t address) + { + for (auto it = m_allocations.begin(); it != m_allocations.end(); it++) + { + if (it->address != address) + continue; + + m_mmu.unmap_range(it->address, it->pages.size() * PAGE_SIZE); + for (auto paddr : it->pages) + Heap::get().release_page(paddr); + + m_allocations.remove(it); + + return true; + } + + return false; + } + +} \ No newline at end of file diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index ed300406..5cc387aa 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -118,6 +118,7 @@ namespace Kernel { ASSERT(m_threads.empty()); ASSERT(m_fixed_width_allocators.empty()); + ASSERT(m_general_allocator == nullptr); if (m_mmu) { MMU::get().load(); @@ -152,6 +153,11 @@ namespace Kernel // NOTE: We must clear allocators while the mmu is still alive m_fixed_width_allocators.clear(); + if (m_general_allocator) + { + delete m_general_allocator; + m_general_allocator = nullptr; + } dprintln("process {} exit", pid()); s_process_lock.lock(); @@ -385,6 +391,8 @@ namespace Kernel BAN::ErrorOr Process::allocate(size_t bytes) { + vaddr_t address = 0; + if (bytes <= PAGE_SIZE) { // Do fixed width allocation @@ -393,18 +401,40 @@ namespace Kernel LockGuard _(m_lock); - for (auto& allocator : m_fixed_width_allocators) - if (allocator.allocation_size() == allocation_size && allocator.allocations() < allocator.max_allocations()) - return (void*)allocator.allocate(); + bool needs_new_allocator { true }; - MUST(m_fixed_width_allocators.emplace_back(mmu(), allocation_size)); - return (void*)m_fixed_width_allocators.back().allocate(); + for (auto& allocator : m_fixed_width_allocators) + { + if (allocator.allocation_size() == allocation_size && allocator.allocations() < allocator.max_allocations()) + { + address = allocator.allocate(); + needs_new_allocator = false; + } + } + + if (needs_new_allocator) + { + TRY(m_fixed_width_allocators.emplace_back(mmu(), allocation_size)); + address = m_fixed_width_allocators.back().allocate(); + } } else { - // TODO: Do general allocation - return BAN::Error::from_errno(ENOMEM); + LockGuard _(m_lock); + + if (!m_general_allocator) + { + m_general_allocator = new GeneralAllocator(mmu()); + if (m_general_allocator == nullptr) + return BAN::Error::from_errno(ENOMEM); + } + + address = m_general_allocator->allocate(bytes); } + + if (address == 0) + return BAN::Error::from_errno(ENOMEM); + return (void*)address; } void Process::free(void* ptr) @@ -422,6 +452,10 @@ namespace Kernel return; } } + + if (m_general_allocator && m_general_allocator->deallocate((vaddr_t)ptr)) + return; + dwarnln("free called on pointer that was not allocated"); } diff --git a/userspace/test.c b/userspace/test.c index 92b551cd..3a6d3146 100644 --- a/userspace/test.c +++ b/userspace/test.c @@ -1,7 +1,7 @@ #include #include -#define N 512 +#define N 1024 int main() {