[edk2-devel] [RFC PATCH v3 28/43] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase

Lendacky, Thomas posted 43 patches 6 years, 2 months ago
There is a newer version of this series
[edk2-devel] [RFC PATCH v3 28/43] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
Posted by Lendacky, Thomas 6 years, 2 months ago
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198

Allocate memory for the GHCB pages and the per-CPU variable pages during
SEV initialization for use during Pei and Dxe phases. The GHCB page(s)
must be shared pages, so clear the encryption mask from the current page
table entries. Upon successful allocation, set the GHCB PCDs (PcdGhcbBase
and PcdGhcbSize).

The per-CPU variable page needs to be unique per AP. Using the page after
the GHCB ensures that it is unique per AP. But, it also ends up being
marked shared/unencrypted when it doesn't need to be. It is possible
during PEI to mark only the GHCB pages as shared (and that is done), but
DXE is not as easy. There needs to be a way to change the pagetables
created for DXE using CreateIdentityMappingPageTables() before switching
to them.

The GHCB pages (one per vCPU) will be used by the PEI and DXE #VC
exception handlers. The #VC exception handler will fill in the necessary
fields of the GHCB and exit to the hypervisor using the VMGEXIT
instruction. The hypervisor then accesses the GHCB associated with the
vCPU in order to perform the requested function.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/OvmfPkgIa32.dsc             |  2 ++
 OvmfPkg/OvmfPkgIa32X64.dsc          |  2 ++
 OvmfPkg/OvmfPkgX64.dsc              |  2 ++
 OvmfPkg/PlatformPei/PlatformPei.inf |  2 ++
 OvmfPkg/PlatformPei/AmdSev.c        | 38 ++++++++++++++++++++++++++++-
 5 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index d9dd2db52ea6..56670eefde6b 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -570,6 +570,8 @@ [PcdsDynamicDefault]
 
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
 
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 291cb6d1f603..9897e6889573 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -582,6 +582,8 @@ [PcdsDynamicDefault]
 
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
 
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 5990dab4f65e..59c4f9207fc3 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -581,6 +581,8 @@ [PcdsDynamicDefault]
 
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
 
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 920b619446f0..25bb59d161de 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -100,6 +100,8 @@ [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled
   gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase
   gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize
   gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy
   gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index c12aea46d94e..900b0d977d61 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -9,12 +9,15 @@
 //
 // The package level header files this module uses
 //
+#include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
 #include <Library/HobLib.h>
 #include <Library/MemEncryptSevLib.h>
+#include <Library/MemoryAllocationLib.h>
 #include <Library/PcdLib.h>
 #include <PiPei.h>
 #include <Register/Amd/Cpuid.h>
+#include <Register/Amd/Msr.h>
 #include <Register/Cpuid.h>
 
 #include "Platform.h"
@@ -30,7 +33,10 @@ AmdSevEsInitialize (
   VOID
   )
 {
-  RETURN_STATUS     PcdStatus;
+  VOID              *GhcbBase;
+  PHYSICAL_ADDRESS  GhcbBasePa;
+  UINTN             GhcbPageCount;
+  RETURN_STATUS     PcdStatus, DecryptStatus;
 
   if (!MemEncryptSevEsIsEnabled ()) {
     return;
@@ -38,6 +44,36 @@ AmdSevEsInitialize (
 
   PcdStatus = PcdSetBoolS (PcdSevEsIsEnabled, TRUE);
   ASSERT_RETURN_ERROR (PcdStatus);
+
+  //
+  // Allocate GHCB and per-CPU variable pages.
+  //
+  GhcbPageCount = mMaxCpuCount * 2;
+  GhcbBase = AllocatePages (GhcbPageCount);
+  ASSERT (GhcbBase != NULL);
+
+  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
+
+  DecryptStatus = MemEncryptSevClearPageEncMask (
+    0,
+    GhcbBasePa,
+    GhcbPageCount,
+    TRUE
+    );
+  ASSERT_RETURN_ERROR (DecryptStatus);
+
+  ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));
+
+  PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);
+  ASSERT_RETURN_ERROR (PcdStatus);
+  PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  DEBUG ((DEBUG_INFO,
+    "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
+    (UINT64)GhcbPageCount, GhcbBase));
+
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);
 }
 
 /**
-- 
2.17.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#50968): https://edk2.groups.io/g/devel/message/50968
Mute This Topic: https://groups.io/mt/60973127/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-

Re: [edk2-devel] [RFC PATCH v3 28/43] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
Posted by Ni, Ray 6 years, 1 month ago
> +  // Allocate GHCB and per-CPU variable pages.
> +  //
> +  GhcbPageCount = mMaxCpuCount * 2;
> +  GhcbBase = AllocatePages (GhcbPageCount);
> +  ASSERT (GhcbBase != NULL);
> +
> +  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
> +
> +  DecryptStatus = MemEncryptSevClearPageEncMask (
> +    0,
> +    GhcbBasePa,
> +    GhcbPageCount,
> +    TRUE
> +    );
> +  ASSERT_RETURN_ERROR (DecryptStatus);
> +
> +  ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));
> +
> +  PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);
> +  ASSERT_RETURN_ERROR (PcdStatus);
> +  PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));
> +  ASSERT_RETURN_ERROR (PcdStatus);
> +
> +  DEBUG ((DEBUG_INFO,
> +    "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
> +    (UINT64)GhcbPageCount, GhcbBase));
> +
> +  AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);

As I said in the comments to PcdGhcbBase/Size, can all PCD consumers read the GHCB MSR instead?

Does the GHCB buffer contains size information? If no, how does CPU know the GHCB buffer size?
I am asking this because I want to see a way to remove the PcdGhcbSize.

Thanks,
Ray

-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#52150): https://edk2.groups.io/g/devel/message/52150
Mute This Topic: https://groups.io/mt/60973127/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-

Re: [edk2-devel] [RFC PATCH v3 28/43] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
Posted by Lendacky, Thomas 6 years, 1 month ago
On 12/12/19 12:54 AM, Ni, Ray wrote:
>> +  // Allocate GHCB and per-CPU variable pages.
>> +  //
>> +  GhcbPageCount = mMaxCpuCount * 2;
>> +  GhcbBase = AllocatePages (GhcbPageCount);
>> +  ASSERT (GhcbBase != NULL);
>> +
>> +  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
>> +
>> +  DecryptStatus = MemEncryptSevClearPageEncMask (
>> +    0,
>> +    GhcbBasePa,
>> +    GhcbPageCount,
>> +    TRUE
>> +    );
>> +  ASSERT_RETURN_ERROR (DecryptStatus);
>> +
>> +  ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));
>> +
>> +  PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);
>> +  ASSERT_RETURN_ERROR (PcdStatus);
>> +  PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));
>> +  ASSERT_RETURN_ERROR (PcdStatus);
>> +
>> +  DEBUG ((DEBUG_INFO,
>> +    "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
>> +    (UINT64)GhcbPageCount, GhcbBase));
>> +
>> +  AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);
> 
> As I said in the comments to PcdGhcbBase/Size, can all PCD consumers read the GHCB MSR instead?
> 
> Does the GHCB buffer contains size information? If no, how does CPU know the GHCB buffer size?
> I am asking this because I want to see a way to remove the PcdGhcbSize.

The GHCB is one page in size and is a defined structure. The PcdGhcbSize
represents the total size of the allocation, which is one GHCB page per
CPU and one page per CPU to hold per-CPU data (currently the DR7 value).

Thanks,
Tom

> 
> Thanks,
> Ray
> 

-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#52180): https://edk2.groups.io/g/devel/message/52180
Mute This Topic: https://groups.io/mt/60973127/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-