]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/PlatformPei/AmdSev.c
OvmfPkg/PlatformPei: SEV-SNP make >=4GB unaccepted
[mirror_edk2.git] / OvmfPkg / PlatformPei / AmdSev.c
index c60a153a059e044acd64cf822777d8461939330f..e6b602d79a05173fe5472865902765dc095374ce 100644 (file)
 #include <Library/MemEncryptSevLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
 #include <Library/PcdLib.h>\r
+#include <Pi/PrePiHob.h>\r
 #include <PiPei.h>\r
 #include <Register/Amd/Msr.h>\r
 #include <Register/Intel/SmramSaveStateMap.h>\r
-#include <Library/VmgExitLib.h>\r
+#include <Library/CcExitLib.h>\r
 #include <ConfidentialComputingGuestAttr.h>\r
 \r
 #include "Platform.h"\r
 \r
+STATIC\r
+UINT64\r
+GetHypervisorFeature (\r
+  VOID\r
+  );\r
+\r
 /**\r
   Initialize SEV-SNP support if running as an SEV-SNP guest.\r
 \r
@@ -36,11 +43,21 @@ AmdSevSnpInitialize (
 {\r
   EFI_PEI_HOB_POINTERS         Hob;\r
   EFI_HOB_RESOURCE_DESCRIPTOR  *ResourceHob;\r
+  UINT64                       HvFeatures;\r
+  EFI_STATUS                   PcdStatus;\r
 \r
   if (!MemEncryptSevSnpIsEnabled ()) {\r
     return;\r
   }\r
 \r
+  //\r
+  // Query the hypervisor feature using the CcExitVmgExit and set the value in the\r
+  // hypervisor features PCD.\r
+  //\r
+  HvFeatures = GetHypervisorFeature ();\r
+  PcdStatus  = PcdSet64S (PcdGhcbHypervisorFeatures, HvFeatures);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
   //\r
   // Iterate through the system RAM and validate it.\r
   //\r
@@ -49,6 +66,11 @@ AmdSevSnpInitialize (
       ResourceHob = Hob.ResourceDescriptor;\r
 \r
       if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {\r
+        if (ResourceHob->PhysicalStart >= SIZE_4GB) {\r
+          ResourceHob->ResourceType = BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED;\r
+          continue;\r
+        }\r
+\r
         MemEncryptSevSnpPreValidateSystemRam (\r
           ResourceHob->PhysicalStart,\r
           EFI_SIZE_TO_PAGES ((UINTN)ResourceHob->ResourceLength)\r
@@ -91,6 +113,45 @@ SevEsProtocolFailure (
   CpuDeadLoop ();\r
 }\r
 \r
+/**\r
+ Get the hypervisor features bitmap\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+GetHypervisorFeature (\r
+  VOID\r
+  )\r
+{\r
+  UINT64                    Status;\r
+  GHCB                      *Ghcb;\r
+  MSR_SEV_ES_GHCB_REGISTER  Msr;\r
+  BOOLEAN                   InterruptState;\r
+  UINT64                    Features;\r
+\r
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
+  Ghcb                    = Msr.Ghcb;\r
+\r
+  //\r
+  // Initialize the GHCB\r
+  //\r
+  CcExitVmgInit (Ghcb, &InterruptState);\r
+\r
+  //\r
+  // Query the Hypervisor Features.\r
+  //\r
+  Status = CcExitVmgExit (Ghcb, SVM_EXIT_HYPERVISOR_FEATURES, 0, 0);\r
+  if ((Status != 0)) {\r
+    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);\r
+  }\r
+\r
+  Features = Ghcb->SaveArea.SwExitInfo2;\r
+\r
+  CcExitVmgDone (Ghcb, InterruptState);\r
+\r
+  return Features;\r
+}\r
+\r
 /**\r
 \r
   This function can be used to register the GHCB GPA.\r
@@ -146,7 +207,7 @@ GhcbRegister (
 STATIC\r
 VOID\r
 AmdSevEsInitialize (\r
-  VOID\r
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob\r
   )\r
 {\r
   UINT8                *GhcbBase;\r
@@ -157,7 +218,7 @@ AmdSevEsInitialize (
   UINTN                GhcbBackupPageCount;\r
   SEV_ES_PER_CPU_DATA  *SevEsData;\r
   UINTN                PageCount;\r
-  RETURN_STATUS        PcdStatus, DecryptStatus;\r
+  RETURN_STATUS        Status;\r
   IA32_DESCRIPTOR      Gdtr;\r
   VOID                 *Gdt;\r
 \r
@@ -165,15 +226,15 @@ AmdSevEsInitialize (
     return;\r
   }\r
 \r
-  PcdStatus = PcdSetBoolS (PcdSevEsIsEnabled, TRUE);\r
-  ASSERT_RETURN_ERROR (PcdStatus);\r
+  Status = PcdSetBoolS (PcdSevEsIsEnabled, TRUE);\r
+  ASSERT_RETURN_ERROR (Status);\r
 \r
   //\r
   // Allocate GHCB and per-CPU variable pages.\r
   //   Since the pages must survive across the UEFI to OS transition\r
   //   make them reserved.\r
   //\r
-  GhcbPageCount = mMaxCpuCount * 2;\r
+  GhcbPageCount = PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber * 2;\r
   GhcbBase      = AllocateReservedPages (GhcbPageCount);\r
   ASSERT (GhcbBase != NULL);\r
 \r
@@ -185,20 +246,20 @@ AmdSevEsInitialize (
   // only clear the encryption mask for the GHCB pages.\r
   //\r
   for (PageCount = 0; PageCount < GhcbPageCount; PageCount += 2) {\r
-    DecryptStatus = MemEncryptSevClearPageEncMask (\r
-                      0,\r
-                      GhcbBasePa + EFI_PAGES_TO_SIZE (PageCount),\r
-                      1\r
-                      );\r
-    ASSERT_RETURN_ERROR (DecryptStatus);\r
+    Status = MemEncryptSevClearPageEncMask (\r
+               0,\r
+               GhcbBasePa + EFI_PAGES_TO_SIZE (PageCount),\r
+               1\r
+               );\r
+    ASSERT_RETURN_ERROR (Status);\r
   }\r
 \r
   ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));\r
 \r
-  PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);\r
-  ASSERT_RETURN_ERROR (PcdStatus);\r
-  PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));\r
-  ASSERT_RETURN_ERROR (PcdStatus);\r
+  Status = PcdSet64S (PcdGhcbBase, GhcbBasePa);\r
+  ASSERT_RETURN_ERROR (Status);\r
+  Status = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));\r
+  ASSERT_RETURN_ERROR (Status);\r
 \r
   DEBUG ((\r
     DEBUG_INFO,\r
@@ -211,7 +272,7 @@ AmdSevEsInitialize (
   // Allocate #VC recursion backup pages. The number of backup pages needed is\r
   // one less than the maximum VC count.\r
   //\r
-  GhcbBackupPageCount = mMaxCpuCount * (VMGEXIT_MAXIMUM_VC_COUNT - 1);\r
+  GhcbBackupPageCount = PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber * (VMGEXIT_MAXIMUM_VC_COUNT - 1);\r
   GhcbBackupBase      = AllocatePages (GhcbBackupPageCount);\r
   ASSERT (GhcbBackupBase != NULL);\r
 \r
@@ -240,6 +301,20 @@ AmdSevEsInitialize (
 \r
   AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);\r
 \r
+  //\r
+  // Now that the PEI GHCB is set up, the SEC GHCB page is no longer necessary\r
+  // to keep shared. Later, it is exposed to the OS as EfiConventionalMemory, so\r
+  // it needs to be marked private. The size of the region is hardcoded in\r
+  // OvmfPkg/ResetVector/ResetVector.nasmb in the definition of\r
+  // SNP_SEC_MEM_BASE_DESC_2.\r
+  //\r
+  Status = MemEncryptSevSetPageEncMask (\r
+             0,                                  // Cr3 -- use system Cr3\r
+             FixedPcdGet32 (PcdOvmfSecGhcbBase), // BaseAddress\r
+             1                                   // NumPages\r
+             );\r
+  ASSERT_RETURN_ERROR (Status);\r
+\r
   //\r
   // The SEV support will clear the C-bit from non-RAM areas.  The early GDT\r
   // lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT\r
@@ -265,7 +340,7 @@ AmdSevEsInitialize (
   **/\r
 VOID\r
 AmdSevInitialize (\r
-  VOID\r
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob\r
   )\r
 {\r
   UINT64         EncryptionMask;\r
@@ -312,7 +387,7 @@ AmdSevInitialize (
   // until after re-encryption, in order to prevent an information leak to the\r
   // hypervisor.\r
   //\r
-  if (FeaturePcdGet (PcdSmmSmramRequire) && (mBootMode != BOOT_ON_S3_RESUME)) {\r
+  if (PlatformInfoHob->SmmSmramRequire && (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME)) {\r
     RETURN_STATUS  LocateMapStatus;\r
     UINTN          MapPagesBase;\r
     UINTN          MapPagesCount;\r
@@ -323,7 +398,7 @@ AmdSevInitialize (
                         );\r
     ASSERT_RETURN_ERROR (LocateMapStatus);\r
 \r
-    if (mQ35SmramAtDefaultSmbase) {\r
+    if (PlatformInfoHob->Q35SmramAtDefaultSmbase) {\r
       //\r
       // The initial SMRAM Save State Map has been covered as part of a larger\r
       // reserved memory allocation in InitializeRamRegions().\r
@@ -345,7 +420,7 @@ AmdSevInitialize (
   //\r
   // Check and perform SEV-ES initialization if required.\r
   //\r
-  AmdSevEsInitialize ();\r
+  AmdSevEsInitialize (PlatformInfoHob);\r
 \r
   //\r
   // Set the Confidential computing attr PCD to communicate which SEV\r
@@ -361,3 +436,34 @@ AmdSevInitialize (
 \r
   ASSERT_RETURN_ERROR (PcdStatus);\r
 }\r
+\r
+/**\r
+ The function performs SEV specific region initialization.\r
+\r
+ **/\r
+VOID\r
+SevInitializeRam (\r
+  VOID\r
+  )\r
+{\r
+  if (MemEncryptSevSnpIsEnabled ()) {\r
+    //\r
+    // If SEV-SNP is enabled, reserve the Secrets and CPUID memory area.\r
+    //\r
+    // This memory range is given to the PSP by the hypervisor to populate\r
+    // the information used during the SNP VM boots, and it need to persist\r
+    // across the kexec boots. Mark it as EfiReservedMemoryType so that\r
+    // the guest firmware and OS does not use it as a system memory.\r
+    //\r
+    BuildMemoryAllocationHob (\r
+      (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSnpSecretsBase),\r
+      (UINT64)(UINTN)PcdGet32 (PcdOvmfSnpSecretsSize),\r
+      EfiReservedMemoryType\r
+      );\r
+    BuildMemoryAllocationHob (\r
+      (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfCpuidBase),\r
+      (UINT64)(UINTN)PcdGet32 (PcdOvmfCpuidSize),\r
+      EfiReservedMemoryType\r
+      );\r
+  }\r
+}\r