2022-10-13 15:58:13 +00:00
|
|
|
#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"
|
2022-10-13 15:58:13 +00:00
|
|
|
#include "log/Log.h"
|
2022-09-24 19:27:45 +00:00
|
|
|
#include "memory/PMM.h"
|
2022-10-13 15:58:13 +00:00
|
|
|
#include "misc/utils.h"
|
2022-09-06 11:49:17 +00:00
|
|
|
#include "std/string.h"
|
|
|
|
|
2022-10-12 12:35:34 +00:00
|
|
|
// FIXME: There is a lot of duplicate code in this file. This should probably be refactored.
|
|
|
|
|
2022-10-12 18:02:25 +00:00
|
|
|
static PageTable* PML4;
|
|
|
|
|
|
|
|
void VMM::init()
|
2022-09-05 14:13:51 +00:00
|
|
|
{
|
2022-10-12 18:02:25 +00:00
|
|
|
asm volatile("mov %%cr3, %0" : "=r"(PML4));
|
|
|
|
}
|
2022-09-05 14:13:51 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
void VMM::unmap(uint64_t virtualAddress)
|
2022-10-12 18:02:25 +00:00
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
virtualAddress = Utilities::round_down_to_nearest_page(virtualAddress);
|
|
|
|
|
|
|
|
PageDirectoryEntry* pde = find_pde(PML4, virtualAddress);
|
|
|
|
if (!pde) return; // Already unmapped
|
|
|
|
|
|
|
|
memset(pde, 0, sizeof(PageDirectoryEntry));
|
|
|
|
flush_tlb(virtualAddress);
|
2022-10-12 18:02:25 +00:00
|
|
|
}
|
2022-09-05 14:13:51 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t VMM::getPhysical(uint64_t virtualAddress)
|
2022-10-12 18:02:25 +00:00
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
PageDirectoryEntry* pde = find_pde(PML4, Utilities::round_down_to_nearest_page(virtualAddress));
|
|
|
|
if (!pde) return UINT64_MAX; // Not mapped
|
2022-09-05 14:13:51 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
return pde->Address << 12 | (virtualAddress % PAGE_SIZE);
|
|
|
|
}
|
2022-09-05 14:13:51 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t VMM::getFlags(uint64_t virtualAddress)
|
|
|
|
{
|
|
|
|
PageDirectoryEntry* pde = find_pde(PML4, Utilities::round_down_to_nearest_page(virtualAddress));
|
|
|
|
if (!pde) return 0; // Not mapped
|
2022-09-05 14:13:51 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t flags = 0;
|
|
|
|
if (pde->UserSuper) flags |= User;
|
|
|
|
if (pde->ReadWrite) flags |= ReadWrite;
|
|
|
|
return flags;
|
|
|
|
}
|
2022-09-05 14:13:51 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
void VMM::map(uint64_t virtualAddress, uint64_t physicalAddress, int flags)
|
|
|
|
{
|
|
|
|
virtualAddress = Utilities::round_down_to_nearest_page(virtualAddress);
|
|
|
|
PageDirectoryEntry* pde = find_pde(PML4, virtualAddress);
|
|
|
|
bool will_flush_tlb = true;
|
|
|
|
if (!pde)
|
2022-10-12 18:02:25 +00:00
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = create_pde_if_not_exists(PML4, virtualAddress);
|
|
|
|
will_flush_tlb = false;
|
2022-10-12 18:02:25 +00:00
|
|
|
}
|
2022-10-13 15:58:13 +00:00
|
|
|
else if (pde->LargerPages)
|
2022-10-12 18:02:25 +00:00
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
unmap(virtualAddress);
|
|
|
|
pde = create_pde_if_not_exists(PML4, virtualAddress);
|
|
|
|
will_flush_tlb = false;
|
2022-10-12 18:02:25 +00:00
|
|
|
}
|
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde->set_address(Utilities::round_down_to_nearest_page(physicalAddress));
|
|
|
|
if (flags & User) propagate_user(PML4, virtualAddress);
|
|
|
|
if (flags & ReadWrite) propagate_read_write(PML4, virtualAddress);
|
|
|
|
if (will_flush_tlb) flush_tlb(virtualAddress);
|
2022-10-12 18:02:25 +00:00
|
|
|
}
|
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
PageDirectoryEntry* VMM::find_pde(PageTable* root, uint64_t virtualAddress)
|
2022-10-12 18:02:25 +00:00
|
|
|
{
|
|
|
|
virtualAddress >>= 12;
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t page_index = virtualAddress & 0x1ff;
|
2022-10-12 18:02:25 +00:00
|
|
|
virtualAddress >>= 9;
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t pt_index = virtualAddress & 0x1ff;
|
2022-10-12 18:02:25 +00:00
|
|
|
virtualAddress >>= 9;
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t pd_index = virtualAddress & 0x1ff;
|
2022-10-12 18:02:25 +00:00
|
|
|
virtualAddress >>= 9;
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t pdp_index = virtualAddress & 0x1ff;
|
|
|
|
PageDirectoryEntry* pde;
|
|
|
|
PageTable* pt;
|
2022-10-12 18:02:25 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &root->entries[pdp_index]; // PML4
|
|
|
|
if (!pde->Present) return nullptr;
|
|
|
|
else if (pde->LargerPages)
|
|
|
|
return pde;
|
|
|
|
else { pt = (PageTable*)((uint64_t)pde->Address << 12); }
|
2022-09-05 14:13:51 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &pt->entries[pd_index]; // PDP
|
|
|
|
if (!pde->Present) return nullptr;
|
|
|
|
else if (pde->LargerPages)
|
|
|
|
return pde;
|
|
|
|
else { pt = (PageTable*)((uint64_t)pde->Address << 12); }
|
2022-09-06 11:49:17 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &pt->entries[pt_index]; // PD
|
|
|
|
if (!pde->Present) return nullptr;
|
|
|
|
else if (pde->LargerPages)
|
|
|
|
return pde;
|
|
|
|
else { pt = (PageTable*)((uint64_t)pde->Address << 12); }
|
|
|
|
|
|
|
|
pde = &pt->entries[page_index]; // PT
|
|
|
|
if (!pde->Present) return nullptr;
|
|
|
|
return pde;
|
|
|
|
}
|
|
|
|
|
|
|
|
PageDirectoryEntry* VMM::create_pde_if_not_exists(PageTable* root, uint64_t virtualAddress)
|
|
|
|
{
|
|
|
|
virtualAddress >>= 12;
|
|
|
|
uint64_t page_index = virtualAddress & 0x1ff;
|
|
|
|
virtualAddress >>= 9;
|
|
|
|
uint64_t pt_index = virtualAddress & 0x1ff;
|
|
|
|
virtualAddress >>= 9;
|
|
|
|
uint64_t pd_index = virtualAddress & 0x1ff;
|
|
|
|
virtualAddress >>= 9;
|
|
|
|
uint64_t pdp_index = virtualAddress & 0x1ff;
|
|
|
|
PageDirectoryEntry* pde;
|
|
|
|
PageTable* pt;
|
|
|
|
|
|
|
|
pde = &root->entries[pdp_index]; // PML4
|
|
|
|
if (!pde->Present)
|
2022-10-12 18:02:25 +00:00
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
pt = (PageTable*)PMM::request_page();
|
|
|
|
ASSERT(!(PMM_DID_FAIL(pt)));
|
|
|
|
memset(pt, 0, PAGE_SIZE);
|
|
|
|
pde->set_address((uint64_t)pt);
|
|
|
|
pde->Present = true;
|
2022-10-12 18:02:25 +00:00
|
|
|
}
|
2022-10-13 15:58:13 +00:00
|
|
|
else if (pde->LargerPages)
|
|
|
|
return pde;
|
|
|
|
else { pt = (PageTable*)((uint64_t)pde->Address << 12); }
|
2022-09-06 16:08:15 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &pt->entries[pd_index]; // PDP
|
|
|
|
if (!pde->Present)
|
2022-10-12 18:02:25 +00:00
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
pt = (PageTable*)PMM::request_page();
|
|
|
|
ASSERT(!(PMM_DID_FAIL(pt)));
|
|
|
|
memset(pt, 0, PAGE_SIZE);
|
|
|
|
pde->set_address((uint64_t)pt);
|
|
|
|
pde->Present = true;
|
2022-10-12 18:02:25 +00:00
|
|
|
}
|
2022-10-13 15:58:13 +00:00
|
|
|
else if (pde->LargerPages)
|
|
|
|
return pde;
|
|
|
|
else { pt = (PageTable*)((uint64_t)pde->Address << 12); }
|
|
|
|
|
|
|
|
pde = &pt->entries[pt_index]; // PD
|
|
|
|
if (!pde->Present)
|
2022-10-12 18:02:25 +00:00
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
pt = (PageTable*)PMM::request_page();
|
|
|
|
ASSERT(!(PMM_DID_FAIL(pt)));
|
|
|
|
memset(pt, 0, PAGE_SIZE);
|
|
|
|
pde->set_address((uint64_t)pt);
|
|
|
|
pde->Present = true;
|
2022-10-12 18:02:25 +00:00
|
|
|
}
|
2022-10-13 15:58:13 +00:00
|
|
|
else if (pde->LargerPages)
|
|
|
|
return pde;
|
|
|
|
else { pt = (PageTable*)((uint64_t)pde->Address << 12); }
|
2022-09-06 16:08:15 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &pt->entries[page_index]; // PT
|
|
|
|
if (!pde->Present) { pde->Present = true; }
|
|
|
|
return pde;
|
2022-10-12 18:02:25 +00:00
|
|
|
}
|
2022-09-06 16:08:15 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
void VMM::propagate_read_write(PageTable* root, uint64_t virtualAddress)
|
2022-10-12 18:02:25 +00:00
|
|
|
{
|
|
|
|
virtualAddress >>= 12;
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t page_index = virtualAddress & 0x1ff;
|
2022-10-12 18:02:25 +00:00
|
|
|
virtualAddress >>= 9;
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t pt_index = virtualAddress & 0x1ff;
|
2022-10-12 18:02:25 +00:00
|
|
|
virtualAddress >>= 9;
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t pd_index = virtualAddress & 0x1ff;
|
2022-10-12 18:02:25 +00:00
|
|
|
virtualAddress >>= 9;
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t pdp_index = virtualAddress & 0x1ff;
|
|
|
|
PageDirectoryEntry* pde;
|
|
|
|
PageTable* pt;
|
2022-09-06 16:08:15 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &root->entries[pdp_index]; // PML4
|
|
|
|
if (!pde->Present) return;
|
2022-10-12 18:05:27 +00:00
|
|
|
else
|
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
pde->ReadWrite = true;
|
|
|
|
if (pde->LargerPages) return;
|
|
|
|
pt = (PageTable*)((uint64_t)pde->Address << 12);
|
2022-10-12 18:05:27 +00:00
|
|
|
}
|
2022-09-06 16:08:15 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &pt->entries[pd_index]; // PDP
|
|
|
|
if (!pde->Present) return;
|
2022-10-12 18:05:27 +00:00
|
|
|
else
|
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
pde->ReadWrite = true;
|
|
|
|
if (pde->LargerPages) return;
|
|
|
|
pt = (PageTable*)((uint64_t)pde->Address << 12);
|
2022-10-12 18:05:27 +00:00
|
|
|
}
|
2022-09-22 06:14:04 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &pt->entries[pt_index]; // PD
|
|
|
|
if (!pde->Present) return;
|
2022-10-12 18:05:27 +00:00
|
|
|
else
|
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
pde->ReadWrite = true;
|
|
|
|
if (pde->LargerPages) return;
|
|
|
|
pt = (PageTable*)((uint64_t)pde->Address << 12);
|
2022-10-12 18:05:27 +00:00
|
|
|
}
|
2022-09-22 06:14:04 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &pt->entries[page_index];
|
|
|
|
if (!pde->Present) return;
|
|
|
|
else
|
|
|
|
pde->ReadWrite = true;
|
2022-10-12 18:02:25 +00:00
|
|
|
}
|
2022-09-22 06:14:04 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
void VMM::propagate_user(PageTable* root, uint64_t virtualAddress)
|
2022-10-12 18:02:25 +00:00
|
|
|
{
|
|
|
|
virtualAddress >>= 12;
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t page_index = virtualAddress & 0x1ff;
|
2022-10-12 18:02:25 +00:00
|
|
|
virtualAddress >>= 9;
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t pt_index = virtualAddress & 0x1ff;
|
2022-10-12 18:02:25 +00:00
|
|
|
virtualAddress >>= 9;
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t pd_index = virtualAddress & 0x1ff;
|
2022-10-12 18:02:25 +00:00
|
|
|
virtualAddress >>= 9;
|
2022-10-13 15:58:13 +00:00
|
|
|
uint64_t pdp_index = virtualAddress & 0x1ff;
|
|
|
|
PageDirectoryEntry* pde;
|
|
|
|
PageTable* pt;
|
2022-09-22 06:14:04 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &root->entries[pdp_index]; // PML4
|
|
|
|
if (!pde->Present) return;
|
2022-10-12 18:02:25 +00:00
|
|
|
else
|
2022-09-06 11:49:17 +00:00
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
pde->UserSuper = true;
|
|
|
|
if (pde->LargerPages) return;
|
|
|
|
pt = (PageTable*)((uint64_t)pde->Address << 12);
|
2022-10-12 18:02:25 +00:00
|
|
|
}
|
2022-09-06 11:49:17 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &pt->entries[pd_index]; // PDP
|
|
|
|
if (!pde->Present) return;
|
2022-10-12 18:02:25 +00:00
|
|
|
else
|
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
pde->UserSuper = true;
|
|
|
|
if (pde->LargerPages) return;
|
|
|
|
pt = (PageTable*)((uint64_t)pde->Address << 12);
|
2022-10-12 18:02:25 +00:00
|
|
|
}
|
2022-09-06 11:49:17 +00:00
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &pt->entries[pt_index]; // PD
|
|
|
|
if (!pde->Present) return;
|
2022-10-12 18:02:25 +00:00
|
|
|
else
|
|
|
|
{
|
2022-10-13 15:58:13 +00:00
|
|
|
pde->UserSuper = true;
|
|
|
|
if (pde->LargerPages) return;
|
|
|
|
pt = (PageTable*)((uint64_t)pde->Address << 12);
|
2022-10-12 18:02:25 +00:00
|
|
|
}
|
|
|
|
|
2022-10-13 15:58:13 +00:00
|
|
|
pde = &pt->entries[page_index];
|
|
|
|
if (!pde->Present) return;
|
|
|
|
else
|
|
|
|
pde->UserSuper = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VMM::flush_tlb(uint64_t addr)
|
|
|
|
{
|
|
|
|
asm volatile("invlpg (%0)" : : "r"(addr) : "memory");
|
2022-09-05 14:13:51 +00:00
|
|
|
}
|