Test kernel bootstrap

This commit is contained in:
Alex
2023-04-29 06:52:22 +03:00
parent 069386b0f2
commit ea1b0bb72a
39 changed files with 7725 additions and 1 deletions

View File

@@ -0,0 +1,28 @@
#include <bitmap.hpp>
bool Bitmap::operator[](uint64_t index) { return Get(index); }
bool Bitmap::Get(uint64_t index)
{
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
if ((Buffer[byteIndex] & bitIndexer) > 0)
return true;
return false;
}
bool Bitmap::Set(uint64_t index, bool value)
{
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
Buffer[byteIndex] &= ~bitIndexer;
if (value)
Buffer[byteIndex] |= bitIndexer;
return true;
}

View File

@@ -0,0 +1,50 @@
#include <memory.hpp>
Memory32::Physical KernelAllocator32{};
Memory32::PageTable *KernelPageTable32 = nullptr;
Memory64::Physical KernelAllocator64{};
Memory64::PageTable *KernelPageTable64 = nullptr;
void InitializeMemoryManagement(BootInfo *Info, bool is32)
{
if (is32)
{
trace("Initializing Physical Memory Manager");
// KernelAllocator32 = Physical(); <- Already called in the constructor
KernelAllocator32.Init(Info);
info("Memory Info: %lldMB / %lldMB (%lldMB reserved)",
TO_MB(KernelAllocator32.UsedMemory),
TO_MB(KernelAllocator32.TotalMemory),
TO_MB(KernelAllocator32.ReservedMemory));
trace("Initializing Virtual Memory Manager");
KernelPageTable32 = (Memory32::PageTable *)KernelAllocator32.RequestPages(TO_PAGES(PAGE_SIZE + 1));
memset(KernelPageTable32, 0, PAGE_SIZE);
{
Memory32::Virtual va = Memory32::Virtual(KernelPageTable32);
debug("Mapping from 0x0 to %#llx", Info->Memory.Size);
size_t MemSize = Info->Memory.Size;
va.Map((void *)0, (void *)0, MemSize, PTFlag::RW);
debug("Mapping Framebuffer");
int itrfb = 0;
while (true)
{
if (!Info->Framebuffer[itrfb].BaseAddress)
break;
va.Map((void *)Info->Framebuffer[itrfb].BaseAddress,
(void *)Info->Framebuffer[itrfb].BaseAddress,
Info->Framebuffer[itrfb].Pitch * Info->Framebuffer[itrfb].Height,
PTFlag::RW | PTFlag::US | PTFlag::G);
itrfb++;
}
}
trace("Applying new page table from address %#lx", KernelPageTable32);
asmv("mov %0, %%cr3" ::"r"(KernelPageTable32));
}
}

View File

@@ -0,0 +1,583 @@
#include <memory.hpp>
namespace Memory32
{
void *Physical::RequestPage()
{
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
{
if (PageBitmap[PageBitmapIndex] == true)
continue;
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
return (void *)(PageBitmapIndex * PAGE_SIZE);
}
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory));
while (1)
asmv("cli; hlt");
__builtin_unreachable();
}
void *Physical::RequestPages(size_t Count)
{
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
{
if (PageBitmap[PageBitmapIndex] == true)
continue;
for (uint64_t Index = PageBitmapIndex; Index < PageBitmap.Size * 8; Index++)
{
if (PageBitmap[Index] == true)
continue;
for (size_t i = 0; i < Count; i++)
{
if (PageBitmap[Index + i] == true)
goto NextPage;
}
this->LockPages((void *)(Index * PAGE_SIZE), Count);
return (void *)(Index * PAGE_SIZE);
NextPage:
Index += Count;
continue;
}
}
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory));
while (1)
asmv("cli; hlt");
__builtin_unreachable();
}
void Physical::FreePage(void *Address)
{
if (unlikely(Address == nullptr))
{
warn("Null pointer passed to FreePage.");
return;
}
size_t Index = (size_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == false))
{
warn("Tried to free an already free page. (%p)", Address);
return;
}
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
UsedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
}
void Physical::FreePages(void *Address, size_t Count)
{
if (unlikely(Address == nullptr || Count == 0))
{
warn("%s%s%s passed to FreePages.", Address == nullptr ? "Null pointer " : "", Address == nullptr && Count == 0 ? "and " : "", Count == 0 ? "Zero count" : "");
return;
}
for (size_t t = 0; t < Count; t++)
this->FreePage((void *)((uintptr_t)Address + (t * PAGE_SIZE)));
}
void Physical::LockPage(void *Address)
{
if (unlikely(Address == nullptr))
warn("Trying to lock null address.");
uintptr_t Index = (uintptr_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == true))
return;
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
UsedMemory += PAGE_SIZE;
}
}
void Physical::LockPages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to lock %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
for (size_t i = 0; i < PageCount; i++)
this->LockPage((void *)((uintptr_t)Address + (i * PAGE_SIZE)));
}
void Physical::ReservePage(void *Address)
{
if (unlikely(Address == nullptr))
warn("Trying to reserve null address.");
uintptr_t Index = (Address == NULL) ? 0 : (uintptr_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == true))
return;
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
ReservedMemory += PAGE_SIZE;
}
}
void Physical::ReservePages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to reserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
for (size_t t = 0; t < PageCount; t++)
{
uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == true))
return;
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
ReservedMemory += PAGE_SIZE;
}
}
}
void Physical::UnreservePage(void *Address)
{
if (unlikely(Address == nullptr))
warn("Trying to unreserve null address.");
uintptr_t Index = (Address == NULL) ? 0 : (uintptr_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == false))
return;
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
ReservedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
}
void Physical::UnreservePages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to unreserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
for (size_t t = 0; t < PageCount; t++)
{
uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == false))
return;
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
ReservedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
}
}
void Physical::Init(BootInfo *Info)
{
uint64_t MemorySize = Info->Memory.Size;
debug("Memory size: %lld bytes (%ld pages)", MemorySize, TO_PAGES(MemorySize));
UsedMemory = 0;
ReservedMemory = 0;
TotalMemory = MemorySize;
FreeMemory = MemorySize;
void *LargestFreeMemorySegment = nullptr;
uint64_t LargestFreeMemorySegmentSize = 0;
for (uint64_t i = 0; i < Info->Memory.Entries; i++)
{
if (Info->Memory.Entry[i].Type == Usable)
{
if (Info->Memory.Entry[i].Length > LargestFreeMemorySegmentSize)
{
/* We don't want to use 0 as a memory address. */
if (Info->Memory.Entry[i].BaseAddress == 0x0)
continue;
LargestFreeMemorySegment = (void *)Info->Memory.Entry[i].BaseAddress;
LargestFreeMemorySegmentSize = Info->Memory.Entry[i].Length;
debug("Largest free memory segment: %llp (%lldMB)",
(void *)Info->Memory.Entry[i].BaseAddress,
TO_MB(Info->Memory.Entry[i].Length));
}
}
}
if (LargestFreeMemorySegment == nullptr)
{
error("No free memory found!");
while (1)
asmv("cli; hlt");
}
size_t BitmapSize = (MemorySize / PAGE_SIZE) / 8 + 1;
void *LargestFreeMemorySegmentNoKernel = nullptr;
if ((uintptr_t)LargestFreeMemorySegment >= (uintptr_t)&_kernel_start &&
(uintptr_t)LargestFreeMemorySegment <= (uintptr_t)&_kernel_end)
{
LargestFreeMemorySegmentNoKernel = (void *)((uintptr_t)LargestFreeMemorySegment + (uintptr_t)&_kernel_end);
if ((uintptr_t)LargestFreeMemorySegmentNoKernel > ((uintptr_t)LargestFreeMemorySegment + LargestFreeMemorySegmentSize))
{
error("No free memory found!");
while (1)
asmv("cli; hlt");
}
}
else
{
LargestFreeMemorySegmentNoKernel = LargestFreeMemorySegment;
}
debug("Initializing Bitmap at %llp-%llp (%lld Bytes)",
LargestFreeMemorySegmentNoKernel,
(void *)((uintptr_t)LargestFreeMemorySegmentNoKernel + BitmapSize),
BitmapSize);
PageBitmap.Size = BitmapSize;
PageBitmap.Buffer = (uint8_t *)LargestFreeMemorySegmentNoKernel;
for (size_t i = 0; i < BitmapSize; i++)
*(uint8_t *)(PageBitmap.Buffer + i) = 0;
debug("Reserving pages...");
this->ReservePages(0, TO_PAGES(Info->Memory.Size));
debug("Unreserving usable pages...");
for (uint64_t i = 0; i < Info->Memory.Entries; i++)
{
if (Info->Memory.Entry[i].Type == Usable)
this->UnreservePages(Info->Memory.Entry[i].BaseAddress, TO_PAGES(Info->Memory.Entry[i].Length));
}
debug("Reserving bitmap pages...");
this->ReservePages(PageBitmap.Buffer, TO_PAGES(PageBitmap.Size));
debug("Reserving kernel...");
this->ReservePages(&_kernel_start, TO_PAGES((uintptr_t)&_kernel_end - (uintptr_t)&_kernel_start));
debug("Reserving kernel and its modules...");
BootInfo::ModuleInfo *Module = &Info->Modules[0];
int ModuleIndex = 0;
do
{
debug("Reserving %s (%p-%p)", Module->CommandLine, Module->Address, (void *)((uintptr_t)Module->Address + Module->Size));
this->ReservePages(Module->Address, TO_PAGES(Module->Size));
Module = &Info->Modules[++ModuleIndex];
} while (Module->Address);
this->ReservePages(0, 16);
}
Physical::Physical() {}
Physical::~Physical() {}
}
namespace Memory64
{
void *Physical::RequestPage()
{
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
{
if (PageBitmap[PageBitmapIndex] == true)
continue;
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
return (void *)(PageBitmapIndex * PAGE_SIZE);
}
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory));
while (1)
asmv("cli; hlt");
__builtin_unreachable();
}
void *Physical::RequestPages(size_t Count)
{
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
{
if (PageBitmap[PageBitmapIndex] == true)
continue;
for (uint64_t Index = PageBitmapIndex; Index < PageBitmap.Size * 8; Index++)
{
if (PageBitmap[Index] == true)
continue;
for (size_t i = 0; i < Count; i++)
{
if (PageBitmap[Index + i] == true)
goto NextPage;
}
this->LockPages((void *)(Index * PAGE_SIZE), Count);
return (void *)(Index * PAGE_SIZE);
NextPage:
Index += Count;
continue;
}
}
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory));
while (1)
asmv("cli; hlt");
__builtin_unreachable();
}
void Physical::FreePage(void *Address)
{
if (unlikely(Address == nullptr))
{
warn("Null pointer passed to FreePage.");
return;
}
size_t Index = (size_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == false))
{
warn("Tried to free an already free page. (%p)", Address);
return;
}
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
UsedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
}
void Physical::FreePages(void *Address, size_t Count)
{
if (unlikely(Address == nullptr || Count == 0))
{
warn("%s%s%s passed to FreePages.", Address == nullptr ? "Null pointer " : "", Address == nullptr && Count == 0 ? "and " : "", Count == 0 ? "Zero count" : "");
return;
}
for (size_t t = 0; t < Count; t++)
this->FreePage((void *)((uintptr_t)Address + (t * PAGE_SIZE)));
}
void Physical::LockPage(void *Address)
{
if (unlikely(Address == nullptr))
warn("Trying to lock null address.");
uintptr_t Index = (uintptr_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == true))
return;
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
UsedMemory += PAGE_SIZE;
}
}
void Physical::LockPages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to lock %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
for (size_t i = 0; i < PageCount; i++)
this->LockPage((void *)((uintptr_t)Address + (i * PAGE_SIZE)));
}
void Physical::ReservePage(void *Address)
{
if (unlikely(Address == nullptr))
warn("Trying to reserve null address.");
uintptr_t Index = (Address == NULL) ? 0 : (uintptr_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == true))
return;
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
ReservedMemory += PAGE_SIZE;
}
}
void Physical::ReservePages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to reserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
for (size_t t = 0; t < PageCount; t++)
{
uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == true))
return;
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
ReservedMemory += PAGE_SIZE;
}
}
}
void Physical::UnreservePage(void *Address)
{
if (unlikely(Address == nullptr))
warn("Trying to unreserve null address.");
uintptr_t Index = (Address == NULL) ? 0 : (uintptr_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == false))
return;
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
ReservedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
}
void Physical::UnreservePages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to unreserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
for (size_t t = 0; t < PageCount; t++)
{
uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == false))
return;
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
ReservedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
}
}
void Physical::Init(BootInfo *Info)
{
uint64_t MemorySize = Info->Memory.Size;
debug("Memory size: %lld bytes (%ld pages)", MemorySize, TO_PAGES(MemorySize));
UsedMemory = 0;
ReservedMemory = 0;
TotalMemory = MemorySize;
FreeMemory = MemorySize;
void *LargestFreeMemorySegment = nullptr;
uint64_t LargestFreeMemorySegmentSize = 0;
for (uint64_t i = 0; i < Info->Memory.Entries; i++)
{
if (Info->Memory.Entry[i].Type == Usable)
{
if (Info->Memory.Entry[i].Length > LargestFreeMemorySegmentSize)
{
/* We don't want to use 0 as a memory address. */
if (Info->Memory.Entry[i].BaseAddress == 0x0)
continue;
LargestFreeMemorySegment = (void *)Info->Memory.Entry[i].BaseAddress;
LargestFreeMemorySegmentSize = Info->Memory.Entry[i].Length;
debug("Largest free memory segment: %llp (%lldMB)",
(void *)Info->Memory.Entry[i].BaseAddress,
TO_MB(Info->Memory.Entry[i].Length));
}
}
}
if (LargestFreeMemorySegment == nullptr)
{
error("No free memory found!");
while (1)
asmv("cli; hlt");
}
size_t BitmapSize = (MemorySize / PAGE_SIZE) / 8 + 1;
void *LargestFreeMemorySegmentNoKernel = nullptr;
if ((uintptr_t)LargestFreeMemorySegment >= (uintptr_t)&_kernel_start &&
(uintptr_t)LargestFreeMemorySegment <= (uintptr_t)&_kernel_end)
{
LargestFreeMemorySegmentNoKernel = (void *)((uintptr_t)LargestFreeMemorySegment + (uintptr_t)&_kernel_end);
if ((uintptr_t)LargestFreeMemorySegmentNoKernel > ((uintptr_t)LargestFreeMemorySegment + LargestFreeMemorySegmentSize))
{
error("No free memory found!");
while (1)
asmv("cli; hlt");
}
}
else
{
LargestFreeMemorySegmentNoKernel = LargestFreeMemorySegment;
}
debug("Initializing Bitmap at %llp-%llp (%lld Bytes)",
LargestFreeMemorySegmentNoKernel,
(void *)((uintptr_t)LargestFreeMemorySegmentNoKernel + BitmapSize),
BitmapSize);
PageBitmap.Size = BitmapSize;
PageBitmap.Buffer = (uint8_t *)LargestFreeMemorySegmentNoKernel;
for (size_t i = 0; i < BitmapSize; i++)
*(uint8_t *)(PageBitmap.Buffer + i) = 0;
debug("Reserving pages...");
this->ReservePages(0, TO_PAGES(Info->Memory.Size));
debug("Unreserving usable pages...");
for (uint64_t i = 0; i < Info->Memory.Entries; i++)
{
if (Info->Memory.Entry[i].Type == Usable)
this->UnreservePages(Info->Memory.Entry[i].BaseAddress, TO_PAGES(Info->Memory.Entry[i].Length));
}
debug("Reserving bitmap pages...");
this->ReservePages(PageBitmap.Buffer, TO_PAGES(PageBitmap.Size));
debug("Reserving fennix loader...");
this->ReservePages(&_kernel_start, TO_PAGES((uintptr_t)&_kernel_end - (uintptr_t)&_kernel_start));
debug("Reserving kernel and its modules...");
BootInfo::ModuleInfo *Module = &Info->Modules[0];
int ModuleIndex = 0;
do
{
debug("Reserving %s (%p-%p)", Module->CommandLine, Module->Address, (void *)((uintptr_t)Module->Address + Module->Size));
this->ReservePages(Module->Address, TO_PAGES(Module->Size));
Module = &Info->Modules[++ModuleIndex];
} while (Module->Address);
this->ReservePages(0, 16);
}
Physical::Physical() {}
Physical::~Physical() {}
}

View File

@@ -0,0 +1,8 @@
[bits 32]
section .text
global EnablePaging
EnablePaging:
mov ecx, cr0
or ecx, 0x80000000 ; Set PG in CR0
mov cr0, ecx
ret

View File

@@ -0,0 +1,316 @@
#include <memory.hpp>
#include <debug.h>
namespace Memory32
{
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags)
{
if (unlikely(!this->Table))
{
error("No page table");
return;
}
Flags |= PTFlag::P;
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
// Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only
uint64_t DirectoryFlags = Flags & 0x3F;
PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex];
PageTableEntryPtr *PTEPtr = nullptr;
if (!PDE->Present)
{
PTEPtr = (PageTableEntryPtr *)KernelAllocator32.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr) + 1));
memset(PTEPtr, 0, sizeof(PageTableEntryPtr));
PDE->Present = true;
PDE->SetAddress((uintptr_t)PTEPtr >> 12);
}
else
PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12);
PDE->raw |= DirectoryFlags;
PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex];
PTE->Present = true;
PTE->raw |= Flags;
PTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
asmv("invlpg (%0)" ::"r"(VirtualAddress)
: "memory");
}
Virtual::Virtual(PageTable *Table)
{
if (Table)
this->Table = Table;
else
{
asmv("movl %%cr3, %0"
: "=r"(this->Table));
}
}
Virtual::~Virtual() {}
}
namespace Memory64
{
bool Virtual::Check(void *VirtualAddress, PTFlag Flag, MapType Type)
{
// 0x1000 aligned
uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 PML4 = this->Table->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTE = nullptr;
PageDirectoryEntryPtr *PDE = nullptr;
PageTableEntryPtr *PTE = nullptr;
if ((PML4.raw & Flag) > 0)
{
PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12);
if (PDPTE)
{
if ((PDPTE->Entries[Index.PDPTEIndex].Present))
{
if (Type == MapType::OneGB && PDPTE->Entries[Index.PDPTEIndex].PageSize)
return true;
PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
if (PDE)
{
if (Type == MapType::TwoMB && PDE->Entries[Index.PDEIndex].PageSize)
return true;
if ((PDE->Entries[Index.PDEIndex].Present))
{
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
if (PTE)
{
if ((PTE->Entries[Index.PTEIndex].Present))
return true;
}
}
}
}
}
}
return false;
}
void *Virtual::GetPhysical(void *VirtualAddress)
{
// 0x1000 aligned
uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 PML4 = this->Table->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTE = nullptr;
PageDirectoryEntryPtr *PDE = nullptr;
PageTableEntryPtr *PTE = nullptr;
if (PML4.Present)
{
PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12);
if (PDPTE)
{
if (PDPTE->Entries[Index.PDPTEIndex].Present)
{
if (PDPTE->Entries[Index.PDPTEIndex].PageSize)
return (void *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
if (PDE)
{
if (PDE->Entries[Index.PDEIndex].Present)
{
if (PDE->Entries[Index.PDEIndex].PageSize)
return (void *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
if (PTE)
{
if (PTE->Entries[Index.PTEIndex].Present)
return (void *)((uintptr_t)PTE->Entries[Index.PTEIndex].GetAddress() << 12);
}
}
}
}
}
}
return nullptr;
}
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type)
{
if (unlikely(!this->Table))
{
error("No page table");
return;
}
Flags |= PTFlag::P;
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
// Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only
uint64_t DirectoryFlags = Flags & 0x3F;
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr;
if (!PML4->Present)
{
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)KernelAllocator64.RequestPages(TO_PAGES(sizeof(PageDirectoryPointerTableEntryPtr) + 1));
memset(PDPTEPtr, 0, sizeof(PageDirectoryPointerTableEntryPtr));
PML4->Present = true;
PML4->SetAddress((uintptr_t)PDPTEPtr >> 12);
}
else
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)(PML4->GetAddress() << 12);
PML4->raw |= DirectoryFlags;
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (Type == MapType::OneGB)
{
PDPTE->raw |= Flags;
PDPTE->PageSize = true;
PDPTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
debug("Mapped 1GB page at %p to %p", VirtualAddress, PhysicalAddress);
return;
}
PageDirectoryEntryPtr *PDEPtr = nullptr;
if (!PDPTE->Present)
{
PDEPtr = (PageDirectoryEntryPtr *)KernelAllocator64.RequestPages(TO_PAGES(sizeof(PageDirectoryEntryPtr) + 1));
memset(PDEPtr, 0, sizeof(PageDirectoryEntryPtr));
PDPTE->Present = true;
PDPTE->SetAddress((uintptr_t)PDEPtr >> 12);
}
else
PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12);
PDPTE->raw |= DirectoryFlags;
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
if (Type == MapType::TwoMB)
{
PDE->raw |= Flags;
PDE->PageSize = true;
PDE->SetAddress((uintptr_t)PhysicalAddress >> 12);
debug("Mapped 2MB page at %p to %p", VirtualAddress, PhysicalAddress);
return;
}
PageTableEntryPtr *PTEPtr = nullptr;
if (!PDE->Present)
{
PTEPtr = (PageTableEntryPtr *)KernelAllocator64.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr) + 1));
memset(PTEPtr, 0, sizeof(PageTableEntryPtr));
PDE->Present = true;
PDE->SetAddress((uintptr_t)PTEPtr >> 12);
}
else
PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12);
PDE->raw |= DirectoryFlags;
PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex];
PTE->Present = true;
PTE->raw |= Flags;
PTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
asmv("invlpg (%0)" ::"r"(VirtualAddress)
: "memory");
#ifdef DEBUG
/* https://stackoverflow.com/a/3208376/9352057 */
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte) \
(byte & 0x80 ? '1' : '0'), \
(byte & 0x40 ? '1' : '0'), \
(byte & 0x20 ? '1' : '0'), \
(byte & 0x10 ? '1' : '0'), \
(byte & 0x08 ? '1' : '0'), \
(byte & 0x04 ? '1' : '0'), \
(byte & 0x02 ? '1' : '0'), \
(byte & 0x01 ? '1' : '0')
if (!this->Check(VirtualAddress, (PTFlag)Flags, Type)) // quick workaround just to see where it fails
warn("Failed to map v:%#lx p:%#lx with flags: " BYTE_TO_BINARY_PATTERN, VirtualAddress, PhysicalAddress, BYTE_TO_BINARY(Flags));
#endif
}
void Virtual::Unmap(void *VirtualAddress, MapType Type)
{
if (!this->Table)
{
error("No page table");
return;
}
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
if (!PML4->Present)
{
error("Page %#lx not present", PML4->GetAddress());
return;
}
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (!PDPTE->Present)
{
error("Page %#lx not present", PDPTE->GetAddress());
return;
}
if (Type == MapType::OneGB && PDPTE->PageSize)
{
PDPTE->Present = false;
return;
}
PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Address << 12);
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
if (!PDE->Present)
{
error("Page %#lx not present", PDE->GetAddress());
return;
}
if (Type == MapType::TwoMB && PDE->PageSize)
{
PDE->Present = false;
return;
}
PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE->Address << 12);
PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex];
if (!PTE.Present)
{
error("Page %#lx not present", PTE.GetAddress());
return;
}
PTE.Present = false;
PTEPtr->Entries[Index.PTEIndex] = PTE;
asmv("invlpg (%0)" ::"r"(VirtualAddress)
: "memory");
}
Virtual::Virtual(PageTable *Table)
{
if (Table)
this->Table = Table;
else
{
asmv("movl %%cr3, %0" // FIXME: movq
: "=r"(this->Table));
}
}
Virtual::~Virtual() {}
}

View File

@@ -0,0 +1,18 @@
#include <memory.hpp>
void *memcpy(void *dest, const void *src, size_t n)
{
unsigned char *d = (unsigned char *)dest;
const unsigned char *s = (const unsigned char *)src;
while (n--)
*d++ = *s++;
return dest;
}
void *memset(void *s, int c, size_t n)
{
unsigned char *p = (unsigned char *)s;
while (n--)
*p++ = (unsigned char)c;
return s;
}