Add basic address space infrastructure

This commit is contained in:
apio 2022-10-13 19:19:51 +02:00
parent 522aa2f812
commit 229b06c63b
5 changed files with 130 additions and 12 deletions

View File

@ -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;
};

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "memory/AddressSpace.h"
#include "memory/Paging.h" #include "memory/Paging.h"
enum Flags 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, void decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index,
uint64_t& pdp_index); uint64_t& pdp_index);
void install_kernel_page_directory_into_address_space(AddressSpace& space);
}; };

View File

@ -16,6 +16,7 @@
#include "io/PIC.h" #include "io/PIC.h"
#include "io/Serial.h" #include "io/Serial.h"
#include "log/Log.h" #include "log/Log.h"
#include "memory/AddressSpace.h"
#include "memory/Memory.h" #include "memory/Memory.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "memory/MemoryMap.h" #include "memory/MemoryMap.h"
@ -87,6 +88,10 @@ extern "C" void _start()
Init::finish_kernel_boot(); Init::finish_kernel_boot();
AddressSpace vaspace = AddressSpace::create();
vaspace.destroy();
Interrupts::enable(); // Task switching commences here Interrupts::enable(); // Task switching commences here
kinfoln("Interrupts enabled"); kinfoln("Interrupts enabled");

View File

@ -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);
}

View File

@ -7,20 +7,20 @@
#include "misc/utils.h" #include "misc/utils.h"
#include "std/string.h" #include "std/string.h"
// FIXME: There is a lot of duplicate code in this file. This should probably be refactored. static PageTable* kernel_pml4;
static PageTable* current_pml4;
static PageTable* PML4;
void VMM::init() 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) void VMM::unmap(uint64_t vaddr)
{ {
vaddr = Utilities::round_down_to_nearest_page(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 if (!pde) return; // Already unmapped
memset(pde, 0, sizeof(PageDirectoryEntry)); memset(pde, 0, sizeof(PageDirectoryEntry));
@ -29,7 +29,7 @@ void VMM::unmap(uint64_t vaddr)
uint64_t VMM::get_physical(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 if (!pde) return UINT64_MAX; // Not mapped
return pde->get_address() | (vaddr % PAGE_SIZE); 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) 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 if (!pde) return 0; // Not mapped
uint64_t flags = 0; 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) void VMM::map(uint64_t vaddr, uint64_t paddr, int flags)
{ {
vaddr = Utilities::round_down_to_nearest_page(vaddr); 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; bool will_flush_tlb = true;
if (!pde) if (!pde)
{ {
pde = create_pde_if_not_exists(PML4, vaddr); pde = create_pde_if_not_exists(current_pml4, vaddr);
will_flush_tlb = false; will_flush_tlb = false;
} }
else if (pde->larger_pages) else if (pde->larger_pages)
{ {
unmap(vaddr); unmap(vaddr);
pde = create_pde_if_not_exists(PML4, vaddr); pde = create_pde_if_not_exists(current_pml4, vaddr);
will_flush_tlb = false; will_flush_tlb = false;
} }
pde->set_address(Utilities::round_down_to_nearest_page(paddr)); pde->set_address(Utilities::round_down_to_nearest_page(paddr));
if (flags & User) propagate_user(PML4, vaddr); if (flags & User) propagate_user(current_pml4, vaddr);
if (flags & ReadWrite) propagate_read_write(PML4, vaddr); if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr);
if (will_flush_tlb) flush_tlb(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; pd_index = vaddr & 0x1ff;
vaddr >>= 9; vaddr >>= 9;
pdp_index = vaddr & 0x1ff; 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);
} }