]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
UefiCpuPkg/PiSmmCpuDxeSmm: Use SMM Interrupt Shadow Stack
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / X64 / SmmFuncsArch.c
index ca3f5ff91a0bac83bd6fcff9a6248875c7a75627..ce7afce6d4dafc8f07bcf32331fb72e6ff8ec795 100644 (file)
@@ -24,24 +24,24 @@ UINT32 mCetInterruptSspTable;
 UINTN  mSmmInterruptSspTables;\r
 \r
 /**\r
-  Initialize IDT for SMM Stack Guard.\r
+  Initialize IDT IST Field.\r
+\r
+  @param[in]  ExceptionType       Exception type.\r
+  @param[in]  Ist                 IST value.\r
 \r
 **/\r
 VOID\r
 EFIAPI\r
-InitializeIDTSmmStackGuard (\r
-  VOID\r
+InitializeIdtIst (\r
+  IN EFI_EXCEPTION_TYPE            ExceptionType,\r
+  IN UINT8                         Ist\r
   )\r
 {\r
   IA32_IDT_GATE_DESCRIPTOR  *IdtGate;\r
 \r
-  //\r
-  // If SMM Stack Guard feature is enabled, set the IST field of\r
-  // the interrupt gate for Page Fault Exception to be 1\r
-  //\r
   IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;\r
-  IdtGate += EXCEPT_IA32_PAGE_FAULT;\r
-  IdtGate->Bits.Reserved_0 = 1;\r
+  IdtGate += ExceptionType;\r
+  IdtGate->Bits.Reserved_0 = Ist;\r
 }\r
 \r
 /**\r
@@ -89,7 +89,7 @@ InitGdt (
     GdtDescriptor->Bits.BaseMid = (UINT8)((UINTN)TssBase >> 16);\r
     GdtDescriptor->Bits.BaseHigh = (UINT8)((UINTN)TssBase >> 24);\r
 \r
-    if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
+    if ((FeaturePcdGet (PcdCpuSmmStackGuard)) || ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported)) {\r
       //\r
       // Setup top of known good stack as IST1 for each processor.\r
       //\r
@@ -177,8 +177,16 @@ InitShadowStack (
 \r
   if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {\r
     SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));\r
+    //\r
+    // Add 1 page as known good shadow stack\r
+    //\r
+    SmmShadowStackSize += EFI_PAGES_TO_SIZE (1);\r
+\r
     if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
-      SmmShadowStackSize += EFI_PAGES_TO_SIZE (2);\r
+      //\r
+      // Add one guard page between Known Good Shadow Stack and SMM Shadow Stack.\r
+      //\r
+      SmmShadowStackSize += EFI_PAGES_TO_SIZE (1);\r
     }\r
     mCetPl0Ssp = (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - sizeof(UINT64));\r
     PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4);\r
@@ -186,33 +194,32 @@ InitShadowStack (
     DEBUG ((DEBUG_INFO, "ShadowStack - 0x%x\n", ShadowStack));\r
     DEBUG ((DEBUG_INFO, "  SmmShadowStackSize - 0x%x\n", SmmShadowStackSize));\r
 \r
-    if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
-      if (mSmmInterruptSspTables == 0) {\r
-        mSmmInterruptSspTables = (UINTN)AllocateZeroPool(sizeof(UINT64) * 8 * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);\r
-        ASSERT (mSmmInterruptSspTables != 0);\r
-        DEBUG ((DEBUG_INFO, "mSmmInterruptSspTables - 0x%x\n", mSmmInterruptSspTables));\r
-      }\r
-\r
-      //\r
-      // The highest address on the stack (0xFF8) is a save-previous-ssp token pointing to a location that is 40 bytes away - 0xFD0.\r
-      // The supervisor shadow stack token is just above it at address 0xFF0. This is where the interrupt SSP table points.\r
-      // So when an interrupt of exception occurs, we can use SAVESSP/RESTORESSP/CLEARSSBUSY for the supervisor shadow stack,\r
-      // due to the reason the RETF in SMM exception handler cannot clear the BUSY flag with same CPL.\r
-      // (only IRET or RETF with different CPL can clear BUSY flag)\r
-      // Please refer to UefiCpuPkg/Library/CpuExceptionHandlerLib/X64 for the full stack frame at runtime.\r
-      //\r
-      InterruptSsp = (UINT32)((UINTN)ShadowStack + EFI_PAGES_TO_SIZE(1) - sizeof(UINT64));\r
-      *(UINT64 *)(UINTN)InterruptSsp = (InterruptSsp - sizeof(UINT64) * 4) | 0x2;\r
-      mCetInterruptSsp = InterruptSsp - sizeof(UINT64);\r
-\r
-      mCetInterruptSspTable = (UINT32)(UINTN)(mSmmInterruptSspTables + sizeof(UINT64) * 8 * CpuIndex);\r
-      InterruptSspTable = (UINT64 *)(UINTN)mCetInterruptSspTable;\r
-      InterruptSspTable[1] = mCetInterruptSsp;\r
-      PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4);\r
-      PatchInstructionX86 (mPatchCetInterruptSspTable, mCetInterruptSspTable, 4);\r
-      DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp));\r
-      DEBUG ((DEBUG_INFO, "mCetInterruptSspTable - 0x%x\n", mCetInterruptSspTable));\r
+    if (mSmmInterruptSspTables == 0) {\r
+      mSmmInterruptSspTables = (UINTN)AllocateZeroPool(sizeof(UINT64) * 8 * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);\r
+      ASSERT (mSmmInterruptSspTables != 0);\r
+      DEBUG ((DEBUG_INFO, "mSmmInterruptSspTables - 0x%x\n", mSmmInterruptSspTables));\r
     }\r
+\r
+    //\r
+    // The highest address on the stack (0xFE0) is a save-previous-ssp token pointing to a location that is 40 bytes away - 0xFB8.\r
+    // The supervisor shadow stack token is just above it at address 0xFD8. This is where the interrupt SSP table points.\r
+    // So when an interrupt of exception occurs, we can use SAVESSP/RESTORESSP/CLEARSSBUSY for the supervisor shadow stack,\r
+    // due to the reason the RETF in SMM exception handler cannot clear the BUSY flag with same CPL.\r
+    // (only IRET or RETF with different CPL can clear BUSY flag)\r
+    // Please refer to UefiCpuPkg/Library/CpuExceptionHandlerLib/X64 for the full stack frame at runtime.\r
+    // According to SDM (ver. 075 June 2021), shadow stack should be 32 bytes aligned.\r
+    //\r
+    InterruptSsp = (UINT32)(((UINTN)ShadowStack + EFI_PAGES_TO_SIZE(1) - (sizeof(UINT64) * 4)) & ~0x1f);\r
+    *(UINT64 *)(UINTN)InterruptSsp = (InterruptSsp - sizeof(UINT64) * 4) | 0x2;\r
+    mCetInterruptSsp = InterruptSsp - sizeof(UINT64);\r
+\r
+    mCetInterruptSspTable = (UINT32)(UINTN)(mSmmInterruptSspTables + sizeof(UINT64) * 8 * CpuIndex);\r
+    InterruptSspTable = (UINT64 *)(UINTN)mCetInterruptSspTable;\r
+    InterruptSspTable[1] = mCetInterruptSsp;\r
+    PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4);\r
+    PatchInstructionX86 (mPatchCetInterruptSspTable, mCetInterruptSspTable, 4);\r
+    DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp));\r
+    DEBUG ((DEBUG_INFO, "mCetInterruptSspTable - 0x%x\n", mCetInterruptSspTable));\r
   }\r
 }\r
 \r