\r
#include "PiSmmCpuDxeSmm.h"\r
\r
-EFI_PHYSICAL_ADDRESS mGdtBuffer;\r
-UINTN mGdtBufferSize;\r
+EFI_PHYSICAL_ADDRESS mGdtBuffer;\r
+UINTN mGdtBufferSize;\r
\r
-extern BOOLEAN mCetSupported;\r
-extern UINTN mSmmShadowStackSize;\r
+extern BOOLEAN mCetSupported;\r
+extern UINTN mSmmShadowStackSize;\r
\r
-X86_ASSEMBLY_PATCH_LABEL mPatchCetPl0Ssp;\r
-X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSsp;\r
-X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSspTable;\r
-UINT32 mCetPl0Ssp;\r
-UINT32 mCetInterruptSsp;\r
-UINT32 mCetInterruptSspTable;\r
+X86_ASSEMBLY_PATCH_LABEL mPatchCetPl0Ssp;\r
+X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSsp;\r
+X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSspTable;\r
+UINT32 mCetPl0Ssp;\r
+UINT32 mCetInterruptSsp;\r
+UINT32 mCetInterruptSspTable;\r
\r
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 = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;\r
+ IdtGate += ExceptionType;\r
+ IdtGate->Bits.Reserved_0 = Ist;\r
}\r
\r
/**\r
OUT UINTN *GdtStepSize\r
)\r
{\r
- UINTN Index;\r
- IA32_SEGMENT_DESCRIPTOR *GdtDescriptor;\r
- UINTN TssBase;\r
- UINTN GdtTssTableSize;\r
- UINT8 *GdtTssTables;\r
- UINTN GdtTableStepSize;\r
+ UINTN Index;\r
+ IA32_SEGMENT_DESCRIPTOR *GdtDescriptor;\r
+ UINTN TssBase;\r
+ UINTN GdtTssTableSize;\r
+ UINT8 *GdtTssTables;\r
+ UINTN GdtTableStepSize;\r
\r
//\r
// For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention\r
// on each SMI entry.\r
//\r
GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + 7) & ~7; // 8 bytes aligned\r
- mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
- GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));\r
+ mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
+ GdtTssTables = (UINT8 *)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));\r
ASSERT (GdtTssTables != NULL);\r
- mGdtBuffer = (UINTN)GdtTssTables;\r
+ mGdtBuffer = (UINTN)GdtTssTables;\r
GdtTableStepSize = GdtTssTableSize;\r
\r
for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {\r
- CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE);\r
+ CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID *)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE);\r
\r
//\r
// Fixup TSS descriptors\r
//\r
- TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);\r
- GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;\r
- GdtDescriptor->Bits.BaseLow = (UINT16)(UINTN)TssBase;\r
- GdtDescriptor->Bits.BaseMid = (UINT8)((UINTN)TssBase >> 16);\r
+ TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);\r
+ GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;\r
+ GdtDescriptor->Bits.BaseLow = (UINT16)(UINTN)TssBase;\r
+ 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
- *(UINTN *)(TssBase + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize);\r
+ *(UINTN *)(TssBase + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * (mSmmStackSize + mSmmShadowStackSize));\r
}\r
}\r
\r
\r
AsmReadGdtr (&GdtrDesc);\r
GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
- GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;\r
+ GdtEntry = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;\r
for (Index = 0; Index < GdtEntryCount; Index++) {\r
if (GdtEntry->Bits.L == 0) {\r
- if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.DB == 1) {\r
+ if ((GdtEntry->Bits.Type > 8) && (GdtEntry->Bits.DB == 1)) {\r
break;\r
}\r
}\r
+\r
GdtEntry++;\r
}\r
+\r
ASSERT (Index != GdtEntryCount);\r
return Index * 8;\r
}\r
IN VOID *ShadowStack\r
)\r
{\r
- UINTN SmmShadowStackSize;\r
- UINT64 *InterruptSspTable;\r
- UINT32 InterruptSsp;\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
+ //\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
+\r
+ mCetPl0Ssp = (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - sizeof (UINT64));\r
PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4);\r
DEBUG ((DEBUG_INFO, "mCetPl0Ssp - 0x%x\n", mCetPl0Ssp));\r
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
- *(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
- 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