Luna/kernel/src/memory/VMM.cpp

222 lines
6.1 KiB
C++
Raw Normal View History

#define MODULE "vmm"
2022-09-05 14:13:51 +00:00
#include "memory/VMM.h"
2022-09-24 21:09:39 +00:00
#include "assert.h"
#include "log/Log.h"
#include "memory/PMM.h"
#include "misc/utils.h"
2022-09-06 11:49:17 +00:00
#include "std/string.h"
2022-10-13 17:19:51 +00:00
static PageTable* kernel_pml4;
static PageTable* current_pml4;
void VMM::init()
2022-09-05 14:13:51 +00:00
{
2022-10-13 17:19:51 +00:00
asm volatile("mov %%cr3, %0" : "=r"(current_pml4));
kernel_pml4 = current_pml4;
}
2022-09-05 14:13:51 +00:00
2022-10-13 16:42:53 +00:00
void VMM::unmap(uint64_t vaddr)
{
2022-10-13 16:42:53 +00:00
vaddr = Utilities::round_down_to_nearest_page(vaddr);
2022-10-13 17:19:51 +00:00
PageDirectoryEntry* pde = find_pde(current_pml4, vaddr);
if (!pde) return; // Already unmapped
memset(pde, 0, sizeof(PageDirectoryEntry));
2022-10-13 16:42:53 +00:00
flush_tlb(vaddr);
}
2022-09-05 14:13:51 +00:00
2022-10-13 16:42:53 +00:00
uint64_t VMM::get_physical(uint64_t vaddr)
{
2022-10-13 17:19:51 +00:00
PageDirectoryEntry* pde = find_pde(current_pml4, Utilities::round_down_to_nearest_page(vaddr));
if (!pde) return UINT64_MAX; // Not mapped
2022-09-05 14:13:51 +00:00
2022-10-13 16:42:53 +00:00
return pde->get_address() | (vaddr % PAGE_SIZE);
}
2022-09-05 14:13:51 +00:00
2022-10-13 16:42:53 +00:00
uint64_t VMM::get_flags(uint64_t vaddr)
{
2022-10-13 17:19:51 +00:00
PageDirectoryEntry* pde = find_pde(current_pml4, Utilities::round_down_to_nearest_page(vaddr));
if (!pde) return 0; // Not mapped
2022-09-05 14:13:51 +00:00
uint64_t flags = 0;
2022-10-13 16:42:53 +00:00
if (pde->user) flags |= User;
if (pde->read_write) flags |= ReadWrite;
return flags;
}
2022-09-05 14:13:51 +00:00
2022-10-13 16:42:53 +00:00
void VMM::map(uint64_t vaddr, uint64_t paddr, int flags)
{
2022-10-13 16:42:53 +00:00
vaddr = Utilities::round_down_to_nearest_page(vaddr);
2022-10-13 17:19:51 +00:00
PageDirectoryEntry* pde = find_pde(current_pml4, vaddr);
bool will_flush_tlb = true;
if (!pde)
{
2022-10-13 17:19:51 +00:00
pde = create_pde_if_not_exists(current_pml4, vaddr);
will_flush_tlb = false;
}
2022-10-13 16:42:53 +00:00
else if (pde->larger_pages)
{
2022-10-13 16:42:53 +00:00
unmap(vaddr);
2022-10-13 17:19:51 +00:00
pde = create_pde_if_not_exists(current_pml4, vaddr);
will_flush_tlb = false;
}
2022-10-13 16:42:53 +00:00
pde->set_address(Utilities::round_down_to_nearest_page(paddr));
2022-10-13 17:19:51 +00:00
if (flags & User) propagate_user(current_pml4, vaddr);
if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr);
2022-10-13 16:42:53 +00:00
if (will_flush_tlb) flush_tlb(vaddr);
}
2022-10-13 16:42:53 +00:00
PageDirectoryEntry* VMM::find_pde(PageTable* root, uint64_t vaddr)
{
2022-10-13 16:15:52 +00:00
uint64_t page_index, pt_index, pd_index, pdp_index;
PageDirectoryEntry* pde;
2022-10-13 16:15:52 +00:00
PageTable* pt = root;
2022-10-13 16:42:53 +00:00
decompose_vaddr(vaddr, page_index, pt_index, pd_index, pdp_index);
2022-09-05 14:13:51 +00:00
2022-10-13 16:15:52 +00:00
uint64_t indexes[3] = {pdp_index, pd_index, pt_index};
2022-09-06 11:49:17 +00:00
2022-10-13 16:15:52 +00:00
for (int i = 0; i < 3;
i++) // Walk through the page map level 4, page directory pointer, and page directory to find the page table.
{
pde = &pt->entries[indexes[i]];
2022-10-13 16:42:53 +00:00
if (!pde->present) return nullptr;
else if (pde->larger_pages)
2022-10-13 16:15:52 +00:00
return pde;
2022-10-13 16:42:53 +00:00
else { pt = (PageTable*)pde->get_address(); }
2022-10-13 16:15:52 +00:00
}
pde = &pt->entries[page_index]; // PT
2022-10-13 16:42:53 +00:00
if (!pde->present) return nullptr;
return pde;
}
2022-10-13 16:42:53 +00:00
PageDirectoryEntry* VMM::create_pde_if_not_exists(PageTable* root, uint64_t vaddr)
{
2022-10-13 16:15:52 +00:00
uint64_t page_index, pt_index, pd_index, pdp_index;
PageDirectoryEntry* pde;
2022-10-13 16:15:52 +00:00
PageTable* pt = root;
2022-10-13 16:42:53 +00:00
decompose_vaddr(vaddr, page_index, pt_index, pd_index, pdp_index);
2022-10-13 16:15:52 +00:00
auto pde_create_if_not_present = [&]() {
pt = (PageTable*)PMM::request_page();
ASSERT(!(PMM_DID_FAIL(pt)));
memset(pt, 0, PAGE_SIZE);
pde->set_address((uint64_t)pt);
2022-10-13 16:42:53 +00:00
pde->present = true;
2022-10-13 16:15:52 +00:00
};
2022-10-13 16:15:52 +00:00
uint64_t indexes[3] = {pdp_index, pd_index, pt_index};
for (int i = 0; i < 3; i++)
{
2022-10-13 16:15:52 +00:00
pde = &pt->entries[indexes[i]];
2022-10-13 16:42:53 +00:00
if (!pde->present) { pde_create_if_not_present(); }
else if (pde->larger_pages)
2022-10-13 16:15:52 +00:00
return pde;
2022-10-13 16:42:53 +00:00
else { pt = (PageTable*)pde->get_address(); }
}
2022-10-13 16:15:52 +00:00
pde = &pt->entries[page_index];
2022-10-13 16:42:53 +00:00
if (!pde->present) { pde->present = true; }
return pde;
}
2022-10-13 16:42:53 +00:00
void VMM::propagate_read_write(PageTable* root, uint64_t vaddr)
{
2022-10-13 16:15:52 +00:00
uint64_t page_index, pt_index, pd_index, pdp_index;
PageDirectoryEntry* pde;
2022-10-13 16:15:52 +00:00
PageTable* pt = root;
2022-10-13 16:42:53 +00:00
decompose_vaddr(vaddr, page_index, pt_index, pd_index, pdp_index);
2022-10-13 16:15:52 +00:00
uint64_t indexes[3] = {pdp_index, pd_index, pt_index};
2022-10-13 16:15:52 +00:00
for (int i = 0; i < 3; i++)
{
2022-10-13 16:15:52 +00:00
pde = &pt->entries[indexes[i]];
2022-10-13 16:42:53 +00:00
if (!pde->present) return;
2022-10-13 16:15:52 +00:00
else
{
2022-10-13 16:42:53 +00:00
pde->read_write = true;
if (pde->larger_pages) return;
pt = (PageTable*)pde->get_address();
2022-10-13 16:15:52 +00:00
}
}
pde = &pt->entries[page_index];
2022-10-13 16:42:53 +00:00
if (!pde->present) return;
else
2022-10-13 16:42:53 +00:00
pde->read_write = true;
}
2022-10-13 16:42:53 +00:00
void VMM::propagate_user(PageTable* root, uint64_t vaddr)
{
2022-10-13 16:15:52 +00:00
uint64_t page_index, pt_index, pd_index, pdp_index;
PageDirectoryEntry* pde;
2022-10-13 16:15:52 +00:00
PageTable* pt = root;
2022-10-13 16:42:53 +00:00
decompose_vaddr(vaddr, page_index, pt_index, pd_index, pdp_index);
2022-09-06 11:49:17 +00:00
2022-10-13 16:15:52 +00:00
uint64_t indexes[3] = {pdp_index, pd_index, pt_index};
2022-09-06 11:49:17 +00:00
2022-10-13 16:15:52 +00:00
for (int i = 0; i < 3; i++)
{
2022-10-13 16:15:52 +00:00
pde = &pt->entries[indexes[i]];
2022-10-13 16:42:53 +00:00
if (!pde->present) return;
2022-10-13 16:15:52 +00:00
else
{
2022-10-13 16:42:53 +00:00
pde->user = true;
if (pde->larger_pages) return;
pt = (PageTable*)pde->get_address();
2022-10-13 16:15:52 +00:00
}
}
pde = &pt->entries[page_index];
2022-10-13 16:42:53 +00:00
if (!pde->present) return;
else
2022-10-13 16:42:53 +00:00
pde->user = true;
}
void VMM::flush_tlb(uint64_t addr)
{
asm volatile("invlpg (%0)" : : "r"(addr) : "memory");
2022-10-13 16:15:52 +00:00
}
void VMM::decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index,
uint64_t& pdp_index)
{
vaddr >>= 12;
page_index = vaddr & 0x1ff;
vaddr >>= 9;
pt_index = vaddr & 0x1ff;
vaddr >>= 9;
pd_index = vaddr & 0x1ff;
vaddr >>= 9;
pdp_index = vaddr & 0x1ff;
2022-10-13 17:19:51 +00:00
}
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);
2022-09-05 14:13:51 +00:00
}