]> git.proxmox.com Git - mirror_edk2.git/commitdiff
UefiCpuPkg/MpInitLib: move SEV specific routines in AmdSev.c
authorBrijesh Singh <brijesh.singh@amd.com>
Thu, 9 Dec 2021 03:27:30 +0000 (11:27 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Thu, 9 Dec 2021 06:28:10 +0000 (06:28 +0000)
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

Move all the SEV specific function in AmdSev.c.

No functional change intended.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Michael Roth <michael.roth@amd.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Suggested-by: Jiewen Yao <Jiewen.yao@intel.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
UefiCpuPkg/Library/MpInitLib/AmdSev.c [new file with mode: 0644]
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/Library/MpInitLib/MpLib.h
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
UefiCpuPkg/Library/MpInitLib/X64/AmdSev.nasm [new file with mode: 0644]
UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm

diff --git a/UefiCpuPkg/Library/MpInitLib/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/AmdSev.c
new file mode 100644 (file)
index 0000000..0e3c6e2
--- /dev/null
@@ -0,0 +1,245 @@
+/** @file\r
+  CPU MP Initialize helper function for AMD SEV.\r
+\r
+  Copyright (c) 2021, AMD Inc. All rights reserved.<BR>\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "MpLib.h"\r
+#include <Library/VmgExitLib.h>\r
+\r
+/**\r
+  Get Protected mode code segment with 16-bit default addressing\r
+  from current GDT table.\r
+\r
+  @return  Protected mode 16-bit code segment value.\r
+**/\r
+STATIC\r
+UINT16\r
+GetProtectedMode16CS (\r
+  VOID\r
+  )\r
+{\r
+  IA32_DESCRIPTOR          GdtrDesc;\r
+  IA32_SEGMENT_DESCRIPTOR  *GdtEntry;\r
+  UINTN                    GdtEntryCount;\r
+  UINT16                   Index;\r
+\r
+  Index = (UINT16)-1;\r
+  AsmReadGdtr (&GdtrDesc);\r
+  GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
+  GdtEntry      = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;\r
+  for (Index = 0; Index < GdtEntryCount; Index++) {\r
+    if ((GdtEntry->Bits.L == 0) &&\r
+        (GdtEntry->Bits.DB == 0) &&\r
+        (GdtEntry->Bits.Type > 8))\r
+    {\r
+      break;\r
+    }\r
+\r
+    GdtEntry++;\r
+  }\r
+\r
+  ASSERT (Index != GdtEntryCount);\r
+  return Index * 8;\r
+}\r
+\r
+/**\r
+  Get Protected mode code segment with 32-bit default addressing\r
+  from current GDT table.\r
+\r
+  @return  Protected mode 32-bit code segment value.\r
+**/\r
+STATIC\r
+UINT16\r
+GetProtectedMode32CS (\r
+  VOID\r
+  )\r
+{\r
+  IA32_DESCRIPTOR          GdtrDesc;\r
+  IA32_SEGMENT_DESCRIPTOR  *GdtEntry;\r
+  UINTN                    GdtEntryCount;\r
+  UINT16                   Index;\r
+\r
+  Index = (UINT16)-1;\r
+  AsmReadGdtr (&GdtrDesc);\r
+  GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
+  GdtEntry      = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;\r
+  for (Index = 0; Index < GdtEntryCount; Index++) {\r
+    if ((GdtEntry->Bits.L == 0) &&\r
+        (GdtEntry->Bits.DB == 1) &&\r
+        (GdtEntry->Bits.Type > 8))\r
+    {\r
+      break;\r
+    }\r
+\r
+    GdtEntry++;\r
+  }\r
+\r
+  ASSERT (Index != GdtEntryCount);\r
+  return Index * 8;\r
+}\r
+\r
+/**\r
+  Reset an AP when in SEV-ES mode.\r
+\r
+  If successful, this function never returns.\r
+\r
+  @param[in] Ghcb                 Pointer to the GHCB\r
+  @param[in] CpuMpData            Pointer to CPU MP Data\r
+\r
+**/\r
+VOID\r
+MpInitLibSevEsAPReset (\r
+  IN GHCB         *Ghcb,\r
+  IN CPU_MP_DATA  *CpuMpData\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       ProcessorNumber;\r
+  UINT16      Code16, Code32;\r
+  AP_RESET    *APResetFn;\r
+  UINTN       BufferStart;\r
+  UINTN       StackStart;\r
+\r
+  Status = GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Code16 = GetProtectedMode16CS ();\r
+  Code32 = GetProtectedMode32CS ();\r
+\r
+  if (CpuMpData->WakeupBufferHigh != 0) {\r
+    APResetFn = (AP_RESET *)(CpuMpData->WakeupBufferHigh + CpuMpData->AddressMap.SwitchToRealNoNxOffset);\r
+  } else {\r
+    APResetFn = (AP_RESET *)(CpuMpData->MpCpuExchangeInfo->BufferStart + CpuMpData->AddressMap.SwitchToRealOffset);\r
+  }\r
+\r
+  BufferStart = CpuMpData->MpCpuExchangeInfo->BufferStart;\r
+  StackStart  = CpuMpData->SevEsAPResetStackStart -\r
+                (AP_RESET_STACK_SIZE * ProcessorNumber);\r
+\r
+  //\r
+  // This call never returns.\r
+  //\r
+  APResetFn (BufferStart, Code16, Code32, StackStart);\r
+}\r
+\r
+/**\r
+  Allocate the SEV-ES AP jump table buffer.\r
+\r
+  @param[in, out]  CpuMpData  The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+AllocateSevEsAPMemory (\r
+  IN OUT CPU_MP_DATA  *CpuMpData\r
+  )\r
+{\r
+  if (CpuMpData->SevEsAPBuffer == (UINTN)-1) {\r
+    CpuMpData->SevEsAPBuffer =\r
+      CpuMpData->SevEsIsEnabled ? GetSevEsAPMemory () : 0;\r
+  }\r
+}\r
+\r
+/**\r
+  Program the SEV-ES AP jump table buffer.\r
+\r
+  @param[in]  SipiVector  The SIPI vector used for the AP Reset\r
+**/\r
+VOID\r
+SetSevEsJumpTable (\r
+  IN UINTN  SipiVector\r
+  )\r
+{\r
+  SEV_ES_AP_JMP_FAR  *JmpFar;\r
+  UINT32             Offset, InsnByte;\r
+  UINT8              LoNib, HiNib;\r
+\r
+  JmpFar = (SEV_ES_AP_JMP_FAR *)(UINTN)FixedPcdGet32 (PcdSevEsWorkAreaBase);\r
+  ASSERT (JmpFar != NULL);\r
+\r
+  //\r
+  // Obtain the address of the Segment/Rip location in the workarea.\r
+  // This will be set to a value derived from the SIPI vector and will\r
+  // be the memory address used for the far jump below.\r
+  //\r
+  Offset  = FixedPcdGet32 (PcdSevEsWorkAreaBase);\r
+  Offset += sizeof (JmpFar->InsnBuffer);\r
+  LoNib   = (UINT8)Offset;\r
+  HiNib   = (UINT8)(Offset >> 8);\r
+\r
+  //\r
+  // Program the workarea (which is the initial AP boot address) with\r
+  // far jump to the SIPI vector (where XX and YY represent the\r
+  // address of where the SIPI vector is stored.\r
+  //\r
+  //   JMP FAR [CS:XXYY] => 2E FF 2E YY XX\r
+  //\r
+  InsnByte                       = 0;\r
+  JmpFar->InsnBuffer[InsnByte++] = 0x2E;  // CS override prefix\r
+  JmpFar->InsnBuffer[InsnByte++] = 0xFF;  // JMP (FAR)\r
+  JmpFar->InsnBuffer[InsnByte++] = 0x2E;  // ModRM (JMP memory location)\r
+  JmpFar->InsnBuffer[InsnByte++] = LoNib; // YY offset ...\r
+  JmpFar->InsnBuffer[InsnByte++] = HiNib; // XX offset ...\r
+\r
+  //\r
+  // Program the Segment/Rip based on the SIPI vector (always at least\r
+  // 16-byte aligned, so Rip is set to 0).\r
+  //\r
+  JmpFar->Rip     = 0;\r
+  JmpFar->Segment = (UINT16)(SipiVector >> 4);\r
+}\r
+\r
+/**\r
+  The function puts the AP in halt loop.\r
+\r
+  @param[in]  CpuMpData  The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+SevEsPlaceApHlt (\r
+  CPU_MP_DATA  *CpuMpData\r
+  )\r
+{\r
+  MSR_SEV_ES_GHCB_REGISTER  Msr;\r
+  GHCB                      *Ghcb;\r
+  UINT64                    Status;\r
+  BOOLEAN                   DoDecrement;\r
+  BOOLEAN                   InterruptState;\r
+\r
+  DoDecrement = (BOOLEAN)(CpuMpData->InitFlag == ApInitConfig);\r
+\r
+  while (TRUE) {\r
+    Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
+    Ghcb                    = Msr.Ghcb;\r
+\r
+    VmgInit (Ghcb, &InterruptState);\r
+\r
+    if (DoDecrement) {\r
+      DoDecrement = FALSE;\r
+\r
+      //\r
+      // Perform the delayed decrement just before issuing the first\r
+      // VMGEXIT with AP_RESET_HOLD.\r
+      //\r
+      InterlockedDecrement ((UINT32 *)&CpuMpData->MpCpuExchangeInfo->NumApsExecuting);\r
+    }\r
+\r
+    Status = VmgExit (Ghcb, SVM_EXIT_AP_RESET_HOLD, 0, 0);\r
+    if ((Status == 0) && (Ghcb->SaveArea.SwExitInfo2 != 0)) {\r
+      VmgDone (Ghcb, InterruptState);\r
+      break;\r
+    }\r
+\r
+    VmgDone (Ghcb, InterruptState);\r
+  }\r
+\r
+  //\r
+  // Awakened in a new phase? Use the new CpuMpData\r
+  //\r
+  if (CpuMpData->NewCpuMpData != NULL) {\r
+    CpuMpData = CpuMpData->NewCpuMpData;\r
+  }\r
+\r
+  MpInitLibSevEsAPReset (Ghcb, CpuMpData);\r
+}\r
index d34419c2a524a9515188cbe243e6f4e349b2ae2a..6e510aa891207a68c760ff32f1043e5e04e616b6 100644 (file)
@@ -28,6 +28,7 @@
   X64/MpFuncs.nasm\r
 \r
 [Sources.common]\r
+  AmdSev.c\r
   MpEqu.inc\r
   DxeMpLib.c\r
   MpLib.c\r
index 2d8e9512ab98e261f8b6956aee3c98f76b6e7de8..34555c069331c4e2e4a2897db43a0b358ac05909 100644 (file)
@@ -599,123 +599,6 @@ InitializeApData (
   SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
 }\r
 \r
-/**\r
-  Get Protected mode code segment with 16-bit default addressing\r
-  from current GDT table.\r
-\r
-  @return  Protected mode 16-bit code segment value.\r
-**/\r
-STATIC\r
-UINT16\r
-GetProtectedMode16CS (\r
-  VOID\r
-  )\r
-{\r
-  IA32_DESCRIPTOR          GdtrDesc;\r
-  IA32_SEGMENT_DESCRIPTOR  *GdtEntry;\r
-  UINTN                    GdtEntryCount;\r
-  UINT16                   Index;\r
-\r
-  Index = (UINT16)-1;\r
-  AsmReadGdtr (&GdtrDesc);\r
-  GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
-  GdtEntry      = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;\r
-  for (Index = 0; Index < GdtEntryCount; Index++) {\r
-    if ((GdtEntry->Bits.L == 0) &&\r
-        (GdtEntry->Bits.DB == 0) &&\r
-        (GdtEntry->Bits.Type > 8))\r
-    {\r
-      break;\r
-    }\r
-\r
-    GdtEntry++;\r
-  }\r
-\r
-  ASSERT (Index != GdtEntryCount);\r
-  return Index * 8;\r
-}\r
-\r
-/**\r
-  Get Protected mode code segment with 32-bit default addressing\r
-  from current GDT table.\r
-\r
-  @return  Protected mode 32-bit code segment value.\r
-**/\r
-STATIC\r
-UINT16\r
-GetProtectedMode32CS (\r
-  VOID\r
-  )\r
-{\r
-  IA32_DESCRIPTOR          GdtrDesc;\r
-  IA32_SEGMENT_DESCRIPTOR  *GdtEntry;\r
-  UINTN                    GdtEntryCount;\r
-  UINT16                   Index;\r
-\r
-  Index = (UINT16)-1;\r
-  AsmReadGdtr (&GdtrDesc);\r
-  GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
-  GdtEntry      = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;\r
-  for (Index = 0; Index < GdtEntryCount; Index++) {\r
-    if ((GdtEntry->Bits.L == 0) &&\r
-        (GdtEntry->Bits.DB == 1) &&\r
-        (GdtEntry->Bits.Type > 8))\r
-    {\r
-      break;\r
-    }\r
-\r
-    GdtEntry++;\r
-  }\r
-\r
-  ASSERT (Index != GdtEntryCount);\r
-  return Index * 8;\r
-}\r
-\r
-/**\r
-  Reset an AP when in SEV-ES mode.\r
-\r
-  If successful, this function never returns.\r
-\r
-  @param[in] Ghcb                 Pointer to the GHCB\r
-  @param[in] CpuMpData            Pointer to CPU MP Data\r
-\r
-**/\r
-STATIC\r
-VOID\r
-MpInitLibSevEsAPReset (\r
-  IN GHCB         *Ghcb,\r
-  IN CPU_MP_DATA  *CpuMpData\r
-  )\r
-{\r
-  EFI_STATUS  Status;\r
-  UINTN       ProcessorNumber;\r
-  UINT16      Code16, Code32;\r
-  AP_RESET    *APResetFn;\r
-  UINTN       BufferStart;\r
-  UINTN       StackStart;\r
-\r
-  Status = GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  Code16 = GetProtectedMode16CS ();\r
-  Code32 = GetProtectedMode32CS ();\r
-\r
-  if (CpuMpData->WakeupBufferHigh != 0) {\r
-    APResetFn = (AP_RESET *)(CpuMpData->WakeupBufferHigh + CpuMpData->AddressMap.SwitchToRealNoNxOffset);\r
-  } else {\r
-    APResetFn = (AP_RESET *)(CpuMpData->MpCpuExchangeInfo->BufferStart + CpuMpData->AddressMap.SwitchToRealOffset);\r
-  }\r
-\r
-  BufferStart = CpuMpData->MpCpuExchangeInfo->BufferStart;\r
-  StackStart  = CpuMpData->SevEsAPResetStackStart -\r
-                (AP_RESET_STACK_SIZE * ProcessorNumber);\r
-\r
-  //\r
-  // This call never returns.\r
-  //\r
-  APResetFn (BufferStart, Code16, Code32, StackStart);\r
-}\r
-\r
 /**\r
   This function will be called from AP reset code if BSP uses WakeUpAP.\r
 \r
@@ -895,47 +778,7 @@ ApWakeupFunction (
       while (TRUE) {\r
         DisableInterrupts ();\r
         if (CpuMpData->SevEsIsEnabled) {\r
-          MSR_SEV_ES_GHCB_REGISTER  Msr;\r
-          GHCB                      *Ghcb;\r
-          UINT64                    Status;\r
-          BOOLEAN                   DoDecrement;\r
-          BOOLEAN                   InterruptState;\r
-\r
-          DoDecrement = (BOOLEAN)(CpuMpData->InitFlag == ApInitConfig);\r
-\r
-          while (TRUE) {\r
-            Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
-            Ghcb                    = Msr.Ghcb;\r
-\r
-            VmgInit (Ghcb, &InterruptState);\r
-\r
-            if (DoDecrement) {\r
-              DoDecrement = FALSE;\r
-\r
-              //\r
-              // Perform the delayed decrement just before issuing the first\r
-              // VMGEXIT with AP_RESET_HOLD.\r
-              //\r
-              InterlockedDecrement ((UINT32 *)&CpuMpData->MpCpuExchangeInfo->NumApsExecuting);\r
-            }\r
-\r
-            Status = VmgExit (Ghcb, SVM_EXIT_AP_RESET_HOLD, 0, 0);\r
-            if ((Status == 0) && (Ghcb->SaveArea.SwExitInfo2 != 0)) {\r
-              VmgDone (Ghcb, InterruptState);\r
-              break;\r
-            }\r
-\r
-            VmgDone (Ghcb, InterruptState);\r
-          }\r
-\r
-          //\r
-          // Awakened in a new phase? Use the new CpuMpData\r
-          //\r
-          if (CpuMpData->NewCpuMpData != NULL) {\r
-            CpuMpData = CpuMpData->NewCpuMpData;\r
-          }\r
-\r
-          MpInitLibSevEsAPReset (Ghcb, CpuMpData);\r
+          SevEsPlaceApHlt (CpuMpData);\r
         } else {\r
           CpuSleep ();\r
         }\r
@@ -1268,71 +1111,6 @@ FreeResetVector (
   }\r
 }\r
 \r
-/**\r
-  Allocate the SEV-ES AP jump table buffer.\r
-\r
-  @param[in, out]  CpuMpData  The pointer to CPU MP Data structure.\r
-**/\r
-VOID\r
-AllocateSevEsAPMemory (\r
-  IN OUT CPU_MP_DATA  *CpuMpData\r
-  )\r
-{\r
-  if (CpuMpData->SevEsAPBuffer == (UINTN)-1) {\r
-    CpuMpData->SevEsAPBuffer =\r
-      CpuMpData->SevEsIsEnabled ? GetSevEsAPMemory () : 0;\r
-  }\r
-}\r
-\r
-/**\r
-  Program the SEV-ES AP jump table buffer.\r
-\r
-  @param[in]  SipiVector  The SIPI vector used for the AP Reset\r
-**/\r
-VOID\r
-SetSevEsJumpTable (\r
-  IN UINTN  SipiVector\r
-  )\r
-{\r
-  SEV_ES_AP_JMP_FAR  *JmpFar;\r
-  UINT32             Offset, InsnByte;\r
-  UINT8              LoNib, HiNib;\r
-\r
-  JmpFar = (SEV_ES_AP_JMP_FAR *)(UINTN)FixedPcdGet32 (PcdSevEsWorkAreaBase);\r
-  ASSERT (JmpFar != NULL);\r
-\r
-  //\r
-  // Obtain the address of the Segment/Rip location in the workarea.\r
-  // This will be set to a value derived from the SIPI vector and will\r
-  // be the memory address used for the far jump below.\r
-  //\r
-  Offset  = FixedPcdGet32 (PcdSevEsWorkAreaBase);\r
-  Offset += sizeof (JmpFar->InsnBuffer);\r
-  LoNib   = (UINT8)Offset;\r
-  HiNib   = (UINT8)(Offset >> 8);\r
-\r
-  //\r
-  // Program the workarea (which is the initial AP boot address) with\r
-  // far jump to the SIPI vector (where XX and YY represent the\r
-  // address of where the SIPI vector is stored.\r
-  //\r
-  //   JMP FAR [CS:XXYY] => 2E FF 2E YY XX\r
-  //\r
-  InsnByte                       = 0;\r
-  JmpFar->InsnBuffer[InsnByte++] = 0x2E;  // CS override prefix\r
-  JmpFar->InsnBuffer[InsnByte++] = 0xFF;  // JMP (FAR)\r
-  JmpFar->InsnBuffer[InsnByte++] = 0x2E;  // ModRM (JMP memory location)\r
-  JmpFar->InsnBuffer[InsnByte++] = LoNib; // YY offset ...\r
-  JmpFar->InsnBuffer[InsnByte++] = HiNib; // XX offset ...\r
-\r
-  //\r
-  // Program the Segment/Rip based on the SIPI vector (always at least\r
-  // 16-byte aligned, so Rip is set to 0).\r
-  //\r
-  JmpFar->Rip     = 0;\r
-  JmpFar->Segment = (UINT16)(SipiVector >> 4);\r
-}\r
-\r
 /**\r
   This function will be called by BSP to wakeup AP.\r
 \r
index a647772088d9d979ddc0d5557105713a43e87d4e..16b4d76d019bc7d6a58037bb53a075ffb8c1d1a0 100644 (file)
@@ -34,6 +34,9 @@
 #include <Library/PcdLib.h>\r
 #include <Library/MicrocodeLib.h>\r
 \r
+#include <Register/Amd/Fam17Msr.h>\r
+#include <Register/Amd/Ghcb.h>\r
+\r
 #include <Guid/MicrocodePatchHob.h>\r
 \r
 #define WAKEUP_AP_SIGNAL  SIGNATURE_32 ('S', 'T', 'A', 'P')\r
@@ -321,7 +324,7 @@ typedef struct {
                            from long mode to real mode.\r
 **/\r
 typedef\r
-VOID\r
+  VOID\r
 (EFIAPI AP_RESET)(\r
   IN UINTN    BufferStart,\r
   IN UINT16   Code16,\r
@@ -346,7 +349,7 @@ extern EFI_GUID  mCpuInitMpLibHobGuid;
   @param[in] PmCodeSegment   Protected mode code segment value.\r
 **/\r
 typedef\r
-VOID\r
+  VOID\r
 (EFIAPI *ASM_RELOCATE_AP_LOOP)(\r
   IN BOOLEAN                 MwaitSupport,\r
   IN UINTN                   ApTargetCState,\r
@@ -740,4 +743,34 @@ PlatformShadowMicrocode (
   IN OUT CPU_MP_DATA  *CpuMpData\r
   );\r
 \r
+/**\r
+  Allocate the SEV-ES AP jump table buffer.\r
+\r
+  @param[in, out]  CpuMpData  The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+AllocateSevEsAPMemory (\r
+  IN OUT CPU_MP_DATA  *CpuMpData\r
+  );\r
+\r
+/**\r
+  Program the SEV-ES AP jump table buffer.\r
+\r
+  @param[in]  SipiVector  The SIPI vector used for the AP Reset\r
+**/\r
+VOID\r
+SetSevEsJumpTable (\r
+  IN UINTN  SipiVector\r
+  );\r
+\r
+/**\r
+  The function puts the AP in halt loop.\r
+\r
+  @param[in]  CpuMpData  The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+SevEsPlaceApHlt (\r
+  CPU_MP_DATA  *CpuMpData\r
+  );\r
+\r
 #endif\r
index 36fcb96b5852c25f39a2d4d1e4932bf281ad1213..2cbd9b8b8acc24428e9b15e78ebe73f92a259d94 100644 (file)
@@ -28,6 +28,7 @@
   X64/MpFuncs.nasm\r
 \r
 [Sources.common]\r
+  AmdSev.c\r
   MpEqu.inc\r
   PeiMpLib.c\r
   MpLib.c\r
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.nasm b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.nasm
new file mode 100644 (file)
index 0000000..0ccafe2
--- /dev/null
@@ -0,0 +1,119 @@
+;------------------------------------------------------------------------------ ;\r
+; Copyright (c) 2021, AMD Inc. All rights reserved.<BR>\r
+; SPDX-License-Identifier: BSD-2-Clause-Patent\r
+;\r
+; Module Name:\r
+;\r
+;   AmdSev.nasm\r
+;\r
+; Abstract:\r
+;\r
+;   This provides helper used by the MpFunc.nasm. If AMD SEV-ES is active\r
+;   then helpers perform the additional setups (such as GHCB).\r
+;\r
+;-------------------------------------------------------------------------------\r
+\r
+%define SIZE_4KB    0x1000\r
+\r
+;\r
+; The function checks whether SEV-ES is enabled, if enabled\r
+; then setup the GHCB page.\r
+;\r
+SevEsSetupGhcb:\r
+    lea        edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]\r
+    cmp        byte [edi], 1        ; SevEsIsEnabled\r
+    jne        SevEsSetupGhcbExit\r
+\r
+    ;\r
+    ; program GHCB\r
+    ;   Each page after the GHCB is a per-CPU page, so the calculation programs\r
+    ;   a GHCB to be every 8KB.\r
+    ;\r
+    mov        eax, SIZE_4KB\r
+    shl        eax, 1                            ; EAX = SIZE_4K * 2\r
+    mov        ecx, ebx\r
+    mul        ecx                               ; EAX = SIZE_4K * 2 * CpuNumber\r
+    mov        edi, esi\r
+    add        edi, MP_CPU_EXCHANGE_INFO_FIELD (GhcbBase)\r
+    add        rax, qword [edi]\r
+    mov        rdx, rax\r
+    shr        rdx, 32\r
+    mov        rcx, 0xc0010130\r
+    wrmsr\r
+\r
+SevEsSetupGhcbExit:\r
+    OneTimeCallRet    SevEsSetupGhcb\r
+\r
+;\r
+; The function checks whether SEV-ES is enabled, if enabled, use\r
+; the GHCB\r
+;\r
+SevEsGetApicId:\r
+    lea        edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]\r
+    cmp        byte [edi], 1        ; SevEsIsEnabled\r
+    jne        SevEsGetApicIdExit\r
+\r
+    ;\r
+    ; Since we don't have a stack yet, we can't take a #VC\r
+    ; exception. Use the GHCB protocol to perform the CPUID\r
+    ; calls.\r
+    ;\r
+    mov        rcx, 0xc0010130\r
+    rdmsr\r
+    shl        rdx, 32\r
+    or         rax, rdx\r
+    mov        rdi, rax             ; RDI now holds the original GHCB GPA\r
+\r
+    mov        rdx, 0               ; CPUID function 0\r
+    mov        rax, 0               ; RAX register requested\r
+    or         rax, 4\r
+    wrmsr\r
+    rep vmmcall\r
+    rdmsr\r
+    cmp        edx, 0bh\r
+    jb         NoX2ApicSevEs        ; CPUID level below CPUID_EXTENDED_TOPOLOGY\r
+\r
+    mov        rdx, 0bh             ; CPUID function 0x0b\r
+    mov        rax, 040000000h      ; RBX register requested\r
+    or         rax, 4\r
+    wrmsr\r
+    rep vmmcall\r
+    rdmsr\r
+    test       edx, 0ffffh\r
+    jz         NoX2ApicSevEs        ; CPUID.0BH:EBX[15:0] is zero\r
+\r
+    mov        rdx, 0bh             ; CPUID function 0x0b\r
+    mov        rax, 0c0000000h      ; RDX register requested\r
+    or         rax, 4\r
+    wrmsr\r
+    rep vmmcall\r
+    rdmsr\r
+\r
+    ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX\r
+    jmp        RestoreGhcb\r
+\r
+NoX2ApicSevEs:\r
+    ; Processor is not x2APIC capable, so get 8-bit APIC ID\r
+    mov        rdx, 1               ; CPUID function 1\r
+    mov        rax, 040000000h      ; RBX register requested\r
+    or         rax, 4\r
+    wrmsr\r
+    rep vmmcall\r
+    rdmsr\r
+    shr        edx, 24\r
+\r
+RestoreGhcb:\r
+    mov        rbx, rdx             ; Save x2APIC/APIC ID\r
+\r
+    mov        rdx, rdi             ; RDI holds the saved GHCB GPA\r
+    shr        rdx, 32\r
+    mov        eax, edi\r
+    wrmsr\r
+\r
+    mov        rdx, rbx\r
+\r
+    ; x2APIC ID or APIC ID is in EDX\r
+    jmp        GetProcessorNumber\r
+\r
+SevEsGetApicIdExit:\r
+    OneTimeCallRet    SevEsGetApicId\r
index 50df802d1fca4318c312118d0b4c9637f123f94a..f7f2937fafadd6f4c192c671f5a446039a93e51f 100644 (file)
 %include "MpEqu.inc"\r
 extern ASM_PFX(InitializeFloatingPointUnits)\r
 \r
+%macro  OneTimeCall 1\r
+    jmp     %1\r
+%1 %+ OneTimerCallReturn:\r
+%endmacro\r
+\r
+%macro  OneTimeCallRet 1\r
+    jmp     %1 %+ OneTimerCallReturn\r
+%endmacro\r
+\r
 DEFAULT REL\r
 \r
 SECTION .text\r
@@ -144,6 +153,12 @@ SkipEnable5LevelPaging:
     jmp far    [edi]\r
 \r
 BITS 64\r
+\r
+;\r
+; Required for the AMD SEV helper functions\r
+;\r
+%include "AmdSev.nasm"\r
+\r
 LongModeStart:\r
     mov        esi, ebx\r
     lea        edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (InitFlag)]\r
@@ -175,94 +190,17 @@ LongModeStart:
     add        rax, qword [edi]\r
     mov        rsp, rax\r
 \r
-    lea        edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]\r
-    cmp        byte [edi], 1        ; SevEsIsEnabled\r
-    jne        CProcedureInvoke\r
-\r
     ;\r
-    ; program GHCB\r
-    ;   Each page after the GHCB is a per-CPU page, so the calculation programs\r
-    ;   a GHCB to be every 8KB.\r
+    ;  Setup the GHCB when AMD SEV-ES active.\r
     ;\r
-    mov        eax, SIZE_4KB\r
-    shl        eax, 1                            ; EAX = SIZE_4K * 2\r
-    mov        ecx, ebx\r
-    mul        ecx                               ; EAX = SIZE_4K * 2 * CpuNumber\r
-    mov        edi, esi\r
-    add        edi, MP_CPU_EXCHANGE_INFO_FIELD (GhcbBase)\r
-    add        rax, qword [edi]\r
-    mov        rdx, rax\r
-    shr        rdx, 32\r
-    mov        rcx, 0xc0010130\r
-    wrmsr\r
+    OneTimeCall SevEsSetupGhcb\r
     jmp        CProcedureInvoke\r
 \r
 GetApicId:\r
-    lea        edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]\r
-    cmp        byte [edi], 1        ; SevEsIsEnabled\r
-    jne        DoCpuid\r
-\r
     ;\r
-    ; Since we don't have a stack yet, we can't take a #VC\r
-    ; exception. Use the GHCB protocol to perform the CPUID\r
-    ; calls.\r
+    ; Use the GHCB protocol to get the ApicId when SEV-ES is active.\r
     ;\r
-    mov        rcx, 0xc0010130\r
-    rdmsr\r
-    shl        rdx, 32\r
-    or         rax, rdx\r
-    mov        rdi, rax             ; RDI now holds the original GHCB GPA\r
-\r
-    mov        rdx, 0               ; CPUID function 0\r
-    mov        rax, 0               ; RAX register requested\r
-    or         rax, 4\r
-    wrmsr\r
-    rep vmmcall\r
-    rdmsr\r
-    cmp        edx, 0bh\r
-    jb         NoX2ApicSevEs        ; CPUID level below CPUID_EXTENDED_TOPOLOGY\r
-\r
-    mov        rdx, 0bh             ; CPUID function 0x0b\r
-    mov        rax, 040000000h      ; RBX register requested\r
-    or         rax, 4\r
-    wrmsr\r
-    rep vmmcall\r
-    rdmsr\r
-    test       edx, 0ffffh\r
-    jz         NoX2ApicSevEs        ; CPUID.0BH:EBX[15:0] is zero\r
-\r
-    mov        rdx, 0bh             ; CPUID function 0x0b\r
-    mov        rax, 0c0000000h      ; RDX register requested\r
-    or         rax, 4\r
-    wrmsr\r
-    rep vmmcall\r
-    rdmsr\r
-\r
-    ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX\r
-    jmp        RestoreGhcb\r
-\r
-NoX2ApicSevEs:\r
-    ; Processor is not x2APIC capable, so get 8-bit APIC ID\r
-    mov        rdx, 1               ; CPUID function 1\r
-    mov        rax, 040000000h      ; RBX register requested\r
-    or         rax, 4\r
-    wrmsr\r
-    rep vmmcall\r
-    rdmsr\r
-    shr        edx, 24\r
-\r
-RestoreGhcb:\r
-    mov        rbx, rdx             ; Save x2APIC/APIC ID\r
-\r
-    mov        rdx, rdi             ; RDI holds the saved GHCB GPA\r
-    shr        rdx, 32\r
-    mov        eax, edi\r
-    wrmsr\r
-\r
-    mov        rdx, rbx\r
-\r
-    ; x2APIC ID or APIC ID is in EDX\r
-    jmp        GetProcessorNumber\r
+    OneTimeCall SevEsGetApicId\r
 \r
 DoCpuid:\r
     mov        eax, 0\r