From 7c056aa005ebf34e68944ddf1d0b8a7b5dbad9bc Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 17 Sep 2019 18:56:03 +0300 Subject: [PATCH] [amd64] Add amd64_phys_alloc/free_page() --- src/arch/amd64/mm/phys.c | 77 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/src/arch/amd64/mm/phys.c b/src/arch/amd64/mm/phys.c index e478de0..0a978a0 100644 --- a/src/arch/amd64/mm/phys.c +++ b/src/arch/amd64/mm/phys.c @@ -1,19 +1,86 @@ #include "arch/amd64/mm/phys.h" +#include "arch/amd64/mm/pool.h" +#include "sys/panic.h" #include "sys/debug.h" +#include "sys/mm.h" + +// Roughly 36MiB of lower memory is occupied by kernel so far: +// The rest is available for both kernel and user allocation +#define PHYS_ALLOWED_BEGIN (((/* Kernel image end */ 0x400000 + MM_POOL_SIZE) + 0xFFF) & ~0xFFF) + +// TODO: move to sys/util.h +#define MAX(x, y) ((x) > (y) ? (x) : (y)) + +// TODO: this could be a better allocator +// + Support more memory +#define PHYS_MAX_PAGES 16384 // Gives exactly 4GiB available for allocation +#define PHYS_TRACK_INDEX(page) ((page) >> 18) +#define PHYS_TRACK_BIT(page) (((page) >> 12) & 0x3F) + +static uint64_t amd64_phys_memory_track[PHYS_MAX_PAGES]; +static uint64_t amd64_phys_last_index = 0; + +// Allocate a single 4K page +uintptr_t amd64_phys_alloc_page(void) { + for (uint64_t i = amd64_phys_last_index; i < (PHYS_MAX_PAGES >> 6); ++i) { + for (uint64_t j = 0; j < 64; ++j) { + if (!(amd64_phys_memory_track[i] & (1ULL << j))) { + amd64_phys_memory_track[i] |= (1ULL << j); + amd64_phys_last_index = i; + return PHYS_ALLOWED_BEGIN + ((i << 18) | (j << 12)); + } + } + } + for (uint64_t i = 0; i < amd64_phys_last_index; ++i) { + for (uint64_t j = 0; j < 64; ++j) { + if (!(amd64_phys_memory_track[i] & (1ULL << j))) { + amd64_phys_memory_track[i] |= (1ULL << j); + amd64_phys_last_index = i; + return PHYS_ALLOWED_BEGIN + ((i << 18) | (j << 12)); + } + } + } + return MM_NADDR; +} + +void amd64_phys_free(uintptr_t page) { + // Address is too low + if (page < PHYS_ALLOWED_BEGIN) { + panic("Tried to free kernel physical pages\n"); + } + // Address is too high + if (PHYS_TRACK_INDEX(page) >= (PHYS_MAX_PAGES >> 6)) { + panic("Tried to free non-available physical page\n"); + } + + uint64_t bit = 1ULL << PHYS_TRACK_BIT(page); + uint64_t index = PHYS_TRACK_INDEX(page); + + // Double free error + if (!(amd64_phys_memory_track[index] & bit)) { + panic("Tried to free non-allocated physical page\n"); + } + + amd64_phys_memory_track[index] &= ~bit; +} void amd64_phys_memory_map(const multiboot_memory_map_t *mmap, size_t length) { - static const char *mmap_region_strings[6] = { - "Unknown", "Available", "Used", "ACPI", "Reserved", "Defective" - }; + kdebug("Kernel table pool ends @ %p\n", PHYS_ALLOWED_BEGIN); kdebug("Memory map @ %p\n", mmap); uintptr_t curr_item = (uintptr_t) mmap; uintptr_t mmap_end = length + curr_item; + // Collect usable physical memory information while (curr_item < mmap_end) { const multiboot_memory_map_t *entry = (const multiboot_memory_map_t *) (curr_item); - size_t type_index = (entry->type >= (sizeof(mmap_region_strings) / sizeof(mmap_region_strings[0]))) ? 0 : entry->type; - kdebug("%p - %p: %s\n", entry->addr, entry->addr + entry->size, mmap_region_strings[type_index]); + uintptr_t page_aligned_begin = MAX((entry->addr + 0xFFF) & ~0xFFF, PHYS_ALLOWED_BEGIN); + uintptr_t page_aligned_end = (entry->addr + entry->len) & ~0xFFF; + + if (entry->type == 1 && page_aligned_end > page_aligned_begin) { + // TODO: size pretty-printing + kdebug("+++ %uKiB @ %p\n", (page_aligned_end - page_aligned_begin) / 1024, page_aligned_begin); + } curr_item += entry->size + sizeof(uint32_t); }