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

View File

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

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