From 358837ed690ec5da3325c963acff4366f83869bb Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sat, 28 Apr 2018 02:17:17 -0700 Subject: [PATCH] Implement first-pass simple virtual memory manager --- src/kernel/main.cpp | 4 ++++ src/kernel/memory.cpp | 47 ++++++++++++++++++++++++++++++++++--- src/kernel/memory.h | 27 +++++++++++++++++++-- src/kernel/memory_pages.cpp | 13 ++++++++++ 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index c33848e..44d8669 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -54,6 +54,10 @@ kernel_main(popcorn_data *header) header->memory_map_length, header->memory_map_desc_size); + size_t n = 5000; + void *p = kalloc(n); + g_console.printf("kalloc'd %d bytes at %lx\n", n, p); + interrupts_init(); interrupts_enable(); diff --git a/src/kernel/memory.cpp b/src/kernel/memory.cpp index 2a99900..6ef373c 100644 --- a/src/kernel/memory.cpp +++ b/src/kernel/memory.cpp @@ -3,9 +3,50 @@ #include "memory.h" #include "memory_pages.h" -memory_manager g_memory_manager; +memory_manager g_kernel_memory_manager; -memory_manager::memory_manager() +struct memory_allocation_header +{ + uint64_t pages; + uint64_t reserved; + uint8_t data[0]; +} __attribute__ ((packed)); + +memory_manager::memory_manager() : + m_start(nullptr), + m_length(0) { - kassert(this == &g_memory_manager, "Attempt to create another memory_manager."); +} + +memory_manager::memory_manager(void *start, size_t length) : + m_start(start), + m_length(length) +{ +} + +void * +memory_manager::allocate(size_t length) +{ + length = page_align(length + sizeof(memory_allocation_header)); + + if (length > m_length) return nullptr; + + 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; + return &header->data; +} + +void +memory_manager::free(void *p) +{ + // In this simple version, we don't care about freed pointers } diff --git a/src/kernel/memory.h b/src/kernel/memory.h index 0df400d..7a94286 100644 --- a/src/kernel/memory.h +++ b/src/kernel/memory.h @@ -3,21 +3,44 @@ /// The block memory manager and related definitions. #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(const memory_manager &) = delete; + /// Allocate memory from the area managed. + /// \arg length The amount of memory to allocate, in bytes + /// \returns A pointer to the allocated memory, or nullptr if + /// allocation failed. + void * allocate(size_t length); + + /// Free a previous allocation. + /// \arg p A pointer previously retuned by allocate() + void free(void *p); private: friend class page_manager; + + // Simple incrementing pointer. + void *m_start; + size_t m_length; + + memory_manager(const memory_manager &) = delete; }; -extern memory_manager g_memory_manager; +extern memory_manager g_kernel_memory_manager; /// Bootstrap the memory managers. void memory_initialize_managers(const void *memory_map, size_t map_length, size_t desc_length); +/// Allocate kernel space memory. +/// \arg length The amount of memory to allocate, in bytes +/// \returns A pointer to the allocated memory, or nullptr if +/// allocation failed. +inline void * kalloc(size_t length) { return g_kernel_memory_manager.allocate(length); } diff --git a/src/kernel/memory_pages.cpp b/src/kernel/memory_pages.cpp index 2a41642..00e19ff 100644 --- a/src/kernel/memory_pages.cpp +++ b/src/kernel/memory_pages.cpp @@ -2,6 +2,7 @@ #include "assert.h" #include "console.h" +#include "memory.h" #include "memory_pages.h" page_manager g_page_manager; @@ -224,6 +225,18 @@ page_manager::init( page_block::dump(m_used, "used", true); page_block::dump(m_free, "free", true); + // 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) + end = b->virtual_end(); + else + break; + + } + new (&g_kernel_memory_manager) memory_manager( + reinterpret_cast(end), + page_offset - end); } void