]> xenbits.xensource.com Git - ovmf.git/commitdiff
UefiCpuPkg/MpInitLib: Reuse VMSA allocation to avoid unreserved allocation
authorLendacky, Thomas via groups.io <thomas.lendacky=amd.com@groups.io>
Tue, 28 Mar 2023 18:09:23 +0000 (02:09 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Sat, 1 Apr 2023 03:15:51 +0000 (03:15 +0000)
https://bugzilla.tianocore.org/show_bug.cgi?id=4353

When parking the APs on exiting from UEFI, a new page allocation is made.
This allocation, however, does not end up being marked reserved in the
memory map supplied to the OS. To avoid this, re-use the VMSA by clearing
the VMSA RMP flag, updating the page contents and re-setting the VMSA RMP
flag.

Fixes: 06544455d0d4 ("UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation ...")
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Ray Ni <ray.ni@intel.com>
UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c

index bfda1e19030d2c7bb24c3391019996c1c55ce211..509be9b41757255b1beb4a7a5b03d96709bbea0a 100644 (file)
 #include <Register/Amd/Fam17Msr.h>\r
 #include <Register/Amd/Ghcb.h>\r
 \r
+/**\r
+  Perform the requested AP Creation action.\r
+\r
+  @param[in]  SaveArea         Pointer to VM save area (VMSA)\r
+  @param[in]  ApicId           APIC ID of the vCPU\r
+  @param[in]  Action           AP action to perform\r
+\r
+  @retval  TRUE   Action completed successfully\r
+  @retval  FALSE  Action did not complete successfully\r
+**/\r
+STATIC\r
+BOOLEAN\r
+SevSnpPerformApAction (\r
+  IN SEV_ES_SAVE_AREA  *SaveArea,\r
+  IN UINT32            ApicId,\r
+  IN UINTN             Action\r
+  )\r
+{\r
+  MSR_SEV_ES_GHCB_REGISTER  Msr;\r
+  GHCB                      *Ghcb;\r
+  BOOLEAN                   InterruptState;\r
+  UINT64                    ExitInfo1;\r
+  UINT64                    ExitInfo2;\r
+  UINT32                    RmpAdjustStatus;\r
+  UINT64                    VmgExitStatus;\r
+\r
+  if (Action == SVM_VMGEXIT_SNP_AP_CREATE) {\r
+    //\r
+    // To turn the page into a recognized VMSA page, issue RMPADJUST:\r
+    //   Target VMPL but numerically higher than current VMPL\r
+    //   Target PermissionMask is not used\r
+    //\r
+    RmpAdjustStatus = SevSnpRmpAdjust (\r
+                        (EFI_PHYSICAL_ADDRESS)(UINTN)SaveArea,\r
+                        TRUE\r
+                        );\r
+    if (RmpAdjustStatus != 0) {\r
+      DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed for VMSA creation\n"));\r
+      ASSERT (FALSE);\r
+\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  ExitInfo1  = (UINT64)ApicId << 32;\r
+  ExitInfo1 |= Action;\r
+  ExitInfo2  = (UINT64)(UINTN)SaveArea;\r
+\r
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
+  Ghcb                    = Msr.Ghcb;\r
+\r
+  CcExitVmgInit (Ghcb, &InterruptState);\r
+\r
+  if (Action == SVM_VMGEXIT_SNP_AP_CREATE) {\r
+    Ghcb->SaveArea.Rax = SaveArea->SevFeatures;\r
+    CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
+  }\r
+\r
+  VmgExitStatus = CcExitVmgExit (\r
+                    Ghcb,\r
+                    SVM_EXIT_SNP_AP_CREATION,\r
+                    ExitInfo1,\r
+                    ExitInfo2\r
+                    );\r
+\r
+  CcExitVmgDone (Ghcb, InterruptState);\r
+\r
+  if (VmgExitStatus != 0) {\r
+    DEBUG ((DEBUG_INFO, "SEV-SNP: AP Destroy failed\n"));\r
+    ASSERT (FALSE);\r
+\r
+    return FALSE;\r
+  }\r
+\r
+  if (Action == SVM_VMGEXIT_SNP_AP_DESTROY) {\r
+    //\r
+    // Make the current VMSA not runnable and accessible to be\r
+    // reprogrammed.\r
+    //\r
+    RmpAdjustStatus = SevSnpRmpAdjust (\r
+                        (EFI_PHYSICAL_ADDRESS)(UINTN)SaveArea,\r
+                        FALSE\r
+                        );\r
+    if (RmpAdjustStatus != 0) {\r
+      DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed for VMSA reset\n"));\r
+      ASSERT (FALSE);\r
+\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
 /**\r
   Create an SEV-SNP AP save area (VMSA) for use in running the vCPU.\r
 \r
@@ -27,27 +121,33 @@ SevSnpCreateSaveArea (
   UINT32          ApicId\r
   )\r
 {\r
-  SEV_ES_SAVE_AREA          *SaveArea;\r
-  IA32_CR0                  ApCr0;\r
-  IA32_CR0                  ResetCr0;\r
-  IA32_CR4                  ApCr4;\r
-  IA32_CR4                  ResetCr4;\r
-  UINTN                     StartIp;\r
-  UINT8                     SipiVector;\r
-  UINT32                    RmpAdjustStatus;\r
-  UINT64                    VmgExitStatus;\r
-  MSR_SEV_ES_GHCB_REGISTER  Msr;\r
-  GHCB                      *Ghcb;\r
-  BOOLEAN                   InterruptState;\r
-  UINT64                    ExitInfo1;\r
-  UINT64                    ExitInfo2;\r
+  SEV_ES_SAVE_AREA  *SaveArea;\r
+  IA32_CR0          ApCr0;\r
+  IA32_CR0          ResetCr0;\r
+  IA32_CR4          ApCr4;\r
+  IA32_CR4          ResetCr4;\r
+  UINTN             StartIp;\r
+  UINT8             SipiVector;\r
+\r
+  if (CpuData->SevEsSaveArea == NULL) {\r
+    //\r
+    // Allocate a single page for the SEV-ES Save Area and initialize it.\r
+    //\r
+    SaveArea = AllocateReservedPages (1);\r
+    if (!SaveArea) {\r
+      return;\r
+    }\r
 \r
-  //\r
-  // Allocate a single page for the SEV-ES Save Area and initialize it.\r
-  //\r
-  SaveArea = AllocateReservedPages (1);\r
-  if (!SaveArea) {\r
-    return;\r
+    CpuData->SevEsSaveArea = SaveArea;\r
+  } else {\r
+    SaveArea = CpuData->SevEsSaveArea;\r
+\r
+    //\r
+    // Tell the hypervisor to not use the current VMSA\r
+    //\r
+    if (!SevSnpPerformApAction (SaveArea, ApicId, SVM_VMGEXIT_SNP_AP_DESTROY)) {\r
+      return;\r
+    }\r
   }\r
 \r
   ZeroMem (SaveArea, EFI_PAGE_SIZE);\r
@@ -132,63 +232,7 @@ SevSnpCreateSaveArea (
   SaveArea->Vmpl        = 0;\r
   SaveArea->SevFeatures = AsmReadMsr64 (MSR_SEV_STATUS) >> 2;\r
 \r
-  //\r
-  // To turn the page into a recognized VMSA page, issue RMPADJUST:\r
-  //   Target VMPL but numerically higher than current VMPL\r
-  //   Target PermissionMask is not used\r
-  //\r
-  RmpAdjustStatus = SevSnpRmpAdjust (\r
-                      (EFI_PHYSICAL_ADDRESS)(UINTN)SaveArea,\r
-                      TRUE\r
-                      );\r
-  ASSERT (RmpAdjustStatus == 0);\r
-\r
-  ExitInfo1  = (UINT64)ApicId << 32;\r
-  ExitInfo1 |= SVM_VMGEXIT_SNP_AP_CREATE;\r
-  ExitInfo2  = (UINT64)(UINTN)SaveArea;\r
-\r
-  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
-  Ghcb                    = Msr.Ghcb;\r
-\r
-  CcExitVmgInit (Ghcb, &InterruptState);\r
-  Ghcb->SaveArea.Rax = SaveArea->SevFeatures;\r
-  CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
-  VmgExitStatus = CcExitVmgExit (\r
-                    Ghcb,\r
-                    SVM_EXIT_SNP_AP_CREATION,\r
-                    ExitInfo1,\r
-                    ExitInfo2\r
-                    );\r
-  CcExitVmgDone (Ghcb, InterruptState);\r
-\r
-  ASSERT (VmgExitStatus == 0);\r
-  if (VmgExitStatus != 0) {\r
-    RmpAdjustStatus = SevSnpRmpAdjust (\r
-                        (EFI_PHYSICAL_ADDRESS)(UINTN)SaveArea,\r
-                        FALSE\r
-                        );\r
-    if (RmpAdjustStatus == 0) {\r
-      FreePages (SaveArea, 1);\r
-    } else {\r
-      DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n"));\r
-    }\r
-\r
-    SaveArea = NULL;\r
-  }\r
-\r
-  if (CpuData->SevEsSaveArea) {\r
-    RmpAdjustStatus = SevSnpRmpAdjust (\r
-                        (EFI_PHYSICAL_ADDRESS)(UINTN)CpuData->SevEsSaveArea,\r
-                        FALSE\r
-                        );\r
-    if (RmpAdjustStatus == 0) {\r
-      FreePages (CpuData->SevEsSaveArea, 1);\r
-    } else {\r
-      DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n"));\r
-    }\r
-  }\r
-\r
-  CpuData->SevEsSaveArea = SaveArea;\r
+  SevSnpPerformApAction (SaveArea, ApicId, SVM_VMGEXIT_SNP_AP_CREATE);\r
 }\r
 \r
 /**\r