mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-24 11:45:27 +01:00
f35acfa5ab
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
551 lines
19 KiB
C
551 lines
19 KiB
C
/**
|
|
|
|
Virtual memory functions.
|
|
|
|
by dmazar
|
|
|
|
**/
|
|
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
|
|
#include "VMem.h"
|
|
#include "Lib.h"
|
|
#include "NVRAMDebug.h"
|
|
|
|
|
|
// DBG_TO: 0=no debug, 1=serial, 2=console
|
|
// serial requires
|
|
// [PcdsFixedAtBuild]
|
|
// gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x07
|
|
// gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0xFFFFFFFF
|
|
// in package DSC file
|
|
#define DBG_TO 0
|
|
|
|
#if DBG_TO == 2
|
|
#define DBG(...) AsciiPrint(__VA_ARGS__);
|
|
#elif DBG_TO == 1
|
|
#define DBG(...) DebugPrint(1, __VA_ARGS__);
|
|
#else
|
|
#define DBG(...)
|
|
#endif
|
|
|
|
|
|
/** Memory allocation for VM map pages that we will create with VmMapVirtualPage.
|
|
* We need to have it preallocated during boot services.
|
|
*/
|
|
UINT8 *VmMemoryPool = NULL;
|
|
INTN VmMemoryPoolFreePages = 0;
|
|
|
|
VOID
|
|
GetCurrentPageTable(PAGE_MAP_AND_DIRECTORY_POINTER **PageTable, UINTN *Flags)
|
|
{
|
|
UINTN CR3;
|
|
|
|
CR3 = AsmReadCr3();
|
|
DBG("GetCurrentPageTable: CR3 = 0x%lx\n", CR3);
|
|
*PageTable = (PAGE_MAP_AND_DIRECTORY_POINTER*)(UINTN)(CR3 & CR3_ADDR_MASK);
|
|
*Flags = CR3 & (CR3_FLAG_PWT | CR3_FLAG_PCD);
|
|
}
|
|
|
|
VOID
|
|
PrintPageTablePTE(PAGE_TABLE_4K_ENTRY *PTE, VIRTUAL_ADDR VA)
|
|
{
|
|
#if DBG_TO
|
|
UINTN Index;
|
|
UINT64 Start;
|
|
|
|
for (Index = 0; Index < 10; Index++) {
|
|
VA.Pg4K.PTOffset = Index;
|
|
DBG(" PTE %03x at %p = %lx => ", Index, PTE, PTE->Uint64);
|
|
// 4KB PTE
|
|
Start = (PTE->Uint64 & PT_ADDR_MASK_4K);
|
|
DBG("4KB Fl: %lx VA: %lx - %lx ==> PH %lx - %lx\n",
|
|
(PTE->Uint64 & ~PT_ADDR_MASK_4K), VA.Uint64, VA.Uint64 + 0x1000 - 1, Start, Start + 0x1000 - 1);
|
|
PTE++;
|
|
}
|
|
//WaitForKeyPress(L"more ...");
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
PrintPageTablePDE(PAGE_MAP_AND_DIRECTORY_POINTER *PDE, VIRTUAL_ADDR VA)
|
|
{
|
|
#if DBG_TO
|
|
UINTN Index;
|
|
PAGE_TABLE_2M_ENTRY *PT2M;
|
|
PAGE_TABLE_4K_ENTRY *PTE;
|
|
UINT64 Start;
|
|
|
|
for (Index = 0; Index < 10; Index++) {
|
|
VA.Pg4K.PDOffset = Index;
|
|
DBG(" PDE %03x at %p = %lx => ", Index, PDE, PDE->Uint64);
|
|
if (PDE->Bits.MustBeZero & 0x1) {
|
|
// 2MB PDE
|
|
PT2M = (PAGE_TABLE_2M_ENTRY *)PDE;
|
|
Start = (PT2M->Uint64 & PT_ADDR_MASK_2M);
|
|
DBG("2MB Fl: %lx VA: %lx - %lx ==> PH %lx - %lx\n",
|
|
(PT2M->Uint64 & ~PT_ADDR_MASK_2M), VA.Uint64, VA.Uint64 + 0x200000 - 1, Start, Start + 0x200000 - 1);
|
|
} else {
|
|
DBG(" Fl: %lx %lx ->\n", (PDE->Uint64 & ~PT_ADDR_MASK_4K), (PDE->Uint64 & PT_ADDR_MASK_4K));
|
|
PTE = (PAGE_TABLE_4K_ENTRY *)(PDE->Uint64 & PT_ADDR_MASK_4K);
|
|
PrintPageTablePTE(PTE, VA);
|
|
}
|
|
PDE++;
|
|
}
|
|
//WaitForKeyPress(L"more ...");
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
PrintPageTablePDPE(PAGE_MAP_AND_DIRECTORY_POINTER *PDPE, VIRTUAL_ADDR VA)
|
|
{
|
|
#if DBG_TO
|
|
UINTN Index;
|
|
PAGE_TABLE_1G_ENTRY *PT1G;
|
|
PAGE_MAP_AND_DIRECTORY_POINTER *PDE;
|
|
UINT64 Start;
|
|
|
|
for (Index = 0; Index < 10; Index++) {
|
|
VA.Pg4K.PDPOffset = Index;
|
|
DBG(" PDPE %03x at %p = %lx => ", Index, PDPE, PDPE->Uint64);
|
|
if (PDPE->Bits.MustBeZero & 0x1) {
|
|
// 1GB PDPE
|
|
PT1G = (PAGE_TABLE_1G_ENTRY *)PDPE;
|
|
Start = (PT1G->Uint64 & PT_ADDR_MASK_1G);
|
|
DBG("1GB Fl: %lx VA: %lx - %lx ==> PH %lx - %lx\n",
|
|
(PT1G->Uint64 & ~PT_ADDR_MASK_1G), VA.Uint64, VA.Uint64 + 0x40000000 - 1, Start, Start + 0x40000000 - 1);
|
|
} else {
|
|
DBG(" Fl: %lx %lx ->\n", (PDPE->Uint64 & ~PT_ADDR_MASK_4K), (PDPE->Uint64 & PT_ADDR_MASK_4K));
|
|
PDE = (PAGE_MAP_AND_DIRECTORY_POINTER *)(PDPE->Uint64 & PT_ADDR_MASK_4K);
|
|
PrintPageTablePDE(PDE, VA);
|
|
}
|
|
PDPE++;
|
|
}
|
|
//WaitForKeyPress(L"more ...");
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
PrintPageTable(PAGE_MAP_AND_DIRECTORY_POINTER *PageTable, UINTN Flags)
|
|
{
|
|
UINTN Index;
|
|
VIRTUAL_ADDR VA;
|
|
PAGE_MAP_AND_DIRECTORY_POINTER *PML4;
|
|
PAGE_MAP_AND_DIRECTORY_POINTER *PDPE;
|
|
|
|
DBG("PrintPageTable: %p, Flags: PWT: %d, PCD: %d\n", PageTable, (Flags & CR3_FLAG_PWT), (Flags & CR3_FLAG_PCD));
|
|
PML4 = PageTable;
|
|
for (Index = 0; Index < 3; Index++) {
|
|
VA.Uint64 = 0;
|
|
VA.Pg4K.PML4Offset = Index;
|
|
VA_FIX_SIGN_EXTEND(VA);
|
|
DBG("PML4 %03x at %p = %lx => Fl: %lx %lx ->\n", Index, PML4, PML4->Uint64, (PML4->Uint64 & ~PT_ADDR_MASK_4K), (PML4->Uint64 & PT_ADDR_MASK_4K));
|
|
PDPE = (PAGE_MAP_AND_DIRECTORY_POINTER *)(PML4->Uint64 & PT_ADDR_MASK_4K);
|
|
PrintPageTablePDPE(PDPE, VA);
|
|
PML4++;
|
|
}
|
|
//WaitForKeyPress(L"END");
|
|
}
|
|
|
|
EFI_STATUS
|
|
GetPhysicalAddr(PAGE_MAP_AND_DIRECTORY_POINTER *PageTable, EFI_VIRTUAL_ADDRESS VirtualAddr, EFI_PHYSICAL_ADDRESS *PhysicalAddr)
|
|
{
|
|
EFI_PHYSICAL_ADDRESS Start;
|
|
VIRTUAL_ADDR VA;
|
|
VIRTUAL_ADDR VAStart;
|
|
VIRTUAL_ADDR VAEnd;
|
|
PAGE_MAP_AND_DIRECTORY_POINTER *PML4;
|
|
PAGE_MAP_AND_DIRECTORY_POINTER *PDPE;
|
|
PAGE_MAP_AND_DIRECTORY_POINTER *PDE;
|
|
PAGE_TABLE_4K_ENTRY *PTE4K;
|
|
PAGE_TABLE_2M_ENTRY *PTE2M;
|
|
PAGE_TABLE_1G_ENTRY *PTE1G;
|
|
|
|
VA.Uint64 = (UINT64)VirtualAddr;
|
|
//VA_FIX_SIGN_EXTEND(VA);
|
|
DBG("PageTable: %p\n", PageTable);
|
|
DBG("VA: %lx => Indexes PML4=%x, PDP=%x, PD=%x, PT=%x\n",
|
|
VA.Uint64, VA.Pg4K.PML4Offset, VA.Pg4K.PDPOffset, VA.Pg4K.PDOffset, VA.Pg4K.PTOffset);
|
|
|
|
// PML4
|
|
PML4 = PageTable;
|
|
PML4 += VA.Pg4K.PML4Offset;
|
|
// prepare region start and end
|
|
VAStart.Uint64 = 0;
|
|
VAStart.Pg4K.PML4Offset = VA.Pg4K.PML4Offset;
|
|
VA_FIX_SIGN_EXTEND(VAStart);
|
|
VAEnd.Uint64 = ~(UINT64)0;
|
|
VAEnd.Pg4K.PML4Offset = VA.Pg4K.PML4Offset;
|
|
VA_FIX_SIGN_EXTEND(VAEnd);
|
|
// print it
|
|
DBG("PML4[%03x] at %p = %lx Region: %lx - %lx\n", VA.Pg4K.PML4Offset, PML4, PML4->Uint64, VAStart.Uint64, VAEnd.Uint64);
|
|
if (!PML4->Bits.Present) {
|
|
DBG("-> Mapping not present!\n");
|
|
return EFI_NO_MAPPING;
|
|
}
|
|
DBG("-> Nx:%x|A:%x|PCD:%x|PWT:%x|US:%x|RW:%x|P:%x -> %lx\n",
|
|
PML4->Bits.Nx, PML4->Bits.Accessed,
|
|
PML4->Bits.CacheDisabled, PML4->Bits.WriteThrough,
|
|
PML4->Bits.UserSupervisor, PML4->Bits.ReadWrite, PML4->Bits.Present,
|
|
(PML4->Uint64 & PT_ADDR_MASK_4K)
|
|
);
|
|
|
|
// PDPE
|
|
PDPE = (PAGE_MAP_AND_DIRECTORY_POINTER *)(PML4->Uint64 & PT_ADDR_MASK_4K);
|
|
PDPE += VA.Pg4K.PDPOffset;
|
|
VAStart.Pg4K.PDPOffset = VA.Pg4K.PDPOffset;
|
|
VAEnd.Pg4K.PDPOffset = VA.Pg4K.PDPOffset;
|
|
DBG("PDPE[%03x] at %p = %lx Region: %lx - %lx\n", VA.Pg4K.PDPOffset, PDPE, PDPE->Uint64, VAStart.Uint64, VAEnd.Uint64);
|
|
if (!PDPE->Bits.Present) {
|
|
DBG("-> Mapping not present!\n");
|
|
return EFI_NO_MAPPING;
|
|
}
|
|
if (PDPE->Bits.MustBeZero & 0x1) {
|
|
// 1GB PDPE
|
|
PTE1G = (PAGE_TABLE_1G_ENTRY *)PDPE;
|
|
DBG("-> Nx:%x|G:%x|PAT:%x|D:%x|A:%x|PCD:%x|PWT:%x|US:%x|RW:%x|P:%x\n",
|
|
PTE1G->Bits.Nx, PTE1G->Bits.Global, PTE1G->Bits.PAT,
|
|
PTE1G->Bits.Dirty, PTE1G->Bits.Accessed,
|
|
PTE1G->Bits.CacheDisabled, PTE1G->Bits.WriteThrough,
|
|
PTE1G->Bits.UserSupervisor, PTE1G->Bits.ReadWrite, PTE1G->Bits.Present
|
|
);
|
|
Start = (PTE1G->Uint64 & PT_ADDR_MASK_1G);
|
|
*PhysicalAddr = Start + VA.Pg1G.PhysPgOffset;
|
|
DBG("-> 1GB page %lx - %lx => %lx\n", Start, Start + 0x40000000 - 1, *PhysicalAddr);
|
|
return EFI_SUCCESS;
|
|
}
|
|
DBG("-> Nx:%x|A:%x|PCD:%x|PWT:%x|US:%x|RW:%x|P:%x -> %lx\n",
|
|
PDPE->Bits.Nx, PDPE->Bits.Accessed,
|
|
PDPE->Bits.CacheDisabled, PDPE->Bits.WriteThrough,
|
|
PDPE->Bits.UserSupervisor, PDPE->Bits.ReadWrite, PDPE->Bits.Present,
|
|
(PDPE->Uint64 & PT_ADDR_MASK_4K)
|
|
);
|
|
|
|
// PDE
|
|
PDE = (PAGE_MAP_AND_DIRECTORY_POINTER *)(PDPE->Uint64 & PT_ADDR_MASK_4K);
|
|
PDE += VA.Pg4K.PDOffset;
|
|
VAStart.Pg4K.PDOffset = VA.Pg4K.PDOffset;
|
|
VAEnd.Pg4K.PDOffset = VA.Pg4K.PDOffset;
|
|
DBG("PDE[%03x] at %p = %lx Region: %lx - %lx\n", VA.Pg4K.PDOffset, PDE, PDE->Uint64, VAStart.Uint64, VAEnd.Uint64);
|
|
if (!PDE->Bits.Present) {
|
|
DBG("-> Mapping not present!\n");
|
|
return EFI_NO_MAPPING;
|
|
}
|
|
if (PDE->Bits.MustBeZero & 0x1) {
|
|
// 2MB PDE
|
|
PTE2M = (PAGE_TABLE_2M_ENTRY *)PDE;
|
|
DBG("-> Nx:%x|G:%x|PAT:%x|D:%x|A:%x|PCD:%x|PWT:%x|US:%x|RW:%x|P:%x\n",
|
|
PTE2M->Bits.Nx, PTE2M->Bits.Global, PTE2M->Bits.PAT,
|
|
PTE2M->Bits.Dirty, PTE2M->Bits.Accessed,
|
|
PTE2M->Bits.CacheDisabled, PTE2M->Bits.WriteThrough,
|
|
PTE2M->Bits.UserSupervisor, PTE2M->Bits.ReadWrite, PTE2M->Bits.Present
|
|
);
|
|
Start = (PTE2M->Uint64 & PT_ADDR_MASK_2M);
|
|
*PhysicalAddr = Start + VA.Pg2M.PhysPgOffset;
|
|
DBG("-> 2MB page %lx - %lx => %lx\n", Start, Start + 0x200000 - 1, *PhysicalAddr);
|
|
return EFI_SUCCESS;
|
|
}
|
|
DBG("-> Nx:%x|A:%x|PCD:%x|PWT:%x|US:%x|RW:%x|P:%x -> %lx\n",
|
|
PDE->Bits.Nx, PDE->Bits.Accessed,
|
|
PDE->Bits.CacheDisabled, PDE->Bits.WriteThrough,
|
|
PDE->Bits.UserSupervisor, PDE->Bits.ReadWrite, PDE->Bits.Present,
|
|
(PDE->Uint64 & PT_ADDR_MASK_4K)
|
|
);
|
|
|
|
// PTE
|
|
PTE4K = (PAGE_TABLE_4K_ENTRY *)(PDE->Uint64 & PT_ADDR_MASK_4K);
|
|
PTE4K += VA.Pg4K.PTOffset;
|
|
VAStart.Pg4K.PTOffset = VA.Pg4K.PTOffset;
|
|
VAEnd.Pg4K.PTOffset = VA.Pg4K.PTOffset;
|
|
DBG("PTE[%03x] at %p = %lx Region: %lx - %lx\n", VA.Pg4K.PTOffset, PTE4K, PTE4K->Uint64, VAStart.Uint64, VAEnd.Uint64);
|
|
if (!PTE4K->Bits.Present) {
|
|
DBG("-> Mapping not present!\n");
|
|
return EFI_NO_MAPPING;
|
|
}
|
|
DBG("-> Nx:%x|G:%x|PAT:%x|D:%x|A:%x|PCD:%x|PWT:%x|US:%x|RW:%x|P:%x -> %lx\n",
|
|
PTE4K->Bits.Nx, PTE4K->Bits.Global, PTE4K->Bits.PAT,
|
|
PTE4K->Bits.Dirty, PTE4K->Bits.Accessed,
|
|
PTE4K->Bits.CacheDisabled, PTE4K->Bits.WriteThrough,
|
|
PTE4K->Bits.UserSupervisor, PTE4K->Bits.ReadWrite, PTE4K->Bits.Present,
|
|
(PTE4K->Uint64 & PT_ADDR_MASK_4K)
|
|
);
|
|
Start = (PTE4K->Uint64 & PT_ADDR_MASK_4K);
|
|
*PhysicalAddr = Start + VA.Pg4K.PhysPgOffset;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Inits vm memory pool. Should be called while boot services are still usable. */
|
|
EFI_STATUS
|
|
VmAllocateMemoryPool(VOID)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PHYSICAL_ADDRESS Addr;
|
|
|
|
if (VmMemoryPool != NULL) {
|
|
// already allocated
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
VmMemoryPoolFreePages = 0x200; // 2 MB should be enough
|
|
Addr = 0x100000000; // max address
|
|
|
|
Status = AllocatePagesFromTop(EfiBootServicesData, VmMemoryPoolFreePages, &Addr);
|
|
if (Status != EFI_SUCCESS) {
|
|
Print(L"VmAllocateMemoryPool: AllocatePagesFromTop(EfiBootServicesData) = %r\n", Status);
|
|
} else {
|
|
VmMemoryPool = (UINT8*)Addr;
|
|
DBG("VmMemoryPool = %lx - %lx\n", VmMemoryPool, VmMemoryPool + EFI_PAGES_TO_SIZE(VmMemoryPoolFreePages) - 1);
|
|
DBGnvr("VmMemoryPool = %lx - %lx\n", VmMemoryPool, VmMemoryPool + EFI_PAGES_TO_SIZE(VmMemoryPoolFreePages) - 1);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/** Central method for allocating pages for VM page maps. */
|
|
VOID *
|
|
VmAllocatePages(UINTN NumPages)
|
|
{
|
|
VOID *AllocatedPages = NULL;
|
|
/*
|
|
EFI_STATUS Status;
|
|
EFI_PHYSICAL_ADDRESS Addr;
|
|
|
|
// for now, just allocate EfiBootServicesData as usuall.
|
|
// if needed, we'll allocate somwhere from the top of mem.
|
|
Status = gBS->AllocatePages(AllocateAnyPages, EfiBootServicesData, NumPages, &Addr);
|
|
if (EFI_ERROR(Status)) {
|
|
Addr = 0;
|
|
}
|
|
return (VOID*)Addr;
|
|
*/
|
|
if (VmMemoryPoolFreePages >= (INTN)NumPages) {
|
|
AllocatedPages = VmMemoryPool;
|
|
VmMemoryPool += EFI_PAGES_TO_SIZE(NumPages);
|
|
VmMemoryPoolFreePages -= NumPages;
|
|
} else {
|
|
DBGnvr("VmAllocatePages - no more pages!\n");
|
|
CpuDeadLoop();
|
|
}
|
|
return AllocatedPages;
|
|
}
|
|
|
|
/** Maps (remaps) 4K page given by VirtualAddr to PhysicalAddr page in PageTable. */
|
|
EFI_STATUS
|
|
VmMapVirtualPage(PAGE_MAP_AND_DIRECTORY_POINTER *PageTable, EFI_VIRTUAL_ADDRESS VirtualAddr, EFI_PHYSICAL_ADDRESS PhysicalAddr)
|
|
{
|
|
EFI_PHYSICAL_ADDRESS Start;
|
|
VIRTUAL_ADDR VA;
|
|
VIRTUAL_ADDR VAStart;
|
|
VIRTUAL_ADDR VAEnd;
|
|
PAGE_MAP_AND_DIRECTORY_POINTER *PML4;
|
|
PAGE_MAP_AND_DIRECTORY_POINTER *PDPE;
|
|
PAGE_MAP_AND_DIRECTORY_POINTER *PDE;
|
|
PAGE_TABLE_4K_ENTRY *PTE4K;
|
|
PAGE_TABLE_4K_ENTRY *PTE4KTmp;
|
|
PAGE_TABLE_2M_ENTRY *PTE2M;
|
|
PAGE_TABLE_1G_ENTRY *PTE1G;
|
|
UINTN Index;
|
|
|
|
VA.Uint64 = (UINT64)VirtualAddr;
|
|
//VA_FIX_SIGN_EXTEND(VA);
|
|
DBG("VmMapVirtualPage VA %lx => PA %lx\nPageTable: %p\n", VirtualAddr, PhysicalAddr, PageTable);
|
|
DBG("VA: %lx => Indexes PML4=%x, PDP=%x, PD=%x, PT=%x\n",
|
|
VA.Uint64, VA.Pg4K.PML4Offset, VA.Pg4K.PDPOffset, VA.Pg4K.PDOffset, VA.Pg4K.PTOffset);
|
|
|
|
// PML4
|
|
PML4 = PageTable;
|
|
PML4 += VA.Pg4K.PML4Offset;
|
|
// there is a problem if our PML4 points to the same table as first PML4 entry
|
|
// since we may mess the mapping of first virtual region (happens in VBox and probably DUET).
|
|
// check for this on first call and if true, just clear our PML4 - we'll rebuild it in later step
|
|
if (PML4 != PageTable && PML4->Bits.Present && PageTable->Bits.PageTableBaseAddress == PML4->Bits.PageTableBaseAddress) {
|
|
DBG("PML4 points to the same table as first PML4 - releasing it and rebuiding in a separate table\n");
|
|
PML4->Uint64 = 0;
|
|
}
|
|
|
|
// prepare region start and end
|
|
VAStart.Uint64 = 0;
|
|
VAStart.Pg4K.PML4Offset = VA.Pg4K.PML4Offset;
|
|
VA_FIX_SIGN_EXTEND(VAStart);
|
|
VAEnd.Uint64 = ~(UINT64)0;
|
|
VAEnd.Pg4K.PML4Offset = VA.Pg4K.PML4Offset;
|
|
VA_FIX_SIGN_EXTEND(VAEnd);
|
|
// print it
|
|
DBG("PML4[%03x] at %p = %lx Region: %lx - %lx\n", VA.Pg4K.PML4Offset, PML4, PML4->Uint64, VAStart.Uint64, VAEnd.Uint64);
|
|
if (!PML4->Bits.Present) {
|
|
DBG("-> Mapping not present, creating new PML4 entry and page with PDPE entries!\n");
|
|
PDPE = (PAGE_MAP_AND_DIRECTORY_POINTER *)VmAllocatePages(1);
|
|
if (PDPE == NULL) {
|
|
DBG("No memory - exiting.\n");
|
|
return EFI_NO_MAPPING;
|
|
}
|
|
|
|
ZeroMem(PDPE, EFI_PAGE_SIZE);
|
|
// init this whole 512GB region with 512 1GB entry pages to map first 512GB phys space
|
|
PTE1G = (PAGE_TABLE_1G_ENTRY *)PDPE;
|
|
Start = 0;
|
|
for (Index = 0; Index < 512; Index++) {
|
|
PTE1G->Uint64 = Start & PT_ADDR_MASK_1G;
|
|
PTE1G->Bits.ReadWrite = 1;
|
|
PTE1G->Bits.Present = 1;
|
|
PTE1G->Bits.MustBe1 = 1;
|
|
PTE1G++;
|
|
Start += 0x40000000;
|
|
}
|
|
|
|
// put it to PML4
|
|
PML4->Uint64 = ((UINT64)PDPE) & PT_ADDR_MASK_4K;
|
|
PML4->Bits.ReadWrite = 1;
|
|
PML4->Bits.Present = 1;
|
|
DBG("added to PLM4 as %lx\n", PML4->Uint64);
|
|
// and continue with mapping ...
|
|
}
|
|
DBG("-> Nx:%x|A:%x|PCD:%x|PWT:%x|US:%x|RW:%x|P:%x -> %lx\n",
|
|
PML4->Bits.Nx, PML4->Bits.Accessed,
|
|
PML4->Bits.CacheDisabled, PML4->Bits.WriteThrough,
|
|
PML4->Bits.UserSupervisor, PML4->Bits.ReadWrite, PML4->Bits.Present,
|
|
(PML4->Uint64 & PT_ADDR_MASK_4K)
|
|
);
|
|
|
|
// PDPE
|
|
PDPE = (PAGE_MAP_AND_DIRECTORY_POINTER *)(PML4->Uint64 & PT_ADDR_MASK_4K);
|
|
PDPE += VA.Pg4K.PDPOffset;
|
|
VAStart.Pg4K.PDPOffset = VA.Pg4K.PDPOffset;
|
|
VAEnd.Pg4K.PDPOffset = VA.Pg4K.PDPOffset;
|
|
DBG("PDPE[%03x] at %p = %lx Region: %lx - %lx\n", VA.Pg4K.PDPOffset, PDPE, PDPE->Uint64, VAStart.Uint64, VAEnd.Uint64);
|
|
if (!PDPE->Bits.Present || (PDPE->Bits.MustBeZero & 0x1)) {
|
|
DBG("-> Mapping not present or mapped as 1GB page, creating new PDPE entry and page with PDE entries!\n");
|
|
PDE = (PAGE_MAP_AND_DIRECTORY_POINTER *)VmAllocatePages(1);
|
|
if (PDE == NULL) {
|
|
DBG("No memory - exiting.\n");
|
|
return EFI_NO_MAPPING;
|
|
}
|
|
ZeroMem(PDE, EFI_PAGE_SIZE);
|
|
|
|
if (PDPE->Bits.MustBeZero & 0x1) {
|
|
// was 1GB page - init new PDE array to get the same mapping but with 2MB pages
|
|
DBG("-> was 1GB page, initing new PDE array to get the same mapping but with 2MB pages!\n");
|
|
PTE2M = (PAGE_TABLE_2M_ENTRY *)PDE;
|
|
Start = (PDPE->Uint64 & PT_ADDR_MASK_1G);
|
|
for (Index = 0; Index < 512; Index++) {
|
|
PTE2M->Uint64 = Start & PT_ADDR_MASK_2M;
|
|
PTE2M->Bits.ReadWrite = 1;
|
|
PTE2M->Bits.Present = 1;
|
|
PTE2M->Bits.MustBe1 = 1;
|
|
PTE2M++;
|
|
Start += 0x200000;
|
|
}
|
|
}
|
|
|
|
// put it to PDPE
|
|
PDPE->Uint64 = ((UINT64)PDE) & PT_ADDR_MASK_4K;
|
|
PDPE->Bits.ReadWrite = 1;
|
|
PDPE->Bits.Present = 1;
|
|
DBG("added to PDPE as %lx\n", PDPE->Uint64);
|
|
// and continue with mapping ...
|
|
}
|
|
DBG("-> Nx:%x|A:%x|PCD:%x|PWT:%x|US:%x|RW:%x|P:%x -> %lx\n",
|
|
PDPE->Bits.Nx, PDPE->Bits.Accessed,
|
|
PDPE->Bits.CacheDisabled, PDPE->Bits.WriteThrough,
|
|
PDPE->Bits.UserSupervisor, PDPE->Bits.ReadWrite, PDPE->Bits.Present,
|
|
(PDPE->Uint64 & PT_ADDR_MASK_4K)
|
|
);
|
|
|
|
// PDE
|
|
PDE = (PAGE_MAP_AND_DIRECTORY_POINTER *)(PDPE->Uint64 & PT_ADDR_MASK_4K);
|
|
PDE += VA.Pg4K.PDOffset;
|
|
VAStart.Pg4K.PDOffset = VA.Pg4K.PDOffset;
|
|
VAEnd.Pg4K.PDOffset = VA.Pg4K.PDOffset;
|
|
DBG("PDE[%03x] at %p = %lx Region: %lx - %lx\n", VA.Pg4K.PDOffset, PDE, PDE->Uint64, VAStart.Uint64, VAEnd.Uint64);
|
|
if (!PDE->Bits.Present || (PDE->Bits.MustBeZero & 0x1)) {
|
|
DBG("-> Mapping not present or mapped as 2MB page, creating new PDE entry and page with PTE4K entries!\n");
|
|
PTE4K = (PAGE_TABLE_4K_ENTRY *)VmAllocatePages(1);
|
|
if (PTE4K == NULL) {
|
|
DBG("No memory - exiting.\n");
|
|
return EFI_NO_MAPPING;
|
|
}
|
|
ZeroMem(PTE4K, EFI_PAGE_SIZE);
|
|
|
|
if (PDE->Bits.MustBeZero & 0x1) {
|
|
// was 2MB page - init new PTE array to get the same mapping but with 4KB pages
|
|
DBG("-> was 2MB page - initing new PTE array to get the same mapping but with 4KB pages!\n");
|
|
PTE4KTmp = (PAGE_TABLE_4K_ENTRY *)PTE4K;
|
|
Start = (PDE->Uint64 & PT_ADDR_MASK_2M);
|
|
for (Index = 0; Index < 512; Index++) {
|
|
PTE4KTmp->Uint64 = Start & PT_ADDR_MASK_4K;
|
|
PTE4KTmp->Bits.ReadWrite = 1;
|
|
PTE4KTmp->Bits.Present = 1;
|
|
PTE4KTmp++;
|
|
Start += 0x1000;
|
|
}
|
|
}
|
|
|
|
// put it to PDE
|
|
PDE->Uint64 = ((UINT64)PTE4K) & PT_ADDR_MASK_4K;
|
|
PDE->Bits.ReadWrite = 1;
|
|
PDE->Bits.Present = 1;
|
|
DBG("added to PDE as %lx\n", PDE->Uint64);
|
|
// and continue with mapping ...
|
|
}
|
|
DBG("-> Nx:%x|A:%x|PCD:%x|PWT:%x|US:%x|RW:%x|P:%x -> %lx\n",
|
|
PDE->Bits.Nx, PDE->Bits.Accessed,
|
|
PDE->Bits.CacheDisabled, PDE->Bits.WriteThrough,
|
|
PDE->Bits.UserSupervisor, PDE->Bits.ReadWrite, PDE->Bits.Present,
|
|
(PDE->Uint64 & PT_ADDR_MASK_4K)
|
|
);
|
|
|
|
// PTE
|
|
PTE4K = (PAGE_TABLE_4K_ENTRY *)(PDE->Uint64 & PT_ADDR_MASK_4K);
|
|
PTE4K += VA.Pg4K.PTOffset;
|
|
VAStart.Pg4K.PTOffset = VA.Pg4K.PTOffset;
|
|
VAEnd.Pg4K.PTOffset = VA.Pg4K.PTOffset;
|
|
DBG("PTE[%03x] at %p = %lx Region: %lx - %lx\n", VA.Pg4K.PTOffset, PTE4K, PTE4K->Uint64, VAStart.Uint64, VAEnd.Uint64);
|
|
if (PTE4K->Bits.Present) {
|
|
DBG("mapping already present - remapping!\n");
|
|
}
|
|
DBG("-> Nx:%x|G:%x|PAT:%x|D:%x|A:%x|PCD:%x|PWT:%x|US:%x|RW:%x|P:%x -> %lx\n",
|
|
PTE4K->Bits.Nx, PTE4K->Bits.Global, PTE4K->Bits.PAT,
|
|
PTE4K->Bits.Dirty, PTE4K->Bits.Accessed,
|
|
PTE4K->Bits.CacheDisabled, PTE4K->Bits.WriteThrough,
|
|
PTE4K->Bits.UserSupervisor, PTE4K->Bits.ReadWrite, PTE4K->Bits.Present,
|
|
(PTE4K->Uint64 & PT_ADDR_MASK_4K)
|
|
);
|
|
// put it to PTE
|
|
PTE4K->Uint64 = ((UINT64)PhysicalAddr) & PT_ADDR_MASK_4K;
|
|
PTE4K->Bits.ReadWrite = 1;
|
|
PTE4K->Bits.Present = 1;
|
|
DBG("added to PTE4K as %lx\n", PTE4K->Uint64);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
/** Maps (remaps) NumPages 4K pages given by VirtualAddr to PhysicalAddr pages in PageTable. */
|
|
EFI_STATUS
|
|
VmMapVirtualPages(PAGE_MAP_AND_DIRECTORY_POINTER *PageTable, EFI_VIRTUAL_ADDRESS VirtualAddr, UINTN NumPages, EFI_PHYSICAL_ADDRESS PhysicalAddr)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_SUCCESS;
|
|
while (NumPages > 0 && (Status == EFI_SUCCESS)) {
|
|
Status = VmMapVirtualPage(PageTable, VirtualAddr, PhysicalAddr);
|
|
VirtualAddr += 0x1000;
|
|
PhysicalAddr += 0x1000;
|
|
NumPages--;
|
|
DBG("NumPages: %d, %lx => %lx\n", NumPages, VirtualAddr, PhysicalAddr);
|
|
//WaitForKeyPress(L"press a key to continue\n");
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/** Flashes TLB caches. */
|
|
VOID
|
|
VmFlashCaches(VOID)
|
|
{
|
|
|
|
// just reload CR3
|
|
AsmWriteCr3(AsmReadCr3());
|
|
}
|