#include #include //see also ../documentation/memory.txt extern "C" { uint64_t __kernel_p4_paddr; } namespace mercury::kernel::paging { static constexpr uint64_t kernel_vram_start = 0xffffffffc0000000; static constexpr uint64_t kernel_vram_pages = 261888; static constexpr uint64_t kernel_stack_bottom = 0xfffffffffff01000; static constexpr uint64_t kernel_stack_top = 0xfffffffffffff000; static constexpr uint64_t pram_pages = 1 << 23; static uint64_t pram_usage_bitmap[pram_pages / 64]; void mark_all_pram_used() { utility::mark_bitmap_region_one(pram_usage_bitmap, 0, pram_pages); } void mark_pram_region_free(uint64_t start_addr, uint64_t end_addr) { utility::mark_bitmap_region_zero( pram_usage_bitmap, start_addr / 4096, utility::min(end_addr / 4096, pram_pages)); } [[gnu::aligned(4096)]] uint64_t kernel_p4[512]; [[gnu::aligned(4096)]] uint64_t kernel_p3[512]; [[gnu::aligned(4096)]] uint64_t kernel_p2[512]; [[gnu::aligned(4096)]] uint64_t kernel_p1s[512 * 512]; static uint64_t encode_pte( uint64_t addr, bool user, bool write, bool execute) { return (addr & 0x0000ffffffffffff) | (execute ? 0 : (1ULL << 63)) | (user << 2) | (write << 1) | 1; } void init_kernel_page_tables(uint64_t kernel_offset) { __kernel_p4_paddr = (uint64_t)kernel_p4 - kernel_offset; for (int i = 0; i < 511; ++i) kernel_p4[i] = 0; kernel_p4[511] = encode_pte( (uint64_t)kernel_p3 - kernel_offset, false, true, true); for (int i = 0; i < 511; ++i) kernel_p3[i] = 0; kernel_p3[511] = encode_pte( (uint64_t)kernel_p2 - kernel_offset, false, true, true); for (int i = 0; i < 512; ++i) kernel_p2[i] = encode_pte( (uint64_t)kernel_p1s + 4096 * i - kernel_offset, false, true, true); for (int i = 0; i < 512 * 512; ++i) kernel_p1s[i] = 0; } void map_kernel_page( uint64_t paddr, uint64_t vaddr, bool write, bool execute) { uint64_t i = (vaddr - kernel_vram_start) / 4096; kernel_p1s[i] = encode_pte(paddr, false, write, execute); } static uint64_t take_pram_page() { for (uint64_t i = 0; i < pram_pages / 64; ++i) if (pram_usage_bitmap[i] != 0xffffffffffffffff) for (int j = 0; j < 64; ++j) if (!(pram_usage_bitmap[i] & (1ULL << j))) { pram_usage_bitmap[i] |= (1ULL << j); return 4096 * (i * 64 + j); } //TODO: handle error return 0; } void map_kernel_stack() { for (uint64_t vaddr = kernel_stack_bottom; vaddr < kernel_stack_top; vaddr += 4096) map_kernel_page(take_pram_page(), vaddr, true, false); } uint64_t find_unmapped_vram_region(uint64_t page_count) { uint64_t start = 0; uint64_t len = 0; for (uint64_t i = 0; i < kernel_vram_pages; ++i) if (kernel_p1s[i] == 0) { ++len; if (len == page_count) return start * 4096 + kernel_vram_start; } else { start = i + 1; len = 0; } //TODO: handle error return 0; } uint64_t get_used_vram_page_count() { uint64_t count = 0; for (uint64_t i = 0; i < kernel_vram_pages; ++i) if (kernel_p1s[i] != 0) ++count; return count; } uint64_t get_free_pram_page_count() { uint64_t used_count = 0; for (uint64_t i = 0; i < pram_pages / 64; ++i) for (uint64_t j = 0; j < 64; ++j) used_count += (pram_usage_bitmap[i] >> j) & 1; return pram_pages - used_count; } }