/** @file\r
SMM CPU misc functions for Ia32 arch specific.\r
- \r
-Copyright (c) 2015 - 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
-http://opensource.org/licenses/bsd-license.php\r
\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "PiSmmCpuDxeSmm.h"\r
\r
-extern UINT64 gTaskGateDescriptor;\r
+extern UINT64 gTaskGateDescriptor;\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
+\r
+X86_ASSEMBLY_PATCH_LABEL mPatchCetPl0Ssp;\r
+X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSsp;\r
+UINT32 mCetPl0Ssp;\r
+UINT32 mCetInterruptSsp;\r
\r
/**\r
Initialize IDT for SMM Stack Guard.\r
// is a Task Gate Descriptor so that when a Page Fault Exception occurs,\r
// the processors can use a known good stack in case stack is ran out.\r
//\r
- IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;\r
- IdtGate += EXCEPT_IA32_PAGE_FAULT;\r
+ IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;\r
+ IdtGate += EXCEPT_IA32_PAGE_FAULT;\r
IdtGate->Uint64 = gTaskGateDescriptor;\r
}\r
\r
/**\r
Initialize Gdt for all processors.\r
- \r
+\r
@param[in] Cr3 CR3 value.\r
@param[out] GdtStepSize The step size for GDT table.\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
+ UINTN InterruptShadowStack;\r
\r
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
//\r
//\r
gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));\r
\r
- GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned\r
- mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
- GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));\r
+ GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + EXCEPTION_TSS_SIZE + 7) & ~7; // 8 bytes aligned\r
+ mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
+ //\r
+ // IA32 Stack Guard need use task switch to switch stack that need\r
+ // write GDT and TSS, so AllocateCodePages() could not be used here\r
+ // as code pages will be set to RO.\r
+ //\r
+ GdtTssTables = (UINT8 *)AllocatePages (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 * 2);\r
+ CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID *)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE + EXCEPTION_TSS_SIZE);\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)TssBase;\r
- GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);\r
+ TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);\r
+ GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;\r
+ GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;\r
+ GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);\r
GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);\r
\r
TssBase += TSS_SIZE;\r
GdtDescriptor++;\r
- GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;\r
- GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);\r
+ GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;\r
+ GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);\r
GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);\r
//\r
// Fixup TSS segments\r
//\r
// ESP as known good stack\r
//\r
- *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) = mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;\r
+ *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) = mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;\r
*(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;\r
+\r
+ //\r
+ // Setup ShadowStack for stack switch\r
+ //\r
+ if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {\r
+ InterruptShadowStack = (UINTN)(mSmmStackArrayBase + mSmmStackSize + EFI_PAGES_TO_SIZE (1) - sizeof (UINT64) + (mSmmStackSize + mSmmShadowStackSize) * Index);\r
+ *(UINT32 *)(TssBase + TSS_IA32_SSP_OFFSET) = (UINT32)InterruptShadowStack;\r
+ }\r
}\r
} else {\r
//\r
// Just use original table, AllocatePage and copy them here to make sure GDTs are covered in page memory.\r
//\r
GdtTssTableSize = gcSmiGdtr.Limit + 1;\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);\r
+ CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID *)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1);\r
}\r
}\r
\r
/**\r
Transfer AP to safe hlt-loop after it finished restore CPU features on S3 patch.\r
\r
- @param[in] ApHltLoopCode The 32-bit address of the safe hlt-loop function.\r
- @param[in] TopOfStack A pointer to the new stack to use for the ApHltLoopCode.\r
- @param[in] NumberToFinish Semaphore of APs finish count.\r
+ @param[in] ApHltLoopCode The address of the safe hlt-loop function.\r
+ @param[in] TopOfStack A pointer to the new stack to use for the ApHltLoopCode.\r
+ @param[in] NumberToFinishAddress Address of Semaphore of APs finish count.\r
\r
**/\r
VOID\r
TransferApToSafeState (\r
- IN UINT32 ApHltLoopCode,\r
- IN UINT32 TopOfStack,\r
- IN UINT32 *NumberToFinish\r
+ IN UINTN ApHltLoopCode,\r
+ IN UINTN TopOfStack,\r
+ IN UINTN NumberToFinishAddress\r
)\r
{\r
SwitchStack (\r
- (SWITCH_STACK_ENTRY_POINT) (UINTN) ApHltLoopCode,\r
- NumberToFinish,\r
+ (SWITCH_STACK_ENTRY_POINT)ApHltLoopCode,\r
+ (VOID *)NumberToFinishAddress,\r
NULL,\r
- (VOID *) (UINTN) TopOfStack\r
+ (VOID *)TopOfStack\r
);\r
//\r
// It should never reach here\r
//\r
ASSERT (FALSE);\r
}\r
+\r
+/**\r
+ Initialize the shadow stack related data structure.\r
+\r
+ @param CpuIndex The index of CPU.\r
+ @param ShadowStack The bottom of the shadow stack for this CPU.\r
+**/\r
+VOID\r
+InitShadowStack (\r
+ IN UINTN CpuIndex,\r
+ IN VOID *ShadowStack\r
+ )\r
+{\r
+ UINTN SmmShadowStackSize;\r
+\r
+ if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {\r
+ SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));\r
+ if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
+ SmmShadowStackSize += EFI_PAGES_TO_SIZE (2);\r
+ }\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
+ mCetInterruptSsp = (UINT32)((UINTN)ShadowStack + EFI_PAGES_TO_SIZE (1) - sizeof (UINT64));\r
+ PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4);\r
+ DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp));\r
+ }\r
+ }\r
+}\r