Compare commits
2 Commits
531b2848ac
...
b360307f41
Author | SHA1 | Date | |
---|---|---|---|
b360307f41 | |||
9f2c9fb190 |
@ -10,7 +10,6 @@ enum Flags
|
|||||||
namespace VMM
|
namespace VMM
|
||||||
{
|
{
|
||||||
void init(); // fetch page table from cr3
|
void init(); // fetch page table from cr3
|
||||||
void init(PageTable* cr3);
|
|
||||||
|
|
||||||
void map(uint64_t virtualAddress, uint64_t physicalAddress, int flags);
|
void map(uint64_t virtualAddress, uint64_t physicalAddress, int flags);
|
||||||
void remap(uint64_t virtualAddress, int flags);
|
void remap(uint64_t virtualAddress, int flags);
|
||||||
@ -18,4 +17,11 @@ namespace VMM
|
|||||||
uint64_t getPhysical(uint64_t virtualAddress);
|
uint64_t getPhysical(uint64_t virtualAddress);
|
||||||
uint64_t getFlags(uint64_t virtualAddress);
|
uint64_t getFlags(uint64_t virtualAddress);
|
||||||
|
|
||||||
|
PageDirectoryEntry* find_pde(PageTable* root, uint64_t virtualAddress);
|
||||||
|
PageDirectoryEntry* create_pde_if_not_exists(PageTable* root, uint64_t virtualAddress);
|
||||||
|
|
||||||
|
void propagate_read_write(PageTable* root, uint64_t virtualAddress);
|
||||||
|
void propagate_user(PageTable* root, uint64_t virtualAddress);
|
||||||
|
|
||||||
|
void flush_tlb(uint64_t addr);
|
||||||
};
|
};
|
@ -1,13 +1,37 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifndef PAGE_SIZE
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" uint64_t asm_get_rflags();
|
||||||
|
|
||||||
namespace Utilities
|
namespace Utilities
|
||||||
{
|
{
|
||||||
uint64_t get_blocks_from_size(uint64_t blocksize,
|
inline uint64_t get_blocks_from_size(uint64_t blocksize, uint64_t size)
|
||||||
uint64_t size); // Returns how many blocks of size blocksize does size occupy.
|
{
|
||||||
|
return (size + (blocksize - 1)) / blocksize;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t get_rflags();
|
inline uint64_t get_rflags()
|
||||||
uint64_t get_top_of_stack(uint64_t bottom, uint64_t stack_pages);
|
{
|
||||||
uint64_t round_down_to_nearest_page(uint64_t addr);
|
return asm_get_rflags();
|
||||||
uint64_t round_up_to_nearest_page(uint64_t addr);
|
}
|
||||||
|
|
||||||
|
inline uint64_t get_top_of_stack(uint64_t bottom, uint64_t stack_pages)
|
||||||
|
{
|
||||||
|
return bottom + (stack_pages * PAGE_SIZE) - sizeof(uintptr_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t round_down_to_nearest_page(uint64_t addr)
|
||||||
|
{
|
||||||
|
return addr - (addr % PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t round_up_to_nearest_page(uint64_t addr)
|
||||||
|
{
|
||||||
|
if (addr % PAGE_SIZE) return addr + (PAGE_SIZE - (addr % PAGE_SIZE));
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,10 @@
|
|||||||
|
#define MODULE "vmm"
|
||||||
|
|
||||||
#include "memory/VMM.h"
|
#include "memory/VMM.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
#include "log/Log.h"
|
||||||
#include "memory/PMM.h"
|
#include "memory/PMM.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.
|
// FIXME: There is a lot of duplicate code in this file. This should probably be refactored.
|
||||||
@ -12,322 +16,245 @@ void VMM::init()
|
|||||||
asm volatile("mov %%cr3, %0" : "=r"(PML4));
|
asm volatile("mov %%cr3, %0" : "=r"(PML4));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMM::init(PageTable* cr3)
|
|
||||||
{
|
|
||||||
PML4 = cr3;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VMM::unmap(uint64_t virtualAddress)
|
void VMM::unmap(uint64_t virtualAddress)
|
||||||
{
|
{
|
||||||
virtualAddress >>= 12;
|
virtualAddress = Utilities::round_down_to_nearest_page(virtualAddress);
|
||||||
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;
|
PageDirectoryEntry* pde = find_pde(PML4, virtualAddress);
|
||||||
|
if (!pde) return; // Already unmapped
|
||||||
|
|
||||||
PDE = PML4->entries[PDP_i];
|
memset(pde, 0, sizeof(PageDirectoryEntry));
|
||||||
PageTable* PDP;
|
flush_tlb(virtualAddress);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
PDE = PT->entries[P_i];
|
|
||||||
PDE.Present = false;
|
|
||||||
PT->entries[P_i] = PDE;
|
|
||||||
invalidate:
|
|
||||||
asm volatile("invlpg (%0)" : : "r"(virtualAddress) : "memory");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t VMM::getPhysical(uint64_t virtualAddress)
|
uint64_t VMM::getPhysical(uint64_t virtualAddress)
|
||||||
{
|
{
|
||||||
virtualAddress >>= 12;
|
PageDirectoryEntry* pde = find_pde(PML4, Utilities::round_down_to_nearest_page(virtualAddress));
|
||||||
uint64_t P_i = virtualAddress & 0x1ff;
|
if (!pde) return UINT64_MAX; // Not mapped
|
||||||
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;
|
return pde->Address << 12 | (virtualAddress % PAGE_SIZE);
|
||||||
|
|
||||||
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 VMM::getFlags(uint64_t virtualAddress) // FIXME: Add support for larger pages to getFlags.
|
uint64_t VMM::getFlags(uint64_t virtualAddress)
|
||||||
{
|
{
|
||||||
virtualAddress >>= 12;
|
PageDirectoryEntry* pde = find_pde(PML4, Utilities::round_down_to_nearest_page(virtualAddress));
|
||||||
uint64_t P_i = virtualAddress & 0x1ff;
|
if (!pde) return 0; // Not mapped
|
||||||
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
|
|
||||||
{
|
|
||||||
if (PDE.LargerPages) goto read_flags;
|
|
||||||
PDP = (PageTable*)((uint64_t)PDE.Address << 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
PDE = PDP->entries[PD_i];
|
|
||||||
PageTable* PD;
|
|
||||||
if (!PDE.Present)
|
|
||||||
{
|
|
||||||
return 0; // Not mapped
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (PDE.LargerPages) goto read_flags;
|
|
||||||
PD = (PageTable*)((uint64_t)PDE.Address << 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
PDE = PD->entries[PT_i];
|
|
||||||
PageTable* PT;
|
|
||||||
if (!PDE.Present)
|
|
||||||
{
|
|
||||||
return 0; // Not mapped
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (PDE.LargerPages) goto read_flags;
|
|
||||||
PT = (PageTable*)((uint64_t)PDE.Address << 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
PDE = PT->entries[P_i];
|
|
||||||
|
|
||||||
read_flags:
|
|
||||||
uint64_t flags = 0;
|
uint64_t flags = 0;
|
||||||
if (PDE.UserSuper) flags |= User;
|
if (pde->UserSuper) flags |= User;
|
||||||
if (PDE.ReadWrite) flags |= ReadWrite;
|
if (pde->ReadWrite) flags |= ReadWrite;
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMM::map(uint64_t virtualAddress, uint64_t physicalAddress, int flags)
|
void VMM::map(uint64_t virtualAddress, uint64_t physicalAddress, int flags)
|
||||||
{
|
{
|
||||||
virtualAddress >>= 12;
|
virtualAddress = Utilities::round_down_to_nearest_page(virtualAddress);
|
||||||
uint64_t P_i = virtualAddress & 0x1ff;
|
PageDirectoryEntry* pde = find_pde(PML4, virtualAddress);
|
||||||
virtualAddress >>= 9;
|
bool will_flush_tlb = true;
|
||||||
uint64_t PT_i = virtualAddress & 0x1ff;
|
if (!pde)
|
||||||
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();
|
pde = create_pde_if_not_exists(PML4, virtualAddress);
|
||||||
ASSERT(!(PMM_DID_FAIL(PDP)));
|
will_flush_tlb = false;
|
||||||
memset(PDP, 0, PAGE_SIZE);
|
|
||||||
PDE.set_address((uint64_t)PDP);
|
|
||||||
PDE.Present = true;
|
|
||||||
PDE.ReadWrite = true;
|
|
||||||
if (flags & User) PDE.UserSuper = true;
|
|
||||||
PML4->entries[PDP_i] = PDE;
|
|
||||||
}
|
}
|
||||||
else
|
else if (pde->LargerPages)
|
||||||
{
|
{
|
||||||
if (PDE.LargerPages)
|
unmap(virtualAddress);
|
||||||
{
|
pde = create_pde_if_not_exists(PML4, virtualAddress);
|
||||||
unmap(virtualAddress);
|
will_flush_tlb = false;
|
||||||
PDE.LargerPages = false;
|
|
||||||
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;
|
|
||||||
PML4->entries[PDP_i] = PDE;
|
|
||||||
}
|
|
||||||
PDP = (PageTable*)((uint64_t)PDE.Address << 12);
|
|
||||||
}
|
|
||||||
if ((flags & User) && !PDE.UserSuper)
|
|
||||||
{
|
|
||||||
PDE.UserSuper = true;
|
|
||||||
PML4->entries[PDP_i] = PDE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PDE = PDP->entries[PD_i];
|
pde->set_address(Utilities::round_down_to_nearest_page(physicalAddress));
|
||||||
PageTable* PD;
|
if (flags & User) propagate_user(PML4, virtualAddress);
|
||||||
if (!PDE.Present)
|
if (flags & ReadWrite) propagate_read_write(PML4, virtualAddress);
|
||||||
{
|
if (will_flush_tlb) flush_tlb(virtualAddress);
|
||||||
PD = (PageTable*)PMM::request_page();
|
}
|
||||||
ASSERT(!(PMM_DID_FAIL(PD)));
|
|
||||||
memset(PD, 0, PAGE_SIZE);
|
PageDirectoryEntry* VMM::find_pde(PageTable* root, uint64_t virtualAddress)
|
||||||
PDE.set_address((uint64_t)PD);
|
{
|
||||||
PDE.Present = true;
|
virtualAddress >>= 12;
|
||||||
PDE.ReadWrite = true;
|
uint64_t page_index = virtualAddress & 0x1ff;
|
||||||
if (flags & User) PDE.UserSuper = true;
|
virtualAddress >>= 9;
|
||||||
PDP->entries[PD_i] = PDE;
|
uint64_t pt_index = virtualAddress & 0x1ff;
|
||||||
}
|
virtualAddress >>= 9;
|
||||||
else
|
uint64_t pd_index = virtualAddress & 0x1ff;
|
||||||
{
|
virtualAddress >>= 9;
|
||||||
if (PDE.LargerPages)
|
uint64_t pdp_index = virtualAddress & 0x1ff;
|
||||||
{
|
PageDirectoryEntry* pde;
|
||||||
unmap(virtualAddress);
|
PageTable* pt;
|
||||||
PDE.LargerPages = false;
|
|
||||||
PD = (PageTable*)PMM::request_page();
|
pde = &root->entries[pdp_index]; // PML4
|
||||||
ASSERT(!(PMM_DID_FAIL(PD)));
|
if (!pde->Present) return nullptr;
|
||||||
memset(PD, 0, PAGE_SIZE);
|
else if (pde->LargerPages)
|
||||||
PDE.set_address((uint64_t)PD);
|
return pde;
|
||||||
PDE.Present = true;
|
else { pt = (PageTable*)((uint64_t)pde->Address << 12); }
|
||||||
PDE.ReadWrite = true;
|
|
||||||
if (flags & User) PDE.UserSuper = true;
|
pde = &pt->entries[pd_index]; // PDP
|
||||||
PDP->entries[PD_i] = PDE;
|
if (!pde->Present) return nullptr;
|
||||||
}
|
else if (pde->LargerPages)
|
||||||
PD = (PageTable*)((uint64_t)PDE.Address << 12);
|
return pde;
|
||||||
}
|
else { pt = (PageTable*)((uint64_t)pde->Address << 12); }
|
||||||
if ((flags & User) && !PDE.UserSuper)
|
|
||||||
{
|
pde = &pt->entries[pt_index]; // PD
|
||||||
PDE.UserSuper = true;
|
if (!pde->Present) return nullptr;
|
||||||
PDP->entries[PD_i] = PDE;
|
else if (pde->LargerPages)
|
||||||
}
|
return pde;
|
||||||
|
else { pt = (PageTable*)((uint64_t)pde->Address << 12); }
|
||||||
PDE = PD->entries[PT_i];
|
|
||||||
PageTable* PT;
|
pde = &pt->entries[page_index]; // PT
|
||||||
if (!PDE.Present)
|
if (!pde->Present) return nullptr;
|
||||||
{
|
return pde;
|
||||||
PT = (PageTable*)PMM::request_page();
|
}
|
||||||
ASSERT(!(PMM_DID_FAIL(PT)));
|
|
||||||
memset(PT, 0, PAGE_SIZE);
|
PageDirectoryEntry* VMM::create_pde_if_not_exists(PageTable* root, uint64_t virtualAddress)
|
||||||
PDE.set_address((uint64_t)PT);
|
{
|
||||||
PDE.Present = true;
|
virtualAddress >>= 12;
|
||||||
PDE.ReadWrite = true;
|
uint64_t page_index = virtualAddress & 0x1ff;
|
||||||
if (flags & User) PDE.UserSuper = true;
|
virtualAddress >>= 9;
|
||||||
PD->entries[PT_i] = PDE;
|
uint64_t pt_index = virtualAddress & 0x1ff;
|
||||||
}
|
virtualAddress >>= 9;
|
||||||
else
|
uint64_t pd_index = virtualAddress & 0x1ff;
|
||||||
{
|
virtualAddress >>= 9;
|
||||||
if (PDE.LargerPages)
|
uint64_t pdp_index = virtualAddress & 0x1ff;
|
||||||
{
|
PageDirectoryEntry* pde;
|
||||||
unmap(virtualAddress);
|
PageTable* pt;
|
||||||
PDE.LargerPages = false;
|
|
||||||
PT = (PageTable*)PMM::request_page();
|
pde = &root->entries[pdp_index]; // PML4
|
||||||
ASSERT(!(PMM_DID_FAIL(PT)));
|
if (!pde->Present)
|
||||||
memset(PT, 0, PAGE_SIZE);
|
{
|
||||||
PDE.set_address((uint64_t)PT);
|
pt = (PageTable*)PMM::request_page();
|
||||||
PDE.Present = true;
|
ASSERT(!(PMM_DID_FAIL(pt)));
|
||||||
PDE.ReadWrite = true;
|
memset(pt, 0, PAGE_SIZE);
|
||||||
if (flags & User) PDE.UserSuper = true;
|
pde->set_address((uint64_t)pt);
|
||||||
PD->entries[PT_i] = PDE;
|
pde->Present = true;
|
||||||
}
|
}
|
||||||
PT = (PageTable*)((uint64_t)PDE.Address << 12);
|
else if (pde->LargerPages)
|
||||||
}
|
return pde;
|
||||||
if ((flags & User) && !PDE.UserSuper)
|
else { pt = (PageTable*)((uint64_t)pde->Address << 12); }
|
||||||
{
|
|
||||||
PDE.UserSuper = true;
|
pde = &pt->entries[pd_index]; // PDP
|
||||||
PD->entries[PT_i] = PDE;
|
if (!pde->Present)
|
||||||
}
|
{
|
||||||
|
pt = (PageTable*)PMM::request_page();
|
||||||
PDE = PT->entries[P_i];
|
ASSERT(!(PMM_DID_FAIL(pt)));
|
||||||
PDE.Present = true;
|
memset(pt, 0, PAGE_SIZE);
|
||||||
PDE.ReadWrite = flags & ReadWrite;
|
pde->set_address((uint64_t)pt);
|
||||||
PDE.UserSuper = flags & User;
|
pde->Present = true;
|
||||||
PDE.set_address(physicalAddress);
|
}
|
||||||
PT->entries[P_i] = PDE;
|
else if (pde->LargerPages)
|
||||||
|
return pde;
|
||||||
|
else { pt = (PageTable*)((uint64_t)pde->Address << 12); }
|
||||||
|
|
||||||
|
pde = &pt->entries[pt_index]; // PD
|
||||||
|
if (!pde->Present)
|
||||||
|
{
|
||||||
|
pt = (PageTable*)PMM::request_page();
|
||||||
|
ASSERT(!(PMM_DID_FAIL(pt)));
|
||||||
|
memset(pt, 0, PAGE_SIZE);
|
||||||
|
pde->set_address((uint64_t)pt);
|
||||||
|
pde->Present = true;
|
||||||
|
}
|
||||||
|
else if (pde->LargerPages)
|
||||||
|
return pde;
|
||||||
|
else { pt = (PageTable*)((uint64_t)pde->Address << 12); }
|
||||||
|
|
||||||
|
pde = &pt->entries[page_index]; // PT
|
||||||
|
if (!pde->Present) { pde->Present = true; }
|
||||||
|
return pde;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VMM::propagate_read_write(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) return;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pde->ReadWrite = true;
|
||||||
|
if (pde->LargerPages) return;
|
||||||
|
pt = (PageTable*)((uint64_t)pde->Address << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
pde = &pt->entries[pd_index]; // PDP
|
||||||
|
if (!pde->Present) return;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pde->ReadWrite = true;
|
||||||
|
if (pde->LargerPages) return;
|
||||||
|
pt = (PageTable*)((uint64_t)pde->Address << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
pde = &pt->entries[pt_index]; // PD
|
||||||
|
if (!pde->Present) return;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pde->ReadWrite = true;
|
||||||
|
if (pde->LargerPages) return;
|
||||||
|
pt = (PageTable*)((uint64_t)pde->Address << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
pde = &pt->entries[page_index];
|
||||||
|
if (!pde->Present) return;
|
||||||
|
else
|
||||||
|
pde->ReadWrite = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VMM::propagate_user(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) return;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pde->UserSuper = true;
|
||||||
|
if (pde->LargerPages) return;
|
||||||
|
pt = (PageTable*)((uint64_t)pde->Address << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
pde = &pt->entries[pd_index]; // PDP
|
||||||
|
if (!pde->Present) return;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pde->UserSuper = true;
|
||||||
|
if (pde->LargerPages) return;
|
||||||
|
pt = (PageTable*)((uint64_t)pde->Address << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
pde = &pt->entries[pt_index]; // PD
|
||||||
|
if (!pde->Present) return;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pde->UserSuper = true;
|
||||||
|
if (pde->LargerPages) return;
|
||||||
|
pt = (PageTable*)((uint64_t)pde->Address << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
}
|
}
|
@ -1,32 +0,0 @@
|
|||||||
#include "misc/utils.h"
|
|
||||||
|
|
||||||
#ifndef PAGE_SIZE
|
|
||||||
#define PAGE_SIZE 4096
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint64_t Utilities::get_blocks_from_size(uint64_t blocksize, uint64_t size)
|
|
||||||
{
|
|
||||||
return (size + (blocksize - 1)) / blocksize;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" uint64_t asm_get_rflags();
|
|
||||||
uint64_t Utilities::get_rflags()
|
|
||||||
{
|
|
||||||
return asm_get_rflags();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t Utilities::get_top_of_stack(uint64_t bottom, uint64_t stack_pages)
|
|
||||||
{
|
|
||||||
return bottom + (stack_pages * PAGE_SIZE) - sizeof(uintptr_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t Utilities::round_down_to_nearest_page(uint64_t addr)
|
|
||||||
{
|
|
||||||
return addr - (addr % PAGE_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t Utilities::round_up_to_nearest_page(uint64_t addr)
|
|
||||||
{
|
|
||||||
if (addr % PAGE_SIZE) return addr + (PAGE_SIZE - (addr % PAGE_SIZE));
|
|
||||||
return addr;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user