Optimize memory mapping

This commit is contained in:
Alex 2023-04-07 05:12:48 +03:00
parent 540152a339
commit 7fa3e91a53
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
3 changed files with 315 additions and 242 deletions

View File

@ -39,16 +39,18 @@
#define memdbg(m, ...) #define memdbg(m, ...)
#endif #endif
using namespace Memory;
#ifdef DEBUG_ALLOCATIONS_SL #ifdef DEBUG_ALLOCATIONS_SL
NewLock(AllocatorLock); NewLock(AllocatorLock);
NewLock(OperatorAllocatorLock); NewLock(OperatorAllocatorLock);
#endif #endif
using namespace Memory;
Physical KernelAllocator; Physical KernelAllocator;
PageTable4 *KernelPageTable = nullptr; PageTable4 *KernelPageTable = nullptr;
PageTable4 *UserspaceKernelOnlyPageTable = nullptr; PageTable4 *UserspaceKernelOnlyPageTable = nullptr;
bool Page1GBSupport = false;
bool PSESupport = false;
static MemoryAllocatorType AllocatorType = MemoryAllocatorType::Pages; static MemoryAllocatorType AllocatorType = MemoryAllocatorType::Pages;
Xalloc::V1 *XallocV1Allocator = nullptr; Xalloc::V1 *XallocV1Allocator = nullptr;
@ -75,40 +77,27 @@ NIF void tracepagetable(PageTable4 *pt)
NIF void MapFromZero(PageTable4 *PT, BootInfo *Info) NIF void MapFromZero(PageTable4 *PT, BootInfo *Info)
{ {
bool Page1GBSupport = false; debug("Mapping from 0x0 to %#llx", Info->Memory.Size);
bool PSESupport = false;
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
{
CPU::x86::AMD::CPUID0x80000001 cpuid;
cpuid.Get();
Page1GBSupport = cpuid.EDX.Page1GB;
PSESupport = cpuid.EDX.PSE;
}
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
{
CPU::x86::Intel::CPUID0x80000001 cpuid;
cpuid.Get();
}
Virtual va = Virtual(PT); Virtual va = Virtual(PT);
size_t MemSize = Info->Memory.Size; size_t MemSize = Info->Memory.Size;
if (Page1GBSupport && PSESupport) if (Page1GBSupport && PSESupport)
{ {
debug("1GB Page Support Enabled"); /* Map the first 100MB of memory as 4KB pages */
#if defined(a64)
CPU::x64::CR4 cr4 = CPU::x64::readcr4();
cr4.PSE = 1;
CPU::x64::writecr4(cr4);
#elif defined(a32)
CPU::x32::CR4 cr4 = CPU::x32::readcr4();
cr4.PSE = 1;
CPU::x32::writecr4(cr4);
#elif defined(aa64)
#endif
va.Map((void *)0, (void *)0, MemSize, PTFlag::RW | PTFlag::PS /* , Virtual::MapType::OneGB */); // uintptr_t Physical4KBSectionStart = 0x10000000;
// va.Map((void *)0,
// (void *)0,
// Physical4KBSectionStart,
// PTFlag::RW);
// va.Map((void *)Physical4KBSectionStart,
// (void *)Physical4KBSectionStart,
// MemSize - Physical4KBSectionStart,
// PTFlag::RW,
// Virtual::MapType::OneGB);
va.Map((void *)0, (void *)0, MemSize, PTFlag::RW);
} }
else else
va.Map((void *)0, (void *)0, MemSize, PTFlag::RW); va.Map((void *)0, (void *)0, MemSize, PTFlag::RW);
@ -120,6 +109,7 @@ NIF void MapFromZero(PageTable4 *PT, BootInfo *Info)
NIF void MapFramebuffer(PageTable4 *PT, BootInfo *Info) NIF void MapFramebuffer(PageTable4 *PT, BootInfo *Info)
{ {
debug("Mapping Framebuffer");
Virtual va = Virtual(PT); Virtual va = Virtual(PT);
int itrfb = 0; int itrfb = 0;
while (1) while (1)
@ -127,10 +117,10 @@ NIF void MapFramebuffer(PageTable4 *PT, BootInfo *Info)
if (!Info->Framebuffer[itrfb].BaseAddress) if (!Info->Framebuffer[itrfb].BaseAddress)
break; break;
for (uintptr_t fb_base = (uintptr_t)Info->Framebuffer[itrfb].BaseAddress; va.OptimizedMap((void *)Info->Framebuffer[itrfb].BaseAddress,
fb_base < ((uintptr_t)Info->Framebuffer[itrfb].BaseAddress + ((Info->Framebuffer[itrfb].Pitch * Info->Framebuffer[itrfb].Height) + PAGE_SIZE)); (void *)Info->Framebuffer[itrfb].BaseAddress,
fb_base += PAGE_SIZE) Info->Framebuffer[itrfb].Pitch * Info->Framebuffer[itrfb].Height,
va.Map((void *)fb_base, (void *)fb_base, PTFlag::RW | PTFlag::US | PTFlag::G); PTFlag::RW | PTFlag::US | PTFlag::G);
itrfb++; itrfb++;
#ifdef DEBUG #ifdef DEBUG
@ -158,10 +148,7 @@ NIF void MapFramebuffer(PageTable4 *PT, BootInfo *Info)
NIF void MapKernel(PageTable4 *PT, BootInfo *Info) NIF void MapKernel(PageTable4 *PT, BootInfo *Info)
{ {
/* KernelStart KernelTextEnd KernelRoDataEnd KernelEnd debug("Mapping Kernel");
Kernel Start & Text Start ------ Text End ------ Kernel Rodata End ------ Kernel Data End & Kernel End
*/
Virtual va = Virtual(PT);
uintptr_t KernelStart = (uintptr_t)&_kernel_start; uintptr_t KernelStart = (uintptr_t)&_kernel_start;
uintptr_t KernelTextEnd = (uintptr_t)&_kernel_text_end; uintptr_t KernelTextEnd = (uintptr_t)&_kernel_text_end;
uintptr_t KernelDataEnd = (uintptr_t)&_kernel_data_end; uintptr_t KernelDataEnd = (uintptr_t)&_kernel_data_end;
@ -170,8 +157,15 @@ NIF void MapKernel(PageTable4 *PT, BootInfo *Info)
uintptr_t KernelFileStart = (uintptr_t)Info->Kernel.FileBase; uintptr_t KernelFileStart = (uintptr_t)Info->Kernel.FileBase;
uintptr_t KernelFileEnd = KernelFileStart + Info->Kernel.Size; uintptr_t KernelFileEnd = KernelFileStart + Info->Kernel.Size;
debug("File size: %ld KB", TO_KB(Info->Kernel.Size));
debug(".text size: %ld KB", TO_KB(KernelTextEnd - KernelStart));
debug(".data size: %ld KB", TO_KB(KernelDataEnd - KernelTextEnd));
debug(".rodata size: %ld KB", TO_KB(KernelRoDataEnd - KernelDataEnd));
debug(".bss size: %ld KB", TO_KB(KernelEnd - KernelRoDataEnd));
uintptr_t BaseKernelMapAddress = (uintptr_t)Info->Kernel.PhysicalBase; uintptr_t BaseKernelMapAddress = (uintptr_t)Info->Kernel.PhysicalBase;
uintptr_t k; uintptr_t k;
Virtual va = Virtual(PT);
/* Text section */ /* Text section */
for (k = KernelStart; k < KernelTextEnd; k += PAGE_SIZE) for (k = KernelStart; k < KernelTextEnd; k += PAGE_SIZE)
@ -212,9 +206,6 @@ NIF void MapKernel(PageTable4 *PT, BootInfo *Info)
KernelAllocator.LockPage((void *)k); KernelAllocator.LockPage((void *)k);
} }
debug("\nStart: %#llx - Text End: %#llx - RoEnd: %#llx - End: %#llx\nStart Physical: %#llx - End Physical: %#llx",
KernelStart, KernelTextEnd, KernelRoDataEnd, KernelEnd, KernelFileStart, KernelFileEnd);
#ifdef DEBUG #ifdef DEBUG
if (EnableExternalMemoryTracer) if (EnableExternalMemoryTracer)
{ {
@ -309,22 +300,40 @@ NIF void InitializeMemoryManagement(BootInfo *Info)
UserspaceKernelOnlyPageTable = (PageTable4 *)KernelAllocator.RequestPages(TO_PAGES(PAGE_SIZE)); UserspaceKernelOnlyPageTable = (PageTable4 *)KernelAllocator.RequestPages(TO_PAGES(PAGE_SIZE));
memset(UserspaceKernelOnlyPageTable, 0, PAGE_SIZE); memset(UserspaceKernelOnlyPageTable, 0, PAGE_SIZE);
debug("Mapping from 0x0 to %#llx", Info->Memory.Size); if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
{
CPU::x86::AMD::CPUID0x80000001 cpuid;
cpuid.Get();
PSESupport = cpuid.EDX.PSE;
Page1GBSupport = cpuid.EDX.Page1GB;
}
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
{
CPU::x86::Intel::CPUID0x80000001 cpuid;
cpuid.Get();
fixme("Intel PSE support");
}
if (Page1GBSupport && PSESupport)
{
debug("1GB Page Support Enabled");
#if defined(a64)
CPU::x64::CR4 cr4 = CPU::x64::readcr4();
cr4.PSE = 1;
CPU::x64::writecr4(cr4);
#elif defined(a32)
CPU::x32::CR4 cr4 = CPU::x32::readcr4();
cr4.PSE = 1;
CPU::x32::writecr4(cr4);
#elif defined(aa64)
#endif
}
MapFromZero(KernelPageTable, Info); MapFromZero(KernelPageTable, Info);
debug("Mapping from 0x0 %#llx for Userspace Page Table", Info->Memory.Size);
UserspaceKernelOnlyPageTable[0] = KernelPageTable[0];
/* Mapping Framebuffer address */
debug("Mapping Framebuffer");
MapFramebuffer(KernelPageTable, Info); MapFramebuffer(KernelPageTable, Info);
debug("Mapping Framebuffer for Userspace Page Table");
MapFramebuffer(UserspaceKernelOnlyPageTable, Info);
/* Kernel mapping */
debug("Mapping Kernel");
MapKernel(KernelPageTable, Info); MapKernel(KernelPageTable, Info);
debug("Mapping Kernel for Userspace Page Table");
MapKernel(UserspaceKernelOnlyPageTable, Info); memcpy(UserspaceKernelOnlyPageTable, KernelPageTable, sizeof(PageTable4));
trace("Applying new page table from address %p", KernelPageTable); trace("Applying new page table from address %p", KernelPageTable);
#ifdef DEBUG #ifdef DEBUG

View File

@ -127,75 +127,67 @@ namespace Memory
// Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only // 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; uint64_t DirectoryFlags = Flags & 0x3F;
PageMapLevel4 PML4 = this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr; PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr;
if (!PML4.Present) if (!PML4->Present)
{ {
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)KernelAllocator.RequestPage(); PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryPointerTableEntryPtr)));
memset(PDPTEPtr, 0, PAGE_SIZE); memset(PDPTEPtr, 0, PAGE_SIZE);
PML4.Present = true; PML4->Present = true;
PML4.SetAddress((uintptr_t)PDPTEPtr >> 12); PML4->SetAddress((uintptr_t)PDPTEPtr >> 12);
} }
else else
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12); PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)(PML4->GetAddress() << 12);
PML4->raw |= DirectoryFlags;
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (Type == MapType::OneGB) if (Type == MapType::OneGB)
{ {
PageDirectoryPointerTableEntry PDPTE = PDPTEPtr->Entries[Index.PDPTEIndex]; PDPTE->raw |= Flags;
PDPTE.raw |= Flags; PDPTE->PageSize = true;
PDPTE.PageSize = true; PDPTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
PDPTE.SetAddress((uintptr_t)PhysicalAddress >> 12); debug("Mapped 1GB page at %p to %p", VirtualAddress, PhysicalAddress);
PDPTEPtr->Entries[Index.PDPTEIndex] = PDPTE;
return; return;
} }
PML4.raw |= DirectoryFlags;
this->Table->Entries[Index.PMLIndex] = PML4;
PageDirectoryPointerTableEntry PDPTE = PDPTEPtr->Entries[Index.PDPTEIndex];
PageDirectoryEntryPtr *PDEPtr = nullptr; PageDirectoryEntryPtr *PDEPtr = nullptr;
if (!PDPTE.Present) if (!PDPTE->Present)
{ {
PDEPtr = (PageDirectoryEntryPtr *)KernelAllocator.RequestPage(); PDEPtr = (PageDirectoryEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryEntryPtr)));
memset(PDEPtr, 0, PAGE_SIZE); memset(PDEPtr, 0, PAGE_SIZE);
PDPTE.Present = true; PDPTE->Present = true;
PDPTE.SetAddress((uintptr_t)PDEPtr >> 12); PDPTE->SetAddress((uintptr_t)PDEPtr >> 12);
} }
else else
PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE.GetAddress() << 12); PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12);
PDPTE->raw |= DirectoryFlags;
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
if (Type == MapType::TwoMB) if (Type == MapType::TwoMB)
{ {
PageDirectoryEntry PDE = PDEPtr->Entries[Index.PDEIndex]; PDE->raw |= Flags;
PDE.raw |= Flags; PDE->PageSize = true;
PDE.PageSize = true; PDE->SetAddress((uintptr_t)PhysicalAddress >> 12);
PDE.SetAddress((uintptr_t)PhysicalAddress >> 12); debug("Mapped 2MB page at %p to %p", VirtualAddress, PhysicalAddress);
PDEPtr->Entries[Index.PDEIndex] = PDE;
return; return;
} }
PDPTE.raw |= DirectoryFlags;
PDPTEPtr->Entries[Index.PDPTEIndex] = PDPTE;
PageDirectoryEntry PDE = PDEPtr->Entries[Index.PDEIndex];
PageTableEntryPtr *PTEPtr = nullptr; PageTableEntryPtr *PTEPtr = nullptr;
if (!PDE.Present) if (!PDE->Present)
{ {
PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPage(); PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr)));
memset(PTEPtr, 0, PAGE_SIZE); memset(PTEPtr, 0, PAGE_SIZE);
PDE.Present = true; PDE->Present = true;
PDE.SetAddress((uintptr_t)PTEPtr >> 12); PDE->SetAddress((uintptr_t)PTEPtr >> 12);
} }
else else
PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE.GetAddress() << 12); PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12);
PDE.raw |= DirectoryFlags; PDE->raw |= DirectoryFlags;
PDEPtr->Entries[Index.PDEIndex] = PDE;
PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex]; PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex];
PTE.Present = true; PTE->Present = true;
PTE.raw |= Flags; PTE->raw |= Flags;
PTE.SetAddress((uintptr_t)PhysicalAddress >> 12); PTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
PTEPtr->Entries[Index.PTEIndex] = PTE;
#if defined(a64) #if defined(a64)
CPU::x64::invlpg(VirtualAddress); CPU::x64::invlpg(VirtualAddress);
@ -229,19 +221,6 @@ namespace Memory
#endif #endif
} }
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, size_t Length, uint64_t Flags, MapType Type)
{
int PageSize = PAGE_SIZE_4K;
if (Type == MapType::TwoMB)
PageSize = PAGE_SIZE_2M;
else if (Type == MapType::OneGB)
PageSize = PAGE_SIZE_1G;
for (uintptr_t i = 0; i < Length; i += PageSize)
this->Map((void *)((uintptr_t)VirtualAddress + i), (void *)((uintptr_t)PhysicalAddress + i), Flags, Type);
}
void Virtual::Unmap(void *VirtualAddress, MapType Type) void Virtual::Unmap(void *VirtualAddress, MapType Type)
{ {
SmartLock(this->MemoryLock); SmartLock(this->MemoryLock);
@ -252,44 +231,42 @@ namespace Memory
} }
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
PageMapLevel4 PML4 = this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
if (!PML4.Present) if (!PML4->Present)
{ {
error("Page %#lx not present", PML4.GetAddress()); error("Page %#lx not present", PML4->GetAddress());
return; return;
} }
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.Address << 12); PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
PageDirectoryPointerTableEntry PDPTE = PDPTEPtr->Entries[Index.PDPTEIndex]; PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (!PDPTE.Present) if (!PDPTE->Present)
{ {
error("Page %#lx not present", PDPTE.GetAddress()); error("Page %#lx not present", PDPTE->GetAddress());
return; return;
} }
if (Type == MapType::OneGB && PDPTE.PageSize) if (Type == MapType::OneGB && PDPTE->PageSize)
{ {
PDPTE.Present = false; PDPTE->Present = false;
PDPTEPtr->Entries[Index.PDPTEIndex] = PDPTE;
return; return;
} }
PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE.Address << 12); PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Address << 12);
PageDirectoryEntry PDE = PDEPtr->Entries[Index.PDEIndex]; PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
if (!PDE.Present) if (!PDE->Present)
{ {
error("Page %#lx not present", PDE.GetAddress()); error("Page %#lx not present", PDE->GetAddress());
return; return;
} }
if (Type == MapType::TwoMB && PDE.PageSize) if (Type == MapType::TwoMB && PDE->PageSize)
{ {
PDE.Present = false; PDE->Present = false;
PDEPtr->Entries[Index.PDEIndex] = PDE;
return; return;
} }
PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE.Address << 12); PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE->Address << 12);
PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex]; PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex];
if (!PTE.Present) if (!PTE.Present)
{ {
@ -315,25 +292,6 @@ namespace Memory
#endif #endif
} }
void Virtual::Unmap(void *VirtualAddress, size_t Length, MapType Type)
{
int PageSize = PAGE_SIZE_4K;
if (Type == MapType::TwoMB)
PageSize = PAGE_SIZE_2M;
else if (Type == MapType::OneGB)
PageSize = PAGE_SIZE_1G;
for (uintptr_t i = 0; i < Length; i += PageSize)
this->Unmap((void *)((uintptr_t)VirtualAddress + i), Type);
}
void Virtual::Remap(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type)
{
this->Unmap(VirtualAddress, Type);
this->Map(VirtualAddress, PhysicalAddress, Flags, Type);
}
Virtual::Virtual(PageTable4 *Table) Virtual::Virtual(PageTable4 *Table)
{ {
if (Table) if (Table)

View File

@ -33,25 +33,25 @@ extern uintptr_t _kernel_start, _kernel_end;
extern uintptr_t _kernel_text_end, _kernel_data_end, _kernel_rodata_end; extern uintptr_t _kernel_text_end, _kernel_data_end, _kernel_rodata_end;
// kilobyte // kilobyte
#define TO_KB(d) (d / 1024) #define TO_KB(d) ((d) / 1024)
// megabyte // megabyte
#define TO_MB(d) (d / 1024 / 1024) #define TO_MB(d) ((d) / 1024 / 1024)
// gigabyte // gigabyte
#define TO_GB(d) (d / 1024 / 1024 / 1024) #define TO_GB(d) ((d) / 1024 / 1024 / 1024)
// terabyte // terabyte
#define TO_TB(d) (d / 1024 / 1024 / 1024 / 1024) #define TO_TB(d) ((d) / 1024 / 1024 / 1024 / 1024)
// petabyte // petabyte
#define TO_PB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024) #define TO_PB(d) ((d) / 1024 / 1024 / 1024 / 1024 / 1024)
// exobyte // exobyte
#define TO_EB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024) #define TO_EB(d) ((d) / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
// zettabyte // zettabyte
#define TO_ZB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024) #define TO_ZB(d) ((d) / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
// yottabyte // yottabyte
#define TO_YB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024) #define TO_YB(d) ((d) / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
// brontobyte // brontobyte
#define TO_BB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024) #define TO_BB(d) ((d) / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
// geopbyte // geopbyte
#define TO_GPB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024) #define TO_GPB(d) ((d) / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
#define PAGE_SIZE 0x1000 // 4KB #define PAGE_SIZE 0x1000 // 4KB
#define PAGE_SIZE_4K PAGE_SIZE // 4KB #define PAGE_SIZE_4K PAGE_SIZE // 4KB
@ -178,20 +178,20 @@ namespace Memory
{ {
struct struct
{ {
bool Present : 1; // 0 uint64_t Present : 1; // 0
bool ReadWrite : 1; // 1 uint64_t ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2 uint64_t UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3 uint64_t WriteThrough : 1; // 3
bool CacheDisable : 1; // 4 uint64_t CacheDisable : 1; // 4
bool Accessed : 1; // 5 uint64_t Accessed : 1; // 5
bool Dirty : 1; // 6 uint64_t Dirty : 1; // 6
bool PageAttributeTable : 1; // 7 uint64_t PageAttributeTable : 1; // 7
bool Global : 1; // 8 uint64_t Global : 1; // 8
char Available0 : 3; // 9-11 uint64_t Available0 : 3; // 9-11
long Address : 40; // 12-51 uint64_t Address : 40; // 12-51
char Available1 : 7; // 52-58 uint64_t Available1 : 7; // 52-58
char ProtectionKey : 4; // 59-62 uint64_t ProtectionKey : 4; // 59-62
bool ExecuteDisable : 1; // 63 uint64_t ExecuteDisable : 1; // 63
}; };
uint64_t raw; uint64_t raw;
@ -235,38 +235,38 @@ namespace Memory
{ {
struct struct
{ {
bool Present : 1; // 0 uint64_t Present : 1; // 0
bool ReadWrite : 1; // 1 uint64_t ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2 uint64_t UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3 uint64_t WriteThrough : 1; // 3
bool CacheDisable : 1; // 4 uint64_t CacheDisable : 1; // 4
bool Accessed : 1; // 5 uint64_t Accessed : 1; // 5
bool Available0 : 1; // 6 uint64_t Available0 : 1; // 6
bool PageSize : 1; // 7 uint64_t PageSize : 1; // 7
char Available1 : 4; // 8-11 uint64_t Available1 : 4; // 8-11
long Address : 40; // 12-51 uint64_t Address : 40; // 12-51
short Available2 : 11; // 52-62 uint64_t Available2 : 11; // 52-62
bool ExecuteDisable : 1; // 63 uint64_t ExecuteDisable : 1; // 63
}; };
struct struct
{ {
bool Present : 1; // 0 uint64_t Present : 1; // 0
bool ReadWrite : 1; // 1 uint64_t ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2 uint64_t UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3 uint64_t WriteThrough : 1; // 3
bool CacheDisable : 1; // 4 uint64_t CacheDisable : 1; // 4
bool Accessed : 1; // 5 uint64_t Accessed : 1; // 5
bool Dirty : 1; // 6 uint64_t Dirty : 1; // 6
bool PageSize : 1; // 7 uint64_t PageSize : 1; // 7
bool Global : 1; // 8 uint64_t Global : 1; // 8
char Available0 : 3; // 9-11 uint64_t Available0 : 3; // 9-11
bool PageAttributeTable : 1; // 12 uint64_t PageAttributeTable : 1; // 12
char Reserved0 : 8; // 13-20 uint64_t Reserved0 : 8; // 13-20
long Address : 31; // 21-51 uint64_t Address : 31; // 21-51
char Available1 : 7; // 52-58 uint64_t Available1 : 7; // 52-58
char ProtectionKey : 4; // 59-62 uint64_t ProtectionKey : 4; // 59-62
bool ExecuteDisable : 1; // 63 uint64_t ExecuteDisable : 1; // 63
} TwoMB; } TwoMB;
uint64_t raw; uint64_t raw;
@ -311,38 +311,38 @@ namespace Memory
{ {
struct struct
{ {
bool Present : 1; // 0 uint64_t Present : 1; // 0
bool ReadWrite : 1; // 1 uint64_t ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2 uint64_t UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3 uint64_t WriteThrough : 1; // 3
bool CacheDisable : 1; // 4 uint64_t CacheDisable : 1; // 4
bool Accessed : 1; // 5 uint64_t Accessed : 1; // 5
bool Available0 : 1; // 6 uint64_t Available0 : 1; // 6
bool PageSize : 1; // 7 uint64_t PageSize : 1; // 7
char Available1 : 4; // 8-11 uint64_t Available1 : 4; // 8-11
long Address : 40; // 12-51 uint64_t Address : 40; // 12-51
short Available2 : 11; // 52-62 uint64_t Available2 : 11; // 52-62
bool ExecuteDisable : 1; // 63 uint64_t ExecuteDisable : 1; // 63
}; };
struct struct
{ {
bool Present : 1; // 0 uint64_t Present : 1; // 0
bool ReadWrite : 1; // 1 uint64_t ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2 uint64_t UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3 uint64_t WriteThrough : 1; // 3
bool CacheDisable : 1; // 4 uint64_t CacheDisable : 1; // 4
bool Accessed : 1; // 5 uint64_t Accessed : 1; // 5
bool Dirty : 1; // 6 uint64_t Dirty : 1; // 6
bool PageSize : 1; // 7 uint64_t PageSize : 1; // 7
bool Global : 1; // 8 uint64_t Global : 1; // 8
char Available0 : 3; // 9-11 uint64_t Available0 : 3; // 9-11
bool PageAttributeTable : 1; // 12 uint64_t PageAttributeTable : 1; // 12
int Reserved0 : 17; // 13-29 uint64_t Reserved0 : 17; // 13-29
long Address : 22; // 30-51 uint64_t Address : 22; // 30-51
char Available1 : 7; // 52-58 uint64_t Available1 : 7; // 52-58
char ProtectionKey : 4; // 59-62 uint64_t ProtectionKey : 4; // 59-62
bool ExecuteDisable : 1; // 63 uint64_t ExecuteDisable : 1; // 63
} OneGB; } OneGB;
uint64_t raw; uint64_t raw;
@ -387,18 +387,18 @@ namespace Memory
{ {
struct struct
{ {
bool Present : 1; // 0 uint64_t Present : 1; // 0
bool ReadWrite : 1; // 1 uint64_t ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2 uint64_t UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3 uint64_t WriteThrough : 1; // 3
bool CacheDisable : 1; // 4 uint64_t CacheDisable : 1; // 4
bool Accessed : 1; // 5 uint64_t Accessed : 1; // 5
bool Available0 : 1; // 6 uint64_t Available0 : 1; // 6
bool Reserved0 : 1; // 7 uint64_t Reserved0 : 1; // 7
char Available1 : 4; // 8-11 uint64_t Available1 : 4; // 8-11
long Address : 40; // 12-51 uint64_t Address : 40; // 12-51
short Available2 : 11; // 52-62 uint64_t Available2 : 11; // 52-62
bool ExecuteDisable : 1; // 63 uint64_t ExecuteDisable : 1; // 63
}; };
uint64_t raw; uint64_t raw;
@ -598,6 +598,7 @@ namespace Memory
public: public:
enum MapType enum MapType
{ {
NoMapType,
FourKB, FourKB,
TwoMB, TwoMB,
OneGB OneGB
@ -618,6 +619,7 @@ namespace Memory
* *
* @param VirtualAddress Virtual address of the page * @param VirtualAddress Virtual address of the page
* @param Flag Flag to check * @param Flag Flag to check
* @param Type Type of the page. Check MapType enum.
* @return true if page has the specified flag. * @return true if page has the specified flag.
* @return false if page is has the specified flag. * @return false if page is has the specified flag.
*/ */
@ -636,6 +638,7 @@ namespace Memory
* @param VirtualAddress Virtual address of the page. * @param VirtualAddress Virtual address of the page.
* @param PhysicalAddress Physical address of the page. * @param PhysicalAddress Physical address of the page.
* @param Flags Flags of the page. Check PTFlag enum. * @param Flags Flags of the page. Check PTFlag enum.
* @param Type Type of the page. Check MapType enum.
*/ */
void Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flag = PTFlag::P, MapType Type = MapType::FourKB); void Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flag = PTFlag::P, MapType Type = MapType::FourKB);
@ -644,15 +647,101 @@ namespace Memory
* *
* @param VirtualAddress First virtual address of the page. * @param VirtualAddress First virtual address of the page.
* @param PhysicalAddress First physical address of the page. * @param PhysicalAddress First physical address of the page.
* @param PageCount Number of pages. * @param Length Length to map.
* @param Flags Flags of the page. Check PTFlag enum. * @param Flags Flags of the page. Check PTFlag enum.
* @param Type Type of the page. Check MapType enum.
*/ */
void Map(void *VirtualAddress, void *PhysicalAddress, size_t Length, uint64_t Flags, MapType Type = MapType::FourKB); __always_inline inline void Map(void *VirtualAddress, void *PhysicalAddress, size_t Length, uint64_t Flags, MapType Type = MapType::FourKB)
{
int PageSize = PAGE_SIZE_4K;
if (Type == MapType::TwoMB)
PageSize = PAGE_SIZE_2M;
else if (Type == MapType::OneGB)
PageSize = PAGE_SIZE_1G;
for (uintptr_t i = 0; i < Length; i += PageSize)
this->Map((void *)((uintptr_t)VirtualAddress + i), (void *)((uintptr_t)PhysicalAddress + i), Flags, Type);
}
/**
* @brief Map multiple pages efficiently.
*
* This function will detect the best page size to map the pages.
*
* @note This function will not check if PSE or 1GB pages are enabled or supported.
*
* @param VirtualAddress First virtual address of the page.
* @param PhysicalAddress First physical address of the page.
* @param Length Length of the pages.
* @param Flags Flags of the page. Check PTFlag enum.
* @param Fit If true, the function will try to fit the pages in the smallest page size.
* @param FailOnModulo If true, the function will return NoMapType if the length is not a multiple of the page size.
* @return The best page size to map the pages.
*/
__always_inline inline MapType OptimizedMap(void *VirtualAddress, void *PhysicalAddress, size_t Length, uint64_t Flags, bool Fit = false, bool FailOnModulo = false)
{
if (unlikely(Fit))
{
while (Length >= PAGE_SIZE_1G)
{
this->Map(VirtualAddress, PhysicalAddress, Length, Flags, Virtual::MapType::OneGB);
VirtualAddress = (void *)((uintptr_t)VirtualAddress + PAGE_SIZE_1G);
PhysicalAddress = (void *)((uintptr_t)PhysicalAddress + PAGE_SIZE_1G);
Length -= PAGE_SIZE_1G;
}
while (Length >= PAGE_SIZE_2M)
{
this->Map(VirtualAddress, PhysicalAddress, Length, Flags, Virtual::MapType::TwoMB);
VirtualAddress = (void *)((uintptr_t)VirtualAddress + PAGE_SIZE_2M);
PhysicalAddress = (void *)((uintptr_t)PhysicalAddress + PAGE_SIZE_2M);
Length -= PAGE_SIZE_2M;
}
while (Length >= PAGE_SIZE_4K)
{
this->Map(VirtualAddress, PhysicalAddress, Length, Flags, Virtual::MapType::FourKB);
VirtualAddress = (void *)((uintptr_t)VirtualAddress + PAGE_SIZE_4K);
PhysicalAddress = (void *)((uintptr_t)PhysicalAddress + PAGE_SIZE_4K);
Length -= PAGE_SIZE_4K;
}
return Virtual::MapType::FourKB;
}
Virtual::MapType Type = Virtual::MapType::FourKB;
if (Length >= PAGE_SIZE_1G)
{
Type = Virtual::MapType::OneGB;
if (Length % PAGE_SIZE_1G != 0)
{
warn("Length is not a multiple of 1GB.");
if (FailOnModulo)
return Virtual::MapType::NoMapType;
}
}
else if (Length >= PAGE_SIZE_2M)
{
Type = Virtual::MapType::TwoMB;
if (Length % PAGE_SIZE_2M != 0)
{
warn("Length is not a multiple of 2MB.");
if (FailOnModulo)
return Virtual::MapType::NoMapType;
}
}
this->Map(VirtualAddress, PhysicalAddress, Length, Flags, Type);
return Type;
}
/** /**
* @brief Unmap page. * @brief Unmap page.
* *
* @param VirtualAddress Virtual address of the page. * @param VirtualAddress Virtual address of the page.
* @param Type Type of the page. Check MapType enum.
*/ */
void Unmap(void *VirtualAddress, MapType Type = MapType::FourKB); void Unmap(void *VirtualAddress, MapType Type = MapType::FourKB);
@ -660,9 +749,21 @@ namespace Memory
* @brief Unmap multiple pages. * @brief Unmap multiple pages.
* *
* @param VirtualAddress First virtual address of the page. * @param VirtualAddress First virtual address of the page.
* @param Length Number of pages. * @param Length Length to map.
* @param Type Type of the page. Check MapType enum.
*/ */
void Unmap(void *VirtualAddress, size_t Length, MapType Type = MapType::FourKB); __always_inline inline void Unmap(void *VirtualAddress, size_t Length, MapType Type = MapType::FourKB)
{
int PageSize = PAGE_SIZE_4K;
if (Type == MapType::TwoMB)
PageSize = PAGE_SIZE_2M;
else if (Type == MapType::OneGB)
PageSize = PAGE_SIZE_1G;
for (uintptr_t i = 0; i < Length; i += PageSize)
this->Unmap((void *)((uintptr_t)VirtualAddress + i), Type);
}
/** /**
* @brief Remap page. * @brief Remap page.
@ -670,8 +771,13 @@ namespace Memory
* @param VirtualAddress Virtual address of the page. * @param VirtualAddress Virtual address of the page.
* @param PhysicalAddress Physical address of the page. * @param PhysicalAddress Physical address of the page.
* @param Flags Flags of the page. Check PTFlag enum. * @param Flags Flags of the page. Check PTFlag enum.
* @param Type Type of the page. Check MapType enum.
*/ */
void Remap(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type = MapType::FourKB); __always_inline inline void Remap(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type = MapType::FourKB)
{
this->Unmap(VirtualAddress, Type);
this->Map(VirtualAddress, PhysicalAddress, Flags, Type);
}
/** /**
* @brief Construct a new Virtual object * @brief Construct a new Virtual object