diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 687a9c56..e20cca1c 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -7,6 +7,7 @@ set(SOURCES src/video/TextConsole.cpp src/memory/MemoryManager.cpp src/memory/Heap.cpp + src/memory/KernelVM.cpp src/memory/MemoryMap.cpp src/boot/Init.cpp src/arch/Serial.cpp diff --git a/kernel/src/memory/KernelVM.cpp b/kernel/src/memory/KernelVM.cpp new file mode 100644 index 00000000..0a4a445b --- /dev/null +++ b/kernel/src/memory/KernelVM.cpp @@ -0,0 +1,104 @@ +#include "memory/KernelVM.h" +#include "arch/MMU.h" +#include + +static const u64 KERNEL_VM_RANGE_START = 0xfffffffff0000000; + +static Bitmap g_kernelvm_bitmap; + +static u8 bitmap_memory[4096]; + +static const usize KERNEL_VM_RANGE_SIZE = (sizeof(bitmap_memory) * 8) * ARCH_PAGE_SIZE; + +static const u64 KERNEL_VM_RANGE_END = KERNEL_VM_RANGE_SIZE + KERNEL_VM_RANGE_START; + +static_assert(KERNEL_VM_RANGE_END == 0xfffffffff8000000); + +static usize g_used_vm; + +namespace KernelVM +{ + void init() + { + g_kernelvm_bitmap.initialize(bitmap_memory, sizeof(bitmap_memory)); + } + + Result alloc_one_page() + { + for (u64 index = 0; index < g_kernelvm_bitmap.size(); index++) + { + if (g_kernelvm_bitmap.get(index)) continue; + g_kernelvm_bitmap.set(index, true); + g_used_vm += ARCH_PAGE_SIZE; + return KERNEL_VM_RANGE_START + (index * ARCH_PAGE_SIZE); + } + + return err(ENOMEM); + } + + Result alloc_several_pages(usize count) + { + u64 first_free_index = 0; + u64 free_contiguous_pages = 0; + for (u64 index = 0; index < g_kernelvm_bitmap.size(); index++) + { + if (g_kernelvm_bitmap.get(index)) + { + free_contiguous_pages = 0; + continue; + } + + // At this point, we have a free page. + + if (!free_contiguous_pages) first_free_index = index; + free_contiguous_pages++; + + // Found enough contiguous free pages!! + if (free_contiguous_pages == count) + { + g_used_vm += ARCH_PAGE_SIZE * count; + g_kernelvm_bitmap.clear_region(first_free_index, count, true); + return KERNEL_VM_RANGE_START + (first_free_index * ARCH_PAGE_SIZE); + } + } + + return err(ENOMEM); + } + + Result free_one_page(u64 address) + { + if (address < KERNEL_VM_RANGE_START) return err(EFAULT); + + u64 index = (address - KERNEL_VM_RANGE_START) / ARCH_PAGE_SIZE; + + if (index >= g_kernelvm_bitmap.size()) return err(EFAULT); + + g_kernelvm_bitmap.set(index, false); + g_used_vm -= ARCH_PAGE_SIZE; + + return {}; + } + + Result free_several_pages(u64 address, usize count) + { + if (address < KERNEL_VM_RANGE_START) return err(EFAULT); + if (address + (count * ARCH_PAGE_SIZE) >= KERNEL_VM_RANGE_END) return err(EFAULT); + + u64 index = (address - KERNEL_VM_RANGE_START) / ARCH_PAGE_SIZE; + + g_kernelvm_bitmap.clear_region(index, count, false); + g_used_vm -= ARCH_PAGE_SIZE * count; + + return {}; + } + + usize used() + { + return g_used_vm; + } + + usize free() + { + return KERNEL_VM_RANGE_SIZE - g_used_vm; + } +} \ No newline at end of file diff --git a/kernel/src/memory/KernelVM.h b/kernel/src/memory/KernelVM.h new file mode 100644 index 00000000..9a7f358b --- /dev/null +++ b/kernel/src/memory/KernelVM.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include + +// Simple bitmap allocator which hands out kernel-space virtual addresses for use in kmalloc() and friends. +namespace KernelVM +{ + void init(); + + Result alloc_one_page(); + Result alloc_several_pages(usize count); + + Result free_one_page(u64 address); + Result free_several_pages(u64 address, usize count); + + usize free(); + usize used(); +} \ No newline at end of file