feat: pmm
This commit is contained in:
parent
fd6ae9ddc9
commit
cf6ab74375
5 changed files with 134 additions and 20 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
pmm_init();
|
||||
kmain();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,111 @@
|
|||
#include "mod.h"
|
||||
#include <hal>
|
||||
#include <handover>
|
||||
#include <helpers/mem.h>
|
||||
#include <logger>
|
||||
#include <string.h>
|
||||
|
||||
Pmm* pmm = NULL;
|
||||
#include "mod.h"
|
||||
|
||||
void pmm_init(size_t start, size_t len) {
|
||||
(void)start;
|
||||
(void)len;
|
||||
if (pmm != NULL) {
|
||||
error$("PMM already initialized");
|
||||
hal_brkpoint();
|
||||
static PmmBitmap bitmap = {0};
|
||||
|
||||
static bool bitmap_is_bit_set(size_t bit) {
|
||||
return bitmap.bitmap[bit / 8] & (1 << (bit % 8));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct _Page {
|
||||
struct _Page* next;
|
||||
uintptr_t addr;
|
||||
} Page;
|
||||
typedef struct
|
||||
{
|
||||
size_t len;
|
||||
size_t last;
|
||||
uint8_t* bitmap;
|
||||
} PmmBitmap;
|
||||
|
||||
typedef struct {
|
||||
size_t total_pages;
|
||||
size_t free_pages;
|
||||
Page* freelist;
|
||||
} Pmm;
|
||||
typedef struct
|
||||
{
|
||||
size_t len;
|
||||
uintptr_t base;
|
||||
} 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);
|
||||
|
|
|
@ -130,6 +130,12 @@ typedef void HandoverEntry(
|
|||
__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 ------------------------------------------------------------ */
|
||||
|
||||
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);
|
||||
|
||||
HandoverPayload* handover(void);
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
|
|
@ -9,5 +9,3 @@
|
|||
#define mib$(x) (kib$(x) * 1024)
|
||||
|
||||
#define gib$(x) (mib$(x) * 1024)
|
||||
|
||||
#define pages$(x) (kib$(x * 4))
|
||||
|
|
Loading…
Add table
Reference in a new issue