]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/MemEncryptSevLib: add support to validate system RAM
authorBrijesh Singh via groups.io <brijesh.singh=amd.com@groups.io>
Thu, 9 Dec 2021 03:27:42 +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

Many of the integrity guarantees of SEV-SNP are enforced through the
Reverse Map Table (RMP). Each RMP entry contains the GPA at which a
particular page of DRAM should be mapped. The guest can request the
hypervisor to add pages in the RMP table via the Page State Change VMGEXIT
defined in the GHCB specification section 2.5.1 and 4.1.6. Inside each RMP
entry is a Validated flag; this flag is automatically cleared to 0 by the
CPU hardware when a new RMP entry is created for a guest. Each VM page
can be either validated or invalidated, as indicated by the Validated
flag in the RMP entry. Memory access to a private page that is not
validated generates a #VC. A VM can use the PVALIDATE instruction to
validate the private page before using it.

During the guest creation, the boot ROM memory is pre-validated by the
AMD-SEV firmware. The MemEncryptSevSnpValidateSystemRam() can be called
during the SEC and PEI phase to validate the detected system RAM.

One of the fields in the Page State Change NAE is the RMP page size. The
page size input parameter indicates that either a 4KB or 2MB page should
be used while adding the RMP entry. During the validation, when possible,
the MemEncryptSevSnpValidateSystemRam() will use the 2MB entry. A
hypervisor backing the memory may choose to use the different page size
in the RMP entry. In those cases, the PVALIDATE instruction should return
SIZEMISMATCH. If a SIZEMISMATCH is detected, then validate all 512-pages
constituting a 2MB region.

Upon completion, the PVALIDATE instruction sets the rFLAGS.CF to 0 if
instruction changed the RMP entry and to 1 if the instruction did not
change the RMP entry. The rFlags.CF will be 1 only when a memory region
is already validated. We should not double validate a memory
as it could lead to a security compromise. If double validation is
detected, terminate the boot.

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>
Acked-by: Jiewen Yao <Jiewen.yao@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
12 files changed:
OvmfPkg/Include/Library/MemEncryptSevLib.h
OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c
OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf
OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValidate.c [new file with mode: 0644]
OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c [new file with mode: 0644]
OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c [new file with mode: 0644]
OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h [new file with mode: 0644]
OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c [new file with mode: 0644]
OvmfPkg/OvmfPkgIa32.dsc
OvmfPkg/OvmfPkgIa32X64.dsc

index 3c77d71df754c9605c77500f34da3e87fbba8156..4fa9c0d7008391f0680d1f23885e5aff0d806fb8 100644 (file)
@@ -214,4 +214,18 @@ MemEncryptSevClearMmioPageEncMask (
   IN UINTN             NumPages\r
   );\r
 \r
   IN UINTN             NumPages\r
   );\r
 \r
+/**\r
+  Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.\r
+\r
+  @param[in]  BaseAddress             Base address\r
+  @param[in]  NumPages                Number of pages starting from the base address\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MemEncryptSevSnpPreValidateSystemRam (\r
+  IN PHYSICAL_ADDRESS  BaseAddress,\r
+  IN UINTN             NumPages\r
+  );\r
+\r
 #endif // _MEM_ENCRYPT_SEV_LIB_H_\r
 #endif // _MEM_ENCRYPT_SEV_LIB_H_\r
index f2e162d68076b28ed7946f2830a97e37062bf532..f613bb314f5ff350cb989d3e85e646d52d661568 100644 (file)
   PeiDxeMemEncryptSevLibInternal.c\r
 \r
 [Sources.X64]\r
   PeiDxeMemEncryptSevLibInternal.c\r
 \r
 [Sources.X64]\r
+  X64/DxeSnpSystemRamValidate.c\r
   X64/MemEncryptSevLib.c\r
   X64/PeiDxeVirtualMemory.c\r
   X64/MemEncryptSevLib.c\r
   X64/PeiDxeVirtualMemory.c\r
+  X64/SnpPageStateChangeInternal.c\r
   X64/VirtualMemory.c\r
   X64/VirtualMemory.h\r
 \r
   X64/VirtualMemory.c\r
   X64/VirtualMemory.h\r
 \r
@@ -49,6 +51,7 @@
   DebugLib\r
   MemoryAllocationLib\r
   PcdLib\r
   DebugLib\r
   MemoryAllocationLib\r
   PcdLib\r
+  VmgExitLib\r
 \r
 [FeaturePcd]\r
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire\r
 \r
 [FeaturePcd]\r
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire\r
index 9bd66301fc08d9b3b43f7ead82c6b9971fa0eb87..f92299fc773b689aed277c8efb8cf2cf1ba1d869 100644 (file)
@@ -136,3 +136,20 @@ MemEncryptSevClearMmioPageEncMask (
   //\r
   return RETURN_UNSUPPORTED;\r
 }\r
   //\r
   return RETURN_UNSUPPORTED;\r
 }\r
+\r
+/**\r
+  Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.\r
+\r
+  @param[in]  BaseAddress             Base address\r
+  @param[in]  NumPages                Number of pages starting from the base address\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MemEncryptSevSnpPreValidateSystemRam (\r
+  IN PHYSICAL_ADDRESS  BaseAddress,\r
+  IN UINTN             NumPages\r
+  )\r
+{\r
+  ASSERT (FALSE);\r
+}\r
index 03a78c32df280c45f9bb2a888eec95e3dc124ee9..0402e49a1028c9fd39ba142d73e1c016ceb4c1fe 100644 (file)
@@ -36,6 +36,8 @@
 [Sources.X64]\r
   X64/MemEncryptSevLib.c\r
   X64/PeiDxeVirtualMemory.c\r
 [Sources.X64]\r
   X64/MemEncryptSevLib.c\r
   X64/PeiDxeVirtualMemory.c\r
+  X64/PeiSnpSystemRamValidate.c\r
+  X64/SnpPageStateChangeInternal.c\r
   X64/VirtualMemory.c\r
   X64/VirtualMemory.h\r
 \r
   X64/VirtualMemory.c\r
   X64/VirtualMemory.h\r
 \r
@@ -49,6 +51,7 @@
   DebugLib\r
   MemoryAllocationLib\r
   PcdLib\r
   DebugLib\r
   MemoryAllocationLib\r
   PcdLib\r
+  VmgExitLib\r
 \r
 [FeaturePcd]\r
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire\r
 \r
 [FeaturePcd]\r
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire\r
index 279c38bfbc2c9212a300b3e4b4cd69141364bc77..939af0a91ea4c41907a0d8c92b5d7c34be536e9d 100644 (file)
@@ -35,6 +35,8 @@
 [Sources.X64]\r
   X64/MemEncryptSevLib.c\r
   X64/SecVirtualMemory.c\r
 [Sources.X64]\r
   X64/MemEncryptSevLib.c\r
   X64/SecVirtualMemory.c\r
+  X64/SecSnpSystemRamValidate.c\r
+  X64/SnpPageStateChangeInternal.c\r
   X64/VirtualMemory.c\r
   X64/VirtualMemory.h\r
 \r
   X64/VirtualMemory.c\r
   X64/VirtualMemory.h\r
 \r
@@ -46,6 +48,7 @@
   CpuLib\r
   DebugLib\r
   PcdLib\r
   CpuLib\r
   DebugLib\r
   PcdLib\r
+  VmgExitLib\r
 \r
 [FixedPcd]\r
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase\r
 \r
 [FixedPcd]\r
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase\r
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValidate.c
new file mode 100644 (file)
index 0000000..d3a95e4
--- /dev/null
@@ -0,0 +1,40 @@
+/** @file\r
+\r
+  SEV-SNP Page Validation functions.\r
+\r
+  Copyright (c) 2021 AMD Incorporated. All rights reserved.<BR>\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Uefi/UefiBaseType.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemEncryptSevLib.h>\r
+\r
+#include "SnpPageStateChange.h"\r
+\r
+/**\r
+  Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.\r
+\r
+  @param[in]  BaseAddress             Base address\r
+  @param[in]  NumPages                Number of pages starting from the base address\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MemEncryptSevSnpPreValidateSystemRam (\r
+  IN PHYSICAL_ADDRESS  BaseAddress,\r
+  IN UINTN             NumPages\r
+  )\r
+{\r
+  if (!MemEncryptSevSnpIsEnabled ()) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // All the pre-validation must be completed in the PEI phase.\r
+  //\r
+  ASSERT (FALSE);\r
+}\r
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
new file mode 100644 (file)
index 0000000..bc891c2
--- /dev/null
@@ -0,0 +1,36 @@
+/** @file\r
+\r
+  SEV-SNP Page Validation functions.\r
+\r
+  Copyright (c) 2021 AMD Incorporated. All rights reserved.<BR>\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Uefi/UefiBaseType.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemEncryptSevLib.h>\r
+\r
+#include "SnpPageStateChange.h"\r
+\r
+/**\r
+  Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.\r
+\r
+  @param[in]  BaseAddress             Base address\r
+  @param[in]  NumPages                Number of pages starting from the base address\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MemEncryptSevSnpPreValidateSystemRam (\r
+  IN PHYSICAL_ADDRESS  BaseAddress,\r
+  IN UINTN             NumPages\r
+  )\r
+{\r
+  if (!MemEncryptSevSnpIsEnabled ()) {\r
+    return;\r
+  }\r
+\r
+  InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);\r
+}\r
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c
new file mode 100644 (file)
index 0000000..bc891c2
--- /dev/null
@@ -0,0 +1,36 @@
+/** @file\r
+\r
+  SEV-SNP Page Validation functions.\r
+\r
+  Copyright (c) 2021 AMD Incorporated. All rights reserved.<BR>\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Uefi/UefiBaseType.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemEncryptSevLib.h>\r
+\r
+#include "SnpPageStateChange.h"\r
+\r
+/**\r
+  Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.\r
+\r
+  @param[in]  BaseAddress             Base address\r
+  @param[in]  NumPages                Number of pages starting from the base address\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MemEncryptSevSnpPreValidateSystemRam (\r
+  IN PHYSICAL_ADDRESS  BaseAddress,\r
+  IN UINTN             NumPages\r
+  )\r
+{\r
+  if (!MemEncryptSevSnpIsEnabled ()) {\r
+    return;\r
+  }\r
+\r
+  InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);\r
+}\r
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h
new file mode 100644 (file)
index 0000000..b396f0f
--- /dev/null
@@ -0,0 +1,30 @@
+/** @file\r
+\r
+  SEV-SNP Page Validation functions.\r
+\r
+  Copyright (c) 2021 AMD Incorporated. All rights reserved.<BR>\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef SNP_PAGE_STATE_INTERNAL_H_\r
+#define SNP_PAGE_STATE_INTERNAL_H_\r
+\r
+//\r
+// SEV-SNP Page states\r
+//\r
+typedef enum {\r
+  SevSnpPagePrivate,\r
+  SevSnpPageShared,\r
+} SEV_SNP_PAGE_STATE;\r
+\r
+VOID\r
+InternalSetPageState (\r
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
+  IN UINTN                 NumPages,\r
+  IN SEV_SNP_PAGE_STATE    State,\r
+  IN BOOLEAN               UseLargeEntry\r
+  );\r
+\r
+#endif\r
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c
new file mode 100644 (file)
index 0000000..9c552ef
--- /dev/null
@@ -0,0 +1,301 @@
+/** @file\r
+\r
+  SEV-SNP Page Validation functions.\r
+\r
+  Copyright (c) 2021 AMD Incorporated. All rights reserved.<BR>\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Uefi/UefiBaseType.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemEncryptSevLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/VmgExitLib.h>\r
+\r
+#include <Register/Amd/Ghcb.h>\r
+#include <Register/Amd/Msr.h>\r
+\r
+#include "SnpPageStateChange.h"\r
+\r
+#define IS_ALIGNED(x, y)  ((((x) & (y - 1)) == 0))\r
+#define PAGES_PER_LARGE_ENTRY  512\r
+\r
+STATIC\r
+UINTN\r
+MemoryStateToGhcbOp (\r
+  IN SEV_SNP_PAGE_STATE  State\r
+  )\r
+{\r
+  UINTN  Cmd;\r
+\r
+  switch (State) {\r
+    case SevSnpPageShared: Cmd = SNP_PAGE_STATE_SHARED;\r
+      break;\r
+    case SevSnpPagePrivate: Cmd = SNP_PAGE_STATE_PRIVATE;\r
+      break;\r
+    default: ASSERT (0);\r
+  }\r
+\r
+  return Cmd;\r
+}\r
+\r
+STATIC\r
+VOID\r
+SnpPageStateFailureTerminate (\r
+  VOID\r
+  )\r
+{\r
+  MSR_SEV_ES_GHCB_REGISTER  Msr;\r
+\r
+  //\r
+  // Use the GHCB MSR Protocol to request termination by the hypervisor\r
+  //\r
+  Msr.GhcbPhysicalAddress         = 0;\r
+  Msr.GhcbTerminate.Function      = GHCB_INFO_TERMINATE_REQUEST;\r
+  Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;\r
+  Msr.GhcbTerminate.ReasonCode    = GHCB_TERMINATE_GHCB_GENERAL;\r
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);\r
+\r
+  AsmVmgExit ();\r
+\r
+  ASSERT (FALSE);\r
+  CpuDeadLoop ();\r
+}\r
+\r
+/**\r
+ This function issues the PVALIDATE instruction to validate or invalidate the memory\r
+ range specified. If PVALIDATE returns size mismatch then it retry validating with\r
+ smaller page size.\r
+\r
+ */\r
+STATIC\r
+VOID\r
+PvalidateRange (\r
+  IN  SNP_PAGE_STATE_CHANGE_INFO  *Info,\r
+  IN  UINTN                       StartIndex,\r
+  IN  UINTN                       EndIndex,\r
+  IN  BOOLEAN                     Validate\r
+  )\r
+{\r
+  UINTN  Address, RmpPageSize, Ret, i;\r
+\r
+  for ( ; StartIndex <= EndIndex; StartIndex++) {\r
+    //\r
+    // Get the address and the page size from the Info.\r
+    //\r
+    Address     = Info->Entry[StartIndex].GuestFrameNumber << EFI_PAGE_SHIFT;\r
+    RmpPageSize = Info->Entry[StartIndex].PageSize;\r
+\r
+    Ret = AsmPvalidate (RmpPageSize, Validate, Address);\r
+\r
+    //\r
+    // If we fail to validate due to size mismatch then try with the\r
+    // smaller page size. This senario will occur if the backing page in\r
+    // the RMP entry is 4K and we are validating it as a 2MB.\r
+    //\r
+    if ((Ret == PVALIDATE_RET_SIZE_MISMATCH) && (RmpPageSize == PvalidatePageSize2MB)) {\r
+      for (i = 0; i < PAGES_PER_LARGE_ENTRY; i++) {\r
+        Ret = AsmPvalidate (PvalidatePageSize4K, Validate, Address);\r
+        if (Ret) {\r
+          break;\r
+        }\r
+\r
+        Address = Address + EFI_PAGE_SIZE;\r
+      }\r
+    }\r
+\r
+    //\r
+    // If validation failed then do not continue.\r
+    //\r
+    if (Ret) {\r
+      DEBUG ((\r
+        DEBUG_ERROR,\r
+        "%a:%a: Failed to %a address 0x%Lx Error code %d\n",\r
+        gEfiCallerBaseName,\r
+        __FUNCTION__,\r
+        Validate ? "Validate" : "Invalidate",\r
+        Address,\r
+        Ret\r
+        ));\r
+      SnpPageStateFailureTerminate ();\r
+    }\r
+  }\r
+}\r
+\r
+STATIC\r
+EFI_PHYSICAL_ADDRESS\r
+BuildPageStateBuffer (\r
+  IN EFI_PHYSICAL_ADDRESS        BaseAddress,\r
+  IN EFI_PHYSICAL_ADDRESS        EndAddress,\r
+  IN SEV_SNP_PAGE_STATE          State,\r
+  IN BOOLEAN                     UseLargeEntry,\r
+  IN SNP_PAGE_STATE_CHANGE_INFO  *Info\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS  NextAddress;\r
+  UINTN                 i, RmpPageSize;\r
+\r
+  // Clear the page state structure\r
+  SetMem (Info, sizeof (*Info), 0);\r
+\r
+  i           = 0;\r
+  NextAddress = EndAddress;\r
+\r
+  //\r
+  // Populate the page state entry structure\r
+  //\r
+  while ((BaseAddress < EndAddress) && (i < SNP_PAGE_STATE_MAX_ENTRY)) {\r
+    //\r
+    // Is this a 2MB aligned page? Check if we can use the Large RMP entry.\r
+    //\r
+    if (UseLargeEntry && IS_ALIGNED (BaseAddress, SIZE_2MB) &&\r
+        ((EndAddress - BaseAddress) >= SIZE_2MB))\r
+    {\r
+      RmpPageSize = PvalidatePageSize2MB;\r
+      NextAddress = BaseAddress + SIZE_2MB;\r
+    } else {\r
+      RmpPageSize = PvalidatePageSize4K;\r
+      NextAddress = BaseAddress + EFI_PAGE_SIZE;\r
+    }\r
+\r
+    Info->Entry[i].GuestFrameNumber = BaseAddress >> EFI_PAGE_SHIFT;\r
+    Info->Entry[i].PageSize         = RmpPageSize;\r
+    Info->Entry[i].Operation        = MemoryStateToGhcbOp (State);\r
+    Info->Entry[i].CurrentPage      = 0;\r
+    Info->Header.EndEntry           = (UINT16)i;\r
+\r
+    BaseAddress = NextAddress;\r
+    i++;\r
+  }\r
+\r
+  return NextAddress;\r
+}\r
+\r
+STATIC\r
+VOID\r
+PageStateChangeVmgExit (\r
+  IN GHCB                        *Ghcb,\r
+  IN SNP_PAGE_STATE_CHANGE_INFO  *Info\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // As per the GHCB specification, the hypervisor can resume the guest before\r
+  // processing all the entries. Checks whether all the entries are processed.\r
+  //\r
+  // The stragtegy here is to wait for the hypervisor to change the page\r
+  // state in the RMP table before guest access the memory pages. If the\r
+  // page state was not successful, then later memory access will result\r
+  // in the crash.\r
+  //\r
+  while (Info->Header.CurrentEntry <= Info->Header.EndEntry) {\r
+    Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
+    VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
+\r
+    Status = VmgExit (Ghcb, SVM_EXIT_SNP_PAGE_STATE_CHANGE, 0, 0);\r
+\r
+    //\r
+    // The Page State Change VMGEXIT can pass the failure through the\r
+    // ExitInfo2. Lets check both the return value as well as ExitInfo2.\r
+    //\r
+    if ((Status != 0) || (Ghcb->SaveArea.SwExitInfo2)) {\r
+      SnpPageStateFailureTerminate ();\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ The function is used to set the page state when SEV-SNP is active. The page state\r
+ transition consist of changing the page ownership in the RMP table, and using the\r
+ PVALIDATE instruction to update the Validated bit in RMP table.\r
+\r
+ When the UseLargeEntry is set to TRUE, then function will try to use the large RMP\r
+ entry (whevever possible).\r
+ */\r
+VOID\r
+InternalSetPageState (\r
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
+  IN UINTN                 NumPages,\r
+  IN SEV_SNP_PAGE_STATE    State,\r
+  IN BOOLEAN               UseLargeEntry\r
+  )\r
+{\r
+  GHCB                        *Ghcb;\r
+  EFI_PHYSICAL_ADDRESS        NextAddress, EndAddress;\r
+  MSR_SEV_ES_GHCB_REGISTER    Msr;\r
+  BOOLEAN                     InterruptState;\r
+  SNP_PAGE_STATE_CHANGE_INFO  *Info;\r
+\r
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
+  Ghcb                    = Msr.Ghcb;\r
+\r
+  EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages);\r
+\r
+  DEBUG ((\r
+    DEBUG_VERBOSE,\r
+    "%a:%a Address 0x%Lx - 0x%Lx State = %a LargeEntry = %d\n",\r
+    gEfiCallerBaseName,\r
+    __FUNCTION__,\r
+    BaseAddress,\r
+    EndAddress,\r
+    State == SevSnpPageShared ? "Shared" : "Private",\r
+    UseLargeEntry\r
+    ));\r
+\r
+  while (BaseAddress < EndAddress) {\r
+    UINTN  CurrentEntry, EndEntry;\r
+\r
+    //\r
+    // Initialize the GHCB\r
+    //\r
+    VmgInit (Ghcb, &InterruptState);\r
+\r
+    //\r
+    // Build the page state structure\r
+    //\r
+    Info        = (SNP_PAGE_STATE_CHANGE_INFO *)Ghcb->SharedBuffer;\r
+    NextAddress = BuildPageStateBuffer (\r
+                    BaseAddress,\r
+                    EndAddress,\r
+                    State,\r
+                    UseLargeEntry,\r
+                    Info\r
+                    );\r
+\r
+    //\r
+    // Save the current and end entry from the page state structure. We need\r
+    // it later.\r
+    //\r
+    CurrentEntry = Info->Header.CurrentEntry;\r
+    EndEntry     = Info->Header.EndEntry;\r
+\r
+    //\r
+    // If the caller requested to change the page state to shared then\r
+    // invalidate the pages before making the page shared in the RMP table.\r
+    //\r
+    if (State == SevSnpPageShared) {\r
+      PvalidateRange (Info, CurrentEntry, EndEntry, FALSE);\r
+    }\r
+\r
+    //\r
+    // Invoke the page state change VMGEXIT.\r
+    //\r
+    PageStateChangeVmgExit (Ghcb, Info);\r
+\r
+    //\r
+    // If the caller requested to change the page state to private then\r
+    // validate the pages after it has been added in the RMP table.\r
+    //\r
+    if (State == SevSnpPagePrivate) {\r
+      PvalidateRange (Info, CurrentEntry, EndEntry, TRUE);\r
+    }\r
+\r
+    VmgDone (Ghcb, InterruptState);\r
+\r
+    BaseAddress = NextAddress;\r
+  }\r
+}\r
index 6a5be97c059d1c65d210944aab51432288bc6251..1dc069e424200a14fadb1a694352622b6fe213a1 100644 (file)
 !else\r
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf\r
 !endif\r
 !else\r
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf\r
 !endif\r
+  MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf\r
 \r
 [LibraryClasses.common.PEI_CORE]\r
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r
 \r
 [LibraryClasses.common.PEI_CORE]\r
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r
index 13d9a1f111bcc0b089e6cf83b84c7e04b937a0e8..a766457e6bc622dcfb3655dfd82693d50bcc285a 100644 (file)
 !else\r
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf\r
 !endif\r
 !else\r
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf\r
 !endif\r
+  MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf\r
 \r
 [LibraryClasses.common.PEI_CORE]\r
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r
 \r
 [LibraryClasses.common.PEI_CORE]\r
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r