feat: pmm

This commit is contained in:
Jordan ⌨️ 2025-04-23 19:52:58 +02:00
parent fd6ae9ddc9
commit cf6ab74375
5 changed files with 134 additions and 20 deletions

View file

@ -32,6 +32,7 @@ void rv32_start(__attribute__((unused)) size_t hartid, uintptr_t dtb) {
debug$("%s (start: %x, len: %x)", handover_tag_name(handover()->records[i].tag), handover()->records[i].start, handover()->records[i].size); debug$("%s (start: %x, len: %x)", handover_tag_name(handover()->records[i].tag), handover()->records[i].start, handover()->records[i].size);
} }
pmm_init();
kmain(); kmain();
} }

View file

@ -1,14 +1,111 @@
#include "mod.h"
#include <hal> #include <hal>
#include <handover>
#include <helpers/mem.h>
#include <logger> #include <logger>
#include <string.h>
Pmm* pmm = NULL; #include "mod.h"
void pmm_init(size_t start, size_t len) { static PmmBitmap bitmap = {0};
(void)start;
(void)len; static bool bitmap_is_bit_set(size_t bit) {
if (pmm != NULL) { return bitmap.bitmap[bit / 8] & (1 << (bit % 8));
error$("PMM already initialized"); }
hal_brkpoint();
static void pmm_mark_free(uintptr_t base, size_t len) {
size_t start = align_up$(base, page_size()) / page_size();
size_t end = align_down$(base + len, page_size()) / page_size();
for (size_t i = start; i < end; i++) {
bitmap.bitmap[i / 8] &= ~(1 << (i % 8));
} }
} }
static void pmm_mark_used(uintptr_t base, size_t len) {
size_t start = align_up$(base, page_size()) / page_size();
size_t end = align_down$(base + len, page_size()) / page_size();
for (size_t i = start; i < end; i++) {
bitmap.bitmap[i / 8] |= 1 << (i % 8);
}
}
void pmm_init(void) {
HandoverPayload* hand = handover();
HandoverRecord last_entry;
HandoverRecord record;
for (size_t i = hand->count; i; i--) {
if (hand->records[i - 1].tag != HANDOVER_FILE) {
last_entry = hand->records[i - 1];
break;
}
}
bitmap.len = align_up$((last_entry.start + last_entry.size) / (page_size() * 8), page_size());
bitmap.last = 0;
debug$("Bitmap size: %d bytes", bitmap.len);
handover_foreach_record(hand, record) {
if (record.tag == HANDOVER_FREE && record.size >= bitmap.len) {
debug$("Bitmap base: %p", record.start);
bitmap.bitmap = (uint8_t*)record.start;
record.start += bitmap.len;
record.size -= bitmap.len;
break;
}
}
if (bitmap.bitmap == NULL) {
error$("Couldn't allocate bitmap");
hal_brkpoint();
}
memset(bitmap.bitmap, 0xFF, bitmap.len);
handover_foreach_record(hand, record) {
if (record.tag == HANDOVER_FREE) {
pmm_mark_free(record.start, record.size);
}
}
}
PhysObj pmm_alloc(size_t len) {
size_t pages = align_up$(len, page_size()) / page_size();
static bool try_again = false;
size_t size = 0;
size_t start_index = 0;
for (size_t i = bitmap.last; i < bitmap.len * 8; i++) {
if (!bitmap_is_bit_set(i)) {
if (size == 0) {
start_index = i;
}
if (size++ == pages) {
pmm_mark_used(start_index * page_size(), pages * page_size());
bitmap.last = i + 1;
try_again = false;
return (PhysObj){.base = start_index * page_size(), .len = pages * page_size()};
}
} else {
size = 0;
}
}
if (!try_again) {
warn$("End of the bitmap reached, trying again");
try_again = true;
bitmap.last = 0;
return pmm_alloc(pages);
} else {
error$("Out of physical memory");
hal_brkpoint();
}
__builtin_unreachable();
}
void pmm_free(PhysObj obj) {
pmm_mark_free(obj.base, obj.len);
}

View file

@ -1,17 +1,27 @@
#pragma once #pragma once
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
typedef struct _Page { typedef struct
struct _Page* next; {
uintptr_t addr; size_t len;
} Page; size_t last;
uint8_t* bitmap;
} PmmBitmap;
typedef struct { typedef struct
size_t total_pages; {
size_t free_pages; size_t len;
Page* freelist; uintptr_t base;
} Pmm; } PhysObj;
void pmm_init(size_t start, size_t len); struct pmm_alloc_param {
size_t pages;
bool low;
};
PhysObj pmm_alloc(size_t pages);
void pmm_init(void);

View file

@ -130,6 +130,12 @@ typedef void HandoverEntry(
__VA_ARGS__ __VA_OPT__(, ){.tag = HANDOVER_END}, \ __VA_ARGS__ __VA_OPT__(, ){.tag = HANDOVER_END}, \
}; };
#define handover_foreach_record(h, r) \
if ((h)->count > 0) \
for (size_t i = 0; \
i < (h)->count && (((r) = (h)->records[i]), 1); \
++i)
/* --- Utilities ------------------------------------------------------------ */ /* --- Utilities ------------------------------------------------------------ */
char const* handover_tag_name(HandoverTag tag); char const* handover_tag_name(HandoverTag tag);
@ -156,4 +162,6 @@ char const* handover_str(HandoverPayload const* payload, uint32_t offset);
size_t handover_add_string(HandoverPayload* handover, char const* str); size_t handover_add_string(HandoverPayload* handover, char const* str);
HandoverPayload* handover(void);
#pragma GCC diagnostic pop #pragma GCC diagnostic pop

View file

@ -9,5 +9,3 @@
#define mib$(x) (kib$(x) * 1024) #define mib$(x) (kib$(x) * 1024)
#define gib$(x) (mib$(x) * 1024) #define gib$(x) (mib$(x) * 1024)
#define pages$(x) (kib$(x * 4))