Add basic address space infrastructure
This commit is contained in:
parent
522aa2f812
commit
229b06c63b
17
kernel/include/memory/AddressSpace.h
Normal file
17
kernel/include/memory/AddressSpace.h
Normal 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;
|
||||||
|
};
|
@ -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);
|
||||||
};
|
};
|
@ -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");
|
||||||
|
72
kernel/src/memory/AddressSpace.cpp
Normal file
72
kernel/src/memory/AddressSpace.cpp
Normal 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);
|
||||||
|
}
|
@ -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);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user