feat: start adding physical memory allocator

This commit is contained in:
Katharina 2026-06-28 16:19:21 +02:00
parent 8dc53f662e
commit e2ea22ad53
15 changed files with 440 additions and 38 deletions

View file

@ -0,0 +1,10 @@
extern "C" {
void __cxa_pure_virtual() {
for (;;) {
__asm__ volatile("cli; hlt");
}
}
}

View file

@ -3,9 +3,10 @@
#include "init/init.h"
#include "init/multiboot2.h"
#include "init/print.h"
#include "memory/allocator.h"
[[maybe_unused]] [[noreturn]] __attribute__((used)) static void halt() {
while (true) __asm__ volatile ("");
while (true) __asm__ volatile ("hlt");
}
[[maybe_unused]] [[noreturn]] __attribute__((used)) static void panic(const char* msg) {
@ -13,40 +14,116 @@
halt();
}
static int step_depth = 0;
template<typename T>
static void step(const char* name, T&& fn) {
print("Starting ", {});
print(name, {});
print("\n", {});
for(int i = 0; i < step_depth; ++i) {
print(" ");
}
print("Starting ");
print(name);
print("\n");
++step_depth;
fn();
print("Finished ", {});
print(name, {});
print("\n", {});
--step_depth;
for(int i = 0; i < step_depth; ++i) {
print(" ");
}
print("Finished ");
print(name);
print("\n");
}
optional<paddr_t> findInitialMemoryPage(const multiboot::tag_mmap* multiboot_info) {
const auto* base = reinterpret_cast<const uint8_t*>(multiboot_info->entries);
const auto* end = reinterpret_cast<const uint8_t*>(multiboot_info) + multiboot_info->size;
for (const auto* ptr = base; ptr < end; ptr += multiboot_info->entry_size) {
const auto* entry = reinterpret_cast<const multiboot::mem_entry*>(ptr);
if(entry->type != multiboot::mem_type::available) {
continue;
}
auto start_ptr = (entry->addr + page_size - 1) & (~page_size);
auto end_ptr = (entry->addr + entry->len) & (~page_size);
auto size = end_ptr - start_ptr;
if(size < page_size) {
continue;
}
for(auto ptr = start_ptr; ptr < end_ptr; ptr += page_size) {
if(!is_in_reserved_section(paddr_t{ptr}, page_size)) {
return paddr_t{ptr};
}
}
}
return {};
}
void PhysicalAllocator::init(const multiboot::tag_mmap* multiboot_info) {
PhysicalAllocator alloc;
auto page_opt = findInitialMemoryPage(multiboot_info);
if(!page_opt.has_value()) {
panic("System could not find enough valid ram!");
}
auto page = page_opt.value();
memset(page.access<uint8_t*>(), 0, page_size);
alloc.storage = page.access<PhysicalAllocator::Page>();
alloc.storage->entries[0].page_count=68719476736;
alloc.storage->entries[0].owner=pid_reserved;
step("multiboot", [&]() {
const auto* base = reinterpret_cast<const uint8_t*>(multiboot_info->entries);
const auto* end = reinterpret_cast<const uint8_t*>(multiboot_info) + multiboot_info->size;
for (const auto* ptr = base; ptr < end; ptr += multiboot_info->entry_size) {
const auto* entry = reinterpret_cast<const multiboot::mem_entry*>(ptr);
if(entry->type!=multiboot::mem_type::available) {
continue;
}
auto start_ptr = (entry->addr + page_size - 1) & (~page_size);
auto end_ptr = (entry->addr + entry->len) & (~page_size);
auto size = end_ptr - start_ptr;
alloc.storage->forceEntry({size/page_size, pid_free});
}
});
step("reserved_sections", [&]() {
for_each_reserved_section([&](const KernelSection& section){
if(section.vma_start == section.vma_end) {
return;
}
auto start_ptr = (section.phys_start().address) & (~page_size);
auto end_ptr = (section.phys_end().address + page_size - 1) & (~page_size);
auto size = end_ptr - start_ptr;
alloc.storage->forceEntry({size/page_size, pid_kernel});
});
});
alloc.storage->cleanup();
alloc.storage->compact();
PhysicalAllocator::getInstance() = alloc;
}
static void loadMultiboot() {
multiboot::visit_all(overloaded{
[](const multiboot::tag_mmap* mem) {
print("Tag Memory\n", {});
print("Tag Memory Map\n");
step("memory setup", [mem](){PhysicalAllocator::init(mem);});
},
[](const multiboot::tag_string* str) {
print("Tag String (0x", {});
print_hex(static_cast<uint64_t>(str->type), {});
print("): ", {});
print(str->string, {});
print("\n", {});
print("Tag String (");
print(multiboot::get_tag_name(str->type));
print("): ");
print(str->string);
print("\n");
},
[](const auto* tag) {
print("Tag (0x", {});
print_hex(static_cast<uint64_t>(tag->type), {});
print(")\n", {});
print("Tag ");
print(multiboot::get_tag_name(tag->type));
print("\n");
}
});
}
[[maybe_unused]] [[noreturn]] __attribute__((used)) void init() {
initFromLow();
print("Reached init\n", {});
print("Reached init\n");
step("multiboot", loadMultiboot);
halt();
}

View file

@ -6,6 +6,7 @@ static constexpr int VGA_COLS = 80;
static constexpr int VGA_ROWS = 25;
static constexpr int BYTES_PER_CELL = 2;
static constexpr int BYTES_PER_ROW = VGA_COLS * BYTES_PER_CELL;
static constexpr int SCREEN_BYTES = BYTES_PER_ROW * VGA_ROWS;
static constexpr int HEX_BITS = 4;
static constexpr int HEX_TOP_SHIFT = (sizeof(uint64_t) * 8) - HEX_BITS;
@ -17,8 +18,23 @@ static volatile uint16_t* vga_cell(uint32_t offset) {
return paddr_t{VGA_PHYS_BASE + offset}.access<volatile uint16_t>();
}
static void scroll() {
// Shift every row up by one.
for (int i = 0; i < (VGA_ROWS - 1) * VGA_COLS; i++) {
*vga_cell(i * BYTES_PER_CELL) = *vga_cell((i + VGA_COLS) * BYTES_PER_CELL);
}
// Clear the last row.
for (int i = (VGA_ROWS - 1) * VGA_COLS; i < VGA_ROWS * VGA_COLS; i++) {
*vga_cell(i * BYTES_PER_CELL) = 0;
}
cursor -= BYTES_PER_ROW;
}
static void next_line() {
cursor = ((cursor + BYTES_PER_ROW - 1) / BYTES_PER_ROW) * BYTES_PER_ROW;
while (cursor >= SCREEN_BYTES) {
scroll();
}
}
static void put_char(char ch, uint16_t attr_word) {
@ -26,6 +42,9 @@ static void put_char(char ch, uint16_t attr_word) {
next_line();
return;
}
while (cursor >= SCREEN_BYTES) {
scroll();
}
*vga_cell(cursor) = attr_word | (uint16_t)ch;
cursor += BYTES_PER_CELL;
}

View file

@ -13,15 +13,9 @@ RESERVE_SECTION(boot);
RESERVE_SECTION(startup_text);
RESERVE_SECTION(startup_data);
RESERVE_SECTION(text);
RESERVE_SECTION(rodata);
RESERVE_SECTION(rodata); // covers the nested .reserved_ranges array
RESERVE_SECTION(data);
RESERVE_SECTION(bss);
[[maybe_unused]] static const KernelSection _rsv_reserved_ranges
__attribute__((section(".reserved_ranges"), used)) = {
(uint64_t)__reserved_ranges_start__,
(uint64_t)__reserved_ranges_end__,
"reserved_ranges"
};
RESERVE_SECTION(trampoline_text);
RESERVE_SECTION(trampoline_data);
RESERVE_SECTION(trampoline_bss);

View file

@ -0,0 +1,16 @@
#include "memory/allocator.h"
#include "util/optional.h"
static PhysicalAllocator allocator{};
PhysicalAllocator& PhysicalAllocator::getInstance() {
return allocator;
}
PhysicalAllocator::allocation_t PhysicalAllocator::allocPages(size_t count, pid_t owner) {
}
void PhysicalAllocator::free(allocation_t ptr) {
}

View file

@ -1,8 +1,24 @@
#include "init/init.h"
#include "memory/pointer.h"
extern "C" {
// Linker-defined bounds of the (NOLOAD) .bss section and the .init_array of
// global constructors. See linker.ld.
extern char __bss_start__[];
extern char __bss_end__[];
using constructor_t = void (*)();
extern constructor_t __init_array_start__[];
extern constructor_t __init_array_end__[];
}
extern "C" [[maybe_unused]] [[noreturn]] __attribute__((used)) void __entry64() {
memset(__bss_start__, 0, static_cast<size_t>(__bss_end__ - __bss_start__));
for (constructor_t* ctor = __init_array_start__; ctor != __init_array_end__; ++ctor) {
(*ctor)();
}
init();
while (true) __asm__ volatile ("");
while (true) __asm__ volatile ("hlt");
}
asm(R"(