Add beginning of better vmem allocator
This commit is contained in:
1
NOTES.md
1
NOTES.md
@@ -6,4 +6,5 @@
|
|||||||
- Allow for more than one IOAPIC in ACPI module
|
- Allow for more than one IOAPIC in ACPI module
|
||||||
- Slab allocator for kernel structures
|
- Slab allocator for kernel structures
|
||||||
- mark kernel memory pages global
|
- mark kernel memory pages global
|
||||||
|
- kernel allocator free()
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +1,52 @@
|
|||||||
|
#include "kutil/memory.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
#include "log.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "memory_pages.h"
|
#include "memory_pages.h"
|
||||||
|
|
||||||
memory_manager g_kernel_memory_manager;
|
memory_manager g_kernel_memory_manager;
|
||||||
|
|
||||||
struct memory_allocation_header
|
struct memory_manager::alloc_header
|
||||||
{
|
{
|
||||||
uint64_t pages;
|
uint64_t size;
|
||||||
uint64_t reserved;
|
uint64_t reserved;
|
||||||
uint8_t data[0];
|
uint8_t data[0];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct memory_manager::free_header
|
||||||
|
{
|
||||||
|
free_header *next;
|
||||||
|
uint64_t size;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
memory_manager::memory_manager() :
|
memory_manager::memory_manager() :
|
||||||
m_start(nullptr),
|
m_start(nullptr),
|
||||||
m_length(0)
|
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_start(start),
|
||||||
m_length(length)
|
m_length(0)
|
||||||
{
|
{
|
||||||
|
kutil::memset(m_free, 0, sizeof(m_free));
|
||||||
|
grow_memory();
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
memory_manager::allocate(size_t length)
|
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<alloc_header *>(pop_free(size));
|
||||||
|
header->size = size;
|
||||||
|
|
||||||
m_length -= length;
|
log::debug(logs::memory, " Returning %d bytes at %lx", length, &header->data);
|
||||||
memory_allocation_header *header =
|
|
||||||
reinterpret_cast<memory_allocation_header *>(m_start);
|
|
||||||
m_start = reinterpret_cast<uint8_t *>(m_start) + length;
|
|
||||||
|
|
||||||
size_t pages = length / page_manager::page_size;
|
|
||||||
g_page_manager.map_pages(
|
|
||||||
reinterpret_cast<page_manager::addr_t>(header),
|
|
||||||
pages);
|
|
||||||
|
|
||||||
header->pages = pages;
|
|
||||||
return &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
|
// 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<free_header *>(
|
||||||
|
reinterpret_cast<uint64_t>(m_start) + m_length);
|
||||||
|
|
||||||
|
g_page_manager.map_pages(
|
||||||
|
reinterpret_cast<page_manager::addr_t>(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<free_header *>(
|
||||||
|
reinterpret_cast<uint64_t>(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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,14 +5,13 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct memory_block_node;
|
|
||||||
|
|
||||||
/// Manager for allocation of virtual memory.
|
/// Manager for allocation of virtual memory.
|
||||||
class memory_manager
|
class memory_manager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
memory_manager();
|
memory_manager();
|
||||||
memory_manager(void *start, size_t length);
|
memory_manager(void *start);
|
||||||
|
|
||||||
/// Allocate memory from the area managed.
|
/// Allocate memory from the area managed.
|
||||||
/// \arg length The amount of memory to allocate, in bytes
|
/// \arg length The amount of memory to allocate, in bytes
|
||||||
@@ -25,12 +24,30 @@ public:
|
|||||||
void free(void *p);
|
void free(void *p);
|
||||||
|
|
||||||
private:
|
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;
|
void *m_start;
|
||||||
size_t m_length;
|
size_t m_length;
|
||||||
|
|
||||||
|
friend class page_manager;
|
||||||
memory_manager(const memory_manager &) = delete;
|
memory_manager(const memory_manager &) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -199,15 +199,14 @@ page_manager::init(
|
|||||||
// Initialize the kernel memory manager
|
// Initialize the kernel memory manager
|
||||||
addr_t end = 0;
|
addr_t end = 0;
|
||||||
for (page_block *b = m_used; b; b = b->next) {
|
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();
|
end = b->virtual_end();
|
||||||
else
|
} else {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
new (&g_kernel_memory_manager) memory_manager(
|
}
|
||||||
reinterpret_cast<void *>(end),
|
|
||||||
page_offset - end);
|
new (&g_kernel_memory_manager) memory_manager(reinterpret_cast<void *>(end));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -229,7 +228,7 @@ page_manager::map_offset_pointer(void **pointer, size_t length)
|
|||||||
page_block_flags::mapped |
|
page_block_flags::mapped |
|
||||||
page_block_flags::mmio;
|
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);
|
m_used = page_block::insert(m_used, block);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user