#define ACC_MAX_BIT BIT3\r
LIST_ENTRY mPagePool = INITIALIZE_LIST_HEAD_VARIABLE (mPagePool);\r
BOOLEAN m1GPageTableSupport = FALSE;\r
+UINT8 mPhysicalAddressBits;\r
+BOOLEAN mCpuSmmStaticPageTable;\r
\r
/**\r
Check if 1-GByte pages is supported by processor or not.\r
return BitFieldRead64 (*Entry, 52, 60);\r
}\r
\r
+/**\r
+ Calculate the maximum support address.\r
+\r
+ @return the maximum support address.\r
+**/\r
+UINT8\r
+CalculateMaximumSupportAddress (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 RegEax;\r
+ UINT8 PhysicalAddressBits;\r
+ VOID *Hob;\r
+\r
+ //\r
+ // Get physical address bits supported.\r
+ //\r
+ Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
+ if (Hob != NULL) {\r
+ PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
+ } else {\r
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+ if (RegEax >= 0x80000008) {\r
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+ PhysicalAddressBits = (UINT8) RegEax;\r
+ } else {\r
+ PhysicalAddressBits = 36;\r
+ }\r
+ }\r
+\r
+ //\r
+ // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
+ //\r
+ ASSERT (PhysicalAddressBits <= 52);\r
+ if (PhysicalAddressBits > 48) {\r
+ PhysicalAddressBits = 48;\r
+ }\r
+ return PhysicalAddressBits;\r
+}\r
+\r
+/**\r
+ Set static page table.\r
+\r
+ @param[in] PageTable Address of page table.\r
+**/\r
+VOID\r
+SetStaticPageTable (\r
+ IN UINTN PageTable\r
+ )\r
+{\r
+ UINT64 PageAddress;\r
+ UINTN NumberOfPml4EntriesNeeded;\r
+ UINTN NumberOfPdpEntriesNeeded;\r
+ UINTN IndexOfPml4Entries;\r
+ UINTN IndexOfPdpEntries;\r
+ UINTN IndexOfPageDirectoryEntries;\r
+ UINT64 *PageMapLevel4Entry;\r
+ UINT64 *PageMap;\r
+ UINT64 *PageDirectoryPointerEntry;\r
+ UINT64 *PageDirectory1GEntry;\r
+ UINT64 *PageDirectoryEntry;\r
+\r
+ if (mPhysicalAddressBits <= 39 ) {\r
+ NumberOfPml4EntriesNeeded = 1;\r
+ NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (mPhysicalAddressBits - 30));\r
+ } else {\r
+ NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (mPhysicalAddressBits - 39));\r
+ NumberOfPdpEntriesNeeded = 512;\r
+ }\r
+\r
+ //\r
+ // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.\r
+ //\r
+ PageMap = (VOID *) PageTable;\r
+\r
+ PageMapLevel4Entry = PageMap;\r
+ PageAddress = 0;\r
+ for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {\r
+ //\r
+ // Each PML4 entry points to a page of Page Directory Pointer entries.\r
+ //\r
+ PageDirectoryPointerEntry = (UINT64 *) ((*PageMapLevel4Entry) & gPhyMask);\r
+ if (PageDirectoryPointerEntry == NULL) {\r
+ PageDirectoryPointerEntry = AllocatePageTableMemory (1);\r
+ ASSERT(PageDirectoryPointerEntry != NULL);\r
+ ZeroMem (PageDirectoryPointerEntry, EFI_PAGES_TO_SIZE(1));\r
+\r
+ *PageMapLevel4Entry = ((UINTN)PageDirectoryPointerEntry & gPhyMask) | PAGE_ATTRIBUTE_BITS;\r
+ }\r
+\r
+ if (m1GPageTableSupport) {\r
+ PageDirectory1GEntry = PageDirectoryPointerEntry;\r
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {\r
+ if (IndexOfPml4Entries == 0 && IndexOfPageDirectoryEntries < 4) {\r
+ //\r
+ // Skip the < 4G entries\r
+ //\r
+ continue;\r
+ }\r
+ //\r
+ // Fill in the Page Directory entries\r
+ //\r
+ *PageDirectory1GEntry = (PageAddress & gPhyMask) | IA32_PG_PS | PAGE_ATTRIBUTE_BITS;\r
+ }\r
+ } else {\r
+ PageAddress = BASE_4GB;\r
+ for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
+ if (IndexOfPml4Entries == 0 && IndexOfPdpEntries < 4) {\r
+ //\r
+ // Skip the < 4G entries\r
+ //\r
+ continue;\r
+ }\r
+ //\r
+ // Each Directory Pointer entries points to a page of Page Directory entires.\r
+ // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.\r
+ //\r
+ PageDirectoryEntry = (UINT64 *) ((*PageDirectoryPointerEntry) & gPhyMask);\r
+ if (PageDirectoryEntry == NULL) {\r
+ PageDirectoryEntry = AllocatePageTableMemory (1);\r
+ ASSERT(PageDirectoryEntry != NULL);\r
+ ZeroMem (PageDirectoryEntry, EFI_PAGES_TO_SIZE(1));\r
+\r
+ //\r
+ // Fill in a Page Directory Pointer Entries\r
+ //\r
+ *PageDirectoryPointerEntry = (UINT64)(UINTN)PageDirectoryEntry | PAGE_ATTRIBUTE_BITS;\r
+ }\r
+\r
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {\r
+ //\r
+ // Fill in the Page Directory entries\r
+ //\r
+ *PageDirectoryEntry = (UINT64)PageAddress | IA32_PG_PS | PAGE_ATTRIBUTE_BITS;\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
/**\r
Create PageTable for SMM use.\r
\r
UINTN Index;\r
UINTN PageFaultHandlerHookAddress;\r
IA32_IDT_GATE_DESCRIPTOR *IdtEntry;\r
+ EFI_STATUS Status;\r
\r
//\r
// Initialize spin lock\r
//\r
InitializeSpinLock (mPFLock);\r
\r
+ mCpuSmmStaticPageTable = PcdGetBool (PcdCpuSmmStaticPageTable);\r
m1GPageTableSupport = Is1GPageSupport ();\r
+ DEBUG ((DEBUG_INFO, "1GPageTableSupport - 0x%x\n", m1GPageTableSupport));\r
+ DEBUG ((DEBUG_INFO, "PcdCpuSmmStaticPageTable - 0x%x\n", mCpuSmmStaticPageTable));\r
+\r
+ mPhysicalAddressBits = CalculateMaximumSupportAddress ();\r
+ DEBUG ((DEBUG_INFO, "PhysicalAddressBits - 0x%x\n", mPhysicalAddressBits));\r
//\r
// Generate PAE page table for the first 4GB memory space\r
//\r
- Pages = Gen4GPageTable (PAGE_TABLE_PAGES + 1, FALSE);\r
+ Pages = Gen4GPageTable (FALSE);\r
\r
//\r
// Set IA32_PG_PMNT bit to mask this entry\r
//\r
// Fill Page-Table-Level4 (PML4) entry\r
//\r
- PTEntry = (UINT64*)(UINTN)(Pages - EFI_PAGES_TO_SIZE (PAGE_TABLE_PAGES + 1));\r
- *PTEntry = Pages + PAGE_ATTRIBUTE_BITS;\r
+ PTEntry = (UINT64*)AllocatePageTableMemory (1);\r
+ ASSERT (PTEntry != NULL);\r
+ *PTEntry = Pages | PAGE_ATTRIBUTE_BITS;\r
ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry));\r
+\r
//\r
// Set sub-entries number\r
//\r
SetSubEntriesNum (PTEntry, 3);\r
\r
- //\r
- // Add remaining pages to page pool\r
- //\r
- FreePage = (LIST_ENTRY*)(PTEntry + EFI_PAGE_SIZE / sizeof (*PTEntry));\r
- while ((UINTN)FreePage < Pages) {\r
- InsertTailList (&mPagePool, FreePage);\r
- FreePage += EFI_PAGE_SIZE / sizeof (*FreePage);\r
+ if (mCpuSmmStaticPageTable) {\r
+ SetStaticPageTable ((UINTN)PTEntry);\r
+ } else {\r
+ //\r
+ // Add pages to page pool\r
+ //\r
+ FreePage = (LIST_ENTRY*)AllocatePageTableMemory (PAGE_TABLE_PAGES);\r
+ ASSERT (FreePage != NULL);\r
+ for (Index = 0; Index < PAGE_TABLE_PAGES; Index++) {\r
+ InsertTailList (&mPagePool, FreePage);\r
+ FreePage += EFI_PAGE_SIZE / sizeof (*FreePage);\r
+ }\r
}\r
\r
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
//\r
// Register Smm Page Fault Handler\r
//\r
- SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);\r
+ Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);\r
+ ASSERT_EFI_ERROR (Status);\r
}\r
\r
//\r
break;\r
case SmmPageSize1G:\r
if (!m1GPageTableSupport) {\r
- DEBUG ((EFI_D_ERROR, "1-GByte pages is not supported!"));\r
+ DEBUG ((DEBUG_ERROR, "1-GByte pages is not supported!"));\r
ASSERT (FALSE);\r
}\r
//\r
// Check if the entry has already existed, this issue may occur when the different\r
// size page entries created under the same entry\r
//\r
- DEBUG ((EFI_D_ERROR, "PageTable = %lx, PTIndex = %x, PageTable[PTIndex] = %lx\n", PageTable, PTIndex, PageTable[PTIndex]));\r
- DEBUG ((EFI_D_ERROR, "New page table overlapped with old page table!\n"));\r
+ DEBUG ((DEBUG_ERROR, "PageTable = %lx, PTIndex = %x, PageTable[PTIndex] = %lx\n", PageTable, PTIndex, PageTable[PTIndex]));\r
+ DEBUG ((DEBUG_ERROR, "New page table overlapped with old page table!\n"));\r
ASSERT (FALSE);\r
}\r
//\r
\r
PFAddress = AsmReadCr2 ();\r
\r
+ if (mCpuSmmStaticPageTable && (PFAddress >= LShiftU64 (1, (mPhysicalAddressBits - 1)))) {\r
+ DEBUG ((DEBUG_ERROR, "Do not support address 0x%lx by processor!\n", PFAddress));\r
+ CpuDeadLoop ();\r
+ }\r
+\r
//\r
// If a page fault occurs in SMRAM range, it should be in a SMM stack guard page.\r
//\r
if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&\r
(PFAddress >= mCpuHotPlugData.SmrrBase) &&\r
(PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {\r
- DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n"));\r
+ DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));\r
CpuDeadLoop ();\r
}\r
\r
if ((PFAddress < mCpuHotPlugData.SmrrBase) ||\r
(PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
if ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0) {\r
- DEBUG ((EFI_D_ERROR, "Code executed on IP(0x%lx) out of SMM range after SMM is locked!\n", PFAddress));\r
+ DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%lx) out of SMM range after SMM is locked!\n", PFAddress));\r
DEBUG_CODE (\r
DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp);\r
);\r
\r
ReleaseSpinLock (mPFLock);\r
}\r
+\r
+/**\r
+ This function sets memory attribute for page table.\r
+**/\r
+VOID\r
+SetPageTableAttributes (\r
+ VOID\r
+ )\r
+{\r
+ UINTN Index2;\r
+ UINTN Index3;\r
+ UINTN Index4;\r
+ UINT64 *L1PageTable;\r
+ UINT64 *L2PageTable;\r
+ UINT64 *L3PageTable;\r
+ UINT64 *L4PageTable;\r
+ BOOLEAN IsSplitted;\r
+ BOOLEAN PageTableSplitted;\r
+\r
+ if (!mCpuSmmStaticPageTable) {\r
+ return ;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));\r
+\r
+ //\r
+ // Disable write protection, because we need mark page table to be write protected.\r
+ // We need *write* page table memory, to mark itself to be *read only*.\r
+ //\r
+ AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);\r
+\r
+ do {\r
+ DEBUG ((DEBUG_INFO, "Start...\n"));\r
+ PageTableSplitted = FALSE;\r
+\r
+ L4PageTable = (UINT64 *)GetPageTableBase ();\r
+ SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L4PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
+ PageTableSplitted = (PageTableSplitted || IsSplitted);\r
+\r
+ for (Index4 = 0; Index4 < SIZE_4KB/sizeof(UINT64); Index4++) {\r
+ L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);\r
+ if (L3PageTable == NULL) {\r
+ continue;\r
+ }\r
+\r
+ SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
+ PageTableSplitted = (PageTableSplitted || IsSplitted);\r
+\r
+ for (Index3 = 0; Index3 < SIZE_4KB/sizeof(UINT64); Index3++) {\r
+ if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {\r
+ // 1G\r
+ continue;\r
+ }\r
+ L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);\r
+ if (L2PageTable == NULL) {\r
+ continue;\r
+ }\r
+\r
+ SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
+ PageTableSplitted = (PageTableSplitted || IsSplitted);\r
+\r
+ for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {\r
+ if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {\r
+ // 2M\r
+ continue;\r
+ }\r
+ L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);\r
+ if (L1PageTable == NULL) {\r
+ continue;\r
+ }\r
+ SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
+ PageTableSplitted = (PageTableSplitted || IsSplitted);\r
+ }\r
+ }\r
+ }\r
+ } while (PageTableSplitted);\r
+\r
+ //\r
+ // Enable write protection, after page table updated.\r
+ //\r
+ AsmWriteCr0 (AsmReadCr0() | CR0_WP);\r
+\r
+ return ;\r
+}\r