feat(vmm): Add Paging support
This commit is contained in:
Vendored
+27
-1
@@ -69,6 +69,32 @@
|
|||||||
"rope": "cpp",
|
"rope": "cpp",
|
||||||
"slist": "cpp",
|
"slist": "cpp",
|
||||||
"stacktrace": "cpp",
|
"stacktrace": "cpp",
|
||||||
"regex": "cpp"
|
"regex": "cpp",
|
||||||
|
"coroutine": "cpp",
|
||||||
|
"expected": "cpp",
|
||||||
|
"generator": "cpp",
|
||||||
|
"scoped_allocator": "cpp",
|
||||||
|
"source_location": "cpp",
|
||||||
|
"typeindex": "cpp",
|
||||||
|
"any": "cpp",
|
||||||
|
"barrier": "cpp",
|
||||||
|
"cfenv": "cpp",
|
||||||
|
"codecvt": "cpp",
|
||||||
|
"complex": "cpp",
|
||||||
|
"condition_variable": "cpp",
|
||||||
|
"csetjmp": "cpp",
|
||||||
|
"csignal": "cpp",
|
||||||
|
"cuchar": "cpp",
|
||||||
|
"forward_list": "cpp",
|
||||||
|
"unordered_set": "cpp",
|
||||||
|
"future": "cpp",
|
||||||
|
"iostream": "cpp",
|
||||||
|
"latch": "cpp",
|
||||||
|
"semaphore": "cpp",
|
||||||
|
"shared_mutex": "cpp",
|
||||||
|
"spanstream": "cpp",
|
||||||
|
"stop_token": "cpp",
|
||||||
|
"syncstream": "cpp",
|
||||||
|
"valarray": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -6,7 +6,7 @@ MAKEFLAGS += -rR
|
|||||||
ARCH := x86_64
|
ARCH := x86_64
|
||||||
|
|
||||||
# Default user QEMU flags. These are appended to the QEMU command calls.
|
# Default user QEMU flags. These are appended to the QEMU command calls.
|
||||||
QEMUFLAGS := -m 2G -s -S
|
QEMUFLAGS := -m 2G -s -S -d int -D qemu.log
|
||||||
|
|
||||||
override IMAGE_NAME := os220-$(ARCH)
|
override IMAGE_NAME := os220-$(ARCH)
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Research project aiming to create a modern kernel and operating system in C++
|
|||||||
- [x] Kernel-mode heap allocator
|
- [x] Kernel-mode heap allocator
|
||||||
- [x] ISR handling (interrupts)
|
- [x] ISR handling (interrupts)
|
||||||
- [x] Exception handling
|
- [x] Exception handling
|
||||||
- [ ] Virtual memory paging
|
- [x] Virtual memory paging
|
||||||
- [ ] UEFI runtime service support
|
- [ ] UEFI runtime service support
|
||||||
- [ ] ACPI & AML support
|
- [ ] ACPI & AML support
|
||||||
- [ ] PCI-e
|
- [ ] PCI-e
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ SECTIONS
|
|||||||
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
|
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
|
||||||
/* that is the beginning of the region. */
|
/* that is the beginning of the region. */
|
||||||
. = 0xffffffff80000000;
|
. = 0xffffffff80000000;
|
||||||
|
KernelStartSymbol = .;
|
||||||
|
|
||||||
/* Define a section to contain the Limine requests and assign it to its own PHDR */
|
/* Define a section to contain the Limine requests and assign it to its own PHDR */
|
||||||
.limine_requests : {
|
.limine_requests : {
|
||||||
@@ -74,4 +75,6 @@ SECTIONS
|
|||||||
*(.eh_frame*)
|
*(.eh_frame*)
|
||||||
*(.note .note.*)
|
*(.note .note.*)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KernelEndSymbol = .;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#include "Panic.hpp"
|
#include "Panic.hpp"
|
||||||
|
|
||||||
void Panic(const char *meditationString, System::PanicFrame* frame) {
|
void Panic(const char *meditationString, System::PanicFrame* frame) {
|
||||||
kerr << "\nGuru Meditation" << "\n" << "\n";
|
kerr << "\nKernel panic" << "\n" << "\n";
|
||||||
|
|
||||||
kerr << "\t" << "MeditationString: " << meditationString << Kt::newline;
|
kerr << "\t" << meditationString << Kt::newline;
|
||||||
|
|
||||||
#if defined (__x86_64__)
|
#if defined (__x86_64__)
|
||||||
if (frame != nullptr) {
|
if (frame != nullptr) {
|
||||||
|
|||||||
@@ -38,6 +38,6 @@ namespace Hal {
|
|||||||
LoadGDT(&gdtPointer);
|
LoadGDT(&gdtPointer);
|
||||||
ReloadSegments();
|
ReloadSegments();
|
||||||
|
|
||||||
KernelLogStream(DEBUG, "HardwareAbstraction") << "Set new GDT (0x" << base::hex << (uint64_t)&kernelGDT << ")";
|
KernelLogStream(DEBUG, "Hal") << "Set new GDT (0x" << base::hex << (uint64_t)&kernelGDT << ")";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -115,10 +115,10 @@ namespace Hal {
|
|||||||
|
|
||||||
SetHandler<0, 31>::run();
|
SetHandler<0, 31>::run();
|
||||||
|
|
||||||
Kt::KernelLogStream(Kt::OK, "HardwareAbstraction") << "Created exception interrupt vectors";
|
Kt::KernelLogStream(Kt::OK, "Hal") << "Created exception interrupt vectors";
|
||||||
|
|
||||||
LoadIDT(IDTR);
|
LoadIDT(IDTR);
|
||||||
|
|
||||||
Kt::KernelLogStream(Kt::OK, "HardwareAbstraction") << "Loaded new IDT";
|
Kt::KernelLogStream(Kt::OK, "Hal") << "Loaded new IDT";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
+19
-2
@@ -25,6 +25,7 @@
|
|||||||
#include <Memory/PageFrameAllocator.hpp>
|
#include <Memory/PageFrameAllocator.hpp>
|
||||||
#include <Memory/HHDM.hpp>
|
#include <Memory/HHDM.hpp>
|
||||||
#include <Io/IoPort.hpp>
|
#include <Io/IoPort.hpp>
|
||||||
|
#include <Memory/Paging.hpp>
|
||||||
|
|
||||||
using namespace Kt;
|
using namespace Kt;
|
||||||
|
|
||||||
@@ -41,6 +42,9 @@ KernelErrorStream kerr{};
|
|||||||
extern void (*__init_array[])();
|
extern void (*__init_array[])();
|
||||||
extern void (*__init_array_end[])();
|
extern void (*__init_array_end[])();
|
||||||
|
|
||||||
|
extern "C" uint64_t KernelStartSymbol;
|
||||||
|
extern "C" uint64_t KernelEndSymbol;
|
||||||
|
|
||||||
extern "C" void kmain() {
|
extern "C" void kmain() {
|
||||||
if (LIMINE_BASE_REVISION_SUPPORTED == false) {
|
if (LIMINE_BASE_REVISION_SUPPORTED == false) {
|
||||||
Hal::Halt();
|
Hal::Halt();
|
||||||
@@ -80,12 +84,12 @@ extern "C" void kmain() {
|
|||||||
Memory::HHDMBase = hhdm_offset;
|
Memory::HHDMBase = hhdm_offset;
|
||||||
|
|
||||||
if (memmap_request.response != nullptr) {
|
if (memmap_request.response != nullptr) {
|
||||||
Kt::KernelLogStream(OK, "MemoryManagement") << "Creating PageFrameAllocator";
|
Kt::KernelLogStream(OK, "Mem") << "Creating PageFrameAllocator";
|
||||||
|
|
||||||
Memory::PageFrameAllocator pmm(Memory::Scan(memmap_request.response));
|
Memory::PageFrameAllocator pmm(Memory::Scan(memmap_request.response));
|
||||||
Memory::g_pfa = &pmm;
|
Memory::g_pfa = &pmm;
|
||||||
|
|
||||||
Kt::KernelLogStream(OK, "MemoryManagement") << "Creating HeapAllocator";
|
Kt::KernelLogStream(OK, "Mem") << "Creating HeapAllocator";
|
||||||
Memory::HeapAllocator heap{};
|
Memory::HeapAllocator heap{};
|
||||||
Memory::g_heap = &heap;
|
Memory::g_heap = &heap;
|
||||||
|
|
||||||
@@ -95,9 +99,22 @@ extern "C" void kmain() {
|
|||||||
Panic("System memory map missing!", nullptr);
|
Panic("System memory map missing!", nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined (__x86_64__)
|
#if defined (__x86_64__)
|
||||||
Hal::IDTInitialize();
|
Hal::IDTInitialize();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// auto kaddr_request_response = kernel_address_request.response;
|
||||||
|
|
||||||
|
Memory::VMM::Paging g_paging{};
|
||||||
|
|
||||||
|
g_paging.Init((uint64_t)&KernelStartSymbol, ((uint64_t)&KernelEndSymbol - (uint64_t)&KernelStartSymbol));
|
||||||
|
// g_paging.Map(0xcfc0000, 0xcfc0000);
|
||||||
|
|
||||||
|
// kout << "0x" << base::hex << Memory::VMM::GetCR3();
|
||||||
|
|
||||||
|
kout << "0x" << base::hex << 0xdeadbeef << "\n";
|
||||||
|
kout << "0x" << base::hex << Memory::HHDM(0xdeadbeef) << "\n";
|
||||||
|
|
||||||
Hal::Halt();
|
Hal::Halt();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,13 @@ namespace Memory {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* PageFrameAllocator::AllocateZeroed() {
|
||||||
|
auto page = Allocate();
|
||||||
|
memset(page, 0, 0x1000);
|
||||||
|
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
void* PageFrameAllocator::ReallocConsecutive(void* ptr, int n) {
|
void* PageFrameAllocator::ReallocConsecutive(void* ptr, int n) {
|
||||||
auto first = Allocate();
|
auto first = Allocate();
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public:
|
|||||||
PageFrameAllocator(LargestSection section);
|
PageFrameAllocator(LargestSection section);
|
||||||
|
|
||||||
void* Allocate();
|
void* Allocate();
|
||||||
|
void* AllocateZeroed();
|
||||||
void* ReallocConsecutive(void* ptr, int n);
|
void* ReallocConsecutive(void* ptr, int n);
|
||||||
void Free(void* ptr);
|
void Free(void* ptr);
|
||||||
void Free(void* ptr, int n);
|
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