]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
UefiCpuPkg/SmmCpuFeaturesLibStm: Add STM library instance
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / Ia32 / PageTbl.c
index edebaabb47bd892eb0ca77e7c7982092b68daea6..ba79477e645dab687ad560fe2cbde46464e6aa4e 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Page table manipulation functions for IA-32 processors\r
 \r
-Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -14,8 +14,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include "PiSmmCpuDxeSmm.h"\r
 \r
-SPIN_LOCK                           mPFLock;\r
-\r
 /**\r
   Create PageTable for SMM use.\r
 \r
@@ -29,11 +27,12 @@ SmmInitPageTable (
 {\r
   UINTN                             PageFaultHandlerHookAddress;\r
   IA32_IDT_GATE_DESCRIPTOR          *IdtEntry;\r
+  EFI_STATUS                        Status;\r
 \r
   //\r
   // Initialize spin lock\r
   //\r
-  InitializeSpinLock (&mPFLock);\r
+  InitializeSpinLock (mPFLock);\r
 \r
   if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
     //\r
@@ -51,7 +50,8 @@ SmmInitPageTable (
     //\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
@@ -60,7 +60,7 @@ SmmInitPageTable (
   if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
     InitializeIDTSmmStackGuard ();\r
   }\r
-  return Gen4GPageTable (0);\r
+  return Gen4GPageTable (TRUE);\r
 }\r
 \r
 /**\r
@@ -91,17 +91,49 @@ SmiPFHandler (
   )\r
 {\r
   UINTN             PFAddress;\r
+  UINTN             GuardPageAddress;\r
+  UINTN             CpuIndex;\r
 \r
   ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);\r
 \r
-  AcquireSpinLock (&mPFLock);\r
+  AcquireSpinLock (mPFLock);\r
 \r
   PFAddress = AsmReadCr2 ();\r
 \r
-  if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&\r
-      (PFAddress >= mCpuHotPlugData.SmrrBase) &&\r
+  //\r
+  // If a page fault occurs in SMRAM range, it might be in a SMM stack guard page,\r
+  // or SMM page protection violation.\r
+  //\r
+  if ((PFAddress >= mCpuHotPlugData.SmrrBase) &&\r
       (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {\r
-    DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n"));\r
+    CpuIndex = GetCpuIndex ();\r
+    GuardPageAddress = (mSmmStackArrayBase + EFI_PAGE_SIZE + CpuIndex * mSmmStackSize);\r
+    if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&\r
+        (PFAddress >= GuardPageAddress) &&\r
+        (PFAddress < (GuardPageAddress + EFI_PAGE_SIZE))) {\r
+      DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));\r
+    } else {\r
+      DEBUG ((DEBUG_ERROR, "SMM exception data - 0x%x(", SystemContext.SystemContextIa32->ExceptionData));\r
+      DEBUG ((DEBUG_ERROR, "I:%x, R:%x, U:%x, W:%x, P:%x",\r
+        (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0,\r
+        (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_RSVD) != 0,\r
+        (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_US) != 0,\r
+        (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_WR) != 0,\r
+        (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_P) != 0\r
+        ));\r
+      DEBUG ((DEBUG_ERROR, ")\n"));\r
+      if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
+        DEBUG ((DEBUG_ERROR, "SMM exception at execution (0x%x)\n", PFAddress));\r
+        DEBUG_CODE (\r
+          DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
+        );\r
+      } else {\r
+        DEBUG ((DEBUG_ERROR, "SMM exception at access (0x%x)\n", PFAddress));\r
+        DEBUG_CODE (\r
+          DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
+        );\r
+      }\r
+    }\r
     CpuDeadLoop ();\r
   }\r
 \r
@@ -111,7 +143,7 @@ SmiPFHandler (
   if ((PFAddress < mCpuHotPlugData.SmrrBase) ||\r
       (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
     if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
-      DEBUG ((EFI_D_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));\r
+      DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));\r
       DEBUG_CODE (\r
         DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
       );\r
@@ -128,5 +160,70 @@ SmiPFHandler (
     SmiDefaultPFHandler ();\r
   }\r
 \r
-  ReleaseSpinLock (&mPFLock);\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
+  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
 }\r