From 229b06c63b5b7ca69fcfbec9fbfbd49ec80eefdd Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 13 Oct 2022 19:19:51 +0200 Subject: [PATCH] Add basic address space infrastructure --- kernel/include/memory/AddressSpace.h | 17 +++++++ kernel/include/memory/VMM.h | 3 ++ kernel/src/main.cpp | 5 ++ kernel/src/memory/AddressSpace.cpp | 72 ++++++++++++++++++++++++++++ kernel/src/memory/VMM.cpp | 45 ++++++++++++----- 5 files changed, 130 insertions(+), 12 deletions(-) create mode 100644 kernel/include/memory/AddressSpace.h create mode 100644 kernel/src/memory/AddressSpace.cpp diff --git a/kernel/include/memory/AddressSpace.h b/kernel/include/memory/AddressSpace.h new file mode 100644 index 00000000..082ec607 --- /dev/null +++ b/kernel/include/memory/AddressSpace.h @@ -0,0 +1,17 @@ +#pragma once +#include "memory/Paging.h" + +struct AddressSpace +{ + static AddressSpace create(); + + void destroy(); + + PageTable* get_pml4() + { + return m_pml4; + } + + private: + PageTable* m_pml4; +}; \ No newline at end of file diff --git a/kernel/include/memory/VMM.h b/kernel/include/memory/VMM.h index 66aef241..e4dbce24 100644 --- a/kernel/include/memory/VMM.h +++ b/kernel/include/memory/VMM.h @@ -1,4 +1,5 @@ #pragma once +#include "memory/AddressSpace.h" #include "memory/Paging.h" enum Flags @@ -27,4 +28,6 @@ namespace VMM void decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index, uint64_t& pdp_index); + + void install_kernel_page_directory_into_address_space(AddressSpace& space); }; \ No newline at end of file diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 967a35e3..0858ab61 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -16,6 +16,7 @@ #include "io/PIC.h" #include "io/Serial.h" #include "log/Log.h" +#include "memory/AddressSpace.h" #include "memory/Memory.h" #include "memory/MemoryManager.h" #include "memory/MemoryMap.h" @@ -87,6 +88,10 @@ extern "C" void _start() Init::finish_kernel_boot(); + AddressSpace vaspace = AddressSpace::create(); + + vaspace.destroy(); + Interrupts::enable(); // Task switching commences here kinfoln("Interrupts enabled"); diff --git a/kernel/src/memory/AddressSpace.cpp b/kernel/src/memory/AddressSpace.cpp new file mode 100644 index 00000000..875ea606 --- /dev/null +++ b/kernel/src/memory/AddressSpace.cpp @@ -0,0 +1,72 @@ +#define MODULE "vmm" + +#include "memory/AddressSpace.h" +#include "log/Log.h" +#include "memory/PMM.h" +#include "memory/VMM.h" + +AddressSpace AddressSpace::create() +{ + AddressSpace result; + result.m_pml4 = (PageTable*)PMM::request_page(); + VMM::install_kernel_page_directory_into_address_space(result); + return result; +} + +void AddressSpace::destroy() +{ + uint64_t pages_freed = 0; + for (int i = 0; i < 512; i++) + { + PageDirectoryEntry& pdp_pde = m_pml4->entries[i]; + if (!pdp_pde.present) continue; + if (pdp_pde.larger_pages) + { + pages_freed++; + PMM::free_page((void*)pdp_pde.get_address()); + continue; + } + PageTable* pdp = (PageTable*)pdp_pde.get_address(); + for (int j = 0; j < 511; j++) // skip the last page directory, it's the kernel one + { + PageDirectoryEntry& pd_pde = pdp->entries[j]; + if (!pd_pde.present) continue; + if (pd_pde.larger_pages) + { + pages_freed++; + PMM::free_page((void*)pd_pde.get_address()); + continue; + } + PageTable* pd = (PageTable*)pd_pde.get_address(); + for (int k = 0; k < 512; k++) + { + PageDirectoryEntry& pt_pde = pd->entries[k]; + if (!pt_pde.present) continue; + if (pt_pde.larger_pages) + { + pages_freed++; + PMM::free_page((void*)pt_pde.get_address()); + continue; + } + PageTable* pt = (PageTable*)pt_pde.get_address(); + for (int l = 0; l < 512; l++) + { + PageDirectoryEntry& pde = pt->entries[l]; + if (pde.present) continue; + pages_freed++; + PMM::free_page((void*)pde.get_address()); + } + pages_freed++; + PMM::free_page(pt); + } + pages_freed++; + PMM::free_page(pd); + } + pages_freed++; + PMM::free_page(pdp); + } + pages_freed++; + PMM::free_page(m_pml4); + + kdbgln("Reclaimed %ld pages from address space!", pages_freed); +} \ No newline at end of file diff --git a/kernel/src/memory/VMM.cpp b/kernel/src/memory/VMM.cpp index 097de638..e0b81910 100644 --- a/kernel/src/memory/VMM.cpp +++ b/kernel/src/memory/VMM.cpp @@ -7,20 +7,20 @@ #include "misc/utils.h" #include "std/string.h" -// FIXME: There is a lot of duplicate code in this file. This should probably be refactored. - -static PageTable* PML4; +static PageTable* kernel_pml4; +static PageTable* current_pml4; void VMM::init() { - asm volatile("mov %%cr3, %0" : "=r"(PML4)); + asm volatile("mov %%cr3, %0" : "=r"(current_pml4)); + kernel_pml4 = current_pml4; } void VMM::unmap(uint64_t vaddr) { vaddr = Utilities::round_down_to_nearest_page(vaddr); - PageDirectoryEntry* pde = find_pde(PML4, vaddr); + PageDirectoryEntry* pde = find_pde(current_pml4, vaddr); if (!pde) return; // Already unmapped memset(pde, 0, sizeof(PageDirectoryEntry)); @@ -29,7 +29,7 @@ void VMM::unmap(uint64_t vaddr) uint64_t VMM::get_physical(uint64_t vaddr) { - PageDirectoryEntry* pde = find_pde(PML4, Utilities::round_down_to_nearest_page(vaddr)); + PageDirectoryEntry* pde = find_pde(current_pml4, Utilities::round_down_to_nearest_page(vaddr)); if (!pde) return UINT64_MAX; // Not mapped return pde->get_address() | (vaddr % PAGE_SIZE); @@ -37,7 +37,7 @@ uint64_t VMM::get_physical(uint64_t vaddr) uint64_t VMM::get_flags(uint64_t vaddr) { - PageDirectoryEntry* pde = find_pde(PML4, Utilities::round_down_to_nearest_page(vaddr)); + PageDirectoryEntry* pde = find_pde(current_pml4, Utilities::round_down_to_nearest_page(vaddr)); if (!pde) return 0; // Not mapped uint64_t flags = 0; @@ -49,23 +49,23 @@ uint64_t VMM::get_flags(uint64_t vaddr) void VMM::map(uint64_t vaddr, uint64_t paddr, int flags) { vaddr = Utilities::round_down_to_nearest_page(vaddr); - PageDirectoryEntry* pde = find_pde(PML4, vaddr); + PageDirectoryEntry* pde = find_pde(current_pml4, vaddr); bool will_flush_tlb = true; if (!pde) { - pde = create_pde_if_not_exists(PML4, vaddr); + pde = create_pde_if_not_exists(current_pml4, vaddr); will_flush_tlb = false; } else if (pde->larger_pages) { unmap(vaddr); - pde = create_pde_if_not_exists(PML4, vaddr); + pde = create_pde_if_not_exists(current_pml4, vaddr); will_flush_tlb = false; } pde->set_address(Utilities::round_down_to_nearest_page(paddr)); - if (flags & User) propagate_user(PML4, vaddr); - if (flags & ReadWrite) propagate_read_write(PML4, vaddr); + if (flags & User) propagate_user(current_pml4, vaddr); + if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr); if (will_flush_tlb) flush_tlb(vaddr); } @@ -198,4 +198,25 @@ void VMM::decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_ind pd_index = vaddr & 0x1ff; vaddr >>= 9; pdp_index = vaddr & 0x1ff; +} + +void VMM::install_kernel_page_directory_into_address_space(AddressSpace& space) +{ + PageTable* space_pml4 = space.get_pml4(); + PageTable* kernel_last_pdp = (PageTable*)kernel_pml4->entries[511].get_address(); + PageTable* kernel_last_pd = (PageTable*)kernel_last_pdp->entries[511].get_address(); + + PageTable* space_last_pdp = (PageTable*)PMM::request_page(); + + PageDirectoryEntry& space_last_pdp_pde = space_pml4->entries[511]; + + space_last_pdp_pde.present = true; + space_last_pdp_pde.read_write = true; + space_last_pdp_pde.set_address((uint64_t)space_last_pdp); + + PageDirectoryEntry& space_last_pd_pde = space_last_pdp->entries[511]; + + space_last_pd_pde.present = true; + space_last_pd_pde.read_write = true; + space_last_pd_pde.set_address((uint64_t)kernel_last_pd); } \ No newline at end of file