#include "mm.h" typedef struct mm_page_entry_s { size_t count; struct mm_page_entry_s * next; } mm_region_entry_t; static mm_region_entry_t * mm_next_free_region; static size_t mm_free_pages; static size_t mm_total_ram; static size_t kernel_start_address; static size_t kernel_size; extern uint8_t _hos_mem_start; extern uint8_t _hos_mem_end; static void mm_add_ram_region(size_t base, size_t size) { mm_region_entry_t * region = (mm_region_entry_t *)base; size_t pages = size / PAGE_SIZE; region->count = pages; region->next = mm_next_free_region; mm_next_free_region = region; mm_total_ram += size; mm_free_pages = pages; } void mm_register_ram_region(uint64_t base, size_t size) { /* Ignore any RAM region above 4GB. */ if (base >= 0x100000000ull) { return; } if ((base + size) > 0x100000000ull) { size = (size_t)(0x100000000ull - base); } size_t end_address = mm_page_floor((size_t)base + size); size_t start_address = mm_page_ceil(base); size = end_address - start_address; if (size < PAGE_SIZE) { return; } size_t kernel_end_address = kernel_start_address + kernel_size; /* Add regions before and after kernel RAM. */ if (start_address < kernel_start_address) { /* RAM region begins before kernel RAM. */ size_t this_sz = size; if ((start_address + this_sz) > kernel_start_address) { this_sz = kernel_start_address - start_address; } mm_add_ram_region(start_address, this_sz); } if ((start_address + size) > kernel_end_address) { /* RAM region ends after kernel RAM. */ size_t this_sz = size; if (start_address < kernel_end_address) { this_sz = (start_address + size) - kernel_end_address; start_address = kernel_end_address; } mm_add_ram_region(start_address, this_sz); } } void mm_init(void) { kernel_start_address = mm_page_floor((size_t)&_hos_mem_start); kernel_size = mm_page_ceil((size_t)&_hos_mem_end - kernel_start_address); mm_total_ram = kernel_size; } size_t mm_get_total_ram(void) { return mm_total_ram; } size_t mm_get_kernel_address(void) { return kernel_start_address; } size_t mm_get_kernel_size(void) { return kernel_size; }