From 30ffc429fc220558b675459190656cd8b645452a Mon Sep 17 00:00:00 2001 From: Max Wash Date: Wed, 28 Dec 2022 18:41:04 +0000 Subject: [PATCH] Started implementing a boot-time memory manager --- sandbox/memblock/main.c | 44 ++++++++++- sandbox/memblock/memblock.c | 144 ++++++++++++++++++++++++++++++++++++ sandbox/memblock/memblock.h | 48 ++++++++++++ 3 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 sandbox/memblock/memblock.c create mode 100644 sandbox/memblock/memblock.h diff --git a/sandbox/memblock/main.c b/sandbox/memblock/main.c index 71b0ab7..601be27 100644 --- a/sandbox/memblock/main.c +++ b/sandbox/memblock/main.c @@ -1,7 +1,49 @@ #include +#include +#include +#include +#include "memblock.h" + +/* we're working with 4MiB of simulated system RAM */ +#define MEMORY_SIZE 0x400000ULL int main(int argc, const char **argv) { - printf("Hello, world\n"); + void *system_memory = mmap( + NULL, + MEMORY_SIZE, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + + if (system_memory == MAP_FAILED) { + perror("mmap"); + fprintf(stderr, "cannot allocate simulated system RAM buffer"); + return -1; + } + + printf("allocated 0x%llx bytes of memory to act as system RAM at %p\n", MEMORY_SIZE, system_memory); + + memblock_add(0, MEMORY_SIZE); + + memblock_reserve(0x10000, 0x40000); + memblock_reserve(0x60000, 0x20000); + memblock_reserve(0x30000, 0x40000); + + printf("memory regions:\n"); + for (unsigned int i = 0; i < memblock.memory.count; i++) { + printf("\t%08" PRIxPTR "-%08" PRIxPTR "\n", + memblock.memory.regions[i].base, + memblock.memory.regions[i].limit); + } + + printf("reserved regions:\n"); + for (unsigned int i = 0; i < memblock.reserved.count; i++) { + printf("\t%08" PRIxPTR "-%08" PRIxPTR "\n", + memblock.reserved.regions[i].base, + memblock.reserved.regions[i].limit); + } + + munmap(system_memory, MEMORY_SIZE); return 0; } diff --git a/sandbox/memblock/memblock.c b/sandbox/memblock/memblock.c new file mode 100644 index 0000000..2b823be --- /dev/null +++ b/sandbox/memblock/memblock.c @@ -0,0 +1,144 @@ +#include +#include +#include "memblock.h" + +static memblock_region_t init_memory_regions[MEMBLOCK_INIT_MEMORY_REGION_COUNT]; +static memblock_region_t init_reserved_regions[MEMBLOCK_INIT_RESERVED_REGION_COUNT]; + +memblock_t memblock = { + .memory.regions = init_memory_regions, + .memory.count = 0, + .memory.max = MEMBLOCK_INIT_MEMORY_REGION_COUNT, + .memory.name = "memory", + + .reserved.regions = init_reserved_regions, + .reserved.count = 0, + .reserved.max = MEMBLOCK_INIT_RESERVED_REGION_COUNT, + .reserved.name = "reserved", +}; + +static int memblock_insert_region(memblock_type_t *type, memblock_region_t *to_add) +{ + unsigned int i = 0; + + for (i = 0; i < type->count; i++) { + const memblock_region_t *cur = &type->regions[i]; + + if (cur->base >= to_add->limit) { + break; + } + } + + memblock_region_t *src = &type->regions[i]; + memblock_region_t *dst = &type->regions[i + 1]; + unsigned int count = type->count - i; + + memmove(dst, src, count * sizeof *src); + + *src = *to_add; + type->count++; + + return 0; +} + +static int memblock_remove_region(memblock_type_t *type, unsigned int i) +{ + if (i >= type->count) { + return -1; + } + + memblock_region_t *src = &type->regions[i + 1]; + memblock_region_t *dst = &type->regions[i]; + unsigned int count = type->count - i; + + memmove(dst, src, count * sizeof *src); + type->count--; + return 0; +} + +int memblock_add_range(memblock_type_t *type, uintptr_t base, size_t size) +{ + if (size == 0) { + return 0; + } + + uintptr_t limit = base + size - 1; + + if (type->count == 0) { + type->regions[0].base = base; + type->regions[0].limit = limit; + type->count++; + return 0; + } + + memblock_region_t new_region = { .base = base, .limit = limit }; + bool add_new = true; + + for (unsigned int i = 0; i < type->count; i++) { + memblock_region_t *cur_region = &type->regions[i]; + + /* case 1: the region being added and the current region have no connection what-so-ever (no overlaps) */ + if (cur_region->limit + 1 < new_region.base || cur_region->base > new_region.limit) { + continue; + } + + /* case 2: the region being added matches a region already in the list. */ + if (cur_region->base == new_region.base && cur_region->limit == new_region.limit) { + /* nothing needs to be done */ + add_new = false; + break; + } + + + /* case 3: the region being added completely contains a region already in the list. */ + if (cur_region->base > new_region.base && cur_region->limit <= new_region.limit) { + memblock_remove_region(type, i); + + /* after memblock_remove_region(), a different region will have moved into the array slot referenced by i. + * decrementing i means we'll stay at the current index and process this region. */ + i--; + continue; + } + + + /* case 4: the region being added meets or partially overlaps a region already in the list. */ + + /* there can be an overlap at the beginning and the end of the region being added, + * anything else is either a full overlap (case 3) or not within the region being added at all. + * to handle this, remove the region that's already in the list and extend the region being added to cover it */ + if (new_region.base > cur_region->base || new_region.base == cur_region->limit - 1) { + /* the new region overlaps the END of the current region, change the base of the new region to match that of the current region. */ + new_region.base = cur_region->base; + } else if (new_region.base < cur_region->base || new_region.limit + 1 == cur_region->base){ + /* the new region overlaps the BEGINNING of the current region, change the limit of the new region to match that of the current region. */ + new_region.limit = cur_region->limit; + } else { + continue; + } + + /* with the new region updated to include the current region, we can remove the current region from the list */ + memblock_remove_region(type, i); + i--; + } + + if (add_new) { + memblock_insert_region(type, &new_region); + } + + return 0; +} + +int memblock_add(uintptr_t base, size_t size) +{ + return memblock_add_range(&memblock.memory, base, size); +} + +int memblock_reserve(uintptr_t base, size_t size) +{ + return memblock_add_range(&memblock.reserved, base, size); +} + +uintptr_t memblock_alloc(size_t size) +{ + return 0; +} diff --git a/sandbox/memblock/memblock.h b/sandbox/memblock/memblock.h new file mode 100644 index 0000000..2148a6b --- /dev/null +++ b/sandbox/memblock/memblock.h @@ -0,0 +1,48 @@ +#ifndef MEMBLOCK_H_ +#define MEMBLOCK_H_ + +#include +#include + +#define MEMBLOCK_INIT_MEMORY_REGION_COUNT 128 +#define MEMBLOCK_INIT_RESERVED_REGION_COUNT 128 + +#define __for_each_mem_range(i, type_a, type_b, p_start, p_end) \ + +typedef uint64_t memblock_index_t; + +typedef struct memblock_region { + /* the address of the first byte that makes up the region */ + uintptr_t base; + /* the address of the last byte that makes up the region */ + size_t limit; +} memblock_region_t; + +typedef struct memblock_type { + struct memblock_region *regions; + unsigned int count; + unsigned int max; + const char *name; +} memblock_type_t; + +typedef struct memblock { + struct memblock_type memory; + struct memblock_type reserved; +} memblock_t; + +typedef struct memblock_iter { + memblock_index_t idx; + uintptr_t base; + size_t limit; +} memblock_iter_t; + +extern memblock_t memblock; + +extern int __next_mem_range(memblock_iter_t *it); + +extern int memblock_add(uintptr_t base, size_t size); +extern int memblock_reserve(uintptr_t base, size_t size); + +extern uintptr_t memblock_alloc(size_t size); + +#endif