]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
UefiCpuPkg/CpuExceptionHandlerLib: Clear CET shadow stack token busy bit
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / X64 / SmmFuncsArch.c
index 28f8e8e133e5cd8782ae40afc21deb49e7fe27eb..7ef3b1d48855f8e146f6e2cba5ab33ae0528eb98 100644 (file)
@@ -173,6 +173,7 @@ InitShadowStack (
 {\r
   UINTN       SmmShadowStackSize;\r
   UINT64      *InterruptSspTable;\r
+  UINT32      InterruptSsp;\r
 \r
   if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {\r
     SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));\r
@@ -191,7 +192,19 @@ InitShadowStack (
         ASSERT (mSmmInterruptSspTables != 0);\r
         DEBUG ((DEBUG_INFO, "mSmmInterruptSspTables - 0x%x\n", mSmmInterruptSspTables));\r
       }\r
-      mCetInterruptSsp = (UINT32)((UINTN)ShadowStack + EFI_PAGES_TO_SIZE(1) - sizeof(UINT64));\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
+      *(UINT32 *)(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