Luna/kernel/src/memory/VMM.cpp

323 lines
9.2 KiB
C++
Raw Normal View History

2022-09-05 14:13:51 +00:00
#include "memory/VMM.h"
2022-09-24 21:09:39 +00:00
#include "assert.h"
#include "memory/PMM.h"
2022-09-06 11:49:17 +00:00
#include "std/string.h"
Paging::VirtualMemoryManager kernelVMM;
2022-09-05 14:13:51 +00:00
namespace Paging
{
2022-09-06 11:49:17 +00:00
void VirtualMemoryManager::init()
2022-09-05 14:13:51 +00:00
{
asm volatile("mov %%cr3, %0" : "=r"(PML4));
}
2022-10-05 15:34:22 +00:00
void VirtualMemoryManager::init(PageTable* cr3)
2022-09-05 14:13:51 +00:00
{
2022-10-05 15:34:22 +00:00
PML4 = cr3;
2022-09-05 14:13:51 +00:00
}
2022-09-06 11:49:17 +00:00
void VirtualMemoryManager::unmap(uint64_t virtualAddress)
2022-09-05 14:13:51 +00:00
{
virtualAddress >>= 12;
uint64_t P_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PT_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PD_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PDP_i = virtualAddress & 0x1ff;
PageDirectoryEntry PDE;
PDE = PML4->entries[PDP_i];
PageTable* PDP;
if (!PDE.Present)
{
return; // Already unmapped
}
else
{
if (PDE.LargerPages)
{
PDE.Present = false;
PDE.LargerPages = false;
PML4->entries[PDP_i] = PDE;
goto invalidate;
}
PDP = (PageTable*)((uint64_t)PDE.Address << 12);
}
2022-09-05 14:13:51 +00:00
PDE = PDP->entries[PD_i];
PageTable* PD;
if (!PDE.Present)
{
return; // Already unmapped
}
else
{
if (PDE.LargerPages)
{
PDE.Present = false;
PDE.LargerPages = false;
PDP->entries[PD_i] = PDE;
goto invalidate;
}
PD = (PageTable*)((uint64_t)PDE.Address << 12);
}
2022-09-05 14:13:51 +00:00
PDE = PD->entries[PT_i];
PageTable* PT;
if (!PDE.Present)
{
return; // Already unmapped
}
else
{
if (PDE.LargerPages)
{
PDE.LargerPages = false;
PDE.Present = false;
PD->entries[PT_i] = PDE;
goto invalidate;
}
PT = (PageTable*)((uint64_t)PDE.Address << 12);
}
2022-09-05 14:13:51 +00:00
PDE = PT->entries[P_i];
PDE.Present = false;
2022-09-05 14:13:51 +00:00
PT->entries[P_i] = PDE;
invalidate:
asm volatile("invlpg (%0)" : : "r"(virtualAddress) : "memory");
2022-09-05 14:13:51 +00:00
}
2022-09-06 11:49:17 +00:00
uint64_t VirtualMemoryManager::getPhysical(uint64_t virtualAddress)
{
virtualAddress >>= 12;
uint64_t P_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PT_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PD_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PDP_i = virtualAddress & 0x1ff;
PageDirectoryEntry PDE;
PDE = PML4->entries[PDP_i];
PageTable* PDP;
if (!PDE.Present)
{
return UINT64_MAX; // Not mapped
}
else
{
if (PDE.LargerPages) return PDE.Address << 12 | (virtualAddress & PAGE_SIZE);
PDP = (PageTable*)((uint64_t)PDE.Address << 12);
}
PDE = PDP->entries[PD_i];
PageTable* PD;
if (!PDE.Present)
{
return UINT64_MAX; // Not mapped
}
else
{
if (PDE.LargerPages) return PDE.Address << 12 | (virtualAddress & PAGE_SIZE);
PD = (PageTable*)((uint64_t)PDE.Address << 12);
}
PDE = PD->entries[PT_i];
PageTable* PT;
if (!PDE.Present)
{
return UINT64_MAX; // Not mapped
}
else
{
if (PDE.LargerPages) return PDE.Address << 12 | (virtualAddress & PAGE_SIZE);
PT = (PageTable*)((uint64_t)PDE.Address << 12);
}
PDE = PT->entries[P_i];
if (!PDE.Present) return UINT64_MAX;
return PDE.Address << 12 | (virtualAddress & PAGE_SIZE);
}
uint64_t VirtualMemoryManager::getFlags(uint64_t virtualAddress)
{
virtualAddress >>= 12;
uint64_t P_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PT_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PD_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PDP_i = virtualAddress & 0x1ff;
PageDirectoryEntry PDE;
PDE = PML4->entries[PDP_i];
PageTable* PDP;
if (!PDE.Present)
{
return 0; // Not mapped
}
else { PDP = (PageTable*)((uint64_t)PDE.Address << 12); }
PDE = PDP->entries[PD_i];
PageTable* PD;
if (!PDE.Present)
{
return 0; // Not mapped
}
else { PD = (PageTable*)((uint64_t)PDE.Address << 12); }
PDE = PD->entries[PT_i];
PageTable* PT;
if (!PDE.Present)
{
return 0; // Not mapped
}
else { PT = (PageTable*)((uint64_t)PDE.Address << 12); }
uint64_t flags = 0;
PDE = PT->entries[P_i];
if (PDE.UserSuper) flags |= User;
if (PDE.ReadWrite) flags |= ReadWrite;
return flags;
}
2022-09-22 05:57:30 +00:00
void VirtualMemoryManager::map(uint64_t virtualAddress, uint64_t physicalAddress, int flags)
2022-09-06 11:49:17 +00:00
{
virtualAddress >>= 12;
uint64_t P_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PT_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PD_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PDP_i = virtualAddress & 0x1ff;
PageDirectoryEntry PDE;
PDE = PML4->entries[PDP_i];
PageTable* PDP;
if (!PDE.Present)
{
PDP = (PageTable*)PMM::request_page();
2022-09-24 21:09:39 +00:00
ASSERT(!(PMM_DID_FAIL(PDP)));
2022-10-12 11:05:57 +00:00
memset(PDP, 0, PAGE_SIZE);
2022-10-06 15:13:34 +00:00
PDE.set_address((uint64_t)PDP);
2022-09-06 11:49:17 +00:00
PDE.Present = true;
PDE.ReadWrite = true;
2022-09-22 05:57:30 +00:00
if (flags & User) PDE.UserSuper = true;
2022-09-06 11:49:17 +00:00
PML4->entries[PDP_i] = PDE;
}
else
{
if (PDE.LargerPages)
{
unmap(virtualAddress);
PDE.LargerPages = false;
PML4->entries[PDP_i] = PDE;
PDP = (PageTable*)PMM::request_page();
ASSERT(!(PMM_DID_FAIL(PDP)));
memset(PDP, 0, PAGE_SIZE);
PDE.set_address((uint64_t)PDP);
PDE.Present = true;
PDE.ReadWrite = true;
if (flags & User) PDE.UserSuper = true;
return map(virtualAddress, physicalAddress, flags);
}
PDP = (PageTable*)((uint64_t)PDE.Address << 12);
}
if ((flags & User) && !PDE.UserSuper)
{
PDE.UserSuper = true;
PML4->entries[PDP_i] = PDE;
}
2022-09-06 11:49:17 +00:00
PDE = PDP->entries[PD_i];
PageTable* PD;
if (!PDE.Present)
{
PD = (PageTable*)PMM::request_page();
2022-09-24 21:09:39 +00:00
ASSERT(!(PMM_DID_FAIL(PD)));
2022-10-12 11:05:57 +00:00
memset(PD, 0, PAGE_SIZE);
2022-10-06 15:13:34 +00:00
PDE.set_address((uint64_t)PD);
2022-09-06 11:49:17 +00:00
PDE.Present = true;
PDE.ReadWrite = true;
2022-09-22 05:57:30 +00:00
if (flags & User) PDE.UserSuper = true;
2022-09-06 11:49:17 +00:00
PDP->entries[PD_i] = PDE;
}
else
{
if (PDE.LargerPages)
{
unmap(virtualAddress);
PDE.LargerPages = false;
PDP->entries[PD_i] = PDE;
PD = (PageTable*)PMM::request_page();
ASSERT(!(PMM_DID_FAIL(PD)));
memset(PD, 0, PAGE_SIZE);
PDE.set_address((uint64_t)PD);
PDE.Present = true;
PDE.ReadWrite = true;
if (flags & User) PDE.UserSuper = true;
return map(virtualAddress, physicalAddress, flags);
}
PD = (PageTable*)((uint64_t)PDE.Address << 12);
}
if ((flags & User) && !PDE.UserSuper)
{
PDE.UserSuper = true;
PDP->entries[PD_i] = PDE;
}
2022-09-06 11:49:17 +00:00
PDE = PD->entries[PT_i];
PageTable* PT;
if (!PDE.Present)
{
PT = (PageTable*)PMM::request_page();
2022-09-24 21:09:39 +00:00
ASSERT(!(PMM_DID_FAIL(PT)));
2022-10-12 11:05:57 +00:00
memset(PT, 0, PAGE_SIZE);
2022-10-06 15:13:34 +00:00
PDE.set_address((uint64_t)PT);
2022-09-06 11:49:17 +00:00
PDE.Present = true;
PDE.ReadWrite = true;
2022-09-22 05:57:30 +00:00
if (flags & User) PDE.UserSuper = true;
2022-09-06 11:49:17 +00:00
PD->entries[PT_i] = PDE;
}
else
{
if (PDE.LargerPages)
{
unmap(virtualAddress);
PDE.LargerPages = false;
PT = (PageTable*)PMM::request_page();
ASSERT(!(PMM_DID_FAIL(PT)));
memset(PT, 0, PAGE_SIZE);
PDE.set_address((uint64_t)PT);
PDE.Present = true;
PDE.ReadWrite = true;
if (flags & User) PDE.UserSuper = true;
PD->entries[PT_i] = PDE;
}
PT = (PageTable*)((uint64_t)PDE.Address << 12);
}
if ((flags & User) && !PDE.UserSuper)
{
PDE.UserSuper = true;
PD->entries[PT_i] = PDE;
}
2022-09-06 11:49:17 +00:00
PDE = PT->entries[P_i];
PDE.Present = true;
2022-09-23 14:41:43 +00:00
PDE.ReadWrite = flags & ReadWrite;
PDE.UserSuper = flags & User;
2022-10-06 15:13:34 +00:00
PDE.set_address(physicalAddress);
2022-09-06 11:49:17 +00:00
PT->entries[P_i] = PDE;
}
2022-09-05 14:13:51 +00:00
}