UefiCpuPkg/MpInitLib: AP creation support under an SVSM

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4654

When running under an SVSM, the VMPL level of the APs that are started
must match the VMPL level provided by the SVSM. Additionally, each AP
must have a Calling Area for use with the SVSM protocol. Update the AP
creation to properly support running under an SVSM.

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Acked-by: Ray Ni <ray.ni@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
index 9811356..bbdc47b 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
+++ b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
@@ -44,7 +44,8 @@
 

   if (Action == SVM_VMGEXIT_SNP_AP_CREATE) {

     //

-    // Turn the page into a recognized VMSA page.

+    // Turn the page into a recognized VMSA page. When an SVSM is present

+    // the page following the VMSA is the Calling Area page.

     //

     VmsaStatus = AmdSvsmSnpVmsaRmpAdjust (SaveArea, ApicId, TRUE);

     if (EFI_ERROR (VmsaStatus)) {

@@ -56,6 +57,7 @@
   }

 

   ExitInfo1  = (UINT64)ApicId << 32;

+  ExitInfo1 |= (UINT64)SaveArea->Vmpl << 16;

   ExitInfo1 |= Action;

   ExitInfo2  = (UINT64)(UINTN)SaveArea;

 

@@ -87,8 +89,9 @@
 

   if (Action == SVM_VMGEXIT_SNP_AP_DESTROY) {

     //

-    // Make the current VMSA not runnable and accessible to be

-    // reprogrammed.

+    // Make the current VMSA not runnable and accessible to be reprogrammed.

+    // When an SVSM is present the page following the VMSA is the Calling Area

+    // page.

     //

     VmsaStatus = AmdSvsmSnpVmsaRmpAdjust (SaveArea, ApicId, FALSE);

     if (EFI_ERROR (VmsaStatus)) {

@@ -116,6 +119,7 @@
   UINT32          ApicId

   )

 {

+  UINTN             PageCount;

   UINT8             *Pages;

   SEV_ES_SAVE_AREA  *SaveArea;

   IA32_CR0          ApCr0;

@@ -125,13 +129,19 @@
   UINTN             StartIp;

   UINT8             SipiVector;

 

+  //

+  // When running under an SVSM, a Calling Area page is also needed and is

+  // always the page following the VMSA.

+  //

+  PageCount = AmdSvsmIsSvsmPresent () ? 2 : 1;

+

   if (CpuData->SevEsSaveArea == NULL) {

     //

     // Allocate a page for the SEV-ES Save Area and initialize it. Due to AMD

     // erratum #1467 (VMSA cannot be on a 2MB boundary), allocate an extra page

     // to choose from to work around the issue.

     //

-    Pages = AllocateReservedPages (2);

+    Pages = AllocateReservedPages (PageCount + 1);

     if (!Pages) {

       return;

     }

@@ -140,12 +150,12 @@
     // Since page allocation works by allocating downward in the address space,

     // try to always free the first (lower address) page to limit possible holes

     // in the memory map. So, if the address of the second page is 2MB aligned,

-    // then use the first page and free the second page. Otherwise, free the

+    // then use the first page and free the last page. Otherwise, free the

     // first page and use the second page.

     //

     if (_IS_ALIGNED (Pages + EFI_PAGE_SIZE, SIZE_2MB)) {

       SaveArea = (SEV_ES_SAVE_AREA *)Pages;

-      FreePages (Pages + EFI_PAGE_SIZE, 1);

+      FreePages (Pages + (EFI_PAGE_SIZE * PageCount), 1);

     } else {

       SaveArea = (SEV_ES_SAVE_AREA *)(Pages + EFI_PAGE_SIZE);

       FreePages (Pages, 1);

@@ -163,7 +173,7 @@
     }

   }

 

-  ZeroMem (SaveArea, EFI_PAGE_SIZE);

+  ZeroMem (SaveArea, EFI_PAGE_SIZE * PageCount);

 

   //

   // Propogate the CR0.NW and CR0.CD setting to the AP

@@ -239,10 +249,10 @@
 

   //

   // Set the SEV-SNP specific fields for the save area:

-  //   VMPL - always VMPL0

+  //   VMPL - based on current mode

   //   SEV_FEATURES - equivalent to the SEV_STATUS MSR right shifted 2 bits

   //

-  SaveArea->Vmpl        = 0;

+  SaveArea->Vmpl        = AmdSvsmSnpGetVmpl ();

   SaveArea->SevFeatures = AsmReadMsr64 (MSR_SEV_STATUS) >> 2;

 

   SevSnpPerformApAction (SaveArea, ApicId, SVM_VMGEXIT_SNP_AP_CREATE);