feat(vmm): Add Paging support
This commit is contained in:
@@ -61,6 +61,13 @@ namespace Memory {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* PageFrameAllocator::AllocateZeroed() {
|
||||
auto page = Allocate();
|
||||
memset(page, 0, 0x1000);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
void* PageFrameAllocator::ReallocConsecutive(void* ptr, int n) {
|
||||
auto first = Allocate();
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
PageFrameAllocator(LargestSection section);
|
||||
|
||||
void* Allocate();
|
||||
void* AllocateZeroed();
|
||||
void* ReallocConsecutive(void* ptr, int n);
|
||||
void Free(void* ptr);
|
||||
void Free(void* ptr, int n);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[bits 64]
|
||||
section .text
|
||||
global GetCR3
|
||||
global LoadCR3
|
||||
|
||||
GetCR3:
|
||||
mov rax, cr3
|
||||
ret
|
||||
|
||||
LoadCR3:
|
||||
mov cr3, rdi
|
||||
ret
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "Paging.hpp"
|
||||
#include <Memory/PageFrameAllocator.hpp>
|
||||
#include <Common/Panic.hpp>
|
||||
#include <Memory/HHDM.hpp>
|
||||
|
||||
namespace Memory::VMM {
|
||||
extern "C" uint64_t KernelStartSymbol;
|
||||
|
||||
std::uint64_t GetPhysKernelAddress(std::uint64_t virtualAddress) {
|
||||
return Paging::GetPhysAddr(GetCR3(), (std::uint64_t)virtualAddress, true);
|
||||
}
|
||||
|
||||
Paging::Paging() {
|
||||
PML4 = (PageTable*)SubHHDM((PageTable*)Memory::g_pfa->AllocateZeroed());
|
||||
}
|
||||
|
||||
void Paging::Init(std::uint64_t kernelBaseVirt, std::uint64_t kernelSize) {
|
||||
// Map kernel
|
||||
Kt::KernelLogStream(Kt::DEBUG, "VMM") << "Paging::Init called with kernelBaseVirt as 0x" << base::hex << kernelBaseVirt << " and kernelSize as " << base::dec << kernelSize;
|
||||
|
||||
for (std::uint64_t pageAddr = kernelBaseVirt; pageAddr < (kernelBaseVirt + kernelSize); pageAddr += 0x1000) {
|
||||
Kt::KernelLogStream(Kt::DEBUG, "VMM") << "Mapping 0x" << base::hex << GetPhysKernelAddress(pageAddr) << " to 0x" << pageAddr;
|
||||
Map(GetPhysKernelAddress(pageAddr), pageAddr);
|
||||
}
|
||||
|
||||
// TODO map HHDM
|
||||
// TODO map ACPI tables
|
||||
|
||||
LoadCR3((PageTable*)&PML4);
|
||||
}
|
||||
|
||||
PageTable* Paging::HandleLevel(VirtualAddress virtualAddress, PageTable* table, const size_t level) {
|
||||
PageTableEntry* entry = (PageTableEntry*)Memory::HHDM(&table->entries[virtualAddress.GetIndex(level)]);
|
||||
|
||||
entry->Present = true;
|
||||
entry->Writable = true;
|
||||
|
||||
uint64_t downLevelAddr = Memory::SubHHDM((uint64_t)Memory::g_pfa->AllocateZeroed());
|
||||
|
||||
entry->Address = downLevelAddr >> 12;
|
||||
|
||||
return (PageTable*)downLevelAddr;
|
||||
}
|
||||
|
||||
void Paging::Map(std::uint64_t physicalAddress, std::uint64_t virtualAddress) {
|
||||
if (virtualAddress % 0x1000 != 0 || physicalAddress % 0x1000 != 0) {
|
||||
Panic("Value that isn't page-aligned passed as address to Paging::Map!", nullptr);
|
||||
}
|
||||
|
||||
VirtualAddress virtualAddressObj(virtualAddress);
|
||||
|
||||
auto PML3 = HandleLevel(virtualAddressObj, PML4, 4);
|
||||
auto PML2 = HandleLevel(virtualAddressObj, PML3, 3);
|
||||
auto PML1 = HandleLevel(virtualAddressObj, PML2, 2);
|
||||
|
||||
PageTableEntry* pageEntry = (PageTableEntry*)Memory::HHDM(&PML1->entries[virtualAddressObj.GetPageIndex()]);
|
||||
|
||||
pageEntry->Present = true;
|
||||
pageEntry->Writable = true;
|
||||
|
||||
pageEntry->Address = virtualAddress >> 12;
|
||||
}
|
||||
|
||||
std::uint64_t Paging::GetPhysAddr(std::uint64_t pml4, std::uint64_t virtualAddress, bool use40BitL1) {
|
||||
VirtualAddress virtualAddressObj(virtualAddress);
|
||||
|
||||
PageTable* pml4Virt = (PageTable*)HHDM(pml4);
|
||||
|
||||
PageTableEntry* pml4_entry = &pml4Virt->entries[virtualAddressObj.GetL4Index()];
|
||||
|
||||
PageTable* pml3 = (PageTable*)HHDM(pml4_entry->Address << 12);
|
||||
PageTableEntry* pml3_entry = &pml3->entries[virtualAddressObj.GetL3Index()];
|
||||
|
||||
PageTable* pml2 = (PageTable*)HHDM(pml3_entry->Address << 12);
|
||||
PageTableEntry* pml2_entry = &pml2->entries[virtualAddressObj.GetL2Index()];
|
||||
|
||||
PageTable* pml1 = (PageTable*)HHDM(pml2_entry->Address << 12);
|
||||
|
||||
if (use40BitL1 == true) {
|
||||
PageTableEntry40Bit* pml1_entry = (PageTableEntry40Bit*)&pml1->entries[virtualAddressObj.GetPageIndex()];
|
||||
return (uint64_t)pml1_entry->Address << 12;
|
||||
}
|
||||
|
||||
PageTableEntry* pml1_entry = &pml1->entries[virtualAddressObj.GetPageIndex()];
|
||||
return (uint64_t)pml1_entry->Address << 12;
|
||||
}
|
||||
|
||||
std::uint64_t Paging::GetPhysAddr(std::uint64_t virtualAddress) {
|
||||
return GetPhysAddr((std::uint64_t)PML4, virtualAddress, false);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <Terminal/Terminal.hpp>
|
||||
|
||||
namespace Memory::VMM {
|
||||
struct PageTableEntry {
|
||||
std::uint8_t Present : 1;
|
||||
std::uint8_t Writable : 1;
|
||||
std::uint8_t Supervisor : 1;
|
||||
std::uint8_t WriteThrough : 1;
|
||||
std::uint8_t CacheDisabled : 1;
|
||||
std::uint8_t Accessed : 1;
|
||||
std::uint8_t Ignore : 1;
|
||||
std::uint8_t LargerPages : 1;
|
||||
std::uint8_t PageSize : 1;
|
||||
std::uint8_t Available : 3;
|
||||
std::uint64_t Address : 52;
|
||||
};
|
||||
|
||||
struct PageTableEntry40Bit {
|
||||
std::uint8_t Present : 1;
|
||||
std::uint8_t Writable : 1;
|
||||
std::uint8_t Supervisor : 1;
|
||||
std::uint8_t WriteThrough : 1;
|
||||
std::uint8_t CacheDisabled : 1;
|
||||
std::uint8_t Accessed : 1;
|
||||
std::uint8_t Ignore : 1;
|
||||
std::uint8_t LargerPages : 1;
|
||||
std::uint8_t PageSize : 1;
|
||||
std::uint8_t Available : 3;
|
||||
std::uint64_t Address : 40;
|
||||
std::uint8_t AvailableHigh : 7;
|
||||
std::uint8_t PK : 4;
|
||||
std::uint8_t NX : 1;
|
||||
};
|
||||
|
||||
|
||||
struct PageTable {
|
||||
PageTableEntry entries[512];
|
||||
} __attribute__((packed)) __attribute__((aligned(0x1000)));
|
||||
|
||||
struct VirtualAddress {
|
||||
std::uint64_t address;
|
||||
|
||||
VirtualAddress(std::uint64_t newAddress) {
|
||||
if (newAddress % 0x1000 != 0) {
|
||||
Kt::KernelLogStream(Kt::WARNING, "VMM") << "VirtualAddress object created with non-aligned value.";
|
||||
}
|
||||
|
||||
address = newAddress;
|
||||
}
|
||||
|
||||
uint64_t GetL4Index() {
|
||||
return (address >> 39) & 0x1ff;
|
||||
}
|
||||
|
||||
uint64_t GetL3Index() {
|
||||
return (address >> 30) & 0x1ff;
|
||||
}
|
||||
|
||||
uint64_t GetL2Index() {
|
||||
return (address >> 21) & 0x1ff;
|
||||
}
|
||||
|
||||
uint64_t GetPageIndex() {
|
||||
return (address >> 12) & 0x1ff;
|
||||
}
|
||||
|
||||
uint64_t GetIndex(size_t level) {
|
||||
if (level == 4)
|
||||
return GetL4Index();
|
||||
|
||||
else if (level == 3)
|
||||
return GetL3Index();
|
||||
|
||||
else if (level == 2)
|
||||
return GetL2Index();
|
||||
|
||||
else if (level == 1)
|
||||
return GetPageIndex();
|
||||
}
|
||||
};
|
||||
|
||||
class Paging {
|
||||
PageTable* PML4{};
|
||||
|
||||
PageTable* HandleLevel(VirtualAddress virtualAddress, PageTable* table, size_t level);
|
||||
public:
|
||||
Paging();
|
||||
void Init(std::uint64_t kernelBaseVirt, std::uint64_t kernelSize);
|
||||
void Map(std::uint64_t physicalAddress, std::uint64_t virtualAddress);
|
||||
static std::uint64_t GetPhysAddr(std::uint64_t PML4, std::uint64_t virtualAddress, bool use40BitL1 = false);
|
||||
std::uint64_t GetPhysAddr(std::uint64_t virtualAddress);
|
||||
};
|
||||
|
||||
extern "C" uint64_t GetCR3();
|
||||
extern "C" void LoadCR3(PageTable* PML4);
|
||||
};
|
||||
Reference in New Issue
Block a user