]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / Ia32 / SmmFuncsArch.c
index 3c68c970245fba7369dde77e2adefac026f58b09..6c48a53f67dac55e06c5dc36abf1cb9756e7b345 100644 (file)
@@ -1,23 +1,25 @@
 /** @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
@@ -36,14 +38,14 @@ InitializeIDTSmmStackGuard (
   // 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
@@ -56,12 +58,13 @@ 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
+  UINTN                    InterruptShadowStack;\r
 \r
   if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
     //\r
@@ -75,50 +78,63 @@ InitGdt (
     //\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
@@ -126,61 +142,6 @@ InitGdt (
   return GdtTssTables;\r
 }\r
 \r
-/**\r
-  This function sets GDT/IDT buffer to be RO and XP.\r
-**/\r
-VOID\r
-PatchGdtIdtMap (\r
-  VOID\r
-  )\r
-{\r
-  EFI_PHYSICAL_ADDRESS       BaseAddress;\r
-  UINTN                      Size;\r
-\r
-  //\r
-  // GDT\r
-  //\r
-  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));\r
-\r
-  BaseAddress = mGdtBuffer;\r
-  Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);\r
-  if (!FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
-    //\r
-    // Do not set RO for IA32 when stack guard feature is enabled.\r
-    // Stack Guard need use task switch to switch stack.\r
-    // It need write GDT and TSS.\r
-    //\r
-    SmmSetMemoryAttributes (\r
-      BaseAddress,\r
-      Size,\r
-      EFI_MEMORY_RO\r
-      );\r
-  }\r
-  SmmSetMemoryAttributes (\r
-    BaseAddress,\r
-    Size,\r
-    EFI_MEMORY_XP\r
-    );\r
-\r
-  //\r
-  // IDT\r
-  //\r
-  DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));\r
-\r
-  BaseAddress = gcSmiIdtr.Base;\r
-  Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);\r
-  SmmSetMemoryAttributes (\r
-    BaseAddress,\r
-    Size,\r
-    EFI_MEMORY_RO\r
-    );\r
-  SmmSetMemoryAttributes (\r
-    BaseAddress,\r
-    Size,\r
-    EFI_MEMORY_XP\r
-    );\r
-}\r
-\r
 /**\r
   Transfer AP to safe hlt-loop after it finished restore CPU features on S3 patch.\r
 \r
@@ -207,3 +168,37 @@ TransferApToSafeState (
   //\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