Move memory_manager and assert into kutil.

This commit is contained in:
Justin C. Miller
2018-05-08 01:11:03 -07:00
parent 712cd69242
commit 0f54630725
19 changed files with 140 additions and 84 deletions

View File

@@ -1,8 +1,8 @@
#include "kutil/assert.h"
#include "apic.h"
#include "assert.h"
#include "interrupts.h"
#include "log.h"
#include "memory_pages.h"
#include "page_manager.h"
static uint32_t

View File

@@ -1,4 +1,4 @@
#include "assert.h"
#include "kutil/assert.h"
#include "console.h"
[[noreturn]] void

View File

@@ -1,5 +0,0 @@
#pragma once
[[noreturn]] void __kernel_assert(const char *file, unsigned line, const char *message);
#define kassert(stmt, message) if(!(stmt)) { __kernel_assert(__FILE__, __LINE__, (message)); } else {}

View File

@@ -1,15 +1,15 @@
#include <stddef.h>
#include <stdint.h>
#include "kutil/assert.h"
#include "kutil/memory.h"
#include "acpi_tables.h"
#include "apic.h"
#include "assert.h"
#include "device_manager.h"
#include "interrupts.h"
#include "log.h"
#include "memory.h"
#include "memory_pages.h"
#include "page_manager.h"
static const char expected_signature[] = "RSD PTR ";

View File

@@ -1,4 +1,4 @@
#include "assert.h"
#include "kutil/assert.h"
#include "font.h"
/* PSF2 header format

View File

@@ -7,7 +7,7 @@
#include "interrupts.h"
#include "io.h"
#include "log.h"
#include "memory_pages.h"
#include "page_manager.h"
enum class gdt_flags : uint8_t
{

10
src/kernel/kalloc.cpp Normal file
View File

@@ -0,0 +1,10 @@
#include "kutil/memory_manager.h"
kutil::memory_manager g_kernel_memory_manager;
void * kalloc(size_t length) { return g_kernel_memory_manager.allocate(length); }
void kfree(void *p) { g_kernel_memory_manager.free(p); }
void * operator new (size_t n) { return g_kernel_memory_manager.allocate(n); }
void * operator new[] (size_t n) { return g_kernel_memory_manager.allocate(n); }
void operator delete (void *p) { return g_kernel_memory_manager.free(p); }
void operator delete[] (void *p){ return g_kernel_memory_manager.free(p); }

17
src/kernel/kalloc.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
/// \file kalloc.h
/// Definitions of kalloc() and kfree()
#include <stddef.h>
/// 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);
/// Free kernel space memory.
/// \arg p The pointer to free
inline void kfree(void *p);

View File

@@ -1,6 +1,6 @@
#include <type_traits>
#include "kutil/assert.h"
#include "kutil/memory.h"
#include "assert.h"
#include "console.h"
#include "log.h"

View File

@@ -1,6 +1,7 @@
#include <stddef.h>
#include <stdint.h>
#include "kutil/assert.h"
#include "kutil/memory.h"
#include "console.h"
#include "cpu.h"
@@ -11,7 +12,7 @@
#include "kernel_data.h"
#include "log.h"
#include "memory.h"
#include "memory_pages.h"
#include "page_manager.h"
#include "screen.h"
#include "serial.h"
@@ -22,6 +23,9 @@ extern "C" {
void *__bss_start, *__bss_end;
}
extern [[noreturn]] void
__kernel_assert(const char *file, unsigned line, const char *message);
void
init_console(const popcorn_data *header)
{
@@ -58,9 +62,11 @@ void do_error_1() { do_error_2(); }
void
kernel_main(popcorn_data *header)
{
kutil::assert_set_callback(__kernel_assert);
page_manager *pager = new (&g_page_manager) page_manager;
memory_initialize_managers(
memory_initialize(
header->memory_map,
header->memory_map_length,
header->memory_map_desc_size);

View File

@@ -1,187 +0,0 @@
#include "kutil/enum_bitfields.h"
#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_manager::mem_header
{
mem_header(mem_header *prev, mem_header *next, uint8_t size) :
m_prev(prev), m_next(next)
{
set_size(size);
}
inline void set_size(uint8_t size)
{
m_prev = reinterpret_cast<mem_header *>(
reinterpret_cast<addr_t>(prev()) | (size & 0x3f));
}
inline void set_used(bool used)
{
m_next = reinterpret_cast<mem_header *>(
reinterpret_cast<addr_t>(next()) | (used ? 1 : 0));
}
inline void set_next(mem_header *next)
{
bool u = used();
m_next = next;
set_used(u);
}
inline void set_prev(mem_header *prev)
{
uint8_t s = size();
m_prev = prev;
set_size(s);
}
void remove()
{
if (next()) next()->set_prev(prev());
if (prev()) prev()->set_next(next());
set_prev(nullptr);
set_next(nullptr);
}
inline mem_header * next() { return kutil::mask_pointer(m_next, 0x3f); }
inline mem_header * prev() { return kutil::mask_pointer(m_prev, 0x3f); }
inline mem_header * buddy() const {
return reinterpret_cast<mem_header *>(
reinterpret_cast<addr_t>(this) ^ (1 << size()));
}
inline bool eldest() const { return this < buddy(); }
inline uint8_t size() const { return reinterpret_cast<addr_t>(m_prev) & 0x3f; }
inline bool used() const { return reinterpret_cast<addr_t>(m_next) & 0x1; }
private:
mem_header *m_prev;
mem_header *m_next;
};
memory_manager::memory_manager() :
m_start(nullptr),
m_length(0)
{
kutil::memset(m_free, 0, sizeof(m_free));
}
memory_manager::memory_manager(void *start) :
m_start(start),
m_length(0)
{
kutil::memset(m_free, 0, sizeof(m_free));
grow_memory();
}
void *
memory_manager::allocate(size_t length)
{
size_t total = length + sizeof(mem_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);
mem_header *header = pop_free(size);
header->set_used(true);
log::debug(logs::memory, " Returning %d bytes at %lx", length, header + 1);
return header + 1;
}
void
memory_manager::free(void *p)
{
mem_header *header = reinterpret_cast<mem_header *>(p);
header -= 1; // p points after the header
header->set_used(false);
log::debug(logs::memory, "Freeing a block of size %2d at %lx", header->size(), header);
while (true) {
mem_header *buddy = header->buddy();
if (buddy->used() || buddy->size() != header->size()) break;
log::debug(logs::memory, " buddy is same size at %lx", buddy);
buddy->remove();
header = header->eldest() ? header : buddy;
header->set_size(header->size() + 1);
log::debug(logs::memory, " joined into size %2d at %lx", header->size(), header);
}
uint8_t size = header->size();
header->set_next(get_free(size));
get_free(size) = header;
if (header->next())
header->next()->set_prev(header);
}
void
memory_manager::grow_memory()
{
size_t length = (1 << max_size);
void *next = kutil::offset_pointer(m_start, m_length);
g_page_manager.map_pages(
reinterpret_cast<page_manager::addr_t>(next),
length / page_manager::page_size);
mem_header *block = new (next) mem_header(nullptr, get_free(max_size), max_size);
get_free(max_size) = block;
if (block->next())
block->next()->set_prev(block);
m_length += length;
log::debug(logs::memory, "Allocated new block at %lx: size %d next %lx",
block, max_size, block->next());
}
void
memory_manager::ensure_block(unsigned size)
{
if (get_free(size) != nullptr) return;
else if (size == max_size) {
grow_memory();
return;
}
mem_header *orig = pop_free(size + 1);
mem_header *next = kutil::offset_pointer(orig, 1 << size);
new (next) mem_header(orig, nullptr, size);
orig->set_next(next);
orig->set_size(size);
get_free(size) = orig;
log::debug(logs::memory, "ensure_block[%2d] split blocks:", size);
log::debug(logs::memory, " %lx: size %d next %lx", orig, size, orig->next());
log::debug(logs::memory, " %lx: size %d next %lx", next, size, next->next());
}
memory_manager::mem_header *
memory_manager::pop_free(unsigned size)
{
ensure_block(size);
mem_header *block = get_free(size);
get_free(size) = block->next();
block->remove();
return block;
}
void * operator new (size_t, void *p) { return p; }
void * operator new (size_t n) { return g_kernel_memory_manager.allocate(n); }
void * operator new[] (size_t n) { return g_kernel_memory_manager.allocate(n); }
void operator delete (void *p) { return g_kernel_memory_manager.free(p); }
void operator delete[] (void *p){ return g_kernel_memory_manager.free(p); }

View File

@@ -1,71 +0,0 @@
#pragma once
/// \file memory.h
/// The block memory manager and related definitions.
#include <stddef.h>
#include <stdint.h>
/// Manager for allocation of virtual memory.
class memory_manager
{
public:
memory_manager();
memory_manager(void *start);
/// 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:
class mem_header;
/// 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
mem_header *& get_free(unsigned size) { return m_free[size - min_size]; }
/// Helper to get a block of the given size, growing if necessary
mem_header * pop_free(unsigned size);
/// Minimum block size is (2^min_size). Must be at least 6.
static const unsigned min_size = 6;
/// Maximum block size is (2^max_size). Must be less than 64.
static const unsigned max_size = 16;
mem_header *m_free[max_size - min_size];
void *m_start;
size_t m_length;
friend class page_manager;
memory_manager(const memory_manager &) = delete;
};
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); }
/// Free kernel space memory.
/// \arg p The pointer to free
inline void kfree(void *p) { g_kernel_memory_manager.free(p); }
void * operator new (size_t, void *p);

View File

@@ -1,7 +1,7 @@
#include "kutil/assert.h"
#include "kutil/memory.h"
#include "assert.h"
#include "memory.h"
#include "memory_pages.h"
#include "page_manager.h"
const unsigned efi_page_size = 0x1000;
@@ -407,7 +407,7 @@ page_in_ident(
}
void
memory_initialize_managers(const void *memory_map, size_t map_length, size_t desc_length)
memory_initialize(const void *memory_map, size_t map_length, size_t desc_length)
{
// The bootloader reserved 16 pages for page tables, which we'll use to bootstrap.
// The first one is the already-installed PML4, so grab it from CR3.

View File

@@ -1,14 +1,12 @@
#include <algorithm>
#include "assert.h"
#include "kutil/assert.h"
#include "kutil/memory_manager.h"
#include "log.h"
#include "memory.h"
#include "memory_pages.h"
#include "page_manager.h"
page_manager g_page_manager;
using addr_t = page_manager::addr_t;
static addr_t
pt_to_phys(page_table *pt)
@@ -16,6 +14,7 @@ pt_to_phys(page_table *pt)
return reinterpret_cast<addr_t>(pt) - page_manager::page_offset;
}
static page_table *
pt_from_phys(addr_t p)
{
@@ -29,6 +28,18 @@ struct free_page_header
size_t count;
};
void mm_grow_callback(void *next, size_t length)
{
kassert(length % page_manager::page_size == 0,
"Heap manager requested a fractional page.");
size_t pages = length / page_manager::page_size;
log::info(logs::memory, "Heap manager growing heap by %d pages.", pages);
g_page_manager.map_pages(reinterpret_cast<addr_t>(next), pages);
}
size_t
page_block::length(page_block *list)
{
@@ -203,7 +214,10 @@ page_manager::init(
}
}
new (&g_kernel_memory_manager) memory_manager(reinterpret_cast<void *>(end));
extern kutil::memory_manager g_kernel_memory_manager;
new (&g_kernel_memory_manager) kutil::memory_manager(
reinterpret_cast<void *>(end),
mm_grow_callback);
}
void

View File

@@ -1,10 +1,11 @@
#pragma once
/// \file memory_pages.h
/// \file page_manager.h
/// The page memory manager and related definitions.
#include <stddef.h>
#include <stdint.h>
#include "kutil/memory.h"
#include "kutil/enum_bitfields.h"
struct page_block;
@@ -16,8 +17,6 @@ struct free_page_header;
class page_manager
{
public:
using addr_t = uint64_t;
/// Size of a single page.
static const size_t page_size = 0x1000;
@@ -53,8 +52,6 @@ public:
static page_manager * get();
private:
friend void memory_initialize_managers(const void *, size_t, size_t);
/// Set up the memory manager from bootstraped memory
void init(
page_block *free,
@@ -143,6 +140,7 @@ private:
page_block *m_block_cache; ///< Cache of unused page_block structs
free_page_header *m_page_cache; ///< Cache of free pages to use for tables
friend void memory_initialize(const void *, size_t, size_t);
page_manager(const page_manager &) = delete;
};
@@ -175,8 +173,6 @@ IS_BITFIELD(page_block_flags);
/// linked list of such structures.
struct page_block
{
using addr_t = page_manager::addr_t;
addr_t physical_address;
addr_t virtual_address;
uint32_t count;
@@ -294,3 +290,6 @@ template <typename T> inline T page_align(T p)
/// \returns The next page-table-aligned address _after_ `p`.
template <typename T> inline T page_table_align(T p) { return ((p - 1) & ~0x1fffffull) + 0x200000; }
/// Bootstrap the memory managers.
void memory_initialize(const void *memory_map, size_t map_length, size_t desc_length);