]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / X64 / SmmFuncsArch.c
index 89b3f2b7257f3a057d9e9f8257da25ce15db7440..00a284c369dd74049c5dc66a070b39b333d10cf2 100644 (file)
@@ -1,41 +1,47 @@
 /** @file\r
   SMM CPU misc functions for x64 arch specific.\r
 \r
-Copyright (c) 2015 - 2018, 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
-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
+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
@@ -53,41 +59,41 @@ InitGdt (
   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
@@ -112,15 +118,17 @@ GetProtectedModeCS (
 \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.L == 0) {\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
@@ -153,3 +161,67 @@ TransferApToSafeState (
   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
+  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
+      //\r
+      // Add one guard page between Known Good Shadow Stack and SMM Shadow Stack.\r
+      //\r
+      SmmShadowStackSize += EFI_PAGES_TO_SIZE (1);\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 (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