From 9542bd8a44646c0604f921111b4de003c5375323 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Thu, 3 May 2018 00:57:58 -0700 Subject: [PATCH] Add beginning of better vmem allocator --- NOTES.md | 1 + src/kernel/memory.cpp | 99 ++++++++++++++++++++++++++++++------- src/kernel/memory.h | 25 ++++++++-- src/kernel/memory_pages.cpp | 13 +++-- 4 files changed, 110 insertions(+), 28 deletions(-) diff --git a/NOTES.md b/NOTES.md index 6f247a6..b1aab8a 100644 --- a/NOTES.md +++ b/NOTES.md @@ -6,4 +6,5 @@ - Allow for more than one IOAPIC in ACPI module - Slab allocator for kernel structures - mark kernel memory pages global +- kernel allocator free() diff --git a/src/kernel/memory.cpp b/src/kernel/memory.cpp index 656dcdb..721c5e9 100644 --- a/src/kernel/memory.cpp +++ b/src/kernel/memory.cpp @@ -1,46 +1,52 @@ +#include "kutil/memory.h" #include "assert.h" +#include "log.h" #include "memory.h" #include "memory_pages.h" memory_manager g_kernel_memory_manager; -struct memory_allocation_header +struct memory_manager::alloc_header { - uint64_t pages; + uint64_t size; uint64_t reserved; uint8_t data[0]; } __attribute__ ((packed)); +struct memory_manager::free_header +{ + free_header *next; + uint64_t size; +} __attribute__ ((packed)); + memory_manager::memory_manager() : m_start(nullptr), m_length(0) { + kutil::memset(m_free, 0, sizeof(m_free)); } -memory_manager::memory_manager(void *start, size_t length) : +memory_manager::memory_manager(void *start) : m_start(start), - m_length(length) + m_length(0) { + kutil::memset(m_free, 0, sizeof(m_free)); + grow_memory(); } void * memory_manager::allocate(size_t length) { - length = page_align(length + sizeof(memory_allocation_header)); + size_t total = length + sizeof(alloc_header); + unsigned size = min_size; + while (total > (1 << size)) size++; + kassert(size < max_size, "Tried to allocate a block bigger than max_size"); + log::debug(logs::memory, "Allocating %d bytes, which is size %d", total, size); - if (length > m_length) return nullptr; + alloc_header *header = reinterpret_cast(pop_free(size)); + header->size = size; - m_length -= length; - memory_allocation_header *header = - reinterpret_cast(m_start); - m_start = reinterpret_cast(m_start) + length; - - size_t pages = length / page_manager::page_size; - g_page_manager.map_pages( - reinterpret_cast(header), - pages); - - header->pages = pages; + log::debug(logs::memory, " Returning %d bytes at %lx", length, &header->data); return &header->data; } @@ -49,3 +55,62 @@ memory_manager::free(void *p) { // In this simple version, we don't care about freed pointers } + +void +memory_manager::grow_memory() +{ + size_t length = (1 << max_size); + + free_header *block = reinterpret_cast( + reinterpret_cast(m_start) + m_length); + + g_page_manager.map_pages( + reinterpret_cast(block), + length / page_manager::page_size); + + block->size = max_size; + block->next = get_free(max_size); + get_free(max_size) = block; + m_length += length; + + log::debug(logs::memory, "Allocated new block at %lx: size %d next %lx", + block, block->size, block->next); +} + +void +memory_manager::ensure_block(unsigned size) +{ + free_header *header = get_free(size); + if (header != nullptr) return; + else if (size == max_size) { + grow_memory(); + return; + } + + free_header *bigger = pop_free(size + 1); + + uint64_t new_size = bigger->size - 1; + free_header *next = reinterpret_cast( + reinterpret_cast(bigger) + (1 << new_size)); + + next->next = bigger->next; + next->size = new_size; + + bigger->next = next; + bigger->size = new_size; + log::debug(logs::memory, "ensure_block[%2d] split blocks:", size); + log::debug(logs::memory, " %lx: size %d next %lx", bigger, bigger->size, bigger->next); + log::debug(logs::memory, " %lx: size %d next %lx", next, next->size, next->next); + + get_free(size) = bigger; +} + +memory_manager::free_header * +memory_manager::pop_free(unsigned size) +{ + ensure_block(size); + free_header *block = get_free(size); + get_free(size) = block->next; + block->next = nullptr; + return block; +} diff --git a/src/kernel/memory.h b/src/kernel/memory.h index a3a69a9..c7351f9 100644 --- a/src/kernel/memory.h +++ b/src/kernel/memory.h @@ -5,14 +5,13 @@ #include #include -struct memory_block_node; /// Manager for allocation of virtual memory. class memory_manager { public: memory_manager(); - memory_manager(void *start, size_t length); + memory_manager(void *start); /// Allocate memory from the area managed. /// \arg length The amount of memory to allocate, in bytes @@ -25,12 +24,30 @@ public: void free(void *p); private: - friend class page_manager; + struct alloc_header; + struct free_header; - // Simple incrementing pointer. + /// Expand the size of memory + void grow_memory(); + + /// Ensure there is a block of a given size, recursively splitting + /// \arg size Size category of the block we want + void ensure_block(unsigned size); + + /// Helper accessor for the list of blocks of a given size + free_header *& get_free(unsigned size) { return m_free[size - min_size]; } + + /// Helper to get a block of the given size, growing if necessary + free_header * pop_free(unsigned size); + + static const unsigned min_size = 6; ///< Minimum block size is (2^min_size) + static const unsigned max_size = 16; ///< Maximum block size is (2^max_size) + + free_header *m_free[max_size - min_size]; void *m_start; size_t m_length; + friend class page_manager; memory_manager(const memory_manager &) = delete; }; diff --git a/src/kernel/memory_pages.cpp b/src/kernel/memory_pages.cpp index f25b4ad..6082771 100644 --- a/src/kernel/memory_pages.cpp +++ b/src/kernel/memory_pages.cpp @@ -199,15 +199,14 @@ page_manager::init( // Initialize the kernel memory manager addr_t end = 0; for (page_block *b = m_used; b; b = b->next) { - if (b->virtual_address < page_offset) + if (b->virtual_address < page_offset) { end = b->virtual_end(); - else + } else { break; - + } } - new (&g_kernel_memory_manager) memory_manager( - reinterpret_cast(end), - page_offset - end); + + new (&g_kernel_memory_manager) memory_manager(reinterpret_cast(end)); } void @@ -229,7 +228,7 @@ page_manager::map_offset_pointer(void **pointer, size_t length) page_block_flags::mapped | page_block_flags::mmio; - log::info(logs::memory, "Fixing up pointer %lx [%3d] -> %lx", *p, c, v); + log::debug(logs::memory, "Fixing up pointer %lx [%3d] -> %lx", *p, c, v); m_used = page_block::insert(m_used, block);