[boot][kernel] Replace frame allocator with bitmap-based one
The previous frame allocator involved a lot of splitting and merging linked lists and lost all information about frames while they were allocated. The new allocator is based on an array of descriptor structures and a bitmap. Each memory map region of allocatable memory becomes one or more descriptors, each mapping up to 1GiB of physical memory. The descriptors implement two levels of a bitmap tree, and have a pointer into the large contiguous bitmap to track individual pages.
This commit is contained in:
@@ -14,15 +14,8 @@
|
||||
#include "objects/vm_area.h"
|
||||
#include "vm_space.h"
|
||||
|
||||
using memory::frame_size;
|
||||
using memory::heap_start;
|
||||
using memory::kernel_max_heap;
|
||||
using memory::kernel_offset;
|
||||
using memory::heap_start;
|
||||
using memory::page_offset;
|
||||
using memory::pml4e_kernel;
|
||||
using memory::pml4e_offset;
|
||||
using memory::table_entries;
|
||||
|
||||
using namespace kernel;
|
||||
|
||||
@@ -57,49 +50,68 @@ void operator delete (void *p) noexcept { return g_kernel_heap.free(p); }
|
||||
void operator delete [] (void *p) noexcept { return g_kernel_heap.free(p); }
|
||||
|
||||
namespace kutil {
|
||||
void * kalloc(size_t size) { return g_kernel_heap.allocate(size); }
|
||||
void kfree(void *p) { return g_kernel_heap.free(p); }
|
||||
void * kalloc(size_t size) { return g_kernel_heap.allocate(size); }
|
||||
void kfree(void *p) { return g_kernel_heap.free(p); }
|
||||
}
|
||||
|
||||
/*
|
||||
void walk_page_table(
|
||||
page_table *table,
|
||||
page_table::level level,
|
||||
uintptr_t ¤t_start,
|
||||
size_t ¤t_bytes,
|
||||
vm_area &karea)
|
||||
void
|
||||
memory_initialize_pre_ctors(args::header &kargs)
|
||||
{
|
||||
constexpr size_t huge_page_size = (1ull<<30);
|
||||
constexpr size_t large_page_size = (1ull<<21);
|
||||
using kernel::args::frame_block;
|
||||
|
||||
for (unsigned i = 0; i < table_entries; ++i) {
|
||||
page_table *next = table->get(i);
|
||||
if (!next) {
|
||||
if (current_bytes)
|
||||
karea.commit(current_start, current_bytes);
|
||||
current_start = 0;
|
||||
current_bytes = 0;
|
||||
continue;
|
||||
} else if (table->is_page(level, i)) {
|
||||
if (!current_bytes)
|
||||
current_start = reinterpret_cast<uintptr_t>(next);
|
||||
current_bytes +=
|
||||
(level == page_table::level::pt
|
||||
? frame_size
|
||||
: level == page_table::level::pd
|
||||
? large_page_size
|
||||
: huge_page_size);
|
||||
} else {
|
||||
page_table::level deeper =
|
||||
static_cast<page_table::level>(
|
||||
static_cast<unsigned>(level) + 1);
|
||||
new (&g_kernel_heap) kutil::heap_allocator {heap_start, kernel_max_heap};
|
||||
|
||||
walk_page_table(
|
||||
next, deeper, current_start, current_bytes, kspace);
|
||||
frame_block *blocks = reinterpret_cast<frame_block*>(memory::bitmap_start);
|
||||
new (&g_frame_allocator) frame_allocator {blocks, kargs.frame_block_count};
|
||||
|
||||
// Mark all the things the bootloader allocated for us as used
|
||||
g_frame_allocator.used(
|
||||
reinterpret_cast<uintptr_t>(kargs.frame_blocks),
|
||||
kargs.frame_block_pages);
|
||||
|
||||
g_frame_allocator.used(
|
||||
reinterpret_cast<uintptr_t>(kargs.pml4),
|
||||
kargs.table_pages);
|
||||
|
||||
for (unsigned i = 0; i < kargs.num_modules; ++i) {
|
||||
const kernel::args::module &mod = kargs.modules[i];
|
||||
g_frame_allocator.used(
|
||||
reinterpret_cast<uintptr_t>(mod.location),
|
||||
memory::page_count(mod.size));
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < kargs.num_programs; ++i) {
|
||||
const kernel::args::program &prog = kargs.programs[i];
|
||||
for (auto § : prog.sections) {
|
||||
if (!sect.size) continue;
|
||||
g_frame_allocator.used(
|
||||
sect.phys_addr,
|
||||
memory::page_count(sect.size));
|
||||
}
|
||||
}
|
||||
|
||||
page_table *kpml4 = reinterpret_cast<page_table*>(kargs.pml4);
|
||||
process *kp = process::create_kernel_process(kpml4);
|
||||
vm_space &vm = kp->space();
|
||||
|
||||
vm_area *heap = new (&g_kernel_heap_area)
|
||||
vm_area_open(kernel_max_heap, vm, vm_flags::write);
|
||||
|
||||
vm.add(heap_start, heap);
|
||||
}
|
||||
|
||||
void
|
||||
memory_initialize_post_ctors(args::header &kargs)
|
||||
{
|
||||
vm_space &vm = vm_space::kernel_space();
|
||||
vm.add(memory::stacks_start, &g_kernel_stacks);
|
||||
vm.add(memory::buffers_start, &g_kernel_buffers);
|
||||
|
||||
g_frame_allocator.free(
|
||||
reinterpret_cast<uintptr_t>(kargs.page_tables),
|
||||
kargs.table_count);
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
static void
|
||||
log_mtrrs()
|
||||
@@ -166,60 +178,3 @@ setup_pat()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
memory_initialize_pre_ctors(args::header *kargs)
|
||||
{
|
||||
new (&g_kernel_heap) kutil::heap_allocator {heap_start, kernel_max_heap};
|
||||
new (&g_frame_allocator) frame_allocator;
|
||||
|
||||
args::mem_entry *entries = kargs->mem_map;
|
||||
const size_t count = kargs->map_count;
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
// TODO: use entry attributes
|
||||
// TODO: copy anything we need from "pending" memory and free it
|
||||
args::mem_entry &e = entries[i];
|
||||
if (e.type == args::mem_type::free)
|
||||
g_frame_allocator.free(e.start, e.pages);
|
||||
}
|
||||
|
||||
page_table *kpml4 = reinterpret_cast<page_table*>(kargs->pml4);
|
||||
process *kp = process::create_kernel_process(kpml4);
|
||||
vm_space &vm = kp->space();
|
||||
|
||||
vm_area *heap = new (&g_kernel_heap_area)
|
||||
vm_area_open(memory::kernel_max_heap, vm, vm_flags::write);
|
||||
|
||||
vm.add(memory::heap_start, heap);
|
||||
}
|
||||
|
||||
void
|
||||
memory_initialize_post_ctors(args::header *kargs)
|
||||
{
|
||||
/*
|
||||
uintptr_t current_start = 0;
|
||||
size_t current_bytes = 0;
|
||||
|
||||
// TODO: Should we exclude the top of this area? (eg, buffers, stacks, etc)
|
||||
page_table *kpml4 = reinterpret_cast<page_table*>(kargs->pml4);
|
||||
for (unsigned i = pml4e_kernel; i < pml4e_offset; ++i) {
|
||||
page_table *pdp = kpml4->get(i);
|
||||
kassert(pdp, "Bootloader did not create all kernelspace PDs");
|
||||
|
||||
walk_page_table(
|
||||
pdp, page_table::level::pdp,
|
||||
current_start, current_bytes,
|
||||
g_kernel_space);
|
||||
}
|
||||
|
||||
if (current_bytes)
|
||||
g_kernel_space.commit(current_start, current_bytes);
|
||||
*/
|
||||
vm_space &vm = vm_space::kernel_space();
|
||||
vm.add(memory::stacks_start, &g_kernel_stacks);
|
||||
vm.add(memory::buffers_start, &g_kernel_buffers);
|
||||
|
||||
g_frame_allocator.free(
|
||||
reinterpret_cast<uintptr_t>(kargs->page_tables),
|
||||
kargs->table_count);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user