OvmfPkg/AmdSevDxe: decrypt the pages of the initial SMRAM save state map
authorLaszlo Ersek <lersek@redhat.com>
Thu, 1 Mar 2018 21:05:55 +0000 (22:05 +0100)
committerLaszlo Ersek <lersek@redhat.com>
Tue, 6 Mar 2018 12:30:38 +0000 (13:30 +0100)
Based on the following patch from Brijesh Singh <brijesh.singh@amd.com>:

  [PATCH v2 1/2] OvmfPkg/AmdSevDxe: Clear the C-bit from SMM Saved State
  http://mid.mail-archive.com/20180228161415.28723-2-brijesh.singh@amd.com
  https://lists.01.org/pipermail/edk2-devel/2018-February/022016.html

Original commit message from Brijesh:

> When OVMF is built with SMM, SMMSaved State area (SMM_DEFAULT_SMBASE +
> SMRAM_SAVE_STATE_MAP_OFFSET) contains data which need to be accessed by
> both guest and hypervisor. Since the data need to be accessed by both
> hence we must map the SMMSaved State area as unencrypted (i.e C-bit
> cleared).
>
> This patch clears the SavedStateArea address before SMBASE relocation.
> Currently, we do not clear the SavedStateArea address after SMBASE is
> relocated due to the following reasons:
>
> 1) Guest BIOS never access the relocated SavedStateArea.
>
> 2) The C-bit works on page-aligned address, but the SavedStateArea
> address is not a page-aligned. Theoretically, we could roundup the
> address and clear the C-bit of aligned address but looking carefully we
> found that some portion of the page contains code -- which will causes a
> bigger issue for the SEV guest. When SEV is enabled, all the code must
> be encrypted otherwise hardware will cause trap.

Changes by Laszlo:

- separate AmdSevDxe bits from SmmCpuFeaturesLib bits;

- spell out PcdLib dependency with #include and in LibraryClasses;

- replace (SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET) calculation
  with call to new MemEncryptSevLocateInitialSmramSaveStateMapPages()
  function;

- consequently, pass page-aligned BaseAddress to
  MemEncryptSevClearPageEncMask();

- zero the pages before clearing the C-bit;

- pass Flush=TRUE to MemEncryptSevClearPageEncMask();

- harden the treatment of MemEncryptSevClearPageEncMask() failure.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Brijesh Singh <brijesh.singh@amd.com>
Reviewed-by: Brijesh Singh <brijesh.singh@amd.com>
OvmfPkg/AmdSevDxe/AmdSevDxe.c
OvmfPkg/AmdSevDxe/AmdSevDxe.inf

index 8f02d06..c697580 100644 (file)
 \r
 **/\r
 \r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/DxeServicesTableLib.h>\r
 #include <Library/MemEncryptSevLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
+#include <Library/PcdLib.h>\r
 \r
 EFI_STATUS\r
 EFIAPI\r
@@ -68,5 +71,55 @@ AmdSevDxeEntryPoint (
     FreePool (AllDescMap);\r
   }\r
 \r
+  //\r
+  // When SMM is enabled, clear the C-bit from SMM Saved State Area\r
+  //\r
+  // NOTES: The SavedStateArea address cleared here is before SMBASE\r
+  // relocation. Currently, we do not clear the SavedStateArea address after\r
+  // SMBASE is relocated due to the following reasons:\r
+  //\r
+  // 1) Guest BIOS never access the relocated SavedStateArea.\r
+  //\r
+  // 2) The C-bit works on page-aligned address, but the SavedStateArea\r
+  // address is not a page-aligned. Theoretically, we could roundup the address\r
+  // and clear the C-bit of aligned address but looking carefully we found\r
+  // that some portion of the page contains code -- which will causes a bigger\r
+  // issues for SEV guest. When SEV is enabled, all the code must be encrypted\r
+  // otherwise hardware will cause trap.\r
+  //\r
+  // We restore the C-bit for this SMM Saved State Area after SMBASE relocation\r
+  // is completed (See OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c).\r
+  //\r
+  if (FeaturePcdGet (PcdSmmSmramRequire)) {\r
+    UINTN MapPagesBase;\r
+    UINTN MapPagesCount;\r
+\r
+    Status = MemEncryptSevLocateInitialSmramSaveStateMapPages (\r
+               &MapPagesBase,\r
+               &MapPagesCount\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    //\r
+    // Although these pages were set aside (i.e., allocated) by PlatformPei, we\r
+    // could be after a warm reboot from the OS. Don't leak any stale OS data\r
+    // to the hypervisor.\r
+    //\r
+    ZeroMem ((VOID *)MapPagesBase, EFI_PAGES_TO_SIZE (MapPagesCount));\r
+\r
+    Status = MemEncryptSevClearPageEncMask (\r
+               0,             // Cr3BaseAddress -- use current CR3\r
+               MapPagesBase,  // BaseAddress\r
+               MapPagesCount, // NumPages\r
+               TRUE           // Flush\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "%a: MemEncryptSevClearPageEncMask(): %r\n",\r
+        __FUNCTION__, Status));\r
+      ASSERT (FALSE);\r
+      CpuDeadLoop ();\r
+    }\r
+  }\r
+\r
   return EFI_SUCCESS;\r
 }\r
index 3aff7e2..b7e7da0 100644 (file)
   OvmfPkg/OvmfPkg.dec\r
 \r
 [LibraryClasses]\r
+  BaseLib\r
+  BaseMemoryLib\r
   DebugLib\r
   DxeServicesTableLib\r
   MemEncryptSevLib\r
   MemoryAllocationLib\r
+  PcdLib\r
   UefiDriverEntryPoint\r
 \r
 [Depex]\r
   TRUE\r
+\r
+[FeaturePcd]\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire\r