+ 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
+ UINT64 *L1PageTable;\r
+ UINT64 *L2PageTable;\r
+ UINT64 *L3PageTable;\r
+ BOOLEAN IsSplitted;\r
+ BOOLEAN PageTableSplitted;\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
+ L3PageTable = (UINT64 *)GetPageTableBase ();\r
+\r
+ SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
+ PageTableSplitted = (PageTableSplitted || IsSplitted);\r
+\r
+ for (Index3 = 0; Index3 < 4; Index3++) {\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
+ } while (PageTableSplitted);\r
+\r
+ //\r
+ // Enable write protection, after page table updated.\r
+ //\r
+ AsmWriteCr0 (AsmReadCr0() | CR0_WP);\r
+\r
+ return ;\r