diff --git a/src/kernel/hal/rv32/boot.c b/src/kernel/hal/rv32/boot.c index e51dd46..c003c28 100644 --- a/src/kernel/hal/rv32/boot.c +++ b/src/kernel/hal/rv32/boot.c @@ -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(); } diff --git a/src/kernel/pmm/mod.c b/src/kernel/pmm/mod.c index e0038fe..5475871 100644 --- a/src/kernel/pmm/mod.c +++ b/src/kernel/pmm/mod.c @@ -1,14 +1,111 @@ -#include "mod.h" #include +#include +#include #include +#include -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); +} diff --git a/src/kernel/pmm/mod.h b/src/kernel/pmm/mod.h index 268c503..e230c5d 100644 --- a/src/kernel/pmm/mod.h +++ b/src/kernel/pmm/mod.h @@ -1,17 +1,27 @@ #pragma once +#include #include #include -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); diff --git a/src/libs/handover/base/mod.h b/src/libs/handover/base/mod.h index cedc194..7ca45a4 100644 --- a/src/libs/handover/base/mod.h +++ b/src/libs/handover/base/mod.h @@ -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 diff --git a/src/libs/helpers/mem.h b/src/libs/helpers/mem.h index 2b0daea..72401d6 100644 --- a/src/libs/helpers/mem.h +++ b/src/libs/helpers/mem.h @@ -9,5 +9,3 @@ #define mib$(x) (kib$(x) * 1024) #define gib$(x) (mib$(x) * 1024) - -#define pages$(x) (kib$(x * 4))