public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support
@ 2021-09-13 18:19 Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 01/31] OvmfPkg/SecMain: move SEV specific routines in AmdSev.c Brijesh Singh
                   ` (30 more replies)
  0 siblings, 31 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

SEV-SNP builds upon existing SEV and SEV-ES functionality while adding
new hardware-based memory protections. SEV-SNP adds strong memory integrity
protection to help prevent malicious hypervisor-based attacks like data
replay, memory re-mapping and more in order to create an isolated memory
encryption environment.
 
This series provides the basic building blocks to support booting the SEV-SNP
VMs, it does not cover all the security enhancement introduced by the SEV-SNP
such as interrupt protection.

Many of the integrity guarantees of SEV-SNP are enforced through a new
structure called the Reverse Map Table (RMP). Adding a new page to SEV-SNP
VM requires a 2-step process. First, the hypervisor assigns a page to the
guest using the new RMPUPDATE instruction. This transitions the page to
guest-invalid. Second, the guest validates the page using the new PVALIDATE
instruction. The SEV-SNP VMs can use the new "Page State Change Request NAE"
defined in the GHCB specification to ask hypervisor to add or remove page
from the RMP table.

Each page assigned to the SEV-SNP VM can either be validated or unvalidated,
as indicated by the Validated flag in the page's RMP entry. There are two
approaches that can be taken for the page validation: Pre-validation and
Lazy Validation.

Under pre-validation, the pages are validated prior to first use. And under
lazy validation, pages are validated when first accessed. An access to a
unvalidated page results in a #VC exception, at which time the exception
handler may validate the page. Lazy validation requires careful tracking of
the validated pages to avoid validating the same GPA more than once. The
recently introduced "Unaccepted" memory type can be used to communicate the
unvalidated memory ranges to the Guest OS.

At this time we only support the pre-validation. OVMF detects all the available
system RAM in the PEI phase. When SEV-SNP is enabled, the memory is validated
before it is made available to the EDK2 core.

Now that series contains all the basic support required to launch SEV-SNP
guest. We are still missing the Interrupt security feature provided by the
SNP. The feature will be added after the base support is accepted.

Additional resources
---------------------
SEV-SNP whitepaper
https://www.amd.com/system/files/TechDocs/SEV-SNP-strengthening-vm-isolation-with-integrity-protection-and-more.pdf

APM 2: https://www.amd.com/system/files/TechDocs/24593.pdf (section 15.36)

The complete source is available at
https://github.com/AMDESE/ovmf/tree/sev-snp-v7

GHCB spec:
https://developer.amd.com/wp-content/resources/56421.pdf

SEV-SNP firmware specification:
https://www.amd.com/system/files/TechDocs/56860.pdf

Change since v6:
 * Drop the SNP boot block GUID and switch to using the Metadata guided structure
   proposed by Min in TDX series.
 * Exclude the GHCB page from the pre-validated region. It simplifies the reset
   vector code where we do not need to unvalidate the GHCB page.
 * Now that GHCB page is not validated so move the VMPL check from reset vector
   code to the MemEncryptSevLib on the first page validation.
 * Introduce the ConfidentialComputingGuestAttr PCD to communicate which
   memory encryption is active so that MpInitLib can make use of it.
 * Drop the SEVES specific PCD as the information can be communicated via
   the ConfidentialComputingGuestAttr.
 * Move the SNP specific AP creation function in AmdSev.c.
 * Define the SNP Blob GUID in a new file.

Change since v5:
 * When possible use the CPUID value from CPUID page
 * Move the SEV specific functions from SecMain.c in AmdSev.c
 * Rebase to the latest code
 * Add the review feedback from Yao.

Change since v4:
 * Use the correct MSR for the SEV_STATUS
 * Add VMPL-0 check

Change since v3:
 * ResetVector: move all SEV specific code in AmdSev.asm and add macros to keep
   the code readable.
 * Drop extending the EsWorkArea to contain SNP specific state.
 * Drop the GhcbGpa library and call the VmgExit directly to register GHCB GPA.
 * Install the CC blob config table from AmdSevDxe instead of extending the
   AmdSev/SecretsDxe for it.
 * Add the separate PCDs for the SNP Secrets.

Changes since v2:
 * Add support for the AP creation.
 * Use the module-scoping override to make AmdSevDxe use the IO port for PCI reads.
 * Use the reserved memory type for CPUID and Secrets page.
 * 
Changes since v1:
 * Drop the interval tree support to detect the pre-validated overlap region.
 * Use an array to keep track of pre-validated regions.
 * Add support to query the Hypervisor feature and verify that SNP feature is supported.
 * Introduce MemEncryptSevClearMmioPageEncMask() to clear the C-bit from MMIO ranges.
 * Pull the SevSecretDxe and SevSecretPei into OVMF package build.
 * Extend the SevSecretDxe to expose confidential computing blob location through
   EFI configuration table.

Brijesh Singh (27):
  OvmfPkg/SecMain: move SEV specific routines in AmdSev.c
  OvmfPkg/ResetVector: move clearing GHCB in SecMain
  OvmfPkg/ResetVector: introduce metadata descriptor for VMM use
  OvmfPkg: reserve SNP secrets page
  OvmfPkg: reserve CPUID page
  OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase
  OvmfPkg/MemEncryptSevLib: add MemEncryptSevSnpEnabled()
  OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest
  OvmfPkg/PlatformPei: register GHCB gpa for the SEV-SNP guest
  OvmfPkg/AmdSevDxe: do not use extended PCI config space
  OvmfPkg/MemEncryptSevLib: add support to validate system RAM
  OvmfPkg/MemEncryptSevLib: add function to check the VMPL0
  OvmfPkg/BaseMemEncryptSevLib: skip the pre-validated system RAM
  OvmfPkg/MemEncryptSevLib: add support to validate > 4GB memory in PEI
    phase
  OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv
  OvmfPkg/PlatformPei: validate the system RAM when SNP is active
  UefiCpuPkg: Define ConfidentialComputingGuestAttr
  OvmfPkg/PlatformPei: set PcdConfidentialComputingAttr when SEV is
    active
  UefiCpuPkg/MpInitLib: use PcdConfidentialComputingAttr to check SEV
    status
  UefiCpuPkg: add PcdGhcbHypervisorFeatures
  OvmfPkg/PlatformPei: set the Hypervisor Features PCD
  MdePkg/GHCB: increase the GHCB protocol max version
  UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is
    enabled
  OvmfPkg/MemEncryptSevLib: change the page state in the RMP table
  OvmfPkg/MemEncryptSevLib: skip page state change for Mmio address
  OvmfPkg/PlatformPei: mark cpuid and secrets memory reserved in EFI map
  OvmfPkg/AmdSev: expose the SNP reserved pages through configuration
    table

Michael Roth (3):
  OvmfPkg/ResetVector: use SEV-SNP-validated CPUID values
  OvmfPkg/VmgExitLib: use SEV-SNP-validated CPUID values
  UefiCpuPkg/MpInitLib: use BSP to do extended topology check

Tom Lendacky (1):
  UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs

 OvmfPkg/OvmfPkg.dec                           |  19 +
 UefiCpuPkg/UefiCpuPkg.dec                     |   9 +
 OvmfPkg/AmdSev/AmdSevX64.dsc                  |   5 +-
 OvmfPkg/Bhyve/BhyveX64.dsc                    |   5 +-
 OvmfPkg/OvmfPkgIa32.dsc                       |   1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   6 +-
 OvmfPkg/OvmfPkgX64.dsc                        |   5 +-
 OvmfPkg/OvmfXen.dsc                           |   5 +-
 OvmfPkg/OvmfPkgX64.fdf                        |   6 +
 OvmfPkg/AmdSevDxe/AmdSevDxe.inf               |   7 +
 .../DxeMemEncryptSevLib.inf                   |   3 +
 .../PeiMemEncryptSevLib.inf                   |  25 +
 .../SecMemEncryptSevLib.inf                   |   3 +
 OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf  |   2 +
 OvmfPkg/Library/VmgExitLib/VmgExitLib.inf     |   3 +
 OvmfPkg/PlatformPei/PlatformPei.inf           |   8 +
 OvmfPkg/ResetVector/ResetVector.inf           |  11 +
 OvmfPkg/Sec/SecMain.inf                       |   4 +
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   5 +-
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   5 +-
 MdePkg/Include/Register/Amd/Ghcb.h            |   2 +-
 .../Guid/ConfidentialComputingSevSnpBlob.h    |  33 ++
 OvmfPkg/Include/Library/MemEncryptSevLib.h    |  26 +
 .../X64/SnpPageStateChange.h                  |  36 ++
 .../BaseMemEncryptSevLib/X64/VirtualMemory.h  |  19 +
 OvmfPkg/PlatformPei/Platform.h                |   5 +
 OvmfPkg/Sec/AmdSev.h                          |  95 ++++
 .../Include/ConfidentialComputingGuestAttr.h  |  25 +
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  60 +++
 OvmfPkg/AmdSevDxe/AmdSevDxe.c                 |  23 +
 .../DxeMemEncryptSevLibInternal.c             |  27 ++
 .../Ia32/MemEncryptSevLib.c                   |  17 +
 .../PeiMemEncryptSevLibInternal.c             |  27 ++
 .../SecMemEncryptSevLibInternal.c             |  19 +
 .../X64/DxeSnpSystemRamValidate.c             |  40 ++
 .../X64/PeiDxeVirtualMemory.c                 | 167 ++++++-
 .../X64/PeiSnpSystemRamValidate.c             | 163 +++++++
 .../X64/SecSnpSystemRamValidate.c             |  82 ++++
 .../X64/SnpPageStateChangeInternal.c          | 294 ++++++++++++
 OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c | 444 ++++++++++++++++--
 OvmfPkg/PlatformPei/AmdSev.c                  | 235 +++++++++
 OvmfPkg/PlatformPei/MemDetect.c               |   2 +
 OvmfPkg/Sec/AmdSev.c                          | 316 +++++++++++++
 OvmfPkg/Sec/SecMain.c                         | 160 +------
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  16 +-
 UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c    |  70 +++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          | 122 ++++-
 UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |   4 +-
 UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c     | 261 ++++++++++
 OvmfPkg/FvmainCompactScratchEnd.fdf.inc       |   5 +
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm  |  17 +
 OvmfPkg/ResetVector/Ia32/AmdSev.asm           |  86 +++-
 OvmfPkg/ResetVector/ResetVector.nasmb         |  35 ++
 OvmfPkg/ResetVector/X64/OvmfMetadata.asm      | 113 +++++
 UefiCpuPkg/Library/MpInitLib/MpEqu.inc        |   2 +
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm |  80 ++++
 56 files changed, 3034 insertions(+), 231 deletions(-)
 create mode 100644 OvmfPkg/Include/Guid/ConfidentialComputingSevSnpBlob.h
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h
 create mode 100644 OvmfPkg/Sec/AmdSev.h
 create mode 100644 UefiCpuPkg/Include/ConfidentialComputingGuestAttr.h
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValidate.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c
 create mode 100644 OvmfPkg/Sec/AmdSev.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
 create mode 100644 OvmfPkg/ResetVector/X64/OvmfMetadata.asm

-- 
2.17.1


^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v7 01/31] OvmfPkg/SecMain: move SEV specific routines in AmdSev.c
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 02/31] OvmfPkg/ResetVector: move clearing GHCB in SecMain Brijesh Singh
                   ` (29 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

Move all the SEV specific function in AmdSev.c.

No functional change intended.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/Sec/SecMain.inf |   1 +
 OvmfPkg/Sec/AmdSev.h    |  72 ++++++++++++++++++
 OvmfPkg/Sec/AmdSev.c    | 161 ++++++++++++++++++++++++++++++++++++++++
 OvmfPkg/Sec/SecMain.c   | 153 +-------------------------------------
 4 files changed, 236 insertions(+), 151 deletions(-)
 create mode 100644 OvmfPkg/Sec/AmdSev.h
 create mode 100644 OvmfPkg/Sec/AmdSev.c

diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index ea4b9611f52d..9523a8ea6c8f 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -23,6 +23,7 @@ [Defines]
 
 [Sources]
   SecMain.c
+  AmdSev.c
 
 [Sources.IA32]
   Ia32/SecEntry.nasm
diff --git a/OvmfPkg/Sec/AmdSev.h b/OvmfPkg/Sec/AmdSev.h
new file mode 100644
index 000000000000..adad96d23189
--- /dev/null
+++ b/OvmfPkg/Sec/AmdSev.h
@@ -0,0 +1,72 @@
+/** @file
+  File defines the Sec routines for the AMD SEV
+
+  Copyright (c) 2021, Advanced Micro Devices, Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _AMD_SEV_SEC_INTERNAL_H__
+#define _AMD_SEV_SEC_INTERNAL_H__
+
+/**
+  Handle an SEV-ES/GHCB protocol check failure.
+
+  Notify the hypervisor using the VMGEXIT instruction that the SEV-ES guest
+  wishes to be terminated.
+
+  @param[in] ReasonCode  Reason code to provide to the hypervisor for the
+                         termination request.
+
+**/
+VOID
+SevEsProtocolFailure (
+  IN UINT8  ReasonCode
+  );
+
+
+/**
+  Validate the SEV-ES/GHCB protocol level.
+
+  Verify that the level of SEV-ES/GHCB protocol supported by the hypervisor
+  and the guest intersect. If they don't intersect, request termination.
+
+**/
+VOID
+SevEsProtocolCheck (
+  VOID
+  );
+
+/**
+ Determine if the SEV is active.
+
+ During the early booting, GuestType is set in the work area. Verify that it
+ is an SEV guest.
+
+ @retval TRUE   SEV is enabled
+ @retval FALSE  SEV is not enabled
+
+**/
+BOOLEAN
+IsSevGuest (
+  VOID
+  );
+
+/**
+  Determine if SEV-ES is active.
+
+  During early booting, SEV-ES support code will set a flag to indicate that
+  SEV-ES is enabled. Return the value of this flag as an indicator that SEV-ES
+  is enabled.
+
+  @retval TRUE   SEV-ES is enabled
+  @retval FALSE  SEV-ES is not enabled
+
+**/
+BOOLEAN
+SevEsIsEnabled (
+  VOID
+  );
+
+#endif
diff --git a/OvmfPkg/Sec/AmdSev.c b/OvmfPkg/Sec/AmdSev.c
new file mode 100644
index 000000000000..3b4adaae32c7
--- /dev/null
+++ b/OvmfPkg/Sec/AmdSev.c
@@ -0,0 +1,161 @@
+/** @file
+  File defines the Sec routines for the AMD SEV
+
+  Copyright (c) 2021, Advanced Micro Devices, Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemEncryptSevLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Register/Amd/Ghcb.h>
+#include <Register/Amd/Msr.h>
+
+#include "AmdSev.h"
+
+/**
+  Handle an SEV-ES/GHCB protocol check failure.
+
+  Notify the hypervisor using the VMGEXIT instruction that the SEV-ES guest
+  wishes to be terminated.
+
+  @param[in] ReasonCode  Reason code to provide to the hypervisor for the
+                         termination request.
+
+**/
+VOID
+SevEsProtocolFailure (
+  IN UINT8  ReasonCode
+  )
+{
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+
+  //
+  // Use the GHCB MSR Protocol to request termination by the hypervisor
+  //
+  Msr.GhcbPhysicalAddress = 0;
+  Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;
+  Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;
+  Msr.GhcbTerminate.ReasonCode = ReasonCode;
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+  AsmVmgExit ();
+
+  ASSERT (FALSE);
+  CpuDeadLoop ();
+}
+
+/**
+  Validate the SEV-ES/GHCB protocol level.
+
+  Verify that the level of SEV-ES/GHCB protocol supported by the hypervisor
+  and the guest intersect. If they don't intersect, request termination.
+
+**/
+VOID
+SevEsProtocolCheck (
+  VOID
+  )
+{
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+  GHCB                      *Ghcb;
+
+  //
+  // Use the GHCB MSR Protocol to obtain the GHCB SEV-ES Information for
+  // protocol checking
+  //
+  Msr.GhcbPhysicalAddress = 0;
+  Msr.GhcbInfo.Function = GHCB_INFO_SEV_INFO_GET;
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+  AsmVmgExit ();
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+
+  if (Msr.GhcbInfo.Function != GHCB_INFO_SEV_INFO) {
+    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
+  }
+
+  if (Msr.GhcbProtocol.SevEsProtocolMin > Msr.GhcbProtocol.SevEsProtocolMax) {
+    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
+  }
+
+  if ((Msr.GhcbProtocol.SevEsProtocolMin > GHCB_VERSION_MAX) ||
+      (Msr.GhcbProtocol.SevEsProtocolMax < GHCB_VERSION_MIN)) {
+    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
+  }
+
+  //
+  // SEV-ES protocol checking succeeded, set the initial GHCB address
+  //
+  Msr.GhcbPhysicalAddress = FixedPcdGet32 (PcdOvmfSecGhcbBase);
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+  Ghcb = Msr.Ghcb;
+  SetMem (Ghcb, sizeof (*Ghcb), 0);
+
+  //
+  // Set the version to the maximum that can be supported
+  //
+  Ghcb->ProtocolVersion = MIN (Msr.GhcbProtocol.SevEsProtocolMax, GHCB_VERSION_MAX);
+  Ghcb->GhcbUsage = GHCB_STANDARD_USAGE;
+}
+
+/**
+ Determine if the SEV is active.
+
+ During the early booting, GuestType is set in the work area. Verify that it
+ is an SEV guest.
+
+ @retval TRUE   SEV is enabled
+ @retval FALSE  SEV is not enabled
+
+**/
+BOOLEAN
+IsSevGuest (
+  VOID
+  )
+{
+  OVMF_WORK_AREA             *WorkArea;
+
+  //
+  // Ensure that the size of the Confidential Computing work area header
+  // is same as what is provided through a fixed PCD.
+  //
+  ASSERT ((UINTN) FixedPcdGet32 (PcdOvmfConfidentialComputingWorkAreaHeader) ==
+          sizeof(CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER));
+
+  WorkArea = (OVMF_WORK_AREA *) FixedPcdGet32 (PcdOvmfWorkAreaBase);
+
+  return ((WorkArea != NULL) && (WorkArea->Header.GuestType == GUEST_TYPE_AMD_SEV));
+}
+
+/**
+  Determine if SEV-ES is active.
+
+  During early booting, SEV-ES support code will set a flag to indicate that
+  SEV-ES is enabled. Return the value of this flag as an indicator that SEV-ES
+  is enabled.
+
+  @retval TRUE   SEV-ES is enabled
+  @retval FALSE  SEV-ES is not enabled
+
+**/
+BOOLEAN
+SevEsIsEnabled (
+  VOID
+  )
+{
+  SEC_SEV_ES_WORK_AREA  *SevEsWorkArea;
+
+  if (!IsSevGuest()) {
+    return FALSE;
+  }
+
+  SevEsWorkArea = (SEC_SEV_ES_WORK_AREA *) FixedPcdGet32 (PcdSevEsWorkAreaBase);
+
+  return (SevEsWorkArea->SevEsEnabled != 0);
+}
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 707b0d4bbff4..406e3a25d0cd 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -26,12 +26,11 @@
 #include <Library/ExtractGuidedSectionLib.h>
 #include <Library/LocalApicLib.h>
 #include <Library/CpuExceptionHandlerLib.h>
-#include <Library/MemEncryptSevLib.h>
-#include <Register/Amd/Ghcb.h>
-#include <Register/Amd/Msr.h>
 
 #include <Ppi/TemporaryRamSupport.h>
 
+#include "AmdSev.h"
+
 #define SEC_IDT_ENTRY_COUNT  34
 
 typedef struct _SEC_IDT_TABLE {
@@ -717,154 +716,6 @@ FindAndReportEntryPoints (
   return;
 }
 
-/**
-  Handle an SEV-ES/GHCB protocol check failure.
-
-  Notify the hypervisor using the VMGEXIT instruction that the SEV-ES guest
-  wishes to be terminated.
-
-  @param[in] ReasonCode  Reason code to provide to the hypervisor for the
-                         termination request.
-
-**/
-STATIC
-VOID
-SevEsProtocolFailure (
-  IN UINT8  ReasonCode
-  )
-{
-  MSR_SEV_ES_GHCB_REGISTER  Msr;
-
-  //
-  // Use the GHCB MSR Protocol to request termination by the hypervisor
-  //
-  Msr.GhcbPhysicalAddress = 0;
-  Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;
-  Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;
-  Msr.GhcbTerminate.ReasonCode = ReasonCode;
-  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
-
-  AsmVmgExit ();
-
-  ASSERT (FALSE);
-  CpuDeadLoop ();
-}
-
-/**
-  Validate the SEV-ES/GHCB protocol level.
-
-  Verify that the level of SEV-ES/GHCB protocol supported by the hypervisor
-  and the guest intersect. If they don't intersect, request termination.
-
-**/
-STATIC
-VOID
-SevEsProtocolCheck (
-  VOID
-  )
-{
-  MSR_SEV_ES_GHCB_REGISTER  Msr;
-  GHCB                      *Ghcb;
-
-  //
-  // Use the GHCB MSR Protocol to obtain the GHCB SEV-ES Information for
-  // protocol checking
-  //
-  Msr.GhcbPhysicalAddress = 0;
-  Msr.GhcbInfo.Function = GHCB_INFO_SEV_INFO_GET;
-  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
-
-  AsmVmgExit ();
-
-  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
-
-  if (Msr.GhcbInfo.Function != GHCB_INFO_SEV_INFO) {
-    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
-  }
-
-  if (Msr.GhcbProtocol.SevEsProtocolMin > Msr.GhcbProtocol.SevEsProtocolMax) {
-    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
-  }
-
-  if ((Msr.GhcbProtocol.SevEsProtocolMin > GHCB_VERSION_MAX) ||
-      (Msr.GhcbProtocol.SevEsProtocolMax < GHCB_VERSION_MIN)) {
-    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
-  }
-
-  //
-  // SEV-ES protocol checking succeeded, set the initial GHCB address
-  //
-  Msr.GhcbPhysicalAddress = FixedPcdGet32 (PcdOvmfSecGhcbBase);
-  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
-
-  Ghcb = Msr.Ghcb;
-  SetMem (Ghcb, sizeof (*Ghcb), 0);
-
-  //
-  // Set the version to the maximum that can be supported
-  //
-  Ghcb->ProtocolVersion = MIN (Msr.GhcbProtocol.SevEsProtocolMax, GHCB_VERSION_MAX);
-  Ghcb->GhcbUsage = GHCB_STANDARD_USAGE;
-}
-
-/**
- Determine if the SEV is active.
-
- During the early booting, GuestType is set in the work area. Verify that it
- is an SEV guest.
-
- @retval TRUE   SEV is enabled
- @retval FALSE  SEV is not enabled
-
-**/
-STATIC
-BOOLEAN
-IsSevGuest (
-  VOID
-  )
-{
-  OVMF_WORK_AREA             *WorkArea;
-
-  //
-  // Ensure that the size of the Confidential Computing work area header
-  // is same as what is provided through a fixed PCD.
-  //
-  ASSERT ((UINTN) FixedPcdGet32 (PcdOvmfConfidentialComputingWorkAreaHeader) ==
-          sizeof(CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER));
-
-  WorkArea = (OVMF_WORK_AREA *) FixedPcdGet32 (PcdOvmfWorkAreaBase);
-
-  return ((WorkArea != NULL) && (WorkArea->Header.GuestType == GUEST_TYPE_AMD_SEV));
-}
-
-/**
-  Determine if SEV-ES is active.
-
-  During early booting, SEV-ES support code will set a flag to indicate that
-  SEV-ES is enabled. Return the value of this flag as an indicator that SEV-ES
-  is enabled.
-
-  @retval TRUE   SEV-ES is enabled
-  @retval FALSE  SEV-ES is not enabled
-
-**/
-STATIC
-BOOLEAN
-SevEsIsEnabled (
-  VOID
-  )
-{
-  SEC_SEV_ES_WORK_AREA  *SevEsWorkArea;
-
-  if (!IsSevGuest()) {
-    return FALSE;
-  }
-
-  SevEsWorkArea = (SEC_SEV_ES_WORK_AREA *) FixedPcdGet32 (PcdSevEsWorkAreaBase);
-
-  return (SevEsWorkArea->SevEsEnabled != 0);
-}
-
 VOID
 EFIAPI
 SecCoreStartupWithStack (
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 02/31] OvmfPkg/ResetVector: move clearing GHCB in SecMain
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 01/31] OvmfPkg/SecMain: move SEV specific routines in AmdSev.c Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 03/31] OvmfPkg/ResetVector: introduce metadata descriptor for VMM use Brijesh Singh
                   ` (28 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

In preparation for SEV-SNP support move clearing of the GHCB memory from
the ResetVector/AmdSev.asm to SecMain/AmdSev.c. The GHCB page is not
accessed until SevEsProtocolCheck() switch to full GHCB. So, the move
does not make any changes in the code flow or logic. The move will
simplify the SEV-SNP support.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/Sec/AmdSev.c                | 2 +-
 OvmfPkg/ResetVector/Ia32/AmdSev.asm | 6 ------
 2 files changed, 1 insertion(+), 7 deletions(-)

diff --git a/OvmfPkg/Sec/AmdSev.c b/OvmfPkg/Sec/AmdSev.c
index 3b4adaae32c7..7f74e8bfe88e 100644
--- a/OvmfPkg/Sec/AmdSev.c
+++ b/OvmfPkg/Sec/AmdSev.c
@@ -95,7 +95,7 @@ SevEsProtocolCheck (
   AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
 
   Ghcb = Msr.Ghcb;
-  SetMem (Ghcb, sizeof (*Ghcb), 0);
+  SetMem (Ghcb, FixedPcdGet32 (PcdOvmfSecGhcbSize), 0);
 
   //
   // Set the version to the maximum that can be supported
diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
index 250ac8d8b180..48d9178168b0 100644
--- a/OvmfPkg/ResetVector/Ia32/AmdSev.asm
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -177,12 +177,6 @@ pageTableEntries4kLoop:
     mov     ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
     mov     [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
 
-    mov     ecx, GHCB_SIZE / 4
-    xor     eax, eax
-clearGhcbMemoryLoop:
-    mov     dword[ecx * 4 + GHCB_BASE - 4], eax
-    loop    clearGhcbMemoryLoop
-
 SevClearPageEncMaskForGhcbPageExit:
     OneTimeCallRet SevClearPageEncMaskForGhcbPage
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 03/31] OvmfPkg/ResetVector: introduce metadata descriptor for VMM use
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 01/31] OvmfPkg/SecMain: move SEV specific routines in AmdSev.c Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 02/31] OvmfPkg/ResetVector: move clearing GHCB in SecMain Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 04/31] OvmfPkg: reserve SNP secrets page Brijesh Singh
                   ` (27 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

The OvmfPkgX86 build reserves memory regions in MEMFD. The memory regions
get accessed in the SEC phase. Both Intel TDX and AMD SEV-SNP require
that the guest's private memory be accepted or validated before access.

Introduce a Guided metadata structure that describes the reserved memory
regions. The VMM can locate the metadata structure by iterating through
the reset vector guid and process the areas based on the platform
specific requirements.

Min Xu introduced the metadata structure conceptin the TDX patch
series [1].

[1] https://www.mail-archive.com/devel@edk2.groups.io/msg33605.html

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>
Suggested-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 17 ++++++++
 OvmfPkg/ResetVector/ResetVector.nasmb        |  1 +
 OvmfPkg/ResetVector/X64/OvmfMetadata.asm     | 45 ++++++++++++++++++++
 3 files changed, 63 insertions(+)
 create mode 100644 OvmfPkg/ResetVector/X64/OvmfMetadata.asm

diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
index 7ec3c6e980c3..f0e509d0672e 100644
--- a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -47,6 +47,23 @@ TIMES (15 - ((guidedStructureEnd - guidedStructureStart + 15) % 16)) DB 0
 ;
 guidedStructureStart:
 
+%ifdef ARCH_X64
+;
+; OVMF metadata descriptor for the TDX and SEV-SNP
+;
+; Provide the start offset of the metadata blob within the OVMF binary.
+
+; GUID : e47a6535-984a-4798-865e-4685a7bf8ec2
+;
+OvmfMetadataOffsetStart:
+  DD      (fourGigabytes - OvmfMetadataGuid - 16)
+  DW      OvmfMetadataOffsetEnd - OvmfMetadataOffsetStart
+  DB      0x35, 0x65, 0x7a, 0xe4, 0x4a, 0x98, 0x98, 0x47
+  DB      0x86, 0x5e, 0x46, 0x85, 0xa7, 0xbf, 0x8e, 0xc2
+OvmfMetadataOffsetEnd:
+
+%endif
+
 ; SEV Hash Table Block
 ;
 ; This describes the guest ram area where the hypervisor should
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index d1d800c56745..bc61b1d05a24 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -80,6 +80,7 @@
 %include "Ia32/Flat32ToFlat64.asm"
 %include "Ia32/AmdSev.asm"
 %include "Ia32/PageTables64.asm"
+%include "X64/OvmfMetadata.asm"
 %endif
 
 %include "Ia16/Real16ToFlat32.asm"
diff --git a/OvmfPkg/ResetVector/X64/OvmfMetadata.asm b/OvmfPkg/ResetVector/X64/OvmfMetadata.asm
new file mode 100644
index 000000000000..a1260a1ed029
--- /dev/null
+++ b/OvmfPkg/ResetVector/X64/OvmfMetadata.asm
@@ -0,0 +1,45 @@
+;-----------------------------------------------------------------------------
+; @file
+; OVMF metadata for the confidential computing guests (TDX and SEV-SNP)
+;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; Copyright (c) 2021, AMD Inc. All rights reserved.<BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;-----------------------------------------------------------------------------
+
+BITS  64
+
+%define OVMF_METADATA_VERSION     1
+
+%define OVMF_SECTION_TYPE_UNDEFINED   0
+
+;The section contains the code
+%define OVMF_SECTION_TYPE_CODE        0x100
+
+; The section contains the varaibles
+%define OVMF_SECTION_TYPE_VARS        0x101
+
+; The section must be accepted or validated by the VMM before the boot
+%define OVMF_SECTION_TYPE_SEC_MEM     0x102
+
+ALIGN 16
+
+TIMES (15 - ((OvmfGuidedStructureEnd - OvmfGuidedStructureStart + 15) % 16)) DB 0
+
+OvmfGuidedStructureStart:
+;
+; Ovmf metadata descriptor
+;
+OvmfMetadataGuid:
+  DB  0xf3, 0xf9, 0xea, 0xe9, 0x8e, 0x16, 0xd5, 0x44
+  DB  0xa8, 0xeb, 0x7f, 0x4d, 0x87, 0x38, 0xf6, 0xae
+
+_Descriptor:
+  DB 'O','V','M','F'                                  ; Signature
+  DD OvmfGuidedStructureEnd - _Descriptor             ; Length
+  DD OVMF_METADATA_VERSION                            ; Version
+  DD (OvmfGuidedStructureEnd - _Descriptor - 16) / 12 ; Number of sections
+
+OvmfGuidedStructureEnd:
+  ALIGN   16
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 04/31] OvmfPkg: reserve SNP secrets page
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (2 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 03/31] OvmfPkg/ResetVector: introduce metadata descriptor for VMM use Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 05/31] OvmfPkg: reserve CPUID page Brijesh Singh
                   ` (26 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

During the SNP guest launch sequence, a special secrets page needs to be
inserted by the VMM. The PSP will populate the page; it will contain the
VM Platform Communication Key (VMPCKs) used by the guest to send and
receive secure messages to the PSP.

The purpose of the secrets page in the SEV-SNP is different from the one
used in SEV guests. In SEV, the secrets page contains the guest owner's
private data after the remote attestation.

Add a new section for the secrets page in the OVMF metadata structure so
that hypervisor can locate it.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/OvmfPkg.dec                      | 6 ++++++
 OvmfPkg/OvmfPkgX64.fdf                   | 3 +++
 OvmfPkg/ResetVector/ResetVector.inf      | 2 ++
 OvmfPkg/ResetVector/ResetVector.nasmb    | 3 +++
 OvmfPkg/ResetVector/X64/OvmfMetadata.asm | 9 +++++++++
 5 files changed, 23 insertions(+)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index c37dafad49bb..6266fdef6054 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -340,6 +340,12 @@ [PcdsFixedAtBuild]
   # header definition.
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfConfidentialComputingWorkAreaHeader|0|UINT32|0x51
 
+  ## The base address and size of the SEV-SNP Secrets Area that contains
+  #  the VM platform communication key used to send and recieve the
+  #  messages to the PSP. If this is set in the .fdf, the platform
+  #  is responsible to reserve this area from DXE phase overwrites.
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase|0|UINT32|0x52
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize|0|UINT32|0x53
 
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 23936242e74a..5b871db20ab2 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -88,6 +88,9 @@ [FD.MEMFD]
 0x00C000|0x001000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
 
+0x00D000|0x001000
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
+
 0x010000|0x010000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
 
diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index a2520dde5508..09454d0797e6 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -50,3 +50,5 @@ [FixedPcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretSize
   gUefiOvmfPkgTokenSpaceGuid.PcdQemuHashTableBase
   gUefiOvmfPkgTokenSpaceGuid.PcdQemuHashTableSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index bc61b1d05a24..f7d09acd33ed 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -77,6 +77,9 @@
   %define SEV_ES_WORK_AREA_RDRAND (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 8)
   %define SEV_ES_WORK_AREA_ENC_MASK (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 16)
   %define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
+  %define SEV_SNP_SECRETS_BASE  (FixedPcdGet32 (PcdOvmfSnpSecretsBase))
+  %define SEV_SNP_SECRETS_SIZE  (FixedPcdGet32 (PcdOvmfSnpSecretsSize))
+
 %include "Ia32/Flat32ToFlat64.asm"
 %include "Ia32/AmdSev.asm"
 %include "Ia32/PageTables64.asm"
diff --git a/OvmfPkg/ResetVector/X64/OvmfMetadata.asm b/OvmfPkg/ResetVector/X64/OvmfMetadata.asm
index a1260a1ed029..bb348e1c6a79 100644
--- a/OvmfPkg/ResetVector/X64/OvmfMetadata.asm
+++ b/OvmfPkg/ResetVector/X64/OvmfMetadata.asm
@@ -23,6 +23,9 @@ BITS  64
 ; The section must be accepted or validated by the VMM before the boot
 %define OVMF_SECTION_TYPE_SEC_MEM     0x102
 
+; AMD SEV-SNP specific sections
+%define OVMF_SECTION_TYPE_SNP_SECRETS 0x200
+
 ALIGN 16
 
 TIMES (15 - ((OvmfGuidedStructureEnd - OvmfGuidedStructureStart + 15) % 16)) DB 0
@@ -41,5 +44,11 @@ _Descriptor:
   DD OVMF_METADATA_VERSION                            ; Version
   DD (OvmfGuidedStructureEnd - _Descriptor - 16) / 12 ; Number of sections
 
+; SEV-SNP Secrets page
+SevSnpSecrets:
+  DD  SEV_SNP_SECRETS_BASE
+  DD  SEV_SNP_SECRETS_SIZE
+  DD  OVMF_SECTION_TYPE_SNP_SECRETS
+
 OvmfGuidedStructureEnd:
   ALIGN   16
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 05/31] OvmfPkg: reserve CPUID page
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (3 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 04/31] OvmfPkg: reserve SNP secrets page Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-16  8:07   ` Gerd Hoffmann
  2021-09-13 18:19 ` [PATCH v7 06/31] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase Brijesh Singh
                   ` (25 subsequent siblings)
  30 siblings, 1 reply; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

Platform features and capabilities are traditionally discovered via the
CPUID instruction. Hypervisors typically trap and emulate the CPUID
instruction for a variety of reasons. There are some cases where incorrect
CPUID information can potentially lead to a security issue. The SEV-SNP
firmware provides a feature to filter the CPUID results through the PSP.
The filtered CPUID values are saved on a special page for the guest to
consume. Reserve a page in MEMFD that will contain the results of
filtered CPUID values.

Add a new section in Ovmf metadata structure so that hypervisor can
locate and populate the CPUID values before 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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/OvmfPkg.dec                      |  7 +++++++
 OvmfPkg/OvmfPkgX64.fdf                   |  3 +++
 OvmfPkg/ResetVector/ResetVector.inf      |  2 ++
 OvmfPkg/ResetVector/ResetVector.nasmb    |  2 ++
 OvmfPkg/ResetVector/X64/OvmfMetadata.asm | 11 +++++++++++
 5 files changed, 25 insertions(+)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 6266fdef6054..efa0de6d0600 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -347,6 +347,13 @@ [PcdsFixedAtBuild]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase|0|UINT32|0x52
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize|0|UINT32|0x53
 
+  ## The base address and size of a CPUID Area that contains the hypervisor
+  #  provided CPUID results. In the case of SEV-SNP, the CPUID results are
+  #  filtered by the SEV-SNP firmware. If this is set in the .fdf, the
+  #  platform is responsible to reserve this area from DXE phase overwrites.
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase|0|UINT32|0x54
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize|0|UINT32|0x55
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 5b871db20ab2..b38c123b8341 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -91,6 +91,9 @@ [FD.MEMFD]
 0x00D000|0x001000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
 
+0x00E000|0x001000
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
+
 0x010000|0x010000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
 
diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index 09454d0797e6..4cb81a3233f0 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -46,6 +46,8 @@ [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
 
 [FixedPcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
   gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretBase
   gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretSize
   gUefiOvmfPkgTokenSpaceGuid.PcdQemuHashTableBase
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index f7d09acd33ed..84cb5ae81b66 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -79,6 +79,8 @@
   %define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
   %define SEV_SNP_SECRETS_BASE  (FixedPcdGet32 (PcdOvmfSnpSecretsBase))
   %define SEV_SNP_SECRETS_SIZE  (FixedPcdGet32 (PcdOvmfSnpSecretsSize))
+  %define CPUID_BASE  (FixedPcdGet32 (PcdOvmfCpuidBase))
+  %define CPUID_SIZE  (FixedPcdGet32 (PcdOvmfCpuidSize))
 
 %include "Ia32/Flat32ToFlat64.asm"
 %include "Ia32/AmdSev.asm"
diff --git a/OvmfPkg/ResetVector/X64/OvmfMetadata.asm b/OvmfPkg/ResetVector/X64/OvmfMetadata.asm
index bb348e1c6a79..95bac86a3b95 100644
--- a/OvmfPkg/ResetVector/X64/OvmfMetadata.asm
+++ b/OvmfPkg/ResetVector/X64/OvmfMetadata.asm
@@ -23,6 +23,11 @@ BITS  64
 ; The section must be accepted or validated by the VMM before the boot
 %define OVMF_SECTION_TYPE_SEC_MEM     0x102
 
+; The section contains the hypervisor pre-populated CPUID values. In the
+; case of SEV-SNP, the CPUID values are filtered and measured by the SEV-SNP
+; firmware.
+%define OVMF_SECTION_TYPE_CPUID       0x103
+
 ; AMD SEV-SNP specific sections
 %define OVMF_SECTION_TYPE_SNP_SECRETS 0x200
 
@@ -50,5 +55,11 @@ SevSnpSecrets:
   DD  SEV_SNP_SECRETS_SIZE
   DD  OVMF_SECTION_TYPE_SNP_SECRETS
 
+; CPUID values
+CpuidSec:
+  DD  CPUID_BASE
+  DD  CPUID_SIZE
+  DD  OVMF_SECTION_TYPE_CPUID
+
 OvmfGuidedStructureEnd:
   ALIGN   16
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 06/31] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (4 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 05/31] OvmfPkg: reserve CPUID page Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-16  8:26   ` Gerd Hoffmann
  2021-09-13 18:19 ` [PATCH v7 07/31] OvmfPkg/ResetVector: use SEV-SNP-validated CPUID values Brijesh Singh
                   ` (24 subsequent siblings)
  30 siblings, 1 reply; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

An SEV-SNP guest requires that private memory (aka pages mapped encrypted)
must be validated before being accessed.

The validation process consist of the following sequence:

1) Set the memory encryption attribute in the page table (aka C-bit).
   Note: If the processor is in non-PAE mode, then all the memory accesses
   are considered private.
2) Add the memory range as private in the RMP table. This can be performed
   using the Page State Change VMGEXIT defined in the GHCB specification.
3) Use the PVALIDATE instruction to set the Validated Bit in the RMP table.

During the guest creation time, the VMM encrypts the OVMF_CODE.fd using
the SEV-SNP firmware provided LAUNCH_UPDATE_DATA command. In addition to
encrypting the content, the command also validates the memory region.
This allows us to execute the code without going through the validation
sequence.

During execution, the reset vector need to access some data pages
(such as page tables, SevESWorkarea, Sec stack). The data pages are
accessed as private memory. The data pages are not part of the
OVMF_CODE.fd, so they were not validated during the guest creation.

There are two approaches we can take to validate the data pages before
the access:

a) Enhance the OVMF reset vector code to validate the pages as described
   above (go through step 2 - 3).
OR
b) Validate the pages during the guest creation time. The SEV firmware
   provides a command which can be used by the VMM to validate the pages
   without affecting the measurement of the launch.

Approach #b seems much simpler; it does not require any changes to the
OVMF reset vector code.

Update the OVMF metadata with the list of regions that must be
pre-validated by the VMM before 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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/ResetVector/ResetVector.inf      |  7 ++++
 OvmfPkg/ResetVector/ResetVector.nasmb    | 29 ++++++++++++++
 OvmfPkg/ResetVector/X64/OvmfMetadata.asm | 48 ++++++++++++++++++++++++
 3 files changed, 84 insertions(+)

diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index 4cb81a3233f0..af3cf610a2cd 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -37,6 +37,8 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
@@ -44,6 +46,11 @@ [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
+  gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
+  gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
 
 [FixedPcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 84cb5ae81b66..e05e202def1e 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -70,6 +70,7 @@
   %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
 
   %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
+  %define GHCB_PT_SIZE (FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize))
   %define GHCB_BASE (FixedPcdGet32 (PcdOvmfSecGhcbBase))
   %define GHCB_SIZE (FixedPcdGet32 (PcdOvmfSecGhcbSize))
   %define WORK_AREA_GUEST_TYPE (FixedPcdGet32 (PcdOvmfWorkAreaBase))
@@ -81,6 +82,34 @@
   %define SEV_SNP_SECRETS_SIZE  (FixedPcdGet32 (PcdOvmfSnpSecretsSize))
   %define CPUID_BASE  (FixedPcdGet32 (PcdOvmfCpuidBase))
   %define CPUID_SIZE  (FixedPcdGet32 (PcdOvmfCpuidSize))
+  %define SEC_PAGE_TABLE_BASE   (FixedPcdGet32 (PcdOvmfSecPageTablesBase))
+  %define SEC_PAGE_TABLE_SIZE   (FixedPcdGet32 (PcdOvmfSecPageTablesSize))
+  %define LOCK_BOX_STORAGE_BASE (FixedPcdGet32 (PcdOvmfLockBoxStorageBase))
+  %define LOCK_BOX_STORAGE_SIZE (FixedPcdGet32 (PcdOvmfLockBoxStorageSize))
+  ;
+  ; The PcdGuidedExtractHandlerTableAddress is a 64-bit PCD. The FixedPcdGet64() returns
+  ; a number suffix with 'ULL' (e.g 0x1111ULL). NASM does not like the constant ending
+  ; with anything other than 'h'. So, instead of using the FixedPcdGet64(), calculate
+  ; the base address of GuidedExtractHandlerTableBase
+  ;
+  %define GUID_EXTRACT_HANDLER_TABLE_BASE (LOCK_BOX_STORAGE_BASE + LOCK_BOX_STORAGE_SIZE)
+  %define GUID_EXTRACT_HANDLER_TABLE_SIZE (FixedPcdGet32 (PcdGuidedExtractHandlerTableSize))
+  %define WORK_AREA_BASE (FixedPcdGet32 (PcdOvmfWorkAreaBase))
+  %define WORK_AREA_SIZE (FixedPcdGet32 (PcdOvmfWorkAreaSize))
+  %define SEC_PEI_TEMP_RAM_BASE (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase))
+  %define SEC_PEI_TEMP_RAM_SIZE (FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
+
+  ;
+  ; The PcdOvmfSecGhcbBase reserves two GHCB pages. The first page is used
+  ; as GHCB shared page and second is used for booking to support the
+  ; nested GHCB in SEC phase. The booking page is mapped private. The VMM
+  ; does not need to validate the shared page but it need to validate the
+  ; booking page
+  ;
+  %define GHCB_SEC_BACKUP_BASE (FixedPcdGet32 (PcdOvmfSecGhcbBackupBase))
+  %define GHCB_SEC_BACKUP_SIZE (FixedPcdGet32 (PcdOvmfSecGhcbBackupSize))
+  %define GHCB_BOOKKEEPING_BASE (GHCB_BASE + 0x1000)
+  %define GHCB_BOOKKEEPING_SIZE (GHCB_SIZE - 0x1000)
 
 %include "Ia32/Flat32ToFlat64.asm"
 %include "Ia32/AmdSev.asm"
diff --git a/OvmfPkg/ResetVector/X64/OvmfMetadata.asm b/OvmfPkg/ResetVector/X64/OvmfMetadata.asm
index 95bac86a3b95..657d6c298d4e 100644
--- a/OvmfPkg/ResetVector/X64/OvmfMetadata.asm
+++ b/OvmfPkg/ResetVector/X64/OvmfMetadata.asm
@@ -49,6 +49,48 @@ _Descriptor:
   DD OVMF_METADATA_VERSION                            ; Version
   DD (OvmfGuidedStructureEnd - _Descriptor - 16) / 12 ; Number of sections
 
+; Page table used during SEC
+SecPageTable:
+  DD  SEC_PAGE_TABLE_BASE
+  DD  SEC_PAGE_TABLE_SIZE
+  DD  OVMF_SECTION_TYPE_SEC_MEM
+
+; Lockbox storage
+LockBoxStorage:
+  DD  LOCK_BOX_STORAGE_BASE
+  DD  LOCK_BOX_STORAGE_SIZE
+  DD  OVMF_SECTION_TYPE_SEC_MEM
+
+; Guided Extract Handler Table
+ExtractHandlerTable:
+  DD  GUID_EXTRACT_HANDLER_TABLE_BASE
+  DD  GUID_EXTRACT_HANDLER_TABLE_SIZE
+  DD  OVMF_SECTION_TYPE_SEC_MEM
+
+; GHCB page table
+GhcbPageTable:
+  DD  GHCB_PT_ADDR
+  DD  GHCB_PT_SIZE
+  DD  OVMF_SECTION_TYPE_SEC_MEM
+
+; GHCB bookkeeping page used in SEC phase
+GhcbBookkeeping:
+  DD  GHCB_BOOKKEEPING_BASE
+  DD  GHCB_BOOKKEEPING_SIZE
+  DD  OVMF_SECTION_TYPE_SEC_MEM
+
+; Confidential computing work area
+WorkArea:
+  DD  WORK_AREA_BASE
+  DD  WORK_AREA_SIZE
+  DD  OVMF_SECTION_TYPE_SEC_MEM
+
+; GHCB backup page used in SEC
+GhcbBackup:
+  DD  GHCB_SEC_BACKUP_BASE
+  DD  GHCB_SEC_BACKUP_SIZE
+  DD  OVMF_SECTION_TYPE_SEC_MEM
+
 ; SEV-SNP Secrets page
 SevSnpSecrets:
   DD  SEV_SNP_SECRETS_BASE
@@ -61,5 +103,11 @@ CpuidSec:
   DD  CPUID_SIZE
   DD  OVMF_SECTION_TYPE_CPUID
 
+; Temporary RAM used in SEC phase
+SecPeiTempRam:
+  DD  SEC_PEI_TEMP_RAM_BASE
+  DD  SEC_PEI_TEMP_RAM_SIZE
+  DD  OVMF_SECTION_TYPE_SEC_MEM
+
 OvmfGuidedStructureEnd:
   ALIGN   16
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 07/31] OvmfPkg/ResetVector: use SEV-SNP-validated CPUID values
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (5 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 06/31] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 08/31] OvmfPkg/MemEncryptSevLib: add MemEncryptSevSnpEnabled() Brijesh Singh
                   ` (23 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Michael Roth, Brijesh Singh

From: Michael Roth <michael.roth@amd.com>

CPUID instructions are issued during early boot to do things like probe
for SEV support. Currently these are handled by a minimal #VC handler
that uses the MSR-based GHCB protocol to fetch the CPUID values from
the hypervisor. When SEV-SNP is enabled, use the firmware-validated
CPUID values from the CPUID page instead [1].

[1]: SEV SNP Firmware ABI Specification, Rev. 0.8, 8.13.2.6

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>
Signed-off-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/ResetVector/Ia32/AmdSev.asm | 80 +++++++++++++++++++++++++++--
 1 file changed, 75 insertions(+), 5 deletions(-)

diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
index 48d9178168b0..1f827da3b929 100644
--- a/OvmfPkg/ResetVector/Ia32/AmdSev.asm
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -34,6 +34,18 @@ BITS    32
 %define GHCB_CPUID_REGISTER_SHIFT  30
 %define CPUID_INSN_LEN              2
 
+; #VC handler offsets/sizes for accessing SNP CPUID page
+;
+%define SNP_CPUID_ENTRY_SZ         48
+%define SNP_CPUID_COUNT             0
+%define SNP_CPUID_ENTRY            16
+%define SNP_CPUID_ENTRY_EAX_IN      0
+%define SNP_CPUID_ENTRY_ECX_IN      4
+%define SNP_CPUID_ENTRY_EAX        24
+%define SNP_CPUID_ENTRY_EBX        28
+%define SNP_CPUID_ENTRY_ECX        32
+%define SNP_CPUID_ENTRY_EDX        36
+
 
 %define SEV_GHCB_MSR                0xc0010130
 %define SEV_STATUS_MSR              0xc0010131
@@ -335,11 +347,61 @@ SevEsIdtNotCpuid:
     TerminateVmgExit TERM_VC_NOT_CPUID
     iret
 
-    ;
-    ; Total stack usage for the #VC handler is 44 bytes:
-    ;   - 12 bytes for the exception IRET (after popping error code)
-    ;   - 32 bytes for the local variables.
-    ;
+; Use the SNP CPUID page to handle the cpuid lookup
+;
+;  Modified: EAX, EBX, ECX, EDX
+;
+;  Relies on the stack setup/usage in #VC handler:
+;
+;    On entry,
+;      [esp + VC_CPUID_FUNCTION] contains EAX input to cpuid instruction
+;
+;    On return, stores corresponding results of CPUID lookup in:
+;      [esp + VC_CPUID_RESULT_EAX]
+;      [esp + VC_CPUID_RESULT_EBX]
+;      [esp + VC_CPUID_RESULT_ECX]
+;      [esp + VC_CPUID_RESULT_EDX]
+;
+SnpCpuidLookup:
+    mov     eax, [esp + VC_CPUID_FUNCTION]
+    mov     ebx, [CPUID_BASE + SNP_CPUID_COUNT]
+    mov     ecx, CPUID_BASE + SNP_CPUID_ENTRY
+    ; Zero these out now so we can simply return if lookup fails
+    mov     dword[esp + VC_CPUID_RESULT_EAX], 0
+    mov     dword[esp + VC_CPUID_RESULT_EBX], 0
+    mov     dword[esp + VC_CPUID_RESULT_ECX], 0
+    mov     dword[esp + VC_CPUID_RESULT_EDX], 0
+
+SnpCpuidCheckEntry:
+    cmp     ebx, 0
+    je      VmmDoneSnpCpuid
+    cmp     dword[ecx + SNP_CPUID_ENTRY_EAX_IN], eax
+    jne     SnpCpuidCheckEntryNext
+    ; As with SEV-ES handler we assume requested CPUID sub-leaf/index is 0
+    cmp     dword[ecx + SNP_CPUID_ENTRY_ECX_IN], 0
+    je      SnpCpuidEntryFound
+
+SnpCpuidCheckEntryNext:
+    dec     ebx
+    add     ecx, SNP_CPUID_ENTRY_SZ
+    jmp     SnpCpuidCheckEntry
+
+SnpCpuidEntryFound:
+    mov     eax, [ecx + SNP_CPUID_ENTRY_EAX]
+    mov     [esp + VC_CPUID_RESULT_EAX], eax
+    mov     eax, [ecx + SNP_CPUID_ENTRY_EBX]
+    mov     [esp + VC_CPUID_RESULT_EBX], eax
+    mov     eax, [ecx + SNP_CPUID_ENTRY_EDX]
+    mov     [esp + VC_CPUID_RESULT_ECX], eax
+    mov     eax, [ecx + SNP_CPUID_ENTRY_ECX]
+    mov     [esp + VC_CPUID_RESULT_EDX], eax
+    jmp     VmmDoneSnpCpuid
+
+;
+; Total stack usage for the #VC handler is 44 bytes:
+;   - 12 bytes for the exception IRET (after popping error code)
+;   - 32 bytes for the local variables.
+;
 SevEsIdtVmmComm:
     ;
     ; If we're here, then we are an SEV-ES guest and this
@@ -367,6 +429,13 @@ SevEsIdtVmmComm:
     ; Save the CPUID function being requested
     mov     [esp + VC_CPUID_FUNCTION], eax
 
+    ; If SEV-SNP is enabled, use the CPUID page to handle the CPUID
+    ; instruction.
+    mov     ecx, SEV_STATUS_MSR
+    rdmsr
+    bt      eax, 2
+    jc      SnpCpuidLookup
+
     ; The GHCB CPUID protocol uses the following mapping to request
     ; a specific register:
     ;   0 => EAX, 1 => EBX, 2 => ECX, 3 => EDX
@@ -424,6 +493,7 @@ VmmDone:
     mov     ecx, SEV_GHCB_MSR
     wrmsr
 
+VmmDoneSnpCpuid:
     mov     eax, [esp + VC_CPUID_RESULT_EAX]
     mov     ebx, [esp + VC_CPUID_RESULT_EBX]
     mov     ecx, [esp + VC_CPUID_RESULT_ECX]
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 08/31] OvmfPkg/MemEncryptSevLib: add MemEncryptSevSnpEnabled()
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (6 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 07/31] OvmfPkg/ResetVector: use SEV-SNP-validated CPUID values Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 09/31] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest Brijesh Singh
                   ` (22 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

Create a function that can be used to determine if VM is running as an
SEV-SNP guest.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/Include/Library/MemEncryptSevLib.h    | 12 +++++++++
 .../DxeMemEncryptSevLibInternal.c             | 27 +++++++++++++++++++
 .../PeiMemEncryptSevLibInternal.c             | 27 +++++++++++++++++++
 .../SecMemEncryptSevLibInternal.c             | 19 +++++++++++++
 4 files changed, 85 insertions(+)

diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h b/OvmfPkg/Include/Library/MemEncryptSevLib.h
index adc490e466ec..796de62ec2f8 100644
--- a/OvmfPkg/Include/Library/MemEncryptSevLib.h
+++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h
@@ -47,6 +47,18 @@ typedef enum {
   MemEncryptSevAddressRangeError,
 } MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE;
 
+/**
+  Returns a boolean to indicate whether SEV-SNP is enabled
+
+  @retval TRUE           SEV-SNP is enabled
+  @retval FALSE          SEV-SNP is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevSnpIsEnabled (
+  VOID
+  );
+
 /**
   Returns a boolean to indicate whether SEV-ES is enabled.
 
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c
index 2816f859a0c4..057129723824 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c
@@ -19,6 +19,7 @@
 
 STATIC BOOLEAN mSevStatus = FALSE;
 STATIC BOOLEAN mSevEsStatus = FALSE;
+STATIC BOOLEAN mSevSnpStatus = FALSE;
 STATIC BOOLEAN mSevStatusChecked = FALSE;
 
 STATIC UINT64  mSevEncryptionMask = 0;
@@ -82,11 +83,37 @@ InternalMemEncryptSevStatus (
     if (Msr.Bits.SevEsBit) {
       mSevEsStatus = TRUE;
     }
+
+    //
+    // Check MSR_0xC0010131 Bit 2 (Sev-Snp Enabled)
+    //
+    if (Msr.Bits.SevSnpBit) {
+      mSevSnpStatus = TRUE;
+    }
   }
 
   mSevStatusChecked = TRUE;
 }
 
+/**
+  Returns a boolean to indicate whether SEV-SNP is enabled.
+
+  @retval TRUE           SEV-SNP is enabled
+  @retval FALSE          SEV-SNP is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevSnpIsEnabled (
+  VOID
+  )
+{
+  if (!mSevStatusChecked) {
+    InternalMemEncryptSevStatus ();
+  }
+
+  return mSevSnpStatus;
+}
+
 /**
   Returns a boolean to indicate whether SEV-ES is enabled.
 
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLibInternal.c
index e2fd109d120f..b561f211f577 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLibInternal.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLibInternal.c
@@ -19,6 +19,7 @@
 
 STATIC BOOLEAN mSevStatus = FALSE;
 STATIC BOOLEAN mSevEsStatus = FALSE;
+STATIC BOOLEAN mSevSnpStatus = FALSE;
 STATIC BOOLEAN mSevStatusChecked = FALSE;
 
 STATIC UINT64  mSevEncryptionMask = 0;
@@ -82,11 +83,37 @@ InternalMemEncryptSevStatus (
     if (Msr.Bits.SevEsBit) {
       mSevEsStatus = TRUE;
     }
+
+    //
+    // Check MSR_0xC0010131 Bit 2 (Sev-Snp Enabled)
+    //
+    if (Msr.Bits.SevSnpBit) {
+      mSevSnpStatus = TRUE;
+    }
   }
 
   mSevStatusChecked = TRUE;
 }
 
+/**
+  Returns a boolean to indicate whether SEV-SNP is enabled.
+
+  @retval TRUE           SEV-SNP is enabled
+  @retval FALSE          SEV-SNP is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevSnpIsEnabled (
+  VOID
+  )
+{
+  if (!mSevStatusChecked) {
+    InternalMemEncryptSevStatus ();
+  }
+
+  return mSevSnpStatus;
+}
+
 /**
   Returns a boolean to indicate whether SEV-ES is enabled.
 
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c
index 56d8f3f3183f..69852779e2ff 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c
@@ -62,6 +62,25 @@ InternalMemEncryptSevStatus (
   return ReadSevMsr ? AsmReadMsr32 (MSR_SEV_STATUS) : 0;
 }
 
+/**
+  Returns a boolean to indicate whether SEV-SNP is enabled.
+
+  @retval TRUE           SEV-SNP is enabled
+  @retval FALSE          SEV-SNP is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevSnpIsEnabled (
+  VOID
+  )
+{
+  MSR_SEV_STATUS_REGISTER           Msr;
+
+  Msr.Uint32 = InternalMemEncryptSevStatus ();
+
+  return Msr.Bits.SevSnpBit ? TRUE : FALSE;
+}
+
 /**
   Returns a boolean to indicate whether SEV-ES is enabled.
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 09/31] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (7 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 08/31] OvmfPkg/MemEncryptSevLib: add MemEncryptSevSnpEnabled() Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-15 17:08   ` Erdem Aktas
  2021-09-13 18:19 ` [PATCH v7 10/31] OvmfPkg/VmgExitLib: use SEV-SNP-validated CPUID values Brijesh Singh
                   ` (21 subsequent siblings)
  30 siblings, 1 reply; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

The SEV-SNP guest requires that GHCB GPA must be registered before using.
See the GHCB specification section 2.3.2 for more details.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/Sec/AmdSev.c | 137 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 137 insertions(+)

diff --git a/OvmfPkg/Sec/AmdSev.c b/OvmfPkg/Sec/AmdSev.c
index 7f74e8bfe88e..7d4d7cc8a07c 100644
--- a/OvmfPkg/Sec/AmdSev.c
+++ b/OvmfPkg/Sec/AmdSev.c
@@ -48,6 +48,125 @@ SevEsProtocolFailure (
   CpuDeadLoop ();
 }
 
+/**
+  Determine if SEV-SNP is active.
+
+  @retval TRUE   SEV-SNP is enabled
+  @retval FALSE  SEV-SNP is not enabled
+
+**/
+STATIC
+BOOLEAN
+SevSnpIsEnabled (
+  VOID
+  )
+{
+  MSR_SEV_STATUS_REGISTER           Msr;
+
+  //
+  // Read the SEV_STATUS MSR to determine whether SEV-SNP is active.
+  //
+  Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
+
+  //
+  // Check MSR_0xC0010131 Bit 2 (Sev-Snp Enabled)
+  //
+  if (Msr.Bits.SevSnpBit) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+ Register the GHCB GPA
+
+*/
+STATIC
+VOID
+SevSnpGhcbRegister (
+  UINTN   Address
+  )
+{
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+  MSR_SEV_ES_GHCB_REGISTER  CurrentMsr;
+  EFI_PHYSICAL_ADDRESS      GuestFrameNumber;
+
+  GuestFrameNumber = Address >> EFI_PAGE_SHIFT;
+
+  //
+  // Save the current MSR Value
+  //
+  CurrentMsr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+
+  //
+  // Use the GHCB MSR Protocol to request to register the GPA.
+  //
+  Msr.GhcbPhysicalAddress = 0;
+  Msr.GhcbGpaRegister.Function = GHCB_INFO_GHCB_GPA_REGISTER_REQUEST;
+  Msr.GhcbGpaRegister.GuestFrameNumber = GuestFrameNumber;
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+  AsmVmgExit ();
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+
+  //
+  // If hypervisor responded with a different GPA than requested then fail.
+  //
+  if ((Msr.GhcbGpaRegister.Function != GHCB_INFO_GHCB_GPA_REGISTER_RESPONSE) ||
+      (Msr.GhcbGpaRegister.GuestFrameNumber != GuestFrameNumber)) {
+    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
+  }
+
+  //
+  // Restore the MSR
+  //
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, CurrentMsr.GhcbPhysicalAddress);
+}
+
+/**
+ Verify that Hypervisor supports the SNP feature.
+
+ */
+STATIC
+BOOLEAN
+HypervisorSnpFeatureCheck (
+  VOID
+  )
+{
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+  MSR_SEV_ES_GHCB_REGISTER  CurrentMsr;
+
+  //
+  // Save the current MSR Value
+  //
+  CurrentMsr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+
+  //
+  // Use the GHCB MSR Protocol to query the hypervisor capabilities
+  //
+  Msr.GhcbPhysicalAddress = 0;
+  Msr.GhcbHypervisorFeatures.Function = GHCB_HYPERVISOR_FEATURES_REQUEST;
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+  AsmVmgExit ();
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+
+  if ((Msr.GhcbHypervisorFeatures.Function != GHCB_HYPERVISOR_FEATURES_RESPONSE) ||
+      (!(Msr.GhcbHypervisorFeatures.Features & GHCB_HV_FEATURES_SNP))) {
+    return FALSE;
+  }
+
+  //
+  // Restore the MSR
+  //
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, CurrentMsr.GhcbPhysicalAddress);
+
+  return TRUE;
+}
+
 /**
   Validate the SEV-ES/GHCB protocol level.
 
@@ -88,6 +207,24 @@ SevEsProtocolCheck (
     SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
   }
 
+  //
+  // We cannot use the MemEncryptSevSnpIsEnabled () because the
+  // ProcessLibraryConstructorList () is not called yet.
+  //
+  if (SevSnpIsEnabled ()) {
+    //
+    // Check if hypervisor supports the SNP feature
+    //
+    if (!HypervisorSnpFeatureCheck ()) {
+      SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
+    }
+
+    //
+    // SEV-SNP guest requires that GHCB GPA must be registered before using it.
+    //
+    SevSnpGhcbRegister (FixedPcdGet32 (PcdOvmfSecGhcbBase));
+  }
+
   //
   // SEV-ES protocol checking succeeded, set the initial GHCB address
   //
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 10/31] OvmfPkg/VmgExitLib: use SEV-SNP-validated CPUID values
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (8 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 09/31] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 11/31] OvmfPkg/PlatformPei: register GHCB gpa for the SEV-SNP guest Brijesh Singh
                   ` (20 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Michael Roth, Brijesh Singh

From: Michael Roth <michael.roth@amd.com>

SEV-SNP firmware allows a special guest page to be populated with
guest CPUID values so that they can be validated against supported
host features before being loaded into encrypted guest memory to be
used instead of hypervisor-provided values [1].

Add handling for this in the CPUID #VC handler and use it whenever
SEV-SNP is enabled. To do so, existing CPUID handling via VmgExit is
moved to a helper, GetCpuidHyp(), and a new helper that uses the CPUID
page to do the lookup, GetCpuidFw(), is used instead when SNP is
enabled. For cases where SNP CPUID lookups still rely on fetching
specific CPUID fields from hypervisor, GetCpuidHyp() is used there as
well.

[1]: SEV SNP Firmware ABI Specification, Rev. 0.8, 8.13.2.6

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>
Signed-off-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf  |   2 +
 OvmfPkg/Library/VmgExitLib/VmgExitLib.inf     |   3 +
 OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c | 444 ++++++++++++++++--
 3 files changed, 419 insertions(+), 30 deletions(-)

diff --git a/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
index e6f6ea7972fd..78207fa0f9c9 100644
--- a/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
+++ b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
@@ -42,4 +42,6 @@ [LibraryClasses]
 [FixedPcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
 
diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
index c66c68726cdb..7963670e7d30 100644
--- a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
+++ b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
@@ -38,3 +38,6 @@ [LibraryClasses]
   LocalApicLib
   MemEncryptSevLib
 
+[Pcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
index 41b0c8cc5312..cab4e2b230d0 100644
--- a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
+++ b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
@@ -17,6 +17,7 @@
 #include <IndustryStandard/InstructionParsing.h>
 
 #include "VmgExitVcHandler.h"
+//#include <Library/MemEncryptSevLib.h>
 
 //
 // Instruction execution mode definition
@@ -130,6 +131,32 @@ UINT64
   SEV_ES_INSTRUCTION_DATA  *InstructionData
   );
 
+//
+// SEV-SNP Cpuid table entry/function
+//
+typedef PACKED struct {
+  UINT32   EaxIn;
+  UINT32   EcxIn;
+  UINT64   Unused;
+  UINT64   Unused2;
+  UINT32   Eax;
+  UINT32   Ebx;
+  UINT32   Ecx;
+  UINT32   Edx;
+  UINT64   Reserved;
+} SEV_SNP_CPUID_FUNCTION;
+
+//
+// SEV-SNP Cpuid page format
+//
+typedef PACKED struct {
+  UINT32   Count;
+  UINT32   Reserved1;
+  UINT64   Reserved2;
+  SEV_SNP_CPUID_FUNCTION function[0];
+} SEV_SNP_CPUID_INFO;
+
+
 /**
   Return a pointer to the contents of the specified register.
 
@@ -1496,58 +1523,415 @@ InvdExit (
 }
 
 /**
-  Handle a CPUID event.
+  Fetch CPUID leaf/function via hypervisor/VMGEXIT.
 
-  Use the VMGEXIT instruction to handle a CPUID event.
+  @param[in, out] Ghcb         Pointer to the Guest-Hypervisor Communication
+                               Block
+  @param[in]      EaxIn        EAX input for cpuid instruction
+  @param[in]      EcxIn        ECX input for cpuid instruction
+  @param[in]      Xcr0In       XCR0 at time of cpuid instruction
+  @param[in, out] Eax          Pointer to store leaf's EAX value
+  @param[in, out] Ebx          Pointer to store leaf's EBX value
+  @param[in, out] Ecx          Pointer to store leaf's ECX value
+  @param[in, out] Edx          Pointer to store leaf's EDX value
+  @param[in, out] Status       Pointer to store status from VMGEXIT (always 0
+                               unless return value indicates failure)
+  @param[in, out] Unsupported  Pointer to store indication of unsupported
+                               VMGEXIT (always false unless return value
+                               indicates failure)
 
-  @param[in, out] Ghcb             Pointer to the Guest-Hypervisor Communication
-                                   Block
-  @param[in, out] Regs             x64 processor context
-  @param[in]      InstructionData  Instruction parsing context
-
-  @retval 0                        Event handled successfully
-  @return                          New exception value to propagate
+  @retval TRUE                 CPUID leaf fetch successfully.
+  @retval FALSE                Error occurred while fetching CPUID leaf. Callers
+                               should Status and Unsupported and handle
+                               accordingly if they indicate a more precise
+                               error condition.
 
 **/
 STATIC
-UINT64
-CpuidExit (
+BOOLEAN
+GetCpuidHyp (
   IN OUT GHCB                     *Ghcb,
-  IN OUT EFI_SYSTEM_CONTEXT_X64   *Regs,
-  IN     SEV_ES_INSTRUCTION_DATA  *InstructionData
+  IN     UINT32                   EaxIn,
+  IN     UINT32                   EcxIn,
+  IN     UINT64                   XCr0,
+  IN OUT UINT32                   *Eax,
+  IN OUT UINT32                   *Ebx,
+  IN OUT UINT32                   *Ecx,
+  IN OUT UINT32                   *Edx,
+  IN OUT UINT64                   *Status,
+  IN OUT BOOLEAN                  *UnsupportedExit
   )
 {
-  UINT64  Status;
-
-  Ghcb->SaveArea.Rax = Regs->Rax;
+  *UnsupportedExit = FALSE;
+  Ghcb->SaveArea.Rax = EaxIn;
   VmgSetOffsetValid (Ghcb, GhcbRax);
-  Ghcb->SaveArea.Rcx = Regs->Rcx;
+  Ghcb->SaveArea.Rcx = EcxIn;
   VmgSetOffsetValid (Ghcb, GhcbRcx);
-  if (Regs->Rax == CPUID_EXTENDED_STATE) {
-    IA32_CR4  Cr4;
-
-    Cr4.UintN = AsmReadCr4 ();
-    Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;
+  if (EaxIn == CPUID_EXTENDED_STATE) {
+    Ghcb->SaveArea.XCr0 = XCr0;
     VmgSetOffsetValid (Ghcb, GhcbXCr0);
   }
 
-  Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);
-  if (Status != 0) {
-    return Status;
+  *Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);
+  if (*Status != 0) {
+    return FALSE;
   }
 
   if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
       !VmgIsOffsetValid (Ghcb, GhcbRbx) ||
       !VmgIsOffsetValid (Ghcb, GhcbRcx) ||
       !VmgIsOffsetValid (Ghcb, GhcbRdx)) {
-    return UnsupportedExit (Ghcb, Regs, InstructionData);
+    *UnsupportedExit = TRUE;
+    return FALSE;
   }
-  Regs->Rax = Ghcb->SaveArea.Rax;
-  Regs->Rbx = Ghcb->SaveArea.Rbx;
-  Regs->Rcx = Ghcb->SaveArea.Rcx;
-  Regs->Rdx = Ghcb->SaveArea.Rdx;
+
+  if (Eax) {
+    *Eax = Ghcb->SaveArea.Rax;
+  }
+  if (Ebx) {
+    *Ebx = Ghcb->SaveArea.Rbx;
+  }
+  if (Ecx) {
+    *Ecx = Ghcb->SaveArea.Rcx;
+  }
+  if (Edx) {
+    *Edx = Ghcb->SaveArea.Rdx;
+  }
+
+  return TRUE;
+}
+
+/**
+  Check if SEV-SNP enabled.
+
+  @retval TRUE      SEV-SNP is enabled.
+  @retval FALSE     SEV-SNP is disabled.
+
+**/
+STATIC
+BOOLEAN
+SnpEnabled (VOID)
+{
+  MSR_SEV_STATUS_REGISTER  Msr;
+
+  Msr.Uint32 = AsmReadMsr32(MSR_SEV_STATUS);
+
+  return !!Msr.Bits.SevSnpBit;
+}
+
+/**
+  Calculate the total XSAVE area size for enabled XSAVE areas
+
+  @param[in]      XFeaturesEnabled  Bit-mask of enabled XSAVE features/areas as
+                                    indicated by XCR0/MSR_IA32_XSS bits
+  @param[in]      XSaveBaseSize     Base/legacy XSAVE area size (e.g. when
+                                    XCR0 is 1)
+  @param[in, out] XSaveSize         Pointer to storage for calculated XSAVE area
+                                    size
+  @param[in]      Compacted         Whether or not the calculation is for the
+                                    normal XSAVE area size (leaf 0xD,0x0,EBX) or
+                                    compacted XSAVE area size (leaf 0xD,0x1,EBX)
+
+
+  @retval TRUE                      XSAVE size calculation was successful.
+  @retval FALSE                     XSAVE size calculation was unsuccessful.
+**/
+STATIC
+BOOLEAN
+GetCpuidXSaveSize (
+  IN     UINT64   XFeaturesEnabled,
+  IN     UINT32   XSaveBaseSize,
+  IN OUT UINT32   *XSaveSize,
+  IN     BOOLEAN  Compacted
+  )
+{
+  SEV_SNP_CPUID_INFO  *CpuidInfo;
+  UINT64              XFeaturesFound = 0;
+  UINT32              Idx;
+
+  *XSaveSize = XSaveBaseSize;
+  CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32(PcdOvmfCpuidBase);
+
+  for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {
+    SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];
+
+    if (!(CpuidFn->EaxIn == 0xD &&
+          (CpuidFn->EcxIn == 0 || CpuidFn->EcxIn == 1))) {
+      continue;
+    }
+
+    if (XFeaturesFound & (1UL << CpuidFn->EcxIn) ||
+        !(XFeaturesEnabled & (1UL << CpuidFn->EcxIn))) {
+        continue;
+    }
+
+    XFeaturesFound |= (1UL << CpuidFn->EcxIn);
+    if (Compacted) {
+        *XSaveSize += CpuidFn->Eax;
+    } else {
+        *XSaveSize = MAX(*XSaveSize, CpuidFn->Eax + CpuidFn->Ebx);
+    }
+  }
+
+  /*
+   * Either the guest set unsupported XCR0/XSS bits, or the corresponding
+   * entries in the CPUID table were not present. This is an invalid state.
+   */
+  if (XFeaturesFound != (XFeaturesEnabled & ~3UL)) {
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  Check if a CPUID leaf/function is indexed via ECX sub-leaf/sub-function
+
+  @param[in]      EaxIn        EAX input for cpuid instruction
+
+  @retval FALSE                cpuid leaf/function is not indexed by ECX input
+  @retval TRUE                 cpuid leaf/function is indexed by ECX input
+
+**/
+STATIC
+BOOLEAN
+IsFunctionIndexed (
+  IN     UINT32  EaxIn
+  )
+{
+    switch (EaxIn) {
+    case CPUID_CACHE_PARAMS:
+    case CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS:
+    case CPUID_EXTENDED_TOPOLOGY:
+    case CPUID_EXTENDED_STATE:
+    case CPUID_INTEL_RDT_MONITORING:
+    case CPUID_INTEL_RDT_ALLOCATION:
+    case CPUID_INTEL_SGX:
+    case CPUID_INTEL_PROCESSOR_TRACE:
+    case CPUID_DETERMINISTIC_ADDRESS_TRANSLATION_PARAMETERS:
+    case CPUID_V2_EXTENDED_TOPOLOGY:
+    case 0x8000001D: /* Cache Topology Information */
+        return TRUE;
+    }
+    return FALSE;
+}
+
+/**
+  Fetch CPUID leaf/function via SEV-SNP CPUID table.
+
+  @param[in, out] Ghcb         Pointer to the Guest-Hypervisor Communication
+                               Block
+  @param[in]      EaxIn        EAX input for cpuid instruction
+  @param[in]      EcxIn        ECX input for cpuid instruction
+  @param[in]      Xcr0In       XCR0 at time of cpuid instruction
+  @param[in, out] Eax          Pointer to store leaf's EAX value
+  @param[in, out] Ebx          Pointer to store leaf's EBX value
+  @param[in, out] Ecx          Pointer to store leaf's ECX value
+  @param[in, out] Edx          Pointer to store leaf's EDX value
+  @param[in, out] Status       Pointer to store status from VMGEXIT (always 0
+                               unless return value indicates failure)
+  @param[in, out] Unsupported  Pointer to store indication of unsupported
+                               VMGEXIT (always false unless return value
+                               indicates failure)
+
+  @retval TRUE                 CPUID leaf fetch successfully.
+  @retval FALSE                Error occurred while fetching CPUID leaf. Callers
+                               should Status and Unsupported and handle
+                               accordingly if they indicate a more precise
+                               error condition.
+
+**/
+STATIC
+BOOLEAN
+GetCpuidFw (
+  IN OUT GHCB     *Ghcb,
+  IN     UINT32   EaxIn,
+  IN     UINT32   EcxIn,
+  IN     UINT64   XCr0,
+  IN OUT UINT32   *Eax,
+  IN OUT UINT32   *Ebx,
+  IN OUT UINT32   *Ecx,
+  IN OUT UINT32   *Edx,
+  IN OUT UINT64   *Status,
+  IN OUT BOOLEAN  *Unsupported
+  )
+{
+  SEV_SNP_CPUID_INFO  *CpuidInfo;
+  BOOLEAN             Found;
+  UINT32              Idx;
+
+  CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32(PcdOvmfCpuidBase);
+  Found = FALSE;
+
+  for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {
+    SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];
+
+    if (CpuidFn->EaxIn != EaxIn) {
+      continue;
+    }
+
+    if (IsFunctionIndexed(CpuidFn->EaxIn) && CpuidFn->EcxIn != EcxIn) {
+      continue;
+    }
+
+    *Eax = CpuidFn->Eax;
+    *Ebx = CpuidFn->Ebx;
+    *Ecx = CpuidFn->Ecx;
+    *Edx = CpuidFn->Edx;
+
+    Found = TRUE;
+    break;
+  }
+
+  if (!Found) {
+    *Eax = *Ebx = *Ecx = *Edx = 0;
+    goto Out;
+  }
+
+  if (EaxIn == CPUID_VERSION_INFO) {
+    IA32_CR4  Cr4;
+    UINT32    Ebx2;
+    UINT32    Edx2;
+
+    if (!GetCpuidHyp (Ghcb, EaxIn, EcxIn, XCr0, NULL, &Ebx2, NULL, &Edx2,
+                      Status, Unsupported)) {
+      return FALSE;
+    }
+
+    /* initial APIC ID */
+    *Ebx = (*Ebx & 0x00FFFFFF) | (Ebx2 & 0xFF000000);
+    /* APIC enabled bit */
+    *Edx = (*Edx & ~BIT9) | (Edx2 & BIT9);
+    /* OSXSAVE enabled bit */
+    Cr4.UintN = AsmReadCr4 ();
+    *Ecx = (Cr4.Bits.OSXSAVE) ? (*Ecx & ~BIT27) | (*Ecx & BIT27)
+                              : (*Ecx & ~BIT27);
+  } else if (EaxIn == CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) {
+    IA32_CR4  Cr4;
+
+    Cr4.UintN = AsmReadCr4 ();
+    /* OSPKE enabled bit */
+    *Ecx = (Cr4.Bits.PKE) ? (*Ecx | BIT4) : (*Ecx & ~BIT4);
+  } else if (EaxIn == CPUID_EXTENDED_TOPOLOGY) {
+    if (!GetCpuidHyp (Ghcb, EaxIn, EcxIn, XCr0, NULL, NULL, NULL, Edx,
+                      Status, Unsupported)) {
+      return FALSE;
+    }
+  } else if (EaxIn == CPUID_EXTENDED_STATE && (EcxIn == 0 || EcxIn == 1)) {
+    MSR_IA32_XSS_REGISTER  XssMsr;
+    BOOLEAN                Compacted;
+    UINT32                 XSaveSize;
+
+    XssMsr.Uint64 = 0;
+    if (EcxIn == 1) {
+        /*
+         * The PPR and APM aren't clear on what size should be encoded in
+         * 0xD:0x1:EBX when compaction is not enabled by either XSAVEC or
+         * XSAVES, as these are generally fixed to 1 on real CPUs. Report
+         * this undefined case as an error.
+         */
+        if (!(*Eax & (BIT3 | BIT1))) { /* (XSAVES | XSAVEC) */
+            return FALSE;
+        }
+
+        Compacted = TRUE;
+        XssMsr.Uint64 = AsmReadMsr64 (MSR_IA32_XSS);
+    }
+
+    if (!GetCpuidXSaveSize (XCr0 | XssMsr.Uint64, *Ebx, &XSaveSize,
+                            Compacted)) {
+        return FALSE;
+    }
+
+    *Ebx = XSaveSize;
+  } else if (EaxIn == 0x8000001E) {
+    UINT32  Ebx2;
+    UINT32  Ecx2;
+
+    /* extended APIC ID */
+    if (!GetCpuidHyp (Ghcb, EaxIn, EcxIn, XCr0, Eax, &Ebx2, &Ecx2, NULL,
+                      Status, Unsupported)) {
+      return FALSE;
+    }
+    /* compute ID */
+    *Ebx = (*Ebx & 0xFFFFFF00) | (Ebx2 & 0x000000FF);
+    /* node ID */
+    *Ecx = (*Ecx & 0xFFFFFF00) | (Ecx2 & 0x000000FF);
+  }
+
+Out:
+  *Status = 0;
+  *Unsupported = FALSE;
+  return TRUE;
+}
+
+/**
+  Handle a CPUID event.
+
+  Use VMGEXIT instruction or CPUID table to handle a CPUID event.
+
+  @param[in, out] Ghcb             Pointer to the Guest-Hypervisor Communication
+                                   Block
+  @param[in, out] Regs             x64 processor context
+  @param[in]      InstructionData  Instruction parsing context
+
+  @retval 0                        Event handled successfully
+  @return                          New exception value to propagate
+
+**/
+STATIC
+UINT64
+CpuidExit (
+  IN OUT GHCB                     *Ghcb,
+  IN OUT EFI_SYSTEM_CONTEXT_X64   *Regs,
+  IN     SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  BOOLEAN             Unsupported;
+  UINT64              Status;
+  UINT32              EaxIn;
+  UINT32              EcxIn;
+  UINT64              XCr0;
+  UINT32              Eax;
+  UINT32              Ebx;
+  UINT32              Ecx;
+  UINT32              Edx;
+
+  EaxIn = Regs->Rax;
+  EcxIn = Regs->Rcx;
+
+  if (EaxIn == CPUID_EXTENDED_STATE) {
+    IA32_CR4  Cr4;
+
+    Cr4.UintN = AsmReadCr4 ();
+    XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;
+  }
+
+  if (SnpEnabled ()) {
+      if (!GetCpuidFw (Ghcb, EaxIn, EcxIn, XCr0, &Eax, &Ebx, &Ecx, &Edx,
+                       &Status, &Unsupported)) {
+        goto CpuidFail;
+      }
+  } else {
+      if (!GetCpuidHyp (Ghcb, EaxIn, EcxIn, XCr0, &Eax, &Ebx, &Ecx, &Edx,
+                        &Status, &Unsupported)) {
+        goto CpuidFail;
+      }
+  }
+
+  Regs->Rax = Eax;
+  Regs->Rbx = Ebx;
+  Regs->Rcx = Ecx;
+  Regs->Rdx = Edx;
 
   return 0;
+
+CpuidFail:
+  if (Unsupported) {
+    return UnsupportedExit (Ghcb, Regs, InstructionData);
+  }
+
+  return Status;
 }
 
 /**
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 11/31] OvmfPkg/PlatformPei: register GHCB gpa for the SEV-SNP guest
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (9 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 10/31] OvmfPkg/VmgExitLib: use SEV-SNP-validated CPUID values Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-16  8:33   ` Gerd Hoffmann
  2021-09-13 18:19 ` [PATCH v7 12/31] OvmfPkg/AmdSevDxe: do not use extended PCI config space Brijesh Singh
                   ` (19 subsequent siblings)
  30 siblings, 1 reply; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

The SEV-SNP guest requires that GHCB GPA must be registered before using.
See the GHCB specification section 2.3.2 for more details.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/PlatformPei/AmdSev.c | 91 ++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index a8bf610022ba..de876fdb478e 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -19,9 +19,93 @@
 #include <PiPei.h>
 #include <Register/Amd/Msr.h>
 #include <Register/Intel/SmramSaveStateMap.h>
+#include <Library/VmgExitLib.h>
 
 #include "Platform.h"
 
+/**
+  Handle an SEV-SNP/GHCB protocol check failure.
+
+  Notify the hypervisor using the VMGEXIT instruction that the SEV-SNP guest
+  wishes to be terminated.
+
+  @param[in] ReasonCode  Reason code to provide to the hypervisor for the
+                         termination request.
+
+**/
+STATIC
+VOID
+SevEsProtocolFailure (
+  IN UINT8  ReasonCode
+  )
+{
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+
+  //
+  // Use the GHCB MSR Protocol to request termination by the hypervisor
+  //
+  Msr.GhcbPhysicalAddress = 0;
+  Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;
+  Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;
+  Msr.GhcbTerminate.ReasonCode = ReasonCode;
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+  AsmVmgExit ();
+
+  ASSERT (FALSE);
+  CpuDeadLoop ();
+}
+
+/**
+
+  This function can be used to register the GHCB GPA.
+
+  @param[in]  Address           The physical address to be registered.
+
+**/
+STATIC
+VOID
+GhcbRegister (
+  IN  EFI_PHYSICAL_ADDRESS   Address
+  )
+{
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+  MSR_SEV_ES_GHCB_REGISTER  CurrentMsr;
+  EFI_PHYSICAL_ADDRESS      GuestFrameNumber;
+
+  GuestFrameNumber = Address >> EFI_PAGE_SHIFT;
+
+  //
+  // Save the current MSR Value
+  //
+  CurrentMsr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+
+  //
+  // Use the GHCB MSR Protocol to request to register the GPA.
+  //
+  Msr.GhcbPhysicalAddress = 0;
+  Msr.GhcbGpaRegister.Function = GHCB_INFO_GHCB_GPA_REGISTER_REQUEST;
+  Msr.GhcbGpaRegister.GuestFrameNumber = GuestFrameNumber;
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+  AsmVmgExit ();
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+
+  //
+  // If hypervisor responded with a different GPA than requested then fail.
+  //
+  if ((Msr.GhcbGpaRegister.Function != GHCB_INFO_GHCB_GPA_REGISTER_RESPONSE) ||
+      (Msr.GhcbGpaRegister.GuestFrameNumber != GuestFrameNumber)) {
+    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
+  }
+
+  //
+  // Restore the MSR
+  //
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, CurrentMsr.GhcbPhysicalAddress);
+}
+
 /**
 
   Initialize SEV-ES support if running as an SEV-ES guest.
@@ -109,6 +193,13 @@ AmdSevEsInitialize (
     "SEV-ES is enabled, %lu GHCB backup pages allocated starting at 0x%p\n",
     (UINT64)GhcbBackupPageCount, GhcbBackupBase));
 
+  //
+  // SEV-SNP guest requires that GHCB GPA must be registered before using it.
+  //
+  if (MemEncryptSevSnpIsEnabled ()) {
+    GhcbRegister (GhcbBasePa);
+  }
+
   AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);
 
   //
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 12/31] OvmfPkg/AmdSevDxe: do not use extended PCI config space
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (10 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 11/31] OvmfPkg/PlatformPei: register GHCB gpa for the SEV-SNP guest Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 13/31] OvmfPkg/MemEncryptSevLib: add support to validate system RAM Brijesh Singh
                   ` (18 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

Commit 85b8eac59b8c5bd9c7eb9afdb64357ce1aa2e803 added support to ensure
that MMIO is only performed against the un-encrypted memory. If MMIO
is performed against encrypted memory, a #GP is raised.

The AmdSevDxe uses the functions provided by the MemEncryptSevLib to
clear the memory encryption mask from the page table. If the
MemEncryptSevLib is extended to include VmgExitLib then depedency
chain will look like this:

OvmfPkg/AmdSevDxe/AmdSevDxe.inf
-----> MemEncryptSevLib                    class
-----> "OvmfPkg/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf"   instance
-----> VmgExitLib                          class
-----> "OvmfPkg/VmgExitLib"    instance
-----> LocalApicLib                        class
-----> "UefiCpuPkg/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf" instance
-----> TimerLib                            class
-----> "OvmfPkg/AcpiTimerLib/DxeAcpiTimerLib.inf"   instance
-----> PciLib                                           class
-----> "OvmfPkg/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf"    instance
-----> PciExpressLib                                          class
-----> "MdePkg/BasePciExpressLib/BasePciExpressLib.inf"  instance

The LocalApicLib provides a constructor that gets called before the
AmdSevDxe can clear the memory encryption mask from the MMIO regions.

When running under the Q35 machine type, the call chain looks like this:

AcpiTimerLibConstructor ()  [AcpiTimerLib]
  PciRead32 ()              [DxePciLibI440FxQ35]
   PciExpressRead32 ()      [PciExpressLib]

The PciExpressRead32 () reads the MMIO region. The MMIO regions are not
yet mapped un-encrypted, so the check introduced in the commit
85b8eac59b8c5bd9c7eb9afdb64357ce1aa2e803 raises a #GP.

The AmdSevDxe driver does not require the access to the extended PCI
config space. Accessing a normal PCI config space, via IO port should be
sufficent. Use the module-scope override to make the AmdSevDxe use the
BasePciLib instead of BasePciExpressLib so that PciRead32 () uses the
IO ports instead of the extended config space.

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>
Suggested-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/AmdSev/AmdSevX64.dsc | 5 ++++-
 OvmfPkg/Bhyve/BhyveX64.dsc   | 5 ++++-
 OvmfPkg/OvmfPkgIa32X64.dsc   | 5 ++++-
 OvmfPkg/OvmfPkgX64.dsc       | 5 ++++-
 OvmfPkg/OvmfXen.dsc          | 5 ++++-
 5 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index e6cd10b75922..a8ea08a10a99 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -812,7 +812,10 @@ [Components]
 !endif
 
   OvmfPkg/PlatformDxe/Platform.inf
-  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
+  OvmfPkg/AmdSevDxe/AmdSevDxe.inf {
+    <LibraryClasses>
+    PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  }
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
   #
diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc
index d8fe607d1cf7..f45634996247 100644
--- a/OvmfPkg/Bhyve/BhyveX64.dsc
+++ b/OvmfPkg/Bhyve/BhyveX64.dsc
@@ -790,7 +790,10 @@ [Components]
 !endif
 
   OvmfPkg/PlatformDxe/Platform.inf
-  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
+  OvmfPkg/AmdSevDxe/AmdSevDxe.inf {
+    <LibraryClasses>
+    PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  }
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index a467ab7090fb..f42abc041c0c 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -965,7 +965,10 @@ [Components.X64]
 !endif
 
   OvmfPkg/PlatformDxe/Platform.inf
-  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
+  OvmfPkg/AmdSevDxe/AmdSevDxe.inf {
+    <LibraryClasses>
+    PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  }
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index e56b83d95e09..19cc5d4122e2 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -963,7 +963,10 @@ [Components]
 !endif
 
   OvmfPkg/PlatformDxe/Platform.inf
-  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
+  OvmfPkg/AmdSevDxe/AmdSevDxe.inf {
+    <LibraryClasses>
+    PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  }
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index a31519e356b7..383cb03d2a14 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -729,7 +729,10 @@ [Components]
   }
 
   OvmfPkg/PlatformDxe/Platform.inf
-  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
+  OvmfPkg/AmdSevDxe/AmdSevDxe.inf {
+    <LibraryClasses>
+    PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  }
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
   #
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 13/31] OvmfPkg/MemEncryptSevLib: add support to validate system RAM
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (11 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 12/31] OvmfPkg/AmdSevDxe: do not use extended PCI config space Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 14/31] OvmfPkg/MemEncryptSevLib: add function to check the VMPL0 Brijesh Singh
                   ` (17 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/OvmfPkgIa32.dsc                       |   1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   1 +
 .../DxeMemEncryptSevLib.inf                   |   3 +
 .../PeiMemEncryptSevLib.inf                   |   3 +
 .../SecMemEncryptSevLib.inf                   |   3 +
 OvmfPkg/Include/Library/MemEncryptSevLib.h    |  14 +
 .../X64/SnpPageStateChange.h                  |  31 ++
 .../Ia32/MemEncryptSevLib.c                   |  17 +
 .../X64/DxeSnpSystemRamValidate.c             |  40 +++
 .../X64/PeiSnpSystemRamValidate.c             |  36 +++
 .../X64/SecSnpSystemRamValidate.c             |  36 +++
 .../X64/SnpPageStateChangeInternal.c          | 295 ++++++++++++++++++
 12 files changed, 480 insertions(+)
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValidate.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c

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


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 14/31] OvmfPkg/MemEncryptSevLib: add function to check the VMPL0
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (12 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 13/31] OvmfPkg/MemEncryptSevLib: add support to validate system RAM Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 15/31] OvmfPkg/BaseMemEncryptSevLib: skip the pre-validated system RAM Brijesh Singh
                   ` (16 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

Virtual Machine Privilege Level (VMPL) feature in the SEV-SNP
architecture allows a guest VM to divide its address space into four
levels. The level can be used to provide the hardware isolated
abstraction layers with a VM. The VMPL0 is the highest privilege, and
VMPL3 is the least privilege. Certain operations must be done by the
VMPL0 software, such as:

* Validate or invalidate memory range (PVALIDATE instruction)
* Allocate VMSA page (RMPADJUST instruction when VMSA=1)

The initial SEV-SNP support assumes that the guest is running on VMPL0.
Let's add function in the MemEncryptSevLib that can be used for checking
whether guest is booted under the VMPL0.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../X64/SnpPageStateChange.h                  |  5 ++
 .../X64/SecSnpSystemRamValidate.c             | 46 +++++++++++++++++++
 .../X64/SnpPageStateChangeInternal.c          |  1 -
 3 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h
index 8bbdf06468b9..cc1318075523 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h
@@ -28,4 +28,9 @@ InternalSetPageState (
   IN BOOLEAN                          UseLargeEntry
   );
 
+VOID
+SnpPageStateFailureTerminate (
+  VOID
+  );
+
 #endif
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c
index 64aab7f45b6d..3394094a65e5 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c
@@ -14,6 +14,43 @@
 
 #include "SnpPageStateChange.h"
 
+//
+// The variable used for the VMPL check.
+//
+STATIC UINT8 gVmpl0Data[4096];
+
+/**
+ The function checks whether SEV-SNP guest is booted under VMPL0.
+
+ @retval  TRUE      The guest is booted under VMPL0
+ @retval  FALSE     The guest is not booted under VMPL0
+ **/
+STATIC
+BOOLEAN
+SevSnpIsVmpl0 (
+  VOID
+  )
+{
+  UINT64          Rdx;
+  EFI_STATUS      Status;
+
+  //
+  // There is no straightforward way to query the current VMPL level.
+  // The simplest method is to use the RMPADJUST instruction to change
+  // a page permission to a VMPL level-1, and if the guest kernel is
+  // launched at a level <= 1, then RMPADJUST instruction will return
+  // an error.
+  //
+  Rdx = 1;
+
+  Status = AsmRmpAdjust ((UINT64) gVmpl0Data, 0, Rdx);
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
 /**
   Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.
 
@@ -32,5 +69,14 @@ MemEncryptSevSnpPreValidateSystemRam (
     return;
   }
 
+  //
+  // The page state change uses the PVALIDATE instruction. The instruction
+  // can be run on VMPL-0 only. If its not VMPL-0 guest then terminate
+  // the boot.
+  //
+  if (!SevSnpIsVmpl0 ()) {
+    SnpPageStateFailureTerminate ();
+  }
+
   InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);
 }
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c
index 506df12d4e51..653151d4a422 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c
@@ -40,7 +40,6 @@ MemoryStateToGhcbOp (
   return Cmd;
 }
 
-STATIC
 VOID
 SnpPageStateFailureTerminate (
   VOID
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 15/31] OvmfPkg/BaseMemEncryptSevLib: skip the pre-validated system RAM
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (13 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 14/31] OvmfPkg/MemEncryptSevLib: add function to check the VMPL0 Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 16/31] OvmfPkg/MemEncryptSevLib: add support to validate > 4GB memory in PEI phase Brijesh Singh
                   ` (15 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

The MemEncryptSevSnpPreValidateSystemRam() is used for pre-validating the
system RAM. As the boot progress, each phase validates a fixed region of
the RAM. In the PEI phase, the PlatformPei detects all the available RAM
and calls to pre-validate the detected system RAM.

While validating the system RAM in PEI phase, we must skip previously
validated system RAM to avoid the double validation.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../PeiMemEncryptSevLib.inf                   |  20 ++++
 .../X64/PeiSnpSystemRamValidate.c             | 102 +++++++++++++++++-
 2 files changed, 121 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
index 0402e49a1028..1cc9dd6691a2 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
@@ -57,4 +57,24 @@ [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
 
 [FixedPcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
+  gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
+  gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
index 64aab7f45b6d..eae7a31773a4 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
@@ -14,6 +14,81 @@
 
 #include "SnpPageStateChange.h"
 
+typedef struct {
+  UINT64    StartAddress;
+  UINT64    EndAddress;
+} SNP_PRE_VALIDATED_RANGE;
+
+STATIC SNP_PRE_VALIDATED_RANGE mPreValidatedRange[] = {
+  // The below address range was part of the OVMF metadata, and range
+  // should be pre-validated by the Hypervisor.
+  {
+    FixedPcdGet32 (PcdOvmfSecPageTablesBase),
+    FixedPcdGet32 (PcdOvmfSecPageTablesBase) + FixedPcdGet32 (PcdOvmfSecPageTablesSize),
+  },
+  {
+    FixedPcdGet32 (PcdOvmfLockBoxStorageBase),
+    FixedPcdGet32 (PcdOvmfLockBoxStorageBase) + FixedPcdGet32 (PcdOvmfLockBoxStorageSize),
+  },
+  {
+    FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress),
+    FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress) + FixedPcdGet32 (PcdGuidedExtractHandlerTableSize)
+  },
+  {
+    FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase),
+    FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase) + FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize),
+  },
+  {
+    FixedPcdGet32 (PcdOvmfSecGhcbBase),
+    FixedPcdGet32 (PcdOvmfSecGhcbBase) + FixedPcdGet32 (PcdOvmfSecGhcbSize),
+  },
+  {
+    FixedPcdGet32 (PcdOvmfWorkAreaBase),
+    FixedPcdGet32 (PcdOvmfWorkAreaBase) + FixedPcdGet32 (PcdOvmfWorkAreaSize),
+  },
+  {
+    FixedPcdGet32 (PcdOvmfSecGhcbBackupBase),
+    FixedPcdGet32 (PcdOvmfSecGhcbBackupBase) + FixedPcdGet32 (PcdOvmfSecGhcbBackupSize),
+  },
+  {
+    FixedPcdGet32 (PcdOvmfSnpSecretsBase),
+    FixedPcdGet32 (PcdOvmfSnpSecretsBase) + FixedPcdGet32 (PcdOvmfSnpSecretsSize),
+  },
+  {
+    FixedPcdGet32 (PcdOvmfCpuidBase),
+    FixedPcdGet32 (PcdOvmfCpuidBase) + FixedPcdGet32 (PcdOvmfCpuidSize),
+  },
+  {
+    FixedPcdGet32 (PcdOvmfSecPeiTempRamBase),
+    FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize),
+  },
+};
+
+STATIC
+BOOLEAN
+DetectPreValidatedOverLap (
+  IN    PHYSICAL_ADDRESS            StartAddress,
+  IN    PHYSICAL_ADDRESS            EndAddress,
+  OUT   SNP_PRE_VALIDATED_RANGE     *OverlapRange
+  )
+{
+  UINTN               i;
+
+  //
+  // Check if the specified address range exist in pre-validated array.
+  //
+  for (i = 0; i < ARRAY_SIZE (mPreValidatedRange); i++) {
+    if ((mPreValidatedRange[i].StartAddress < EndAddress) &&
+        (StartAddress < mPreValidatedRange[i].EndAddress)) {
+      OverlapRange->StartAddress = mPreValidatedRange[i].StartAddress;
+      OverlapRange->EndAddress = mPreValidatedRange[i].EndAddress;
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
 /**
   Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.
 
@@ -28,9 +103,34 @@ MemEncryptSevSnpPreValidateSystemRam (
   IN UINTN                              NumPages
   )
 {
+  PHYSICAL_ADDRESS          EndAddress;
+  SNP_PRE_VALIDATED_RANGE   OverlapRange;
+
   if (!MemEncryptSevSnpIsEnabled ()) {
     return;
   }
 
-  InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);
+  EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages);
+
+  while (BaseAddress < EndAddress) {
+    //
+    // Check if the range overlaps with the pre-validated ranges.
+    //
+    if (DetectPreValidatedOverLap (BaseAddress, EndAddress, &OverlapRange)) {
+      // Validate the non-overlap regions.
+      if (BaseAddress < OverlapRange.StartAddress) {
+        NumPages = EFI_SIZE_TO_PAGES (OverlapRange.StartAddress - BaseAddress);
+
+        InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);
+      }
+
+      BaseAddress = OverlapRange.EndAddress;
+      continue;
+    }
+
+    // Validate the remaining pages.
+    NumPages = EFI_SIZE_TO_PAGES (EndAddress - BaseAddress);
+    InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);
+    BaseAddress = EndAddress;
+  }
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 16/31] OvmfPkg/MemEncryptSevLib: add support to validate > 4GB memory in PEI phase
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (14 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 15/31] OvmfPkg/BaseMemEncryptSevLib: skip the pre-validated system RAM Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 17/31] OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv Brijesh Singh
                   ` (14 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

The initial page built during the SEC phase is used by the
MemEncryptSevSnpValidateSystemRam() for the system RAM validation. The
page validation process requires using the PVALIDATE instruction;  the
instruction accepts a virtual address of the memory region that needs
to be validated. If hardware encounters a page table walk failure (due
to page-not-present) then it raises #GP.

The initial page table built in SEC phase address up to 4GB. Add an
internal function to extend the page table to cover > 4GB. The function
builds 1GB entries in the page table for access > 4GB. This will provide
the support to call PVALIDATE instruction for the virtual address >
4GB in PEI phase.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../BaseMemEncryptSevLib/X64/VirtualMemory.h  |  19 +++
 .../X64/PeiDxeVirtualMemory.c                 | 115 ++++++++++++++++++
 .../X64/PeiSnpSystemRamValidate.c             |  22 ++++
 3 files changed, 156 insertions(+)

diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h
index 21bbbd1c4f9c..aefef68c30c0 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h
@@ -143,4 +143,23 @@ InternalMemEncryptSevClearMmioPageEncMask (
   IN  PHYSICAL_ADDRESS        PhysicalAddress,
   IN  UINTN                   Length
   );
+
+/**
+  Create 1GB identity mapping for the specified virtual address range.
+
+  @param[in]  Cr3BaseAddress          Cr3 Base Address (if zero then use
+                                      current CR3)
+  @param[in]  VirtualAddress          Virtual address
+  @param[in]  Length                  Length of virtual address range
+
+  @retval RETURN_INVALID_PARAMETER    Number of pages is zero.
+
+**/
+RETURN_STATUS
+EFIAPI
+InternalMemEncryptSevCreateIdentityMap1G (
+  IN    PHYSICAL_ADDRESS      Cr3BaseAddress,
+  IN    PHYSICAL_ADDRESS      PhysicalAddress,
+  IN    UINTN                 Length
+  );
 #endif
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
index c696745f9d26..f146f6d61cc5 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
@@ -536,6 +536,121 @@ EnableReadOnlyPageWriteProtect (
   AsmWriteCr0 (AsmReadCr0() | BIT16);
 }
 
+RETURN_STATUS
+EFIAPI
+InternalMemEncryptSevCreateIdentityMap1G (
+  IN    PHYSICAL_ADDRESS      Cr3BaseAddress,
+  IN    PHYSICAL_ADDRESS      PhysicalAddress,
+  IN    UINTN                 Length
+  )
+{
+  PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
+  PAGE_TABLE_1G_ENTRY            *PageDirectory1GEntry;
+  UINT64                         PgTableMask;
+  UINT64                         AddressEncMask;
+  BOOLEAN                        IsWpEnabled;
+  RETURN_STATUS                  Status;
+
+  //
+  // Set PageMapLevel4Entry to suppress incorrect compiler/analyzer warnings.
+  //
+  PageMapLevel4Entry = NULL;
+
+  DEBUG ((
+    DEBUG_VERBOSE,
+    "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx\n",
+    gEfiCallerBaseName,
+    __FUNCTION__,
+    Cr3BaseAddress,
+    PhysicalAddress,
+    (UINT64)Length
+    ));
+
+  if (Length == 0) {
+    return RETURN_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if we have a valid memory encryption mask
+  //
+  AddressEncMask = InternalGetMemEncryptionAddressMask ();
+  if (!AddressEncMask) {
+    return RETURN_ACCESS_DENIED;
+  }
+
+  PgTableMask = AddressEncMask | EFI_PAGE_MASK;
+
+
+  //
+  // Make sure that the page table is changeable.
+  //
+  IsWpEnabled = IsReadOnlyPageWriteProtected ();
+  if (IsWpEnabled) {
+    DisableReadOnlyPageWriteProtect ();
+  }
+
+  Status = EFI_SUCCESS;
+
+  while (Length)
+  {
+    //
+    // If Cr3BaseAddress is not specified then read the current CR3
+    //
+    if (Cr3BaseAddress == 0) {
+      Cr3BaseAddress = AsmReadCr3();
+    }
+
+    PageMapLevel4Entry = (VOID*) (Cr3BaseAddress & ~PgTableMask);
+    PageMapLevel4Entry += PML4_OFFSET(PhysicalAddress);
+    if (!PageMapLevel4Entry->Bits.Present) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "%a:%a: bad PML4 for Physical=0x%Lx\n",
+        gEfiCallerBaseName,
+        __FUNCTION__,
+        PhysicalAddress
+        ));
+      Status = RETURN_NO_MAPPING;
+      goto Done;
+    }
+
+    PageDirectory1GEntry = (VOID *)(
+                             (PageMapLevel4Entry->Bits.PageTableBaseAddress <<
+                              12) & ~PgTableMask
+                             );
+    PageDirectory1GEntry += PDP_OFFSET(PhysicalAddress);
+    if (!PageDirectory1GEntry->Bits.Present) {
+      PageDirectory1GEntry->Bits.Present = 1;
+      PageDirectory1GEntry->Bits.MustBe1 = 1;
+      PageDirectory1GEntry->Bits.MustBeZero = 0;
+      PageDirectory1GEntry->Bits.ReadWrite = 1;
+      PageDirectory1GEntry->Uint64 |= (UINT64)PhysicalAddress | AddressEncMask;
+    }
+
+    if (Length <= BIT30) {
+      Length = 0;
+    } else {
+      Length -= BIT30;
+    }
+
+    PhysicalAddress += BIT30;
+  }
+
+  //
+  // Flush TLB
+  //
+  CpuFlushTlb();
+
+Done:
+  //
+  // Restore page table write protection, if any.
+  //
+  if (IsWpEnabled) {
+    EnableReadOnlyPageWriteProtect ();
+  }
+
+  return Status;
+}
 
 /**
   This function either sets or clears memory encryption bit for the memory
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
index eae7a31773a4..a0803e1255dc 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
@@ -10,9 +10,12 @@
 
 #include <Uefi/UefiBaseType.h>
 #include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
 #include <Library/MemEncryptSevLib.h>
 
 #include "SnpPageStateChange.h"
+#include "VirtualMemory.h"
 
 typedef struct {
   UINT64    StartAddress;
@@ -105,6 +108,7 @@ MemEncryptSevSnpPreValidateSystemRam (
 {
   PHYSICAL_ADDRESS          EndAddress;
   SNP_PRE_VALIDATED_RANGE   OverlapRange;
+  EFI_STATUS                Status;
 
   if (!MemEncryptSevSnpIsEnabled ()) {
     return;
@@ -112,6 +116,24 @@ MemEncryptSevSnpPreValidateSystemRam (
 
   EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages);
 
+  //
+  // The page table used in PEI can address up to 4GB memory. If we are asked to
+  // validate a range above the 4GB, then create an identity mapping so that the
+  // PVALIDATE instruction can execute correctly. If the page table entry is not
+  // present then PVALIDATE will #GP.
+  //
+  if (BaseAddress >= SIZE_4GB) {
+    Status = InternalMemEncryptSevCreateIdentityMap1G (
+                0,
+                BaseAddress,
+                EFI_PAGES_TO_SIZE (NumPages)
+                );
+    if (EFI_ERROR (Status)) {
+      ASSERT (FALSE);
+      CpuDeadLoop ();
+    }
+  }
+
   while (BaseAddress < EndAddress) {
     //
     // Check if the range overlaps with the pre-validated ranges.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 17/31] OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (15 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 16/31] OvmfPkg/MemEncryptSevLib: add support to validate > 4GB memory in PEI phase Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-16  8:58   ` Gerd Hoffmann
  2021-09-13 18:19 ` [PATCH v7 18/31] OvmfPkg/PlatformPei: validate the system RAM when SNP is active Brijesh Singh
                   ` (13 subsequent siblings)
  30 siblings, 1 reply; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

The VMM launch sequence should have pre-validated all the data pages used
in the Reset vector. The range does not cover the data pages used during
the SEC phase (mainly PEI and DXE firmware volume decompression memory).

When SEV-SNP is active, the memory must be pre-validated before the access.
Add support to pre-validate the memory range from SnpSecPreValidatedStart
to SnpSecPreValidatedEnd. This should be sufficent to enter into the PEI
phase.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/OvmfPkg.dec                           |  5 ++++
 .../PeiMemEncryptSevLib.inf                   |  2 ++
 OvmfPkg/Sec/SecMain.inf                       |  3 +++
 OvmfPkg/Sec/AmdSev.h                          | 23 +++++++++++++++++++
 .../X64/PeiSnpSystemRamValidate.c             |  5 ++++
 OvmfPkg/Sec/AmdSev.c                          | 20 +++++++++++++++-
 OvmfPkg/Sec/SecMain.c                         |  7 ++++++
 OvmfPkg/FvmainCompactScratchEnd.fdf.inc       |  5 ++++
 8 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index efa0de6d0600..e30cb6eafcb8 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -354,6 +354,11 @@ [PcdsFixedAtBuild]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase|0|UINT32|0x54
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize|0|UINT32|0x55
 
+  ## The range of memory that need to be pre-validated in the SEC phase
+  #  when SEV-SNP is active in the guest VM.
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedStart|0|UINT32|0x56
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd|0|UINT32|0x57
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
index 1cc9dd6691a2..01764ab3a1a8 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
@@ -78,3 +78,5 @@ [FixedPcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
   gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
   gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedStart
diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index 9523a8ea6c8f..7e2668ff2f66 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -51,6 +51,7 @@ [LibraryClasses]
   PeCoffExtraActionLib
   ExtractGuidedSectionLib
   LocalApicLib
+  MemEncryptSevLib
   CpuExceptionHandlerLib
 
 [Ppis]
@@ -73,6 +74,8 @@ [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfConfidentialComputingWorkAreaHeader
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedStart
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
diff --git a/OvmfPkg/Sec/AmdSev.h b/OvmfPkg/Sec/AmdSev.h
index adad96d23189..33af32b9925b 100644
--- a/OvmfPkg/Sec/AmdSev.h
+++ b/OvmfPkg/Sec/AmdSev.h
@@ -69,4 +69,27 @@ SevEsIsEnabled (
   VOID
   );
 
+/**
+ Pre-validate System RAM used for decompressing the PEI and DXE firmware volumes
+ when SEV-SNP is active. The PCDs SecPreValidatedStart and SecPreValidatedEnd are
+ set in OvmfPkg/FvmainCompactScratchEnd.fdf.inc.
+
+**/
+VOID
+SevSnpSecPreValidateSystemRam (
+  VOID
+  );
+
+/**
+  Determine if SEV-SNP is active.
+
+  @retval TRUE   SEV-SNP is enabled
+  @retval FALSE  SEV-SNP is not enabled
+
+**/
+BOOLEAN
+SevSnpIsEnabled (
+  VOID
+  );
+
 #endif
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
index a0803e1255dc..c51d565fc176 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
@@ -65,6 +65,11 @@ STATIC SNP_PRE_VALIDATED_RANGE mPreValidatedRange[] = {
     FixedPcdGet32 (PcdOvmfSecPeiTempRamBase),
     FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize),
   },
+  // The below range is pre-validated by the Sec/SecMain.c
+  {
+    FixedPcdGet32 (PcdOvmfSnpSecPreValidatedStart),
+    FixedPcdGet32 (PcdOvmfSnpSecPreValidatedEnd)
+  },
 };
 
 STATIC
diff --git a/OvmfPkg/Sec/AmdSev.c b/OvmfPkg/Sec/AmdSev.c
index 7d4d7cc8a07c..e54a3fa23f6a 100644
--- a/OvmfPkg/Sec/AmdSev.c
+++ b/OvmfPkg/Sec/AmdSev.c
@@ -55,7 +55,6 @@ SevEsProtocolFailure (
   @retval FALSE  SEV-SNP is not enabled
 
 **/
-STATIC
 BOOLEAN
 SevSnpIsEnabled (
   VOID
@@ -296,3 +295,22 @@ SevEsIsEnabled (
 
   return (SevEsWorkArea->SevEsEnabled != 0);
 }
+
+/**
+ Pre-validate System RAM used for decompressing the PEI and DXE firmware volumes
+ when SEV-SNP is active. The PCDs SecPreValidatedStart and SecPreValidatedEnd are
+ set in OvmfPkg/FvmainCompactScratchEnd.fdf.inc.
+
+**/
+VOID
+SevSnpSecPreValidateSystemRam (
+  VOID
+  )
+{
+  PHYSICAL_ADDRESS        Start, End;
+
+  Start = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdOvmfSnpSecPreValidatedStart);
+  End = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdOvmfSnpSecPreValidatedEnd);
+
+  MemEncryptSevSnpPreValidateSystemRam (Start, EFI_SIZE_TO_PAGES (End - Start));
+}
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 406e3a25d0cd..0d80494b062c 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -847,6 +847,13 @@ SecCoreStartupWithStack (
   SecCoreData.BootFirmwareVolumeBase = BootFv;
   SecCoreData.BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
 
+  if (SevSnpIsEnabled ()) {
+    //
+    // Pre-validate the System RAM used in the SEC Phase
+    //
+    SevSnpSecPreValidateSystemRam ();
+  }
+
   //
   // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
   //
diff --git a/OvmfPkg/FvmainCompactScratchEnd.fdf.inc b/OvmfPkg/FvmainCompactScratchEnd.fdf.inc
index 46f52583297c..b560fb0b8e4f 100644
--- a/OvmfPkg/FvmainCompactScratchEnd.fdf.inc
+++ b/OvmfPkg/FvmainCompactScratchEnd.fdf.inc
@@ -63,3 +63,8 @@
 DEFINE DECOMP_SCRATCH_BASE           = (($(DECOMP_SCRATCH_BASE_UNALIGNED) + $(DECOMP_SCRATCH_BASE_ALIGNMENT)) & $(DECOMP_SCRATCH_BASE_MASK))
 
 SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd = $(DECOMP_SCRATCH_BASE) + $(DECOMP_SCRATCH_SIZE)
+
+#
+# The range of pages that should be pre-validated during the SEC phase when SEV-SNP is active in the guest VM.
+SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedStart = $(MEMFD_BASE_ADDRESS) + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
+SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd = $(DECOMP_SCRATCH_BASE) + $(DECOMP_SCRATCH_SIZE)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 18/31] OvmfPkg/PlatformPei: validate the system RAM when SNP is active
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (16 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 17/31] OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 19/31] UefiCpuPkg: Define ConfidentialComputingGuestAttr Brijesh Singh
                   ` (12 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

When SEV-SNP is active, a memory region mapped encrypted in the page
table must be validated before access. There are two approaches that
can be taken to validate the system RAM detected during the PEI phase:

1) Validate on-demand
OR
2) Validate before access

On-demand
=========
If memory is not validated before access, it will cause a #VC
exception with the page-not-validated error code. The VC exception
handler can perform the validation steps.

The pages that have been validated will need to be tracked to avoid
the double validation scenarios. The range of memory that has not
been validated will need to be communicated to the OS through the
recently introduced unaccepted memory type
https://github.com/microsoft/mu_basecore/pull/66, so that OS can
validate those ranges before using them.

Validate before access
======================
Since the PEI phase detects all the available system RAM, use the
MemEncryptSevSnpValidateSystemRam() function to pre-validate the
system RAM in the PEI phase.

For now, choose option 2 due to the dependency and the complexity
of the on-demand validation.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/PlatformPei/AmdSev.c | 42 ++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index de876fdb478e..391e7bbb7dbd 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -23,6 +23,40 @@
 
 #include "Platform.h"
 
+/**
+  Initialize SEV-SNP support if running as an SEV-SNP guest.
+
+**/
+STATIC
+VOID
+AmdSevSnpInitialize (
+  VOID
+  )
+{
+  EFI_PEI_HOB_POINTERS          Hob;
+  EFI_HOB_RESOURCE_DESCRIPTOR   *ResourceHob;
+
+  if (!MemEncryptSevSnpIsEnabled ()) {
+    return;
+  }
+
+  //
+  // Iterate through the system RAM and validate it.
+  //
+  for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+    if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+      ResourceHob = Hob.ResourceDescriptor;
+
+      if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
+        MemEncryptSevSnpPreValidateSystemRam (
+          ResourceHob->PhysicalStart,
+          EFI_SIZE_TO_PAGES ((UINTN) ResourceHob->ResourceLength)
+          );
+      }
+    }
+  }
+}
+
 /**
   Handle an SEV-SNP/GHCB protocol check failure.
 
@@ -240,6 +274,14 @@ AmdSevInitialize (
     return;
   }
 
+  //
+  // Check and perform SEV-SNP initialization if required. This need to be
+  // done before the GHCB page is made shared in the AmdSevEsInitialize(). This
+  // is because the system RAM must be validated before it is made shared.
+  // The AmdSevSnpInitialize() validates the system RAM.
+  //
+  AmdSevSnpInitialize ();
+
   //
   // Set Memory Encryption Mask PCD
   //
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 19/31] UefiCpuPkg: Define ConfidentialComputingGuestAttr
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (17 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 18/31] OvmfPkg/PlatformPei: validate the system RAM when SNP is active Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 20/31] OvmfPkg/PlatformPei: set PcdConfidentialComputingAttr when SEV is active Brijesh Singh
                   ` (11 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth, Ray Ni, Rahul Kumar, Eric Dong

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

While initializing APs, the MpInitLib may need to know whether the
guest is running with active AMD SEV or Intel TDX memory encryption.

Add a new ConfidentialComputingGuestAttr PCD that can be used to query
the memory encryption attribute.

Cc: Michael Roth <michael.roth@amd.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Eric Dong <eric.dong@intel.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>
Suggested-by: Jiewen Yao <jiewen.yao@intel.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 UefiCpuPkg/UefiCpuPkg.dec                     |  4 +++
 .../Include/ConfidentialComputingGuestAttr.h  | 25 +++++++++++++++++++
 2 files changed, 29 insertions(+)
 create mode 100644 UefiCpuPkg/Include/ConfidentialComputingGuestAttr.h

diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 62acb291f309..9dbaa407c399 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -396,5 +396,9 @@ [PcdsDynamic, PcdsDynamicEx]
   # @Prompt SEV-ES Status
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled|FALSE|BOOLEAN|0x60000016
 
+  ## This dynamic PCD indicates the memory encryption attribute of the guest.
+  # @Prompt Memory encryption attribute
+  gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr|0|UINT64|0x60000017
+
 [UserExtensions.TianoCore."ExtraFiles"]
   UefiCpuPkgExtra.uni
diff --git a/UefiCpuPkg/Include/ConfidentialComputingGuestAttr.h b/UefiCpuPkg/Include/ConfidentialComputingGuestAttr.h
new file mode 100644
index 000000000000..495b0df0ac33
--- /dev/null
+++ b/UefiCpuPkg/Include/ConfidentialComputingGuestAttr.h
@@ -0,0 +1,25 @@
+/** @file
+Definitions for Confidential Computing Attribute
+
+Copyright (c) 2021 AMD Inc. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CONFIDENTIAL_COMPUTING_GUEST_ATTR_H_
+#define CONFIDENTIAL_COMPUTING_GUEST_ATTR_H_
+
+typedef enum {
+  /* The guest is running with memory encryption disabled. */
+  CCAttrNotEncrypted = 0,
+
+  /* The guest is running with AMD SEV memory encryption enabled. */
+  CCAttrAmdSev      = 0x100,
+  CCAttrAmdSevEs    = 0x101,
+  CCAttrAmdSevSnp   = 0x102,
+
+  /* The guest is running with Intel TDX memory encryption enabled. */
+  CCAttrIntelTdx    = 0x200,
+} CONFIDENTIAL_COMPUTING_GUEST_ATTR;
+
+#endif
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 20/31] OvmfPkg/PlatformPei: set PcdConfidentialComputingAttr when SEV is active
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (18 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 19/31] UefiCpuPkg: Define ConfidentialComputingGuestAttr Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 21/31] UefiCpuPkg/MpInitLib: use PcdConfidentialComputingAttr to check SEV status Brijesh Singh
                   ` (10 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth, Ray Ni, Rahul Kumar, Eric Dong

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

The MpInitLib uses the ConfidentialComputingAttr PCD to determine whether
AMD SEV is active so that it can use the VMGEXITs defined in the GHCB
specification to create APs.

Cc: Michael Roth <michael.roth@amd.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Eric Dong <eric.dong@intel.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>
Suggested-by: Jiewen Yao <jiewen.yao@intel.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/PlatformPei/PlatformPei.inf |  1 +
 OvmfPkg/PlatformPei/AmdSev.c        | 15 +++++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 67eb7aa7166b..233b9494f64b 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -106,6 +106,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuBootLogicalProcessorNumber
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled
+  gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr
 
 [FixedPcd]
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 391e7bbb7dbd..5e2c891309d4 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -20,6 +20,7 @@
 #include <Register/Amd/Msr.h>
 #include <Register/Intel/SmramSaveStateMap.h>
 #include <Library/VmgExitLib.h>
+#include <ConfidentialComputingGuestAttr.h>
 
 #include "Platform.h"
 
@@ -342,4 +343,18 @@ AmdSevInitialize (
   // Check and perform SEV-ES initialization if required.
   //
   AmdSevEsInitialize ();
+
+  //
+  // Set the Confidential computing attr PCD to communicate which SEV
+  // technology is active.
+  //
+  if (MemEncryptSevSnpIsEnabled ()) {
+    PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrAmdSevSnp);
+  } else if (MemEncryptSevEsIsEnabled ()) {
+    PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrAmdSevEs);
+  } else {
+    PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrAmdSev);
+  }
+  ASSERT_RETURN_ERROR (PcdStatus);
+
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 21/31] UefiCpuPkg/MpInitLib: use PcdConfidentialComputingAttr to check SEV status
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (19 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 20/31] OvmfPkg/PlatformPei: set PcdConfidentialComputingAttr when SEV is active Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 22/31] UefiCpuPkg: add PcdGhcbHypervisorFeatures Brijesh Singh
                   ` (9 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth, Ray Ni, Rahul Kumar, Eric Dong

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

Previous commit introduced a generic confidential computing PCD that can
determine whether AMD SEV-ES is enabled. Update the MpInitLib to drop the
PcdSevEsIsEnabled in favor of PcdConfidentialComputingAttr.

Cc: Michael Roth <michael.roth@amd.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Eric Dong <eric.dong@intel.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>
Suggested-by: Jiewen Yao <jiewen.yao@intel.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |  2 +-
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |  2 +-
 UefiCpuPkg/Library/MpInitLib/MpLib.h          | 13 ++++
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  6 +-
 UefiCpuPkg/Library/MpInitLib/MpLib.c          | 60 ++++++++++++++++++-
 UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |  4 +-
 6 files changed, 77 insertions(+), 10 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index d34419c2a524..76e6aa83b3cb 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -72,7 +72,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                           ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                       ## SOMETIMES_CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds  ## CONSUMES
-  gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled                          ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                       ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                      ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                           ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr          ## CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 36fcb96b5852..a146bab94317 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -62,9 +62,9 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize         ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
-  gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled                      ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                   ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr      ## CONSUMES
 
 [Ppis]
   gEdkiiPeiShadowMicrocodePpiGuid        ## SOMETIMES_CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index e88a5355c983..388ebef7b0dc 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -33,6 +33,7 @@
 #include <Library/HobLib.h>
 #include <Library/PcdLib.h>
 #include <Library/MicrocodeLib.h>
+#include <ConfidentialComputingGuestAttr.h>
 
 #include <Guid/MicrocodePatchHob.h>
 
@@ -741,5 +742,17 @@ PlatformShadowMicrocode (
   IN OUT CPU_MP_DATA             *CpuMpData
   );
 
+/**
+ Check if the specified confidential computing attribute is active.
+
+ @retval TRUE   The specified Attr is active.
+ @retval FALSE  The specified Attr is not active.
+**/
+BOOLEAN
+EFIAPI
+ConfidentialComputingGuestHas (
+  CONFIDENTIAL_COMPUTING_GUEST_ATTR     Attr
+  );
+
 #endif
 
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 93fc63bf93e3..657a73dca05e 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -93,7 +93,7 @@ GetWakeupBuffer (
   EFI_PHYSICAL_ADDRESS    StartAddress;
   EFI_MEMORY_TYPE         MemoryType;
 
-  if (PcdGetBool (PcdSevEsIsEnabled)) {
+  if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
     MemoryType = EfiReservedMemoryType;
   } else {
     MemoryType = EfiBootServicesData;
@@ -107,7 +107,7 @@ GetWakeupBuffer (
   // LagacyBios driver depends on CPU Arch protocol which guarantees below
   // allocation runs earlier than LegacyBios driver.
   //
-  if (PcdGetBool (PcdSevEsIsEnabled)) {
+  if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
     //
     // SEV-ES Wakeup buffer should be under 0x88000 and under any previous one
     //
@@ -124,7 +124,7 @@ GetWakeupBuffer (
   ASSERT_EFI_ERROR (Status);
   if (EFI_ERROR (Status)) {
     StartAddress = (EFI_PHYSICAL_ADDRESS) -1;
-  } else if (PcdGetBool (PcdSevEsIsEnabled)) {
+  } else if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
     //
     // Next SEV-ES wakeup buffer allocation must be below this allocation
     //
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index b9a06747edbf..bfef1237f452 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -295,7 +295,7 @@ GetApLoopMode (
       ApLoopMode = ApInHltLoop;
     }
 
-    if (PcdGetBool (PcdSevEsIsEnabled)) {
+    if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
       //
       // For SEV-ES, force AP in Hlt-loop mode in order to use the GHCB
       // protocol for starting APs
@@ -1197,7 +1197,7 @@ AllocateResetVector (
     // The AP reset stack is only used by SEV-ES guests. Do not allocate it
     // if SEV-ES is not enabled.
     //
-    if (PcdGetBool (PcdSevEsIsEnabled)) {
+    if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
       //
       // Stack location is based on ProcessorNumber, so use the total number
       // of processors for calculating the total stack area.
@@ -2032,7 +2032,7 @@ MpInitLibInitialize (
   CpuMpData->CpuData          = (CPU_AP_DATA *) (CpuMpData + 1);
   CpuMpData->CpuInfoInHob     = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
   InitializeSpinLock(&CpuMpData->MpLock);
-  CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
+  CpuMpData->SevEsIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevEs);
   CpuMpData->SevEsAPBuffer  = (UINTN) -1;
   CpuMpData->GhcbBase       = PcdGet64 (PcdGhcbBase);
 
@@ -2922,3 +2922,57 @@ MpInitLibStartupAllCPUs (
            NULL
            );
 }
+
+/**
+ The function check if the specified Attr is set in the CurrentAttr.
+
+ @retval    TRUE      The specified Attr is set.
+ @retval    FALSE     The specified Attr is not set.
+ **/
+STATIC
+BOOLEAN
+AmdMemEncryptionAttrCheck (
+  UINT64                                CurrentAttr,
+  CONFIDENTIAL_COMPUTING_GUEST_ATTR     Attr
+  )
+{
+  switch (Attr) {
+    case CCAttrAmdSev:
+      return CurrentAttr >= CCAttrAmdSev;
+    case CCAttrAmdSevEs:
+      return CurrentAttr >= CCAttrAmdSevEs;
+    case CCAttrAmdSevSnp:
+      return CurrentAttr == CCAttrAmdSevSnp;
+    default:
+      return FALSE;
+  }
+}
+
+/**
+ Check if the specified confidential computing attribute is active.
+
+ @retval TRUE   The specified Attr is active.
+ @retval FALSE  The specified Attr is not active.
+**/
+BOOLEAN
+EFIAPI
+ConfidentialComputingGuestHas (
+  CONFIDENTIAL_COMPUTING_GUEST_ATTR     Attr
+  )
+{
+  UINT64    CurrentAttr;
+
+  //
+  // Get the current CC attribute.
+  //
+  CurrentAttr = PcdGet64 (PcdConfidentialComputingGuestAttr);
+
+  //
+  // If attr is for the AMD group then call AMD specific checks.
+  //
+  if (((CurrentAttr >> 8) & 0xff) == 1) {
+    return AmdMemEncryptionAttrCheck (CurrentAttr, Attr);
+  }
+
+  return (CurrentAttr == Attr);
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
index 90015c650c68..2f333a00460a 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -222,7 +222,7 @@ GetWakeupBuffer (
         // Need memory under 1MB to be collected here
         //
         WakeupBufferEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
-        if (PcdGetBool (PcdSevEsIsEnabled) &&
+        if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
             WakeupBufferEnd > mSevEsPeiWakeupBuffer) {
           //
           // SEV-ES Wakeup buffer should be under 1MB and under any previous one
@@ -253,7 +253,7 @@ GetWakeupBuffer (
           DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
                                WakeupBufferStart, WakeupBufferSize));
 
-          if (PcdGetBool (PcdSevEsIsEnabled)) {
+          if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
             //
             // Next SEV-ES wakeup buffer allocation must be below this
             // allocation
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 22/31] UefiCpuPkg: add PcdGhcbHypervisorFeatures
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (20 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 21/31] UefiCpuPkg/MpInitLib: use PcdConfidentialComputingAttr to check SEV status Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 23/31] OvmfPkg/PlatformPei: set the Hypervisor Features PCD Brijesh Singh
                   ` (8 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth, Ray Ni, Rahul Kumar, Eric Dong

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

Version 2 of the GHCB specification added a new VMGEXIT that the guest
could use for querying the hypervisor features. One of the immediate
users for it will be an AP creation code. When SEV-SNP is enabled, the
guest can use the newly added AP_CREATE VMGEXIT to create the APs.

The MpInitLib will check the hypervisor feature, and if AP_CREATE is
available, it will use it.

See GHCB spec version 2 for more details on the VMGEXIT.

Cc: Michael Roth <michael.roth@amd.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Eric Dong <eric.dong@intel.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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 UefiCpuPkg/UefiCpuPkg.dec | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 9dbaa407c399..c979a0a90a0e 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -400,5 +400,10 @@ [PcdsDynamic, PcdsDynamicEx]
   # @Prompt Memory encryption attribute
   gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr|0|UINT64|0x60000017
 
+  ## This dynamic PCD contains the hypervisor features value obtained through the GHCB HYPERVISOR
+  #  features VMGEXIT defined in the version 2 of GHCB spec.
+  # @Prompt GHCB Hypervisor Features
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures|0x0|UINT64|0x60000018
+
 [UserExtensions.TianoCore."ExtraFiles"]
   UefiCpuPkgExtra.uni
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 23/31] OvmfPkg/PlatformPei: set the Hypervisor Features PCD
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (21 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 22/31] UefiCpuPkg: add PcdGhcbHypervisorFeatures Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 24/31] MdePkg/GHCB: increase the GHCB protocol max version Brijesh Singh
                   ` (7 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

Version 2 of the GHCB specification added the support to query the
hypervisor feature bitmap. The feature bitmap provide information
such as whether to use the AP create VmgExit or use the AP jump table
approach to create the APs. The MpInitLib will use the
PcdGhcbHypervisorFeatures to determine which method to use for creating
the AP.

Query the hypervisor feature and set the PCD accordingly.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/PlatformPei/PlatformPei.inf |  3 ++
 OvmfPkg/PlatformPei/AmdSev.c        | 56 +++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)

diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 233b9494f64b..d048b692f155 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -62,6 +62,7 @@ [LibraryClasses]
   MtrrLib
   MemEncryptSevLib
   PcdLib
+  VmgExitLib
 
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
@@ -107,6 +108,8 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled
   gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures
+
 
 [FixedPcd]
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 5e2c891309d4..b71a4a7304f7 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -24,6 +24,12 @@
 
 #include "Platform.h"
 
+STATIC
+UINT64
+GetHypervisorFeature (
+  VOID
+  );
+
 /**
   Initialize SEV-SNP support if running as an SEV-SNP guest.
 
@@ -36,11 +42,22 @@ AmdSevSnpInitialize (
 {
   EFI_PEI_HOB_POINTERS          Hob;
   EFI_HOB_RESOURCE_DESCRIPTOR   *ResourceHob;
+  UINT64                        HvFeatures;
+  EFI_STATUS                    PcdStatus;
 
   if (!MemEncryptSevSnpIsEnabled ()) {
     return;
   }
 
+  //
+  // Query the hypervisor feature using the VmgExit and set the value in the
+  // hypervisor features PCD.
+  //
+  HvFeatures = GetHypervisorFeature ();
+  PcdStatus = PcdSet64S (PcdGhcbHypervisorFeatures, HvFeatures);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+
   //
   // Iterate through the system RAM and validate it.
   //
@@ -91,6 +108,45 @@ SevEsProtocolFailure (
   CpuDeadLoop ();
 }
 
+/**
+ Get the hypervisor features bitmap
+
+**/
+STATIC
+UINT64
+GetHypervisorFeature (
+  VOID
+  )
+{
+  UINT64                          Status;
+  GHCB                            *Ghcb;
+  MSR_SEV_ES_GHCB_REGISTER        Msr;
+  BOOLEAN                         InterruptState;
+  UINT64                          Features;
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+  Ghcb = Msr.Ghcb;
+
+  //
+  // Initialize the GHCB
+  //
+  VmgInit (Ghcb, &InterruptState);
+
+  //
+  // Query the Hypervisor Features.
+  //
+  Status = VmgExit (Ghcb, SVM_EXIT_HYPERVISOR_FEATURES, 0, 0);
+  if ((Status != 0)) {
+    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
+  }
+
+  Features = Ghcb->SaveArea.SwExitInfo2;
+
+  VmgDone (Ghcb, InterruptState);
+
+  return Features;
+}
+
 /**
 
   This function can be used to register the GHCB GPA.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 24/31] MdePkg/GHCB: increase the GHCB protocol max version
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (22 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 23/31] OvmfPkg/PlatformPei: set the Hypervisor Features PCD Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled Brijesh Singh
                   ` (6 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth, Ray Ni, Rahul Kumar, Eric Dong

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

Now that OvmfPkg supports version 2 of the GHCB specification, bump the
protocol version.

Cc: Michael Roth <michael.roth@amd.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Eric Dong <eric.dong@intel.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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 MdePkg/Include/Register/Amd/Ghcb.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MdePkg/Include/Register/Amd/Ghcb.h b/MdePkg/Include/Register/Amd/Ghcb.h
index 8c5f46e4bb53..071aae0c9e09 100644
--- a/MdePkg/Include/Register/Amd/Ghcb.h
+++ b/MdePkg/Include/Register/Amd/Ghcb.h
@@ -24,7 +24,7 @@
 #define VC_EXCEPTION 29
 
 #define GHCB_VERSION_MIN     1
-#define GHCB_VERSION_MAX     1
+#define GHCB_VERSION_MAX     2
 
 #define GHCB_STANDARD_USAGE  0
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (23 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 24/31] MdePkg/GHCB: increase the GHCB protocol max version Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-14  2:23   ` Ni, Ray
  2021-09-13 18:19 ` [PATCH v7 26/31] UefiCpuPkg/MpInitLib: use BSP to do extended topology check Brijesh Singh
                   ` (5 subsequent siblings)
  30 siblings, 1 reply; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth, Eric Dong, Ray Ni, Rahul Kumar

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

An SEV-SNP guest requires that the physical address of the GHCB must
be registered with the hypervisor before using it. See the GHCB
specification section 2.3.2 for more details.

Cc: Michael Roth <michael.roth@amd.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  2 +
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  2 +
 UefiCpuPkg/Library/MpInitLib/MpEqu.inc        |  1 +
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 53 +++++++++++++++++++
 4 files changed, 58 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 388ebef7b0dc..56d6d703d8b0 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -219,6 +219,7 @@ typedef struct {
   //
   BOOLEAN               Enable5LevelPaging;
   BOOLEAN               SevEsIsEnabled;
+  BOOLEAN               SevSnpIsEnabled;
   UINTN                 GhcbBase;
 } MP_CPU_EXCHANGE_INFO;
 
@@ -288,6 +289,7 @@ struct _CPU_MP_DATA {
   BOOLEAN                        WakeUpByInitSipiSipi;
 
   BOOLEAN                        SevEsIsEnabled;
+  BOOLEAN                        SevSnpIsEnabled;
   UINTN                          SevEsAPBuffer;
   UINTN                          SevEsAPResetStackStart;
   CPU_MP_DATA                    *NewCpuMpData;
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index bfef1237f452..365c0ff24ebe 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1040,6 +1040,7 @@ FillExchangeInfoData (
   DEBUG ((DEBUG_INFO, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName, ExchangeInfo->Enable5LevelPaging));
 
   ExchangeInfo->SevEsIsEnabled  = CpuMpData->SevEsIsEnabled;
+  ExchangeInfo->SevSnpIsEnabled = CpuMpData->SevSnpIsEnabled;
   ExchangeInfo->GhcbBase        = (UINTN) CpuMpData->GhcbBase;
 
   //
@@ -2033,6 +2034,7 @@ MpInitLibInitialize (
   CpuMpData->CpuInfoInHob     = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
   InitializeSpinLock(&CpuMpData->MpLock);
   CpuMpData->SevEsIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevEs);
+  CpuMpData->SevSnpIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevSnp);
   CpuMpData->SevEsAPBuffer  = (UINTN) -1;
   CpuMpData->GhcbBase       = PcdGet64 (PcdGhcbBase);
 
diff --git a/UefiCpuPkg/Library/MpInitLib/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
index 2e9368a374a4..01668638f245 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
+++ b/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
@@ -92,6 +92,7 @@ struc MP_CPU_EXCHANGE_INFO
   .ModeHighSegment:              CTYPE_UINT16 1
   .Enable5LevelPaging:           CTYPE_BOOLEAN 1
   .SevEsIsEnabled:               CTYPE_BOOLEAN 1
+  .SevSnpIsEnabled               CTYPE_BOOLEAN 1
   .GhcbBase:                     CTYPE_UINTN 1
 endstruc
 
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index 50df802d1fca..018ebe74bf5f 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -194,6 +194,59 @@ LongModeStart:
     mov        rdx, rax
     shr        rdx, 32
     mov        rcx, 0xc0010130
+
+    ;
+    ; If its an SEV-SNP guest then register the GHCB GPA
+    ;
+RegisterGhcbGpa:
+    ;
+    ; Register GHCB GPA when SEV-SNP is enabled
+    ;
+    lea        edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]
+    cmp        byte [edi], 1        ; SevSnpIsEnabled
+    jne        RegisterGhcbGpaDone
+
+    ; Save the rdi and rsi to used for later comparison
+    push       rdi
+    push       rsi
+    mov        edi, eax
+    mov        esi, edx
+    or         eax, 18              ; Ghcb registration request
+    wrmsr
+    rep vmmcall
+    rdmsr
+    mov        r12, rax
+    and        r12, 0fffh
+    cmp        r12, 19              ; Ghcb registration response
+    jne        GhcbGpaRegisterFailure
+
+    ; Verify that GPA is not changed
+    and        eax, 0fffff000h
+    cmp        edi, eax
+    jne        GhcbGpaRegisterFailure
+    cmp        esi, edx
+    jne        GhcbGpaRegisterFailure
+    pop        rsi
+    pop        rdi
+    jmp        RegisterGhcbGpaDone
+
+    ;
+    ; Request the guest termination
+    ;
+GhcbGpaRegisterFailure:
+    xor        edx, edx
+    mov        eax, 256             ; GHCB terminate
+    wrmsr
+    rep vmmcall
+
+    ; We should not return from the above terminate request, but if we do
+    ; then enter into the hlt loop.
+DoHltLoop:
+    cli
+    hlt
+    jmp        DoHltLoop
+
+RegisterGhcbGpaDone:
     wrmsr
     jmp        CProcedureInvoke
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 26/31] UefiCpuPkg/MpInitLib: use BSP to do extended topology check
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (24 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 27/31] OvmfPkg/MemEncryptSevLib: change the page state in the RMP table Brijesh Singh
                   ` (4 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Michael Roth, Eric Dong, Ray Ni, Rahul Kumar, Brijesh Singh

From: Michael Roth <michael.roth@amd.com>

During AP bringup, just after switching to long mode, APs will do some
cpuid calls to verify that the extended topology leaf (0xB) is available
so they can fetch their x2 APIC IDs from it. In the case of SEV-ES,
these cpuid instructions must be handled by direct use of the GHCB MSR
protocol to fetch the values from the hypervisor, since a #VC handler
is not yet available due to the AP's stack not being set up yet.

For SEV-SNP, rather than relying on the GHCB MSR protocol, it is
expected that these values would be obtained from the SEV-SNP CPUID
table instead. The actual x2 APIC ID (and 8-bit APIC IDs) would still
be fetched from hypervisor using the GHCB MSR protocol however, so
introducing support for the SEV-SNP CPUID table in that part of the AP
bring-up code would only be to handle the checks/validation of the
extended topology leaf.

Rather than introducing all the added complexity needed to handle these
checks via the CPUID table, instead let the BSP do the check in advance,
since it can make use of the #VC handler to avoid the need to scan the
SNP CPUID table directly, and add a flag in ExchangeInfo to communicate
the result of this check to APs.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.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>
Suggested-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  1 +
 UefiCpuPkg/Library/MpInitLib/MpLib.c          | 11 ++++++++
 UefiCpuPkg/Library/MpInitLib/MpEqu.inc        |  1 +
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 27 +++++++++++++++++++
 4 files changed, 40 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 56d6d703d8b0..94bd71408384 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -221,6 +221,7 @@ typedef struct {
   BOOLEAN               SevEsIsEnabled;
   BOOLEAN               SevSnpIsEnabled;
   UINTN                 GhcbBase;
+  BOOLEAN               ExtTopoAvail;
 } MP_CPU_EXCHANGE_INFO;
 
 #pragma pack()
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 365c0ff24ebe..12fe3ecb27a7 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1004,6 +1004,7 @@ FillExchangeInfoData (
   UINTN                            Size;
   IA32_SEGMENT_DESCRIPTOR          *Selector;
   IA32_CR4                         Cr4;
+  UINT32                           StdRangeMax;
 
   ExchangeInfo                  = CpuMpData->MpCpuExchangeInfo;
   ExchangeInfo->StackStart      = CpuMpData->Buffer;
@@ -1043,6 +1044,16 @@ FillExchangeInfoData (
   ExchangeInfo->SevSnpIsEnabled = CpuMpData->SevSnpIsEnabled;
   ExchangeInfo->GhcbBase        = (UINTN) CpuMpData->GhcbBase;
 
+  if (ExchangeInfo->SevSnpIsEnabled) {
+    AsmCpuid (CPUID_SIGNATURE, &StdRangeMax, NULL, NULL, NULL);
+    if (StdRangeMax >= CPUID_EXTENDED_TOPOLOGY) {
+      CPUID_EXTENDED_TOPOLOGY_EBX ExtTopoEbx;
+
+      AsmCpuid (CPUID_EXTENDED_TOPOLOGY, NULL, &ExtTopoEbx.Uint32, NULL, NULL);
+      ExchangeInfo->ExtTopoAvail = !!ExtTopoEbx.Bits.LogicalProcessors;
+    }
+  }
+
   //
   // Get the BSP's data of GDT and IDT
   //
diff --git a/UefiCpuPkg/Library/MpInitLib/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
index 01668638f245..aba53f57201c 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
+++ b/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
@@ -94,6 +94,7 @@ struc MP_CPU_EXCHANGE_INFO
   .SevEsIsEnabled:               CTYPE_BOOLEAN 1
   .SevSnpIsEnabled               CTYPE_BOOLEAN 1
   .GhcbBase:                     CTYPE_UINTN 1
+  .ExtTopoAvail:                 CTYPE_BOOLEAN 1
 endstruc
 
 MP_CPU_EXCHANGE_INFO_OFFSET equ (SwitchToRealProcEnd - RendezvousFunnelProcStart)
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index 018ebe74bf5f..91ffe4567a41 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -266,6 +266,32 @@ GetApicId:
     or         rax, rdx
     mov        rdi, rax             ; RDI now holds the original GHCB GPA
 
+    ;
+    ; For SEV-SNP, the recommended handling for getting the x2APIC ID
+    ; would be to use the SNP CPUID table to fetch CPUID.00H:EAX and
+    ; CPUID:0BH:EBX[15:0] instead of the GHCB MSR protocol vmgexits
+    ; below.
+    ;
+    ; To avoid the unecessary ugliness to accomplish that here, the BSP
+    ; has performed these checks in advance (where #VC handler handles
+    ; the CPUID table lookups automatically) and cached them in a flag
+    ; so those checks can be skipped here.
+    ;
+    mov        eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]
+    cmp        al, 1
+    jne        CheckExtTopoAvail
+
+    ;
+    ; Even with SEV-SNP, the actual x2APIC ID in CPUID.0BH:EDX
+    ; fetched from the hypervisor the same way SEV-ES does it.
+    ;
+    mov        eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (ExtTopoAvail)]
+    cmp        al, 1
+    je         GetApicIdSevEs
+    ; The 8-bit APIC ID fallback is also the same as with SEV-ES
+    jmp        NoX2ApicSevEs
+
+CheckExtTopoAvail:
     mov        rdx, 0               ; CPUID function 0
     mov        rax, 0               ; RAX register requested
     or         rax, 4
@@ -284,6 +310,7 @@ GetApicId:
     test       edx, 0ffffh
     jz         NoX2ApicSevEs        ; CPUID.0BH:EBX[15:0] is zero
 
+GetApicIdSevEs:
     mov        rdx, 0bh             ; CPUID function 0x0b
     mov        rax, 0c0000000h      ; RDX register requested
     or         rax, 4
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 27/31] OvmfPkg/MemEncryptSevLib: change the page state in the RMP table
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (25 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 26/31] UefiCpuPkg/MpInitLib: use BSP to do extended topology check Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 28/31] OvmfPkg/MemEncryptSevLib: skip page state change for Mmio address Brijesh Singh
                   ` (3 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

The MemEncryptSev{Set,Clear}PageEncMask() functions are used to set or
clear the memory encryption attribute in the page table. When SEV-SNP
is active, we also need to change the page state in the RMP table so that
it is in sync with the memory encryption attribute change.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../X64/PeiDxeVirtualMemory.c                 | 34 +++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
index f146f6d61cc5..56db1e4b6ecf 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
@@ -17,6 +17,7 @@
 #include <Register/Cpuid.h>
 
 #include "VirtualMemory.h"
+#include "SnpPageStateChange.h"
 
 STATIC BOOLEAN mAddressEncMaskChecked = FALSE;
 STATIC UINT64  mAddressEncMask;
@@ -695,10 +696,12 @@ SetMemoryEncDec (
   PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
   PAGE_TABLE_1G_ENTRY            *PageDirectory1GEntry;
   PAGE_TABLE_ENTRY               *PageDirectory2MEntry;
+  PHYSICAL_ADDRESS               OrigPhysicalAddress;
   PAGE_TABLE_4K_ENTRY            *PageTableEntry;
   UINT64                         PgTableMask;
   UINT64                         AddressEncMask;
   BOOLEAN                        IsWpEnabled;
+  UINTN                          OrigLength;
   RETURN_STATUS                  Status;
 
   //
@@ -751,6 +754,22 @@ SetMemoryEncDec (
 
   Status = EFI_SUCCESS;
 
+  //
+  // To maintain the security gurantees we must set the page to shared in the RMP
+  // table before clearing the memory encryption mask from the current page table.
+  //
+  // The InternalSetPageState() is used for setting the page state in the RMP table.
+  //
+  if ((Mode == ClearCBit) && MemEncryptSevSnpIsEnabled ()) {
+    InternalSetPageState (PhysicalAddress, EFI_SIZE_TO_PAGES (Length), SevSnpPageShared, FALSE);
+  }
+
+  //
+  // Save the specified length and physical address (we need it later).
+  //
+  OrigLength = Length;
+  OrigPhysicalAddress = PhysicalAddress;
+
   while (Length != 0)
   {
     //
@@ -923,6 +942,21 @@ SetMemoryEncDec (
   //
   CpuFlushTlb();
 
+  //
+  // SEV-SNP requires that all the private pages (i.e pages mapped encrypted) must be
+  // added in the RMP table before the access.
+  //
+  // The InternalSetPageState() is used for setting the page state in the RMP table.
+  //
+  if ((Mode == SetCBit) && MemEncryptSevSnpIsEnabled ()) {
+    InternalSetPageState (
+      OrigPhysicalAddress,
+      EFI_SIZE_TO_PAGES (OrigLength),
+      SevSnpPagePrivate,
+      FALSE
+      );
+  }
+
 Done:
   //
   // Restore page table write protection, if any.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 28/31] OvmfPkg/MemEncryptSevLib: skip page state change for Mmio address
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (26 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 27/31] OvmfPkg/MemEncryptSevLib: change the page state in the RMP table Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 29/31] OvmfPkg/PlatformPei: mark cpuid and secrets memory reserved in EFI map Brijesh Singh
                   ` (2 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

The SetMemoryEncDec() is used by the higher level routines to set or clear
the page encryption mask for system RAM and Mmio address. When SEV-SNP is
active, in addition to set/clear page mask it also updates the RMP table.
The RMP table updates are required for the system RAM address and not
the Mmio address.

Add a new parameter in SetMemoryEncDec() to tell whether the specified
address is Mmio. If its Mmio then skip the page state change in the RMP
table.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../X64/PeiDxeVirtualMemory.c                 | 20 ++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
index 56db1e4b6ecf..0bb86d768017 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
@@ -673,6 +673,7 @@ InternalMemEncryptSevCreateIdentityMap1G (
   @param[in]  Mode                    Set or Clear mode
   @param[in]  CacheFlush              Flush the caches before applying the
                                       encryption mask
+  @param[in]  Mmio                    The physical address specified is Mmio
 
   @retval RETURN_SUCCESS              The attributes were cleared for the
                                       memory region.
@@ -688,7 +689,8 @@ SetMemoryEncDec (
   IN    PHYSICAL_ADDRESS         PhysicalAddress,
   IN    UINTN                    Length,
   IN    MAP_RANGE_MODE           Mode,
-  IN    BOOLEAN                  CacheFlush
+  IN    BOOLEAN                  CacheFlush,
+  IN    BOOLEAN                  Mmio
   )
 {
   PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
@@ -711,14 +713,15 @@ SetMemoryEncDec (
 
   DEBUG ((
     DEBUG_VERBOSE,
-    "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx Mode=%a CacheFlush=%u\n",
+    "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx Mode=%a CacheFlush=%u Mmio=%u\n",
     gEfiCallerBaseName,
     __FUNCTION__,
     Cr3BaseAddress,
     PhysicalAddress,
     (UINT64)Length,
     (Mode == SetCBit) ? "Encrypt" : "Decrypt",
-    (UINT32)CacheFlush
+    (UINT32)CacheFlush,
+    (UINT32)Mmio
     ));
 
   //
@@ -760,7 +763,7 @@ SetMemoryEncDec (
   //
   // The InternalSetPageState() is used for setting the page state in the RMP table.
   //
-  if ((Mode == ClearCBit) && MemEncryptSevSnpIsEnabled ()) {
+  if (!Mmio && (Mode == ClearCBit) && MemEncryptSevSnpIsEnabled ()) {
     InternalSetPageState (PhysicalAddress, EFI_SIZE_TO_PAGES (Length), SevSnpPageShared, FALSE);
   }
 
@@ -998,7 +1001,8 @@ InternalMemEncryptSevSetMemoryDecrypted (
            PhysicalAddress,
            Length,
            ClearCBit,
-           TRUE
+           TRUE,
+           FALSE
            );
 }
 
@@ -1031,7 +1035,8 @@ InternalMemEncryptSevSetMemoryEncrypted (
            PhysicalAddress,
            Length,
            SetCBit,
-           TRUE
+           TRUE,
+           FALSE
            );
 }
 
@@ -1064,6 +1069,7 @@ InternalMemEncryptSevClearMmioPageEncMask (
            PhysicalAddress,
            Length,
            ClearCBit,
-           FALSE
+           FALSE,
+           TRUE
            );
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 29/31] OvmfPkg/PlatformPei: mark cpuid and secrets memory reserved in EFI map
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (27 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 28/31] OvmfPkg/MemEncryptSevLib: skip page state change for Mmio address Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 30/31] OvmfPkg/AmdSev: expose the SNP reserved pages through configuration table Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 31/31] UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs Brijesh Singh
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

When SEV-SNP is active, the CPUID and Secrets memory range contains the
information that is used during the VM boot. The content need to be persist
across the kexec boot. Mark the memory range as Reserved in the EFI map
so that guest OS or firmware does not use the range as a system RAM.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/PlatformPei/PlatformPei.inf |  4 ++++
 OvmfPkg/PlatformPei/Platform.h      |  5 +++++
 OvmfPkg/PlatformPei/AmdSev.c        | 31 +++++++++++++++++++++++++++++
 OvmfPkg/PlatformPei/MemDetect.c     |  2 ++
 4 files changed, 42 insertions(+)

diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index d048b692f155..0a89e1a0760e 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -112,6 +112,8 @@ [Pcd]
 
 
 [FixedPcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
   gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS
   gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory
@@ -122,6 +124,8 @@ [FixedPcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index 8b1d270c2b0b..4169019b4c07 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -102,6 +102,11 @@ AmdSevInitialize (
   VOID
   );
 
+VOID
+SevInitializeRam (
+  VOID
+  );
+
 extern EFI_BOOT_MODE mBootMode;
 
 extern BOOLEAN mS3Supported;
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index b71a4a7304f7..133382407bc5 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -414,3 +414,34 @@ AmdSevInitialize (
   ASSERT_RETURN_ERROR (PcdStatus);
 
 }
+
+/**
+ The function performs SEV specific region initialization.
+
+ **/
+VOID
+SevInitializeRam (
+  VOID
+  )
+{
+  if (MemEncryptSevSnpIsEnabled ()) {
+    //
+    // If SEV-SNP is enabled, reserve the Secrets and CPUID memory area.
+    //
+    // This memory range is given to the PSP by the hypervisor to populate
+    // the information used during the SNP VM boots, and it need to persist
+    // across the kexec boots. Mark it as EfiReservedMemoryType so that
+    // the guest firmware and OS does not use it as a system memory.
+    //
+    BuildMemoryAllocationHob (
+      (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSnpSecretsBase),
+      (UINT64)(UINTN) PcdGet32 (PcdOvmfSnpSecretsSize),
+      EfiReservedMemoryType
+      );
+    BuildMemoryAllocationHob (
+      (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfCpuidBase),
+      (UINT64)(UINTN) PcdGet32 (PcdOvmfCpuidSize),
+      EfiReservedMemoryType
+      );
+  }
+}
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index 2c2c4641ec8a..96487b810014 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -817,6 +817,8 @@ InitializeRamRegions (
 {
   QemuInitializeRam ();
 
+  SevInitializeRam ();
+
   if (mS3Supported && mBootMode != BOOT_ON_S3_RESUME) {
     //
     // This is the memory range that will be used for PEI on S3 resume
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 30/31] OvmfPkg/AmdSev: expose the SNP reserved pages through configuration table
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (28 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 29/31] OvmfPkg/PlatformPei: mark cpuid and secrets memory reserved in EFI map Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  2021-09-13 18:19 ` [PATCH v7 31/31] UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs Brijesh Singh
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Brijesh Singh, Michael Roth

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

Now that both the secrets and cpuid pages are reserved in the HOB,
extract the location details through fixed PCD and make it available
to the guest OS through the configuration table.

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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/OvmfPkg.dec                           |  1 +
 OvmfPkg/AmdSevDxe/AmdSevDxe.inf               |  7 ++++
 .../Guid/ConfidentialComputingSevSnpBlob.h    | 33 +++++++++++++++++++
 OvmfPkg/AmdSevDxe/AmdSevDxe.c                 | 23 +++++++++++++
 4 files changed, 64 insertions(+)
 create mode 100644 OvmfPkg/Include/Guid/ConfidentialComputingSevSnpBlob.h

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index e30cb6eafcb8..c2fbd26ed925 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -124,6 +124,7 @@ [Guids]
   gQemuKernelLoaderFsMediaGuid          = {0x1428f772, 0xb64a, 0x441e, {0xb8, 0xc3, 0x9e, 0xbd, 0xd7, 0xf8, 0x93, 0xc7}}
   gGrubFileGuid                         = {0xb5ae312c, 0xbc8a, 0x43b1, {0x9c, 0x62, 0xeb, 0xb8, 0x26, 0xdd, 0x5d, 0x07}}
   gConfidentialComputingSecretGuid      = {0xadf956ad, 0xe98c, 0x484c, {0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47}}
+  gConfidentialComputingSevSnpBlobGuid  = {0x067b1f5f, 0xcf26, 0x44c5, {0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42}}
 
 [Ppis]
   # PPI whose presence in the PPI database signals that the TPM base address
diff --git a/OvmfPkg/AmdSevDxe/AmdSevDxe.inf b/OvmfPkg/AmdSevDxe/AmdSevDxe.inf
index 0676fcc5b6a4..9acf860cf25e 100644
--- a/OvmfPkg/AmdSevDxe/AmdSevDxe.inf
+++ b/OvmfPkg/AmdSevDxe/AmdSevDxe.inf
@@ -42,6 +42,13 @@ [FeaturePcd]
 
 [FixedPcd]
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
+
+[Guids]
+  gConfidentialComputingSevSnpBlobGuid
 
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId
diff --git a/OvmfPkg/Include/Guid/ConfidentialComputingSevSnpBlob.h b/OvmfPkg/Include/Guid/ConfidentialComputingSevSnpBlob.h
new file mode 100644
index 000000000000..c98e7a1dcccd
--- /dev/null
+++ b/OvmfPkg/Include/Guid/ConfidentialComputingSevSnpBlob.h
@@ -0,0 +1,33 @@
+ /** @file
+   UEFI Configuration Table for exposing the SEV-SNP launch blob.
+
+   Copyright (c) 2021, Advanced Micro Devices Inc. All right reserved.
+
+   SPDX-License-Identifier: BSD-2-Clause-Patent
+ **/
+
+#ifndef CONFIDENTIAL_COMPUTING_SEV_SNP_BLOB_H_
+#define CONFIDENTIAL_COMPUTING_SEV_SNP_BLOB_H_
+
+#include <Uefi/UefiBaseType.h>
+
+#define CONFIDENTIAL_COMPUTING_SNP_BLOB_GUID            \
+  { 0x067b1f5f,                                         \
+    0xcf26,                                             \
+    0x44c5,                                             \
+    { 0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42 }, \
+  }
+
+typedef struct {
+  UINT32  Header;
+  UINT16  Version;
+  UINT16  Reserved1;
+  UINT64  SecretsPhysicalAddress;
+  UINT32  SecretsSize;
+  UINT64  CpuidPhysicalAddress;
+  UINT32  CpuidLSize;
+} CONFIDENTIAL_COMPUTING_SNP_BLOB_LOCATION;
+
+extern EFI_GUID gConfidentialComputingSevSnpBlobGuid;
+
+#endif
diff --git a/OvmfPkg/AmdSevDxe/AmdSevDxe.c b/OvmfPkg/AmdSevDxe/AmdSevDxe.c
index c66c4e9b9272..6e1ba35e02b8 100644
--- a/OvmfPkg/AmdSevDxe/AmdSevDxe.c
+++ b/OvmfPkg/AmdSevDxe/AmdSevDxe.c
@@ -17,8 +17,20 @@
 #include <Library/DxeServicesTableLib.h>
 #include <Library/MemEncryptSevLib.h>
 #include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Guid/ConfidentialComputingSevSnpBlob.h>
 #include <Library/PcdLib.h>
 
+STATIC CONFIDENTIAL_COMPUTING_SNP_BLOB_LOCATION mSnpBootDxeTable = {
+  SIGNATURE_32('A','M','D','E'),
+  1,
+  0,
+  (UINT64)(UINTN) FixedPcdGet32 (PcdOvmfSnpSecretsBase),
+  FixedPcdGet32 (PcdOvmfSnpSecretsSize),
+  (UINT64)(UINTN) FixedPcdGet32 (PcdOvmfCpuidBase),
+  FixedPcdGet32 (PcdOvmfCpuidSize),
+};
+
 EFI_STATUS
 EFIAPI
 AmdSevDxeEntryPoint (
@@ -130,5 +142,16 @@ AmdSevDxeEntryPoint (
     }
   }
 
+  //
+  // If its SEV-SNP active guest then install the CONFIDENTIAL_COMPUTING_SEV_SNP_BLOB.
+  // It contains the location for both the Secrets and CPUID page.
+  //
+  if (MemEncryptSevSnpIsEnabled ()) {
+    return gBS->InstallConfigurationTable (
+                  &gConfidentialComputingSevSnpBlobGuid,
+                  &mSnpBootDxeTable
+                  );
+  }
+
   return EFI_SUCCESS;
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 31/31] UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs
  2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (29 preceding siblings ...)
  2021-09-13 18:19 ` [PATCH v7 30/31] OvmfPkg/AmdSev: expose the SNP reserved pages through configuration table Brijesh Singh
@ 2021-09-13 18:19 ` Brijesh Singh
  30 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-13 18:19 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth, Gerd Hoffmann,
	Michael Roth, Eric Dong, Ray Ni, Rahul Kumar, Brijesh Singh

From: Tom Lendacky <thomas.lendacky@amd.com>

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

Use the SEV-SNP AP Creation NAE event to create and launch APs under
SEV-SNP. This capability will be advertised in the SEV Hypervisor
Feature Support PCD (PcdSevEsHypervisorFeatures).

Cc: Michael Roth <michael.roth@amd.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.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>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   3 +
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   3 +
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  44 +++
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  12 +-
 UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c    |  70 +++++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  53 ++--
 UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c     | 261 ++++++++++++++++++
 7 files changed, 426 insertions(+), 20 deletions(-)
 create mode 100644 UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index 76e6aa83b3cb..684d94e8c029 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -22,9 +22,11 @@ [Defines]
 #
 
 [Sources.IA32]
+  Ia32/AmdSev.c
   Ia32/MpFuncs.nasm
 
 [Sources.X64]
+  X64/AmdSev.c
   X64/MpFuncs.nasm
 
 [Sources.common]
@@ -72,6 +74,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                           ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                       ## SOMETIMES_CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds  ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures                  ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                       ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                      ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                           ## CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index a146bab94317..1132606b3379 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -22,9 +22,11 @@ [Defines]
 #
 
 [Sources.IA32]
+  Ia32/AmdSev.c
   Ia32/MpFuncs.nasm
 
 [Sources.X64]
+  X64/AmdSev.c
   X64/MpFuncs.nasm
 
 [Sources.common]
@@ -63,6 +65,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                   ## SOMETIMES_CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures              ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr      ## CONSUMES
 
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 94bd71408384..36d8c6eac9d0 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -15,6 +15,7 @@
 
 #include <Register/Intel/Cpuid.h>
 #include <Register/Amd/Cpuid.h>
+#include <Register/Amd/Ghcb.h>
 #include <Register/Intel/Msr.h>
 #include <Register/Intel/LocalApic.h>
 #include <Register/Intel/Microcode.h>
@@ -147,6 +148,7 @@ typedef struct {
   UINT8                          PlatformId;
   UINT64                         MicrocodeEntryAddr;
   UINT32                         MicrocodeRevision;
+  SEV_ES_SAVE_AREA               *SevEsSaveArea;
 } CPU_AP_DATA;
 
 //
@@ -291,6 +293,7 @@ struct _CPU_MP_DATA {
 
   BOOLEAN                        SevEsIsEnabled;
   BOOLEAN                        SevSnpIsEnabled;
+  BOOLEAN                        UseSevEsAPMethod;
   UINTN                          SevEsAPBuffer;
   UINTN                          SevEsAPResetStackStart;
   CPU_MP_DATA                    *NewCpuMpData;
@@ -757,5 +760,46 @@ ConfidentialComputingGuestHas (
   CONFIDENTIAL_COMPUTING_GUEST_ATTR     Attr
   );
 
+/**
+  Issue RMPADJUST to adjust the VMSA attribute of an SEV-SNP page.
+
+  @param[in]  PageAddress
+  @param[in]  VmsaPage
+
+  @return  RMPADJUST return value
+**/
+UINT32
+SevSnpRmpAdjust (
+  IN  EFI_PHYSICAL_ADDRESS  PageAddress,
+  IN  BOOLEAN               VmsaPage
+  );
+
+/**
+  Create an SEV-SNP AP save area (VMSA) for use in running the vCPU.
+
+  @param[in]  CpuMpData        Pointer to CPU MP Data
+  @param[in]  CpuData          Pointer to CPU AP Data
+  @param[in]  ApicId           APIC ID of the vCPU
+**/
+VOID
+SevSnpCreateSaveArea (
+  IN CPU_MP_DATA               *CpuMpData,
+  IN CPU_AP_DATA               *CpuData,
+  UINT32                       ApicId
+  );
+
+/**
+  Create SEV-SNP APs.
+
+  @param[in]  CpuMpData        Pointer to CPU MP Data
+  @param[in]  ProcessorNumber  The handle number of specified processor
+                               (-1 for all APs)
+**/
+VOID
+SevSnpCreateAP (
+  IN CPU_MP_DATA               *CpuMpData,
+  IN INTN                      ProcessorNumber
+  );
+
 #endif
 
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 657a73dca05e..7a3ef0015a31 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -93,7 +93,13 @@ GetWakeupBuffer (
   EFI_PHYSICAL_ADDRESS    StartAddress;
   EFI_MEMORY_TYPE         MemoryType;
 
-  if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
+  if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
+      !ConfidentialComputingGuestHas (CCAttrAmdSevSnp)) {
+  //
+  // An SEV-ES-only guest requires the memory to be reserved. SEV-SNP, which
+  // is also considered SEV-ES, uses a different AP startup method, though,
+  // which does not have the same requirement.
+  //
     MemoryType = EfiReservedMemoryType;
   } else {
     MemoryType = EfiBootServicesData;
@@ -373,7 +379,7 @@ RelocateApLoop (
   MpInitLibWhoAmI (&ProcessorNumber);
   CpuMpData    = GetCpuMpData ();
   MwaitSupport = IsMwaitSupport ();
-  if (CpuMpData->SevEsIsEnabled) {
+  if (CpuMpData->UseSevEsAPMethod) {
     StackStart = CpuMpData->SevEsAPResetStackStart;
   } else {
     StackStart = mReservedTopOfApStack;
@@ -422,7 +428,7 @@ MpInitChangeApLoopCallback (
     CpuPause ();
   }
 
-  if (CpuMpData->SevEsIsEnabled && (CpuMpData->WakeupBuffer != (UINTN) -1)) {
+  if (CpuMpData->UseSevEsAPMethod && (CpuMpData->WakeupBuffer != (UINTN) -1)) {
     //
     // There are APs present. Re-use reserved memory area below 1MB from
     // WakeupBuffer as the area to be used for transitioning to 16-bit mode
diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c
new file mode 100644
index 000000000000..a4702e298d98
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c
@@ -0,0 +1,70 @@
+/** @file
+
+  AMD SEV helper function.
+
+  Copyright (c) 2021, AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+/**
+  Create an SEV-SNP AP save area (VMSA) for use in running the vCPU.
+
+  @param[in]  CpuMpData        Pointer to CPU MP Data
+  @param[in]  CpuData          Pointer to CPU AP Data
+  @param[in]  ApicId           APIC ID of the vCPU
+**/
+VOID
+SevSnpCreateSaveArea (
+  IN CPU_MP_DATA               *CpuMpData,
+  IN CPU_AP_DATA               *CpuData,
+  UINT32                       ApicId
+  )
+{
+  //
+  // SEV-SNP is not support on 32-bit build.
+  //
+  ASSERT (FALSE);
+}
+
+/**
+  Create SEV-SNP APs.
+
+  @param[in]  CpuMpData        Pointer to CPU MP Data
+  @param[in]  ProcessorNumber  The handle number of specified processor
+                               (-1 for all APs)
+**/
+VOID
+SevSnpCreateAP (
+  IN CPU_MP_DATA               *CpuMpData,
+  IN INTN                      ProcessorNumber
+  )
+{
+  //
+  // SEV-SNP is not support on 32-bit build.
+  //
+  ASSERT (FALSE);
+}
+
+/**
+  Issue RMPADJUST to adjust the VMSA attribute of an SEV-SNP page.
+
+  @param[in]  PageAddress
+  @param[in]  VmsaPage
+
+  @return  RMPADJUST return value
+**/
+UINT32
+SevSnpRmpAdjust (
+  IN  EFI_PHYSICAL_ADDRESS  PageAddress,
+  IN  BOOLEAN               VmsaPage
+  )
+{
+  //
+  // RMPADJUST is not supported in 32-bit mode
+  //
+  return RETURN_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 12fe3ecb27a7..8ecc2d283364 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -295,10 +295,11 @@ GetApLoopMode (
       ApLoopMode = ApInHltLoop;
     }
 
-    if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
+    if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
+        !ConfidentialComputingGuestHas (CCAttrAmdSevSnp)) {
       //
-      // For SEV-ES, force AP in Hlt-loop mode in order to use the GHCB
-      // protocol for starting APs
+      // For SEV-ES (SEV-SNP is also considered SEV-ES), force AP in Hlt-loop
+      // mode in order to use the GHCB protocol for starting APs
       //
       ApLoopMode = ApInHltLoop;
     }
@@ -869,7 +870,7 @@ ApWakeupFunction (
       // to allow the APs to issue an AP_RESET_HOLD before the BSP possibly
       // performs another INIT-SIPI-SIPI sequence.
       //
-      if (!CpuMpData->SevEsIsEnabled) {
+      if (!CpuMpData->UseSevEsAPMethod) {
         InterlockedDecrement ((UINT32 *) &CpuMpData->MpCpuExchangeInfo->NumApsExecuting);
       }
     }
@@ -883,7 +884,7 @@ ApWakeupFunction (
       //
       while (TRUE) {
         DisableInterrupts ();
-        if (CpuMpData->SevEsIsEnabled) {
+        if (CpuMpData->UseSevEsAPMethod) {
           MSR_SEV_ES_GHCB_REGISTER  Msr;
           GHCB                      *Ghcb;
           UINT64                    Status;
@@ -1207,9 +1208,12 @@ AllocateResetVector (
                                     );
     //
     // The AP reset stack is only used by SEV-ES guests. Do not allocate it
-    // if SEV-ES is not enabled.
+    // if SEV-ES is not enabled. An SEV-SNP guest is also considered
+    // an SEV-ES guest, but uses a different method of AP startup, eliminating
+    // the need for the allocation.
     //
-    if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
+    if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
+        !ConfidentialComputingGuestHas (CCAttrAmdSevSnp)) {
       //
       // Stack location is based on ProcessorNumber, so use the total number
       // of processors for calculating the total stack area.
@@ -1259,7 +1263,7 @@ FreeResetVector (
   // perform the restore as this will overwrite memory which has data
   // needed by SEV-ES.
   //
-  if (!CpuMpData->SevEsIsEnabled) {
+  if (!CpuMpData->UseSevEsAPMethod) {
     RestoreWakeupBuffer (CpuMpData);
   }
 }
@@ -1276,7 +1280,7 @@ AllocateSevEsAPMemory (
 {
   if (CpuMpData->SevEsAPBuffer == (UINTN) -1) {
     CpuMpData->SevEsAPBuffer =
-      CpuMpData->SevEsIsEnabled ? GetSevEsAPMemory () : 0;
+      CpuMpData->UseSevEsAPMethod ? GetSevEsAPMemory () : 0;
   }
 }
 
@@ -1360,7 +1364,7 @@ WakeUpAP (
   ResetVectorRequired = FALSE;
 
   if (CpuMpData->WakeUpByInitSipiSipi ||
-      CpuMpData->InitFlag   != ApInitDone) {
+      CpuMpData->InitFlag != ApInitDone) {
     ResetVectorRequired = TRUE;
     AllocateResetVector (CpuMpData);
     AllocateSevEsAPMemory (CpuMpData);
@@ -1401,7 +1405,7 @@ WakeUpAP (
     }
     if (ResetVectorRequired) {
       //
-      // For SEV-ES, the initial AP boot address will be defined by
+      // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by
       // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
       // from the original INIT-SIPI-SIPI.
       //
@@ -1411,8 +1415,14 @@ WakeUpAP (
 
       //
       // Wakeup all APs
+      //   Must use the INIT-SIPI-SIPI method for initial configuration in
+      //   order to obtain the APIC ID.
       //
-      SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
+      if (CpuMpData->SevSnpIsEnabled && CpuMpData->InitFlag != ApInitConfig) {
+        SevSnpCreateAP (CpuMpData, -1);
+      } else {
+        SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
+      }
     }
     if (CpuMpData->InitFlag == ApInitConfig) {
       if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) {
@@ -1502,7 +1512,7 @@ WakeUpAP (
       CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
 
       //
-      // For SEV-ES, the initial AP boot address will be defined by
+      // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by
       // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
       // from the original INIT-SIPI-SIPI.
       //
@@ -1510,10 +1520,14 @@ WakeUpAP (
         SetSevEsJumpTable (ExchangeInfo->BufferStart);
       }
 
-      SendInitSipiSipi (
-        CpuInfoInHob[ProcessorNumber].ApicId,
-        (UINT32) ExchangeInfo->BufferStart
-        );
+      if (CpuMpData->SevSnpIsEnabled && CpuMpData->InitFlag != ApInitConfig) {
+        SevSnpCreateAP (CpuMpData, (INTN) ProcessorNumber);
+      } else {
+        SendInitSipiSipi (
+          CpuInfoInHob[ProcessorNumber].ApicId,
+          (UINT32) ExchangeInfo->BufferStart
+          );
+      }
     }
     //
     // Wait specified AP waken up
@@ -2048,6 +2062,11 @@ MpInitLibInitialize (
   CpuMpData->SevSnpIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevSnp);
   CpuMpData->SevEsAPBuffer  = (UINTN) -1;
   CpuMpData->GhcbBase       = PcdGet64 (PcdGhcbBase);
+  CpuMpData->UseSevEsAPMethod = CpuMpData->SevEsIsEnabled && !CpuMpData->SevSnpIsEnabled;
+
+  if (CpuMpData->SevSnpIsEnabled) {
+    ASSERT ((PcdGet64 (PcdGhcbHypervisorFeatures) & GHCB_HV_FEATURES_SNP_AP_CREATE) == GHCB_HV_FEATURES_SNP_AP_CREATE);
+  }
 
   //
   // Make sure no memory usage outside of the allocated buffer.
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
new file mode 100644
index 000000000000..303271abdaad
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
@@ -0,0 +1,261 @@
+/** @file
+
+  AMD SEV helper function.
+
+  Copyright (c) 2021, AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+#include <Library/VmgExitLib.h>
+#include <Register/Amd/Fam17Msr.h>
+#include <Register/Amd/Ghcb.h>
+
+/**
+  Create an SEV-SNP AP save area (VMSA) for use in running the vCPU.
+
+  @param[in]  CpuMpData        Pointer to CPU MP Data
+  @param[in]  CpuData          Pointer to CPU AP Data
+  @param[in]  ApicId           APIC ID of the vCPU
+**/
+VOID
+SevSnpCreateSaveArea (
+  IN CPU_MP_DATA               *CpuMpData,
+  IN CPU_AP_DATA               *CpuData,
+  UINT32                       ApicId
+  )
+{
+  SEV_ES_SAVE_AREA          *SaveArea;
+  IA32_CR0                  ApCr0;
+  IA32_CR0                  ResetCr0;
+  IA32_CR4                  ApCr4;
+  IA32_CR4                  ResetCr4;
+  UINTN                     StartIp;
+  UINT8                     SipiVector;
+  UINT32                    RmpAdjustStatus;
+  UINT64                    VmgExitStatus;
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+  GHCB                      *Ghcb;
+  BOOLEAN                   InterruptState;
+  UINT64                    ExitInfo1;
+  UINT64                    ExitInfo2;
+
+  //
+  // Allocate a single page for the SEV-ES Save Area and initialize it.
+  //
+  SaveArea = AllocateReservedPages (1);
+  if (!SaveArea) {
+    return;
+  }
+  ZeroMem (SaveArea, EFI_PAGE_SIZE);
+
+  //
+  // Propogate the CR0.NW and CR0.CD setting to the AP
+  //
+  ResetCr0.UintN = 0x00000010;
+  ApCr0.UintN = CpuData->VolatileRegisters.Cr0;
+  if (ApCr0.Bits.NW) {
+    ResetCr0.Bits.NW = 1;
+  }
+  if (ApCr0.Bits.CD) {
+    ResetCr0.Bits.CD = 1;
+  }
+
+  //
+  // Propagate the CR4.MCE setting to the AP
+  //
+  ResetCr4.UintN = 0;
+  ApCr4.UintN = CpuData->VolatileRegisters.Cr4;
+  if (ApCr4.Bits.MCE) {
+    ResetCr4.Bits.MCE = 1;
+  }
+
+  //
+  // Convert the start IP into a SIPI Vector
+  //
+  StartIp = CpuMpData->MpCpuExchangeInfo->BufferStart;
+  SipiVector = (UINT8) (StartIp >> 12);
+
+  //
+  // Set the CS:RIP value based on the start IP
+  //
+  SaveArea->Cs.Base = SipiVector << 12;
+  SaveArea->Cs.Selector = SipiVector << 8;
+  SaveArea->Cs.Limit = 0xFFFF;
+  SaveArea->Cs.Attributes.Bits.Present = 1;
+  SaveArea->Cs.Attributes.Bits.Sbit = 1;
+  SaveArea->Cs.Attributes.Bits.Type = SEV_ES_RESET_CODE_SEGMENT_TYPE;
+  SaveArea->Rip = StartIp & 0xFFF;
+
+  //
+  // Set the remaining values as defined in APM for INIT
+  //
+  SaveArea->Ds.Limit = 0xFFFF;
+  SaveArea->Ds.Attributes.Bits.Present = 1;
+  SaveArea->Ds.Attributes.Bits.Sbit = 1;
+  SaveArea->Ds.Attributes.Bits.Type = SEV_ES_RESET_DATA_SEGMENT_TYPE;
+  SaveArea->Es = SaveArea->Ds;
+  SaveArea->Fs = SaveArea->Ds;
+  SaveArea->Gs = SaveArea->Ds;
+  SaveArea->Ss = SaveArea->Ds;
+
+  SaveArea->Gdtr.Limit = 0xFFFF;
+  SaveArea->Ldtr.Limit = 0xFFFF;
+  SaveArea->Ldtr.Attributes.Bits.Present = 1;
+  SaveArea->Ldtr.Attributes.Bits.Type = SEV_ES_RESET_LDT_TYPE;
+  SaveArea->Idtr.Limit = 0xFFFF;
+  SaveArea->Tr.Limit = 0xFFFF;
+  SaveArea->Ldtr.Attributes.Bits.Present = 1;
+  SaveArea->Ldtr.Attributes.Bits.Type = SEV_ES_RESET_TSS_TYPE;
+
+  SaveArea->Efer   = 0x1000;
+  SaveArea->Cr4    = ResetCr4.UintN;
+  SaveArea->Cr0    = ResetCr0.UintN;
+  SaveArea->Dr7    = 0x0400;
+  SaveArea->Dr6    = 0xFFFF0FF0;
+  SaveArea->Rflags = 0x0002;
+  SaveArea->GPat   = 0x0007040600070406ULL;
+  SaveArea->XCr0   = 0x0001;
+  SaveArea->Mxcsr  = 0x1F80;
+  SaveArea->X87Ftw = 0x5555;
+  SaveArea->X87Fcw = 0x0040;
+
+  //
+  // Set the SEV-SNP specific fields for the save area:
+  //   VMPL - always VMPL0
+  //   SEV_FEATURES - equivalent to the SEV_STATUS MSR right shifted 2 bits
+  //
+  SaveArea->Vmpl        = 0;
+  SaveArea->SevFeatures = AsmReadMsr64 (MSR_SEV_STATUS) >> 2;
+
+  //
+  // To turn the page into a recognized VMSA page, issue RMPADJUST:
+  //   Target VMPL but numerically higher than current VMPL
+  //   Target PermissionMask is not used
+  //
+  RmpAdjustStatus = SevSnpRmpAdjust (
+                      (EFI_PHYSICAL_ADDRESS) (UINTN) SaveArea,
+                      TRUE
+                      );
+  ASSERT (RmpAdjustStatus == 0);
+
+  ExitInfo1 = (UINT64) ApicId << 32;
+  ExitInfo1 |= SVM_VMGEXIT_SNP_AP_CREATE;
+  ExitInfo2 = (UINT64) (UINTN) SaveArea;
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+  Ghcb = Msr.Ghcb;
+
+  VmgInit (Ghcb, &InterruptState);
+  Ghcb->SaveArea.Rax = SaveArea->SevFeatures;
+  VmgSetOffsetValid (Ghcb, GhcbRax);
+  VmgExitStatus = VmgExit (
+                    Ghcb,
+                    SVM_EXIT_SNP_AP_CREATION,
+                    ExitInfo1,
+                    ExitInfo2
+                    );
+  VmgDone (Ghcb, InterruptState);
+
+  ASSERT (VmgExitStatus == 0);
+  if (VmgExitStatus != 0) {
+    RmpAdjustStatus = SevSnpRmpAdjust (
+                        (EFI_PHYSICAL_ADDRESS) (UINTN) SaveArea,
+                        FALSE
+                        );
+    if (RmpAdjustStatus == 0) {
+      FreePages (SaveArea, 1);
+    } else {
+      DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n"));
+    }
+
+    SaveArea = NULL;
+  }
+
+  if (CpuData->SevEsSaveArea) {
+    RmpAdjustStatus = SevSnpRmpAdjust (
+                        (EFI_PHYSICAL_ADDRESS) (UINTN) CpuData->SevEsSaveArea,
+                        FALSE
+                        );
+    if (RmpAdjustStatus == 0) {
+      FreePages (CpuData->SevEsSaveArea, 1);
+    } else {
+      DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n"));
+    }
+  }
+
+  CpuData->SevEsSaveArea = SaveArea;
+}
+
+/**
+  Create SEV-SNP APs.
+
+  @param[in]  CpuMpData        Pointer to CPU MP Data
+  @param[in]  ProcessorNumber  The handle number of specified processor
+                               (-1 for all APs)
+**/
+VOID
+SevSnpCreateAP (
+  IN CPU_MP_DATA               *CpuMpData,
+  IN INTN                      ProcessorNumber
+  )
+{
+  CPU_INFO_IN_HOB  *CpuInfoInHob;
+  CPU_AP_DATA      *CpuData;
+  UINTN            Index;
+  UINT32           ApicId;
+
+  ASSERT (CpuMpData->MpCpuExchangeInfo->BufferStart < 0x100000);
+
+  CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+
+  if (ProcessorNumber < 0) {
+    for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+      if (Index != CpuMpData->BspNumber) {
+        CpuData = &CpuMpData->CpuData[Index];
+        ApicId = CpuInfoInHob[Index].ApicId,
+        SevSnpCreateSaveArea (CpuMpData, CpuData, ApicId);
+      }
+    }
+  } else {
+    Index = (UINTN) ProcessorNumber;
+    CpuData = &CpuMpData->CpuData[Index];
+    ApicId = CpuInfoInHob[ProcessorNumber].ApicId,
+    SevSnpCreateSaveArea (CpuMpData, CpuData, ApicId);
+  }
+}
+
+/**
+  Issue RMPADJUST to adjust the VMSA attribute of an SEV-SNP page.
+
+  @param[in]  PageAddress
+  @param[in]  VmsaPage
+
+  @return  RMPADJUST return value
+**/
+UINT32
+SevSnpRmpAdjust (
+  IN  EFI_PHYSICAL_ADDRESS  PageAddress,
+  IN  BOOLEAN               VmsaPage
+  )
+{
+  UINT64  Rdx;
+
+  //
+  // The RMPADJUST instruction is used to set or clear the VMSA bit for a
+  // page. The VMSA change is only made when running at VMPL0 and is ignored
+  // otherwise. If too low a target VMPL is specified, the instruction can
+  // succeed without changing the VMSA bit when not running at VMPL0. Using a
+  // target VMPL level of 1, RMPADJUST will return a FAIL_PERMISSION error if
+  // not running at VMPL0, thus ensuring that the VMSA bit is set appropriately
+  // when no error is returned.
+  //
+  Rdx = 1;
+  if (VmsaPage) {
+    Rdx |= RMPADJUST_VMSA_PAGE_BIT;
+  }
+
+  return AsmRmpAdjust ((UINT64) PageAddress, 0, Rdx);
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled
  2021-09-13 18:19 ` [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled Brijesh Singh
@ 2021-09-14  2:23   ` Ni, Ray
  2021-09-14  2:25     ` Ni, Ray
  0 siblings, 1 reply; 49+ messages in thread
From: Ni, Ray @ 2021-09-14  2:23 UTC (permalink / raw)
  To: Brijesh Singh, devel@edk2.groups.io
  Cc: James Bottomley, Xu, Min M, Yao, Jiewen, Tom Lendacky,
	Justen, Jordan L, Ard Biesheuvel, Erdem Aktas, Michael Roth,
	Gerd Hoffmann, Michael Roth, Dong, Eric, Kumar, Rahul1

Hi Brijesh,
Can you please separate the SEV logic in separate functions in separate files?
These are not x86 common logics. With more and more SEV specific logics added,
I want to keep the common flow clean.

Thanks,
Ray

-----Original Message-----
From: Brijesh Singh <brijesh.singh@amd.com> 
Sent: Tuesday, September 14, 2021 2:20 AM
To: devel@edk2.groups.io
Cc: James Bottomley <jejb@linux.ibm.com>; Xu, Min M <min.m.xu@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky <thomas.lendacky@amd.com>; Justen, Jordan L <jordan.l.justen@intel.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Erdem Aktas <erdemaktas@google.com>; Michael Roth <Michael.Roth@amd.com>; Gerd Hoffmann <kraxel@redhat.com>; Brijesh Singh <brijesh.singh@amd.com>; Michael Roth <michael.roth@amd.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
Subject: [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

An SEV-SNP guest requires that the physical address of the GHCB must be registered with the hypervisor before using it. See the GHCB specification section 2.3.2 for more details.

Cc: Michael Roth <michael.roth@amd.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  2 +
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  2 +
 UefiCpuPkg/Library/MpInitLib/MpEqu.inc        |  1 +
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 53 +++++++++++++++++++
 4 files changed, 58 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 388ebef7b0dc..56d6d703d8b0 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -219,6 +219,7 @@ typedef struct {
   //
   BOOLEAN               Enable5LevelPaging;
   BOOLEAN               SevEsIsEnabled;
+  BOOLEAN               SevSnpIsEnabled;
   UINTN                 GhcbBase;
 } MP_CPU_EXCHANGE_INFO;
 
@@ -288,6 +289,7 @@ struct _CPU_MP_DATA {
   BOOLEAN                        WakeUpByInitSipiSipi;
 
   BOOLEAN                        SevEsIsEnabled;
+  BOOLEAN                        SevSnpIsEnabled;
   UINTN                          SevEsAPBuffer;
   UINTN                          SevEsAPResetStackStart;
   CPU_MP_DATA                    *NewCpuMpData;
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index bfef1237f452..365c0ff24ebe 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1040,6 +1040,7 @@ FillExchangeInfoData (
   DEBUG ((DEBUG_INFO, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName, ExchangeInfo->Enable5LevelPaging));
 
   ExchangeInfo->SevEsIsEnabled  = CpuMpData->SevEsIsEnabled;
+  ExchangeInfo->SevSnpIsEnabled = CpuMpData->SevSnpIsEnabled;
   ExchangeInfo->GhcbBase        = (UINTN) CpuMpData->GhcbBase;
 
   //
@@ -2033,6 +2034,7 @@ MpInitLibInitialize (
   CpuMpData->CpuInfoInHob     = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
   InitializeSpinLock(&CpuMpData->MpLock);
   CpuMpData->SevEsIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevEs);
+  CpuMpData->SevSnpIsEnabled = ConfidentialComputingGuestHas 
+ (CCAttrAmdSevSnp);
   CpuMpData->SevEsAPBuffer  = (UINTN) -1;
   CpuMpData->GhcbBase       = PcdGet64 (PcdGhcbBase);
 
diff --git a/UefiCpuPkg/Library/MpInitLib/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
index 2e9368a374a4..01668638f245 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
+++ b/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
@@ -92,6 +92,7 @@ struc MP_CPU_EXCHANGE_INFO
   .ModeHighSegment:              CTYPE_UINT16 1
   .Enable5LevelPaging:           CTYPE_BOOLEAN 1
   .SevEsIsEnabled:               CTYPE_BOOLEAN 1
+  .SevSnpIsEnabled               CTYPE_BOOLEAN 1
   .GhcbBase:                     CTYPE_UINTN 1
 endstruc
 
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index 50df802d1fca..018ebe74bf5f 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -194,6 +194,59 @@ LongModeStart:
     mov        rdx, rax
     shr        rdx, 32
     mov        rcx, 0xc0010130
+
+    ;
+    ; If its an SEV-SNP guest then register the GHCB GPA
+    ;
+RegisterGhcbGpa:
+    ;
+    ; Register GHCB GPA when SEV-SNP is enabled
+    ;
+    lea        edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]
+    cmp        byte [edi], 1        ; SevSnpIsEnabled
+    jne        RegisterGhcbGpaDone
+
+    ; Save the rdi and rsi to used for later comparison
+    push       rdi
+    push       rsi
+    mov        edi, eax
+    mov        esi, edx
+    or         eax, 18              ; Ghcb registration request
+    wrmsr
+    rep vmmcall
+    rdmsr
+    mov        r12, rax
+    and        r12, 0fffh
+    cmp        r12, 19              ; Ghcb registration response
+    jne        GhcbGpaRegisterFailure
+
+    ; Verify that GPA is not changed
+    and        eax, 0fffff000h
+    cmp        edi, eax
+    jne        GhcbGpaRegisterFailure
+    cmp        esi, edx
+    jne        GhcbGpaRegisterFailure
+    pop        rsi
+    pop        rdi
+    jmp        RegisterGhcbGpaDone
+
+    ;
+    ; Request the guest termination
+    ;
+GhcbGpaRegisterFailure:
+    xor        edx, edx
+    mov        eax, 256             ; GHCB terminate
+    wrmsr
+    rep vmmcall
+
+    ; We should not return from the above terminate request, but if we do
+    ; then enter into the hlt loop.
+DoHltLoop:
+    cli
+    hlt
+    jmp        DoHltLoop
+
+RegisterGhcbGpaDone:
     wrmsr
     jmp        CProcedureInvoke
 
--
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled
  2021-09-14  2:23   ` Ni, Ray
@ 2021-09-14  2:25     ` Ni, Ray
  2021-09-14 14:21       ` [edk2-devel] " Brijesh Singh
  0 siblings, 1 reply; 49+ messages in thread
From: Ni, Ray @ 2021-09-14  2:25 UTC (permalink / raw)
  To: Brijesh Singh, devel@edk2.groups.io
  Cc: James Bottomley, Xu, Min M, Yao, Jiewen, Tom Lendacky,
	Justen, Jordan L, Ard Biesheuvel, Erdem Aktas, Michael Roth,
	Gerd Hoffmann, Michael Roth, Dong, Eric, Kumar, Rahul1

The comments don't apply to this patch only.
To be clear, it would be great that you can do a cleanup of existing code to try best separating the SEV flow from the common flow.

-----Original Message-----
From: Ni, Ray 
Sent: Tuesday, September 14, 2021 10:24 AM
To: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io
Cc: James Bottomley <jejb@linux.ibm.com>; Xu, Min M <min.m.xu@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky <thomas.lendacky@amd.com>; Justen, Jordan L <jordan.l.justen@intel.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Erdem Aktas <erdemaktas@google.com>; Michael Roth <Michael.Roth@amd.com>; Gerd Hoffmann <kraxel@redhat.com>; Michael Roth <michael.roth@amd.com>; Dong, Eric <eric.dong@intel.com>; Kumar, Rahul1 <Rahul1.Kumar@intel.com>
Subject: RE: [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled

Hi Brijesh,
Can you please separate the SEV logic in separate functions in separate files?
These are not x86 common logics. With more and more SEV specific logics added, I want to keep the common flow clean.

Thanks,
Ray

-----Original Message-----
From: Brijesh Singh <brijesh.singh@amd.com>
Sent: Tuesday, September 14, 2021 2:20 AM
To: devel@edk2.groups.io
Cc: James Bottomley <jejb@linux.ibm.com>; Xu, Min M <min.m.xu@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky <thomas.lendacky@amd.com>; Justen, Jordan L <jordan.l.justen@intel.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Erdem Aktas <erdemaktas@google.com>; Michael Roth <Michael.Roth@amd.com>; Gerd Hoffmann <kraxel@redhat.com>; Brijesh Singh <brijesh.singh@amd.com>; Michael Roth <michael.roth@amd.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
Subject: [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

An SEV-SNP guest requires that the physical address of the GHCB must be registered with the hypervisor before using it. See the GHCB specification section 2.3.2 for more details.

Cc: Michael Roth <michael.roth@amd.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.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>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  2 +
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  2 +
 UefiCpuPkg/Library/MpInitLib/MpEqu.inc        |  1 +
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 53 +++++++++++++++++++
 4 files changed, 58 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 388ebef7b0dc..56d6d703d8b0 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -219,6 +219,7 @@ typedef struct {
   //
   BOOLEAN               Enable5LevelPaging;
   BOOLEAN               SevEsIsEnabled;
+  BOOLEAN               SevSnpIsEnabled;
   UINTN                 GhcbBase;
 } MP_CPU_EXCHANGE_INFO;
 
@@ -288,6 +289,7 @@ struct _CPU_MP_DATA {
   BOOLEAN                        WakeUpByInitSipiSipi;
 
   BOOLEAN                        SevEsIsEnabled;
+  BOOLEAN                        SevSnpIsEnabled;
   UINTN                          SevEsAPBuffer;
   UINTN                          SevEsAPResetStackStart;
   CPU_MP_DATA                    *NewCpuMpData;
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index bfef1237f452..365c0ff24ebe 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1040,6 +1040,7 @@ FillExchangeInfoData (
   DEBUG ((DEBUG_INFO, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName, ExchangeInfo->Enable5LevelPaging));
 
   ExchangeInfo->SevEsIsEnabled  = CpuMpData->SevEsIsEnabled;
+  ExchangeInfo->SevSnpIsEnabled = CpuMpData->SevSnpIsEnabled;
   ExchangeInfo->GhcbBase        = (UINTN) CpuMpData->GhcbBase;
 
   //
@@ -2033,6 +2034,7 @@ MpInitLibInitialize (
   CpuMpData->CpuInfoInHob     = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
   InitializeSpinLock(&CpuMpData->MpLock);
   CpuMpData->SevEsIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevEs);
+  CpuMpData->SevSnpIsEnabled = ConfidentialComputingGuestHas 
+ (CCAttrAmdSevSnp);
   CpuMpData->SevEsAPBuffer  = (UINTN) -1;
   CpuMpData->GhcbBase       = PcdGet64 (PcdGhcbBase);
 
diff --git a/UefiCpuPkg/Library/MpInitLib/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
index 2e9368a374a4..01668638f245 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
+++ b/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
@@ -92,6 +92,7 @@ struc MP_CPU_EXCHANGE_INFO
   .ModeHighSegment:              CTYPE_UINT16 1
   .Enable5LevelPaging:           CTYPE_BOOLEAN 1
   .SevEsIsEnabled:               CTYPE_BOOLEAN 1
+  .SevSnpIsEnabled               CTYPE_BOOLEAN 1
   .GhcbBase:                     CTYPE_UINTN 1
 endstruc
 
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index 50df802d1fca..018ebe74bf5f 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -194,6 +194,59 @@ LongModeStart:
     mov        rdx, rax
     shr        rdx, 32
     mov        rcx, 0xc0010130
+
+    ;
+    ; If its an SEV-SNP guest then register the GHCB GPA
+    ;
+RegisterGhcbGpa:
+    ;
+    ; Register GHCB GPA when SEV-SNP is enabled
+    ;
+    lea        edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]
+    cmp        byte [edi], 1        ; SevSnpIsEnabled
+    jne        RegisterGhcbGpaDone
+
+    ; Save the rdi and rsi to used for later comparison
+    push       rdi
+    push       rsi
+    mov        edi, eax
+    mov        esi, edx
+    or         eax, 18              ; Ghcb registration request
+    wrmsr
+    rep vmmcall
+    rdmsr
+    mov        r12, rax
+    and        r12, 0fffh
+    cmp        r12, 19              ; Ghcb registration response
+    jne        GhcbGpaRegisterFailure
+
+    ; Verify that GPA is not changed
+    and        eax, 0fffff000h
+    cmp        edi, eax
+    jne        GhcbGpaRegisterFailure
+    cmp        esi, edx
+    jne        GhcbGpaRegisterFailure
+    pop        rsi
+    pop        rdi
+    jmp        RegisterGhcbGpaDone
+
+    ;
+    ; Request the guest termination
+    ;
+GhcbGpaRegisterFailure:
+    xor        edx, edx
+    mov        eax, 256             ; GHCB terminate
+    wrmsr
+    rep vmmcall
+
+    ; We should not return from the above terminate request, but if we do
+    ; then enter into the hlt loop.
+DoHltLoop:
+    cli
+    hlt
+    jmp        DoHltLoop
+
+RegisterGhcbGpaDone:
     wrmsr
     jmp        CProcedureInvoke
 
--
2.17.1


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [edk2-devel] [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled
  2021-09-14  2:25     ` Ni, Ray
@ 2021-09-14 14:21       ` Brijesh Singh
  2021-09-16  9:15         ` Gerd Hoffmann
  0 siblings, 1 reply; 49+ messages in thread
From: Brijesh Singh @ 2021-09-14 14:21 UTC (permalink / raw)
  To: devel, ray.ni
  Cc: James Bottomley, Xu, Min M, Yao, Jiewen, Tom Lendacky,
	Justen, Jordan L, Ard Biesheuvel, Erdem Aktas, Michael Roth,
	Gerd Hoffmann, Dong, Eric, Kumar, Rahul1

Hi Ray,

I was hoping that refactor can be done later but sounds like we want to
do it before the SNP. Let me look into it.

thanks

On 9/13/21 9:25 PM, Ni, Ray via groups.io wrote:
> The comments don't apply to this patch only.
> To be clear, it would be great that you can do a cleanup of existing code to try best separating the SEV flow from the common flow.
>
> -----Original Message-----
> From: Ni, Ray 
> Sent: Tuesday, September 14, 2021 10:24 AM
> To: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io
> Cc: James Bottomley <jejb@linux.ibm.com>; Xu, Min M <min.m.xu@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky <thomas.lendacky@amd.com>; Justen, Jordan L <jordan.l.justen@intel.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Erdem Aktas <erdemaktas@google.com>; Michael Roth <Michael.Roth@amd.com>; Gerd Hoffmann <kraxel@redhat.com>; Michael Roth <michael.roth@amd.com>; Dong, Eric <eric.dong@intel.com>; Kumar, Rahul1 <Rahul1.Kumar@intel.com>
> Subject: RE: [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled
>
> Hi Brijesh,
> Can you please separate the SEV logic in separate functions in separate files?
> These are not x86 common logics. With more and more SEV specific logics added, I want to keep the common flow clean.
>
> Thanks,
> Ray
>
> -----Original Message-----
> From: Brijesh Singh <brijesh.singh@amd.com>
> Sent: Tuesday, September 14, 2021 2:20 AM
> To: devel@edk2.groups.io
> Cc: James Bottomley <jejb@linux.ibm.com>; Xu, Min M <min.m.xu@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky <thomas.lendacky@amd.com>; Justen, Jordan L <jordan.l.justen@intel.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Erdem Aktas <erdemaktas@google.com>; Michael Roth <Michael.Roth@amd.com>; Gerd Hoffmann <kraxel@redhat.com>; Brijesh Singh <brijesh.singh@amd.com>; Michael Roth <michael.roth@amd.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
> Subject: [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled
>
> BZ: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D3275&amp;data=04%7C01%7Cbrijesh.singh%40amd.com%7C339dc1ddc21a4db5861108d97726e870%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637671831285377986%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=yKhaiNG%2FHHXatk%2FnJe7A6e%2BlDGRMt56BGUM1f1QUraI%3D&amp;reserved=0
>
> An SEV-SNP guest requires that the physical address of the GHCB must be registered with the hypervisor before using it. See the GHCB specification section 2.3.2 for more details.
>
> Cc: Michael Roth <michael.roth@amd.com>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Rahul Kumar <rahul1.kumar@intel.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>
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  UefiCpuPkg/Library/MpInitLib/MpLib.h          |  2 +
>  UefiCpuPkg/Library/MpInitLib/MpLib.c          |  2 +
>  UefiCpuPkg/Library/MpInitLib/MpEqu.inc        |  1 +
>  UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 53 +++++++++++++++++++
>  4 files changed, 58 insertions(+)
>
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
> index 388ebef7b0dc..56d6d703d8b0 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
> @@ -219,6 +219,7 @@ typedef struct {
>    //
>    BOOLEAN               Enable5LevelPaging;
>    BOOLEAN               SevEsIsEnabled;
> +  BOOLEAN               SevSnpIsEnabled;
>    UINTN                 GhcbBase;
>  } MP_CPU_EXCHANGE_INFO;
>  
> @@ -288,6 +289,7 @@ struct _CPU_MP_DATA {
>    BOOLEAN                        WakeUpByInitSipiSipi;
>  
>    BOOLEAN                        SevEsIsEnabled;
> +  BOOLEAN                        SevSnpIsEnabled;
>    UINTN                          SevEsAPBuffer;
>    UINTN                          SevEsAPResetStackStart;
>    CPU_MP_DATA                    *NewCpuMpData;
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> index bfef1237f452..365c0ff24ebe 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> @@ -1040,6 +1040,7 @@ FillExchangeInfoData (
>    DEBUG ((DEBUG_INFO, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName, ExchangeInfo->Enable5LevelPaging));
>  
>    ExchangeInfo->SevEsIsEnabled  = CpuMpData->SevEsIsEnabled;
> +  ExchangeInfo->SevSnpIsEnabled = CpuMpData->SevSnpIsEnabled;
>    ExchangeInfo->GhcbBase        = (UINTN) CpuMpData->GhcbBase;
>  
>    //
> @@ -2033,6 +2034,7 @@ MpInitLibInitialize (
>    CpuMpData->CpuInfoInHob     = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
>    InitializeSpinLock(&CpuMpData->MpLock);
>    CpuMpData->SevEsIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevEs);
> +  CpuMpData->SevSnpIsEnabled = ConfidentialComputingGuestHas 
> + (CCAttrAmdSevSnp);
>    CpuMpData->SevEsAPBuffer  = (UINTN) -1;
>    CpuMpData->GhcbBase       = PcdGet64 (PcdGhcbBase);
>  
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
> index 2e9368a374a4..01668638f245 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
> +++ b/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
> @@ -92,6 +92,7 @@ struc MP_CPU_EXCHANGE_INFO
>    .ModeHighSegment:              CTYPE_UINT16 1
>    .Enable5LevelPaging:           CTYPE_BOOLEAN 1
>    .SevEsIsEnabled:               CTYPE_BOOLEAN 1
> +  .SevSnpIsEnabled               CTYPE_BOOLEAN 1
>    .GhcbBase:                     CTYPE_UINTN 1
>  endstruc
>  
> diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
> index 50df802d1fca..018ebe74bf5f 100644
> --- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
> +++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
> @@ -194,6 +194,59 @@ LongModeStart:
>      mov        rdx, rax
>      shr        rdx, 32
>      mov        rcx, 0xc0010130
> +
> +    ;
> +    ; If its an SEV-SNP guest then register the GHCB GPA
> +    ;
> +RegisterGhcbGpa:
> +    ;
> +    ; Register GHCB GPA when SEV-SNP is enabled
> +    ;
> +    lea        edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]
> +    cmp        byte [edi], 1        ; SevSnpIsEnabled
> +    jne        RegisterGhcbGpaDone
> +
> +    ; Save the rdi and rsi to used for later comparison
> +    push       rdi
> +    push       rsi
> +    mov        edi, eax
> +    mov        esi, edx
> +    or         eax, 18              ; Ghcb registration request
> +    wrmsr
> +    rep vmmcall
> +    rdmsr
> +    mov        r12, rax
> +    and        r12, 0fffh
> +    cmp        r12, 19              ; Ghcb registration response
> +    jne        GhcbGpaRegisterFailure
> +
> +    ; Verify that GPA is not changed
> +    and        eax, 0fffff000h
> +    cmp        edi, eax
> +    jne        GhcbGpaRegisterFailure
> +    cmp        esi, edx
> +    jne        GhcbGpaRegisterFailure
> +    pop        rsi
> +    pop        rdi
> +    jmp        RegisterGhcbGpaDone
> +
> +    ;
> +    ; Request the guest termination
> +    ;
> +GhcbGpaRegisterFailure:
> +    xor        edx, edx
> +    mov        eax, 256             ; GHCB terminate
> +    wrmsr
> +    rep vmmcall
> +
> +    ; We should not return from the above terminate request, but if we do
> +    ; then enter into the hlt loop.
> +DoHltLoop:
> +    cli
> +    hlt
> +    jmp        DoHltLoop
> +
> +RegisterGhcbGpaDone:
>      wrmsr
>      jmp        CProcedureInvoke
>  
> --
> 2.17.1
>
>
>
> 
>
>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 09/31] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest
  2021-09-13 18:19 ` [PATCH v7 09/31] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest Brijesh Singh
@ 2021-09-15 17:08   ` Erdem Aktas
  2021-09-15 18:50     ` Brijesh Singh
  0 siblings, 1 reply; 49+ messages in thread
From: Erdem Aktas @ 2021-09-15 17:08 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: edk2-devel-groups-io, James Bottomley, Min Xu, Jiewen Yao,
	Tom Lendacky, Jordan Justen, Ard Biesheuvel, Michael Roth,
	Gerd Hoffmann

On Mon, Sep 13, 2021 at 9:20 PM Brijesh Singh <brijesh.singh@amd.com> wrote:
> +*/
> +STATIC
> +VOID
> +SevSnpGhcbRegister (
> +  UINTN   Address
> +  )
> +{
> +  MSR_SEV_ES_GHCB_REGISTER  Msr;
> +  MSR_SEV_ES_GHCB_REGISTER  CurrentMsr;
> +  EFI_PHYSICAL_ADDRESS      GuestFrameNumber;
> +
> +  GuestFrameNumber = Address >> EFI_PAGE_SHIFT;
> +
> +  //
> +  // Save the current MSR Value
> +  //
> +  CurrentMsr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);

We are backing the current MSR value but when was it initialized
before ? Also is not this function supposed to set the Address as the
GHCB address? If it is, do we care about the old value?


> +  // Restore the MSR
> +  //
> +  AsmWriteMsr64 (MSR_SEV_ES_GHCB, CurrentMsr.GhcbPhysicalAddress);

Why are we restoring the old value? I may have misunderstood but I
thought this function will set Address as the new GHCB address?

Thanks
-Erdem

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 09/31] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest
  2021-09-15 17:08   ` Erdem Aktas
@ 2021-09-15 18:50     ` Brijesh Singh
  2021-09-16  8:30       ` Gerd Hoffmann
  0 siblings, 1 reply; 49+ messages in thread
From: Brijesh Singh @ 2021-09-15 18:50 UTC (permalink / raw)
  To: Erdem Aktas
  Cc: brijesh.singh, edk2-devel-groups-io, James Bottomley, Min Xu,
	Jiewen Yao, Tom Lendacky, Jordan Justen, Ard Biesheuvel,
	Michael Roth, Gerd Hoffmann



On 9/15/21 12:08 PM, Erdem Aktas wrote:
> On Mon, Sep 13, 2021 at 9:20 PM Brijesh Singh <brijesh.singh@amd.com> wrote:
>> +*/
>> +STATIC
>> +VOID
>> +SevSnpGhcbRegister (
>> +  UINTN   Address
>> +  )
>> +{
>> +  MSR_SEV_ES_GHCB_REGISTER  Msr;
>> +  MSR_SEV_ES_GHCB_REGISTER  CurrentMsr;
>> +  EFI_PHYSICAL_ADDRESS      GuestFrameNumber;
>> +
>> +  GuestFrameNumber = Address >> EFI_PAGE_SHIFT;
>> +
>> +  //
>> +  // Save the current MSR Value
>> +  //
>> +  CurrentMsr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
> 
> We are backing the current MSR value but when was it initialized
> before ? Also is not this function supposed to set the Address as the
> GHCB address? If it is, do we care about the old value?
> 

Good point, there is no reason to read and restore the old GHCB, I will 
remove it in next version. The function does not set this as a GHCB 
address, it send request to hypervisor saying that it would like to use 
this address. If hypervisor is not okay with the address then it may 
recommend something else. We don't support working with the hypervisor 
preferred address. Setting the GHCB address code is common between Snp 
and Es but checking with hypervisor whether its okay to use is new in 
the GHCBv2 and is SNP specific.


> 
>> +  // Restore the MSR
>> +  //
>> +  AsmWriteMsr64 (MSR_SEV_ES_GHCB, CurrentMsr.GhcbPhysicalAddress);
> 
> Why are we restoring the old value? I may have misunderstood but I
> thought this function will set Address as the new GHCB address?
> 
> Thanks
> -Erdem
> 

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 05/31] OvmfPkg: reserve CPUID page
  2021-09-13 18:19 ` [PATCH v7 05/31] OvmfPkg: reserve CPUID page Brijesh Singh
@ 2021-09-16  8:07   ` Gerd Hoffmann
  2021-09-16 10:46     ` Brijesh Singh
  0 siblings, 1 reply; 49+ messages in thread
From: Gerd Hoffmann @ 2021-09-16  8:07 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: devel, James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky,
	Jordan Justen, Ard Biesheuvel, Erdem Aktas, Michael Roth

  Hi,

> +; The section contains the hypervisor pre-populated CPUID values. In the
> +; case of SEV-SNP, the CPUID values are filtered and measured by the SEV-SNP
> +; firmware.

Pointer to the struct spec would be nice here,

take care,
  Gerd


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 06/31] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase
  2021-09-13 18:19 ` [PATCH v7 06/31] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase Brijesh Singh
@ 2021-09-16  8:26   ` Gerd Hoffmann
  2021-09-16 10:49     ` [edk2-devel] " Brijesh Singh
  0 siblings, 1 reply; 49+ messages in thread
From: Gerd Hoffmann @ 2021-09-16  8:26 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: devel, James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky,
	Jordan Justen, Ard Biesheuvel, Erdem Aktas, Michael Roth

  Hi,

> +; GHCB page table
> +GhcbPageTable:
> +  DD  GHCB_PT_ADDR
> +  DD  GHCB_PT_SIZE
> +  DD  OVMF_SECTION_TYPE_SEC_MEM

Hmm, TDX will re-use those pages for something else.  So as long as TDX
is happy with OVMF_SECTION_TYPE_SEC_MEM everything should work fine and
just mentioning that in the comments will be ok.

If not we might need a SEV_SECTION_TYPE_SEC_MEM to indicate the entry is
valid for SEV only and Intel can add a separate
TDX_SECTION_TYPE_SOMETHING_ELSE entry for the same address range.

take care,
  Gerd


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 09/31] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest
  2021-09-15 18:50     ` Brijesh Singh
@ 2021-09-16  8:30       ` Gerd Hoffmann
  2021-09-16 10:49         ` Brijesh Singh
  0 siblings, 1 reply; 49+ messages in thread
From: Gerd Hoffmann @ 2021-09-16  8:30 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: Erdem Aktas, edk2-devel-groups-io, James Bottomley, Min Xu,
	Jiewen Yao, Tom Lendacky, Jordan Justen, Ard Biesheuvel,
	Michael Roth

  Hi,

> Good point, there is no reason to read and restore the old GHCB, I will
> remove it in next version. The function does not set this as a GHCB address,
> it send request to hypervisor saying that it would like to use this address.
> If hypervisor is not okay with the address then it may recommend something
> else. We don't support working with the hypervisor preferred address.
> Setting the GHCB address code is common between Snp and Es but checking with
> hypervisor whether its okay to use is new in the GHCBv2 and is SNP specific.

A comment explaining those GHCBv1 vs. GHCBv2 differences would be great.

thanks,
  Gerd


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 11/31] OvmfPkg/PlatformPei: register GHCB gpa for the SEV-SNP guest
  2021-09-13 18:19 ` [PATCH v7 11/31] OvmfPkg/PlatformPei: register GHCB gpa for the SEV-SNP guest Brijesh Singh
@ 2021-09-16  8:33   ` Gerd Hoffmann
  2021-09-16 10:59     ` Brijesh Singh
  0 siblings, 1 reply; 49+ messages in thread
From: Gerd Hoffmann @ 2021-09-16  8:33 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: devel, James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky,
	Jordan Justen, Ard Biesheuvel, Erdem Aktas, Michael Roth

On Mon, Sep 13, 2021 at 01:19:21PM -0500, Brijesh Singh wrote:
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275
> 
> The SEV-SNP guest requires that GHCB GPA must be registered before using.
> See the GHCB specification section 2.3.2 for more details.

Already done in SEC phase (patch #9), why again in PEI?

thanks,
  Gerd


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 17/31] OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv
  2021-09-13 18:19 ` [PATCH v7 17/31] OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv Brijesh Singh
@ 2021-09-16  8:58   ` Gerd Hoffmann
  2021-09-16 11:11     ` Brijesh Singh
  0 siblings, 1 reply; 49+ messages in thread
From: Gerd Hoffmann @ 2021-09-16  8:58 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: devel, James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky,
	Jordan Justen, Ard Biesheuvel, Erdem Aktas, Michael Roth

  Hi,

> +  ## The range of memory that need to be pre-validated in the SEC phase
> +  #  when SEV-SNP is active in the guest VM.
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedStart|0|UINT32|0x56
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd|0|UINT32|0x57

I guess TDX needs to do that too?
Should we pick more generic names for the PCDs then?

take care,
  Gerd


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [edk2-devel] [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled
  2021-09-14 14:21       ` [edk2-devel] " Brijesh Singh
@ 2021-09-16  9:15         ` Gerd Hoffmann
  2021-09-16  9:18           ` Ni, Ray
  0 siblings, 1 reply; 49+ messages in thread
From: Gerd Hoffmann @ 2021-09-16  9:15 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: devel, ray.ni, James Bottomley, Xu, Min M, Yao, Jiewen,
	Tom Lendacky, Justen, Jordan L, Ard Biesheuvel, Erdem Aktas,
	Michael Roth, Dong, Eric, Kumar, Rahul1

On Tue, Sep 14, 2021 at 09:21:50AM -0500, Brijesh Singh wrote:
> Hi Ray,
> 
> I was hoping that refactor can be done later but sounds like we want to
> do it before the SNP. Let me look into it.

Well, the problem with the "do it later" approach is that these tasks
then tend to fall down to the bottom of the TODO list ...

take care,
  Gerd


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [edk2-devel] [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled
  2021-09-16  9:15         ` Gerd Hoffmann
@ 2021-09-16  9:18           ` Ni, Ray
  0 siblings, 0 replies; 49+ messages in thread
From: Ni, Ray @ 2021-09-16  9:18 UTC (permalink / raw)
  To: Gerd Hoffmann, Brijesh Singh
  Cc: devel@edk2.groups.io, James Bottomley, Xu, Min M, Yao, Jiewen,
	Tom Lendacky, Justen, Jordan L, Ard Biesheuvel, Erdem Aktas,
	Michael Roth, Dong, Eric, Kumar, Rahul1

Brijesh, thank you for looking into this now!

-----Original Message-----
From: Gerd Hoffmann <kraxel@redhat.com> 
Sent: Thursday, September 16, 2021 5:16 PM
To: Brijesh Singh <brijesh.singh@amd.com>
Cc: devel@edk2.groups.io; Ni, Ray <ray.ni@intel.com>; James Bottomley <jejb@linux.ibm.com>; Xu, Min M <min.m.xu@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky <thomas.lendacky@amd.com>; Justen, Jordan L <jordan.l.justen@intel.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Erdem Aktas <erdemaktas@google.com>; Michael Roth <Michael.Roth@amd.com>; Dong, Eric <eric.dong@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
Subject: Re: [edk2-devel] [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled

On Tue, Sep 14, 2021 at 09:21:50AM -0500, Brijesh Singh wrote:
> Hi Ray,
> 
> I was hoping that refactor can be done later but sounds like we want 
> to do it before the SNP. Let me look into it.

Well, the problem with the "do it later" approach is that these tasks then tend to fall down to the bottom of the TODO list ...

take care,
  Gerd


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 05/31] OvmfPkg: reserve CPUID page
  2021-09-16  8:07   ` Gerd Hoffmann
@ 2021-09-16 10:46     ` Brijesh Singh
  0 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-16 10:46 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: devel, James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky,
	Jordan Justen, Ard Biesheuvel, Erdem Aktas, Michael Roth


On 9/16/21 3:07 AM, Gerd Hoffmann wrote:
>   Hi,
>
>> +; The section contains the hypervisor pre-populated CPUID values. In the
>> +; case of SEV-SNP, the CPUID values are filtered and measured by the SEV-SNP
>> +; firmware.
> Pointer to the struct spec would be nice here,

Noted.

thanks


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [edk2-devel] [PATCH v7 06/31] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase
  2021-09-16  8:26   ` Gerd Hoffmann
@ 2021-09-16 10:49     ` Brijesh Singh
  0 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-16 10:49 UTC (permalink / raw)
  To: devel, kraxel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Michael Roth


On 9/16/21 3:26 AM, Gerd Hoffmann via groups.io wrote:
>   Hi,
>
>> +; GHCB page table
>> +GhcbPageTable:
>> +  DD  GHCB_PT_ADDR
>> +  DD  GHCB_PT_SIZE
>> +  DD  OVMF_SECTION_TYPE_SEC_MEM
> Hmm, TDX will re-use those pages for something else.  So as long as TDX
> is happy with OVMF_SECTION_TYPE_SEC_MEM everything should work fine and
> just mentioning that in the comments will be ok.
>
> If not we might need a SEV_SECTION_TYPE_SEC_MEM to indicate the entry is
> valid for SEV only and Intel can add a separate
> TDX_SECTION_TYPE_SOMETHING_ELSE entry for the same address range.

Yep, looking at the current TDX patches we see that GHCB is used for the
mailbox,  to make integration easy its good idea that we define
SEV_SECTION_TYPE_SEC_MEM and use it for those GHCB memory pages. I will
add in next version.

thanks


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 09/31] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest
  2021-09-16  8:30       ` Gerd Hoffmann
@ 2021-09-16 10:49         ` Brijesh Singh
  0 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-16 10:49 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Erdem Aktas, edk2-devel-groups-io, James Bottomley, Min Xu,
	Jiewen Yao, Tom Lendacky, Jordan Justen, Ard Biesheuvel,
	Michael Roth


On 9/16/21 3:30 AM, Gerd Hoffmann wrote:
>   Hi,
>
>> Good point, there is no reason to read and restore the old GHCB, I will
>> remove it in next version. The function does not set this as a GHCB address,
>> it send request to hypervisor saying that it would like to use this address.
>> If hypervisor is not okay with the address then it may recommend something
>> else. We don't support working with the hypervisor preferred address.
>> Setting the GHCB address code is common between Snp and Es but checking with
>> hypervisor whether its okay to use is new in the GHCBv2 and is SNP specific.
> A comment explaining those GHCBv1 vs. GHCBv2 differences would be great.

Sure, I will add comment.

thanks

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 11/31] OvmfPkg/PlatformPei: register GHCB gpa for the SEV-SNP guest
  2021-09-16  8:33   ` Gerd Hoffmann
@ 2021-09-16 10:59     ` Brijesh Singh
  0 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-16 10:59 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: devel, James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky,
	Jordan Justen, Ard Biesheuvel, Erdem Aktas, Michael Roth


On 9/16/21 3:33 AM, Gerd Hoffmann wrote:
> On Mon, Sep 13, 2021 at 01:19:21PM -0500, Brijesh Singh wrote:
>> BZ: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D3275&amp;data=04%7C01%7Cbrijesh.singh%40amd.com%7C6495c28531da4bc30ce508d978ecab93%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637673780170202032%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=6AyBzL6AReYjbKGIrU%2FnaoPp6UGS09wQu%2FwONhcu9iA%3D&amp;reserved=0
>>
>> The SEV-SNP guest requires that GHCB GPA must be registered before using.
>> See the GHCB specification section 2.3.2 for more details.
> Already done in SEC phase (patch #9), why again in PEI?

The SEC begins with a fixed GHCB page; During the PEI phase, we allocate
and switch to new per-CPU GHCB page and thus need to registration for
the new GHCB. Please see the commit
449a6e493418c337752b68e4f199bd2d7d39af9f.

thanks


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 17/31] OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv
  2021-09-16  8:58   ` Gerd Hoffmann
@ 2021-09-16 11:11     ` Brijesh Singh
  0 siblings, 0 replies; 49+ messages in thread
From: Brijesh Singh @ 2021-09-16 11:11 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: devel, James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky,
	Jordan Justen, Ard Biesheuvel, Erdem Aktas, Michael Roth


On 9/16/21 3:58 AM, Gerd Hoffmann wrote:
>   Hi,
>
>> +  ## The range of memory that need to be pre-validated in the SEC phase
>> +  #  when SEV-SNP is active in the guest VM.
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedStart|0|UINT32|0x56
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd|0|UINT32|0x57
> I guess TDX needs to do that too?
> Should we pick more generic names for the PCDs then?

I was not sure how TDX is approaching the validation in the SEC phase;
i.e, will it go with validating the entire guest RAM at once or validate
the selective portion then push everything to PEI or DXE phase. Min or
Jiewen, can you comment on it ?

But I agree with you that picking generic name to start with is a good
idea. I will drop SNP name from it.

thanks

^ permalink raw reply	[flat|nested] 49+ messages in thread

end of thread, other threads:[~2021-09-16 11:11 UTC | newest]

Thread overview: 49+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-09-13 18:19 [PATCH v7 00/31] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 01/31] OvmfPkg/SecMain: move SEV specific routines in AmdSev.c Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 02/31] OvmfPkg/ResetVector: move clearing GHCB in SecMain Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 03/31] OvmfPkg/ResetVector: introduce metadata descriptor for VMM use Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 04/31] OvmfPkg: reserve SNP secrets page Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 05/31] OvmfPkg: reserve CPUID page Brijesh Singh
2021-09-16  8:07   ` Gerd Hoffmann
2021-09-16 10:46     ` Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 06/31] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase Brijesh Singh
2021-09-16  8:26   ` Gerd Hoffmann
2021-09-16 10:49     ` [edk2-devel] " Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 07/31] OvmfPkg/ResetVector: use SEV-SNP-validated CPUID values Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 08/31] OvmfPkg/MemEncryptSevLib: add MemEncryptSevSnpEnabled() Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 09/31] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest Brijesh Singh
2021-09-15 17:08   ` Erdem Aktas
2021-09-15 18:50     ` Brijesh Singh
2021-09-16  8:30       ` Gerd Hoffmann
2021-09-16 10:49         ` Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 10/31] OvmfPkg/VmgExitLib: use SEV-SNP-validated CPUID values Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 11/31] OvmfPkg/PlatformPei: register GHCB gpa for the SEV-SNP guest Brijesh Singh
2021-09-16  8:33   ` Gerd Hoffmann
2021-09-16 10:59     ` Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 12/31] OvmfPkg/AmdSevDxe: do not use extended PCI config space Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 13/31] OvmfPkg/MemEncryptSevLib: add support to validate system RAM Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 14/31] OvmfPkg/MemEncryptSevLib: add function to check the VMPL0 Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 15/31] OvmfPkg/BaseMemEncryptSevLib: skip the pre-validated system RAM Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 16/31] OvmfPkg/MemEncryptSevLib: add support to validate > 4GB memory in PEI phase Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 17/31] OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv Brijesh Singh
2021-09-16  8:58   ` Gerd Hoffmann
2021-09-16 11:11     ` Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 18/31] OvmfPkg/PlatformPei: validate the system RAM when SNP is active Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 19/31] UefiCpuPkg: Define ConfidentialComputingGuestAttr Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 20/31] OvmfPkg/PlatformPei: set PcdConfidentialComputingAttr when SEV is active Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 21/31] UefiCpuPkg/MpInitLib: use PcdConfidentialComputingAttr to check SEV status Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 22/31] UefiCpuPkg: add PcdGhcbHypervisorFeatures Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 23/31] OvmfPkg/PlatformPei: set the Hypervisor Features PCD Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 24/31] MdePkg/GHCB: increase the GHCB protocol max version Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 25/31] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled Brijesh Singh
2021-09-14  2:23   ` Ni, Ray
2021-09-14  2:25     ` Ni, Ray
2021-09-14 14:21       ` [edk2-devel] " Brijesh Singh
2021-09-16  9:15         ` Gerd Hoffmann
2021-09-16  9:18           ` Ni, Ray
2021-09-13 18:19 ` [PATCH v7 26/31] UefiCpuPkg/MpInitLib: use BSP to do extended topology check Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 27/31] OvmfPkg/MemEncryptSevLib: change the page state in the RMP table Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 28/31] OvmfPkg/MemEncryptSevLib: skip page state change for Mmio address Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 29/31] OvmfPkg/PlatformPei: mark cpuid and secrets memory reserved in EFI map Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 30/31] OvmfPkg/AmdSev: expose the SNP reserved pages through configuration table Brijesh Singh
2021-09-13 18:19 ` [PATCH v7 31/31] UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs Brijesh Singh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox