diff options
-rw-r--r-- | UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c | 105 | ||||
-rw-r--r-- | UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 1 | ||||
-rw-r--r-- | UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c | 136 | ||||
-rw-r--r-- | UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c | 153 |
4 files changed, 136 insertions, 259 deletions
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c index bbc536a567..34bf6e1a25 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c @@ -203,111 +203,6 @@ Exit: }
/**
- This function sets memory attribute for page table.
-**/
-VOID
-SetPageTableAttributes (
- VOID
- )
-{
- UINTN Index2;
- UINTN Index3;
- UINT64 *L1PageTable;
- UINT64 *L2PageTable;
- UINT64 *L3PageTable;
- UINTN PageTableBase;
- BOOLEAN IsSplitted;
- BOOLEAN PageTableSplitted;
- BOOLEAN CetEnabled;
-
- //
- // Don't mark page table to read-only if heap guard is enabled.
- //
- // BIT2: SMM page guard enabled
- // BIT3: SMM pool guard enabled
- //
- if ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) {
- DEBUG ((DEBUG_INFO, "Don't mark page table to read-only as heap guard is enabled\n"));
- return;
- }
-
- //
- // Don't mark page table to read-only if SMM profile is enabled.
- //
- if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
- DEBUG ((DEBUG_INFO, "Don't mark page table to read-only as SMM profile is enabled\n"));
- return;
- }
-
- DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));
-
- //
- // Disable write protection, because we need mark page table to be write protected.
- // We need *write* page table memory, to mark itself to be *read only*.
- //
- CetEnabled = ((AsmReadCr4 () & CR4_CET_ENABLE) != 0) ? TRUE : FALSE;
- if (CetEnabled) {
- //
- // CET must be disabled if WP is disabled.
- //
- DisableCet ();
- }
-
- AsmWriteCr0 (AsmReadCr0 () & ~CR0_WP);
-
- do {
- DEBUG ((DEBUG_INFO, "Start...\n"));
- PageTableSplitted = FALSE;
-
- PageTableBase = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64;
- L3PageTable = (UINT64 *)PageTableBase;
-
- SmmSetMemoryAttributesEx (PageTableBase, FALSE, (EFI_PHYSICAL_ADDRESS)PageTableBase, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
- PageTableSplitted = (PageTableSplitted || IsSplitted);
-
- for (Index3 = 0; Index3 < 4; Index3++) {
- L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
- if (L2PageTable == NULL) {
- continue;
- }
-
- SmmSetMemoryAttributesEx (PageTableBase, FALSE, (EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
- PageTableSplitted = (PageTableSplitted || IsSplitted);
-
- for (Index2 = 0; Index2 < SIZE_4KB/sizeof (UINT64); Index2++) {
- if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
- // 2M
- continue;
- }
-
- L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
- if (L1PageTable == NULL) {
- continue;
- }
-
- SmmSetMemoryAttributesEx (PageTableBase, FALSE, (EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
- PageTableSplitted = (PageTableSplitted || IsSplitted);
- }
- }
- } while (PageTableSplitted);
-
- //
- // Enable write protection, after page table updated.
- //
- AsmWriteCr0 (AsmReadCr0 () | CR0_WP);
- if (CetEnabled) {
- //
- // re-enable CET.
- //
- EnableCet ();
- }
-
- mIsReadOnlyPageTable = TRUE;
-
- return;
-}
-
-/**
This function returns with no action for 32 bit.
@param[out] *Cr2 Pointer to variable to hold CR2 register value.
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h index 3e69e043ca..5f0a38e400 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h @@ -260,7 +260,6 @@ extern UINTN mNumberOfCpus; extern EFI_SMM_CPU_PROTOCOL mSmmCpu;
extern EFI_MM_MP_PROTOCOL mSmmMp;
extern BOOLEAN m5LevelPagingNeeded;
-extern BOOLEAN mIsReadOnlyPageTable;
///
/// The mode of the CPU at the time an SMI occurs
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c index 11df7af016..4bb23f6920 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c @@ -1753,3 +1753,139 @@ EdkiiSmmGetMemoryAttributes ( return EFI_SUCCESS;
}
+
+/**
+ Prevent the memory pages used for SMM page table from been overwritten.
+**/
+VOID
+EnablePageTableProtection (
+ VOID
+ )
+{
+ PAGE_TABLE_POOL *HeadPool;
+ PAGE_TABLE_POOL *Pool;
+ UINT64 PoolSize;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINTN PageTableBase;
+
+ if (mPageTablePool == NULL) {
+ return;
+ }
+
+ PageTableBase = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64;
+
+ //
+ // ConvertMemoryPageAttributes might update mPageTablePool. It's safer to
+ // remember original one in advance.
+ //
+ HeadPool = mPageTablePool;
+ Pool = HeadPool;
+ do {
+ Address = (EFI_PHYSICAL_ADDRESS)(UINTN)Pool;
+ PoolSize = Pool->Offset + EFI_PAGES_TO_SIZE (Pool->FreePages);
+ //
+ // Set entire pool including header, used-memory and left free-memory as ReadOnly in SMM page table.
+ //
+ ConvertMemoryPageAttributes (PageTableBase, m5LevelPagingNeeded, Address, PoolSize, EFI_MEMORY_RO, TRUE, NULL, NULL);
+ Pool = Pool->NextPool;
+ } while (Pool != HeadPool);
+}
+
+/**
+ Return whether memory used by SMM page table need to be set as Read Only.
+
+ @retval TRUE Need to set SMM page table as Read Only.
+ @retval FALSE Do not set SMM page table as Read Only.
+**/
+BOOLEAN
+IfReadOnlyPageTableNeeded (
+ VOID
+ )
+{
+ //
+ // Don't mark page table memory as read-only if
+ // - no restriction on access to non-SMRAM memory; or
+ // - SMM heap guard feature enabled; or
+ // BIT2: SMM page guard enabled
+ // BIT3: SMM pool guard enabled
+ // - SMM profile feature enabled
+ //
+ if (!IsRestrictedMemoryAccess () ||
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) ||
+ FeaturePcdGet (PcdCpuSmmProfileEnable))
+ {
+ if (sizeof (UINTN) == sizeof (UINT64)) {
+ //
+ // Restriction on access to non-SMRAM memory and heap guard could not be enabled at the same time.
+ //
+ ASSERT (
+ !(IsRestrictedMemoryAccess () &&
+ (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0)
+ );
+
+ //
+ // Restriction on access to non-SMRAM memory and SMM profile could not be enabled at the same time.
+ //
+ ASSERT (!(IsRestrictedMemoryAccess () && FeaturePcdGet (PcdCpuSmmProfileEnable)));
+ }
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ This function sets memory attribute for page table.
+**/
+VOID
+SetPageTableAttributes (
+ VOID
+ )
+{
+ BOOLEAN CetEnabled;
+
+ if (!IfReadOnlyPageTableNeeded ()) {
+ return;
+ }
+
+ DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));
+
+ //
+ // Disable write protection, because we need mark page table to be write protected.
+ // We need *write* page table memory, to mark itself to be *read only*.
+ //
+ CetEnabled = ((AsmReadCr4 () & CR4_CET_ENABLE) != 0) ? TRUE : FALSE;
+ if (CetEnabled) {
+ //
+ // CET must be disabled if WP is disabled.
+ //
+ DisableCet ();
+ }
+
+ AsmWriteCr0 (AsmReadCr0 () & ~CR0_WP);
+
+ // Set memory used by page table as Read Only.
+ DEBUG ((DEBUG_INFO, "Start...\n"));
+ EnablePageTableProtection ();
+
+ //
+ // Enable write protection, after page table attribute updated.
+ //
+ AsmWriteCr0 (AsmReadCr0 () | CR0_WP);
+ mIsReadOnlyPageTable = TRUE;
+
+ //
+ // Flush TLB after mark all page table pool as read only.
+ //
+ FlushTlbForAll ();
+
+ if (CetEnabled) {
+ //
+ // re-enable CET.
+ //
+ EnableCet ();
+ }
+
+ return;
+}
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c index 8d42d89801..3deb1ffd67 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c @@ -1140,159 +1140,6 @@ Exit: }
/**
- This function sets memory attribute for page table.
-**/
-VOID
-SetPageTableAttributes (
- VOID
- )
-{
- UINTN Index2;
- UINTN Index3;
- UINTN Index4;
- UINTN Index5;
- UINT64 *L1PageTable;
- UINT64 *L2PageTable;
- UINT64 *L3PageTable;
- UINT64 *L4PageTable;
- UINT64 *L5PageTable;
- UINTN PageTableBase;
- BOOLEAN IsSplitted;
- BOOLEAN PageTableSplitted;
- BOOLEAN CetEnabled;
- BOOLEAN Enable5LevelPaging;
- IA32_CR4 Cr4;
-
- //
- // Don't mark page table memory as read-only if
- // - no restriction on access to non-SMRAM memory; or
- // - SMM heap guard feature enabled; or
- // BIT2: SMM page guard enabled
- // BIT3: SMM pool guard enabled
- // - SMM profile feature enabled
- //
- if (!mCpuSmmRestrictedMemoryAccess ||
- ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) ||
- FeaturePcdGet (PcdCpuSmmProfileEnable))
- {
- //
- // Restriction on access to non-SMRAM memory and heap guard could not be enabled at the same time.
- //
- ASSERT (
- !(mCpuSmmRestrictedMemoryAccess &&
- (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0)
- );
-
- //
- // Restriction on access to non-SMRAM memory and SMM profile could not be enabled at the same time.
- //
- ASSERT (!(mCpuSmmRestrictedMemoryAccess && FeaturePcdGet (PcdCpuSmmProfileEnable)));
- return;
- }
-
- DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));
-
- //
- // Disable write protection, because we need mark page table to be write protected.
- // We need *write* page table memory, to mark itself to be *read only*.
- //
- CetEnabled = ((AsmReadCr4 () & CR4_CET_ENABLE) != 0) ? TRUE : FALSE;
- if (CetEnabled) {
- //
- // CET must be disabled if WP is disabled.
- //
- DisableCet ();
- }
-
- AsmWriteCr0 (AsmReadCr0 () & ~CR0_WP);
-
- do {
- DEBUG ((DEBUG_INFO, "Start...\n"));
- PageTableSplitted = FALSE;
- L5PageTable = NULL;
-
- PageTableBase = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64;
- Cr4.UintN = AsmReadCr4 ();
- Enable5LevelPaging = (BOOLEAN)(Cr4.Bits.LA57 == 1);
-
- if (Enable5LevelPaging) {
- L5PageTable = (UINT64 *)PageTableBase;
- SmmSetMemoryAttributesEx (PageTableBase, Enable5LevelPaging, (EFI_PHYSICAL_ADDRESS)PageTableBase, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
- PageTableSplitted = (PageTableSplitted || IsSplitted);
- }
-
- for (Index5 = 0; Index5 < (Enable5LevelPaging ? SIZE_4KB/sizeof (UINT64) : 1); Index5++) {
- if (Enable5LevelPaging) {
- L4PageTable = (UINT64 *)(UINTN)(L5PageTable[Index5] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
- if (L4PageTable == NULL) {
- continue;
- }
- } else {
- L4PageTable = (UINT64 *)PageTableBase;
- }
-
- SmmSetMemoryAttributesEx (PageTableBase, Enable5LevelPaging, (EFI_PHYSICAL_ADDRESS)(UINTN)L4PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
- PageTableSplitted = (PageTableSplitted || IsSplitted);
-
- for (Index4 = 0; Index4 < SIZE_4KB/sizeof (UINT64); Index4++) {
- L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
- if (L3PageTable == NULL) {
- continue;
- }
-
- SmmSetMemoryAttributesEx (PageTableBase, Enable5LevelPaging, (EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
- PageTableSplitted = (PageTableSplitted || IsSplitted);
-
- for (Index3 = 0; Index3 < SIZE_4KB/sizeof (UINT64); Index3++) {
- if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {
- // 1G
- continue;
- }
-
- L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
- if (L2PageTable == NULL) {
- continue;
- }
-
- SmmSetMemoryAttributesEx (PageTableBase, Enable5LevelPaging, (EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
- PageTableSplitted = (PageTableSplitted || IsSplitted);
-
- for (Index2 = 0; Index2 < SIZE_4KB/sizeof (UINT64); Index2++) {
- if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
- // 2M
- continue;
- }
-
- L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
- if (L1PageTable == NULL) {
- continue;
- }
-
- SmmSetMemoryAttributesEx (PageTableBase, Enable5LevelPaging, (EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
- PageTableSplitted = (PageTableSplitted || IsSplitted);
- }
- }
- }
- }
- } while (PageTableSplitted);
-
- //
- // Enable write protection, after page table updated.
- //
- AsmWriteCr0 (AsmReadCr0 () | CR0_WP);
- if (CetEnabled) {
- //
- // re-enable CET.
- //
- EnableCet ();
- }
-
- mIsReadOnlyPageTable = TRUE;
-
- return;
-}
-
-/**
This function reads CR2 register when on-demand paging is enabled.
@param[out] *Cr2 Pointer to variable to hold CR2 register value.
|