Date   

Re: [PATCH v2 3/5] ArmVirtPkg: enable ACPI for cloud hypervisor

Jianyong Wu
 

Hi Sami,

 

Thanks for lots of great comments here, I will fix it one by one.

 

Thanks

Jianyong

 

From: Sami Mujawar <Sami.Mujawar@...>
Sent: Wednesday, May 19, 2021 4:26 AM
To: Jianyong Wu <Jianyong.Wu@...>; devel@edk2.groups.io; lersek@...; ardb+tianocore@...
Cc: hao.a.wu@...; Justin He <Justin.He@...>; nd <nd@...>
Subject: Re: [PATCH v2 3/5] ArmVirtPkg: enable ACPI for cloud hypervisor

 

Hi Jianyon,

Thank you for this patch.

Please find my response inline marked [SAMI].

Regards,

Sami Mujawar

 

On 17/05/2021 07:50 AM, Jianyong Wu wrote:

The current implementation of PlatformHasAcpiDt is not a common
library and is on behalf of qemu. So give a specific version for
Cloud Hypervisor here.
 
There is no device like Fw-cfg in qemu in Cloud Hypervisor, so a specific
Acpi handler is introduced here.
 
The handler implemented here is in a very simple way:
firstly, aquire the Rsdp address from the PCD varaible in the top
".dsc";
secondly, get the Xsdp address from Rsdp structure;
thirdly, get the Acpi tables following the Xsdp structrue and install it
one by one.
 
Signed-off-by: Jianyong Wu <jianyong.wu@...>
---
 .../CloudHvAcpiPlatformDxe.inf                | 51 +++++++++++++
 .../CloudHvHasAcpiDtDxe.inf                   | 43 +++++++++++
 .../CloudHvAcpiPlatformDxe/CloudHvAcpi.c      | 73 +++++++++++++++++++
 .../CloudHvHasAcpiDtDxe.c                     | 69 ++++++++++++++++++
 4 files changed, 236 insertions(+)
 create mode 100644 ArmVirtPkg/CloudHvAcpiPlatformDxe/CloudHvAcpiPlatformDxe.inf
 create mode 100644 ArmVirtPkg/CloudHvPlatformHasAcpiDtDxe/CloudHvHasAcpiDtDxe.inf
 create mode 100644 ArmVirtPkg/CloudHvAcpiPlatformDxe/CloudHvAcpi.c
 create mode 100644 ArmVirtPkg/CloudHvPlatformHasAcpiDtDxe/CloudHvHasAcpiDtDxe.c

[SAMI] I think these should be split as 2 patches covering CloudHvAcpiPlatformDx/* and CloudHvPlatformHasAcpiDtDx/*

 
 
diff --git a/ArmVirtPkg/CloudHvAcpiPlatformDxe/CloudHvAcpiPlatformDxe.inf b/ArmVirtPkg/CloudHvAcpiPlatformDxe/CloudHvAcpiPlatformDxe.inf
new file mode 100644
index 000000000000..63c74e84eb27
--- /dev/null
+++ b/ArmVirtPkg/CloudHvAcpiPlatformDxe/CloudHvAcpiPlatformDxe.inf
@@ -0,0 +1,51 @@
+## @file
+#  OVMF ACPI Platform Driver for Cloud Hypervisor

[SAMI] I think the reference to OVMF can be removed, right?

 
+#
+#  Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = ClhFwCfgAcpiPlatform

[SAMI] Can ClhFwCfgAcpiPlatform  be changed to CloudHvAcpiPlatform?

 
+  FILE_GUID                      = 6c76e407-73f2-dc1c-938f-5d6c4691ea93
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = CloudHvAcpiPlatformEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64

[SAMI] Minor. The above line is just a comment, but can you revisit this, please?

 
+#
+
+[Sources]
+  CloudHvAcpi.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  MemoryAllocationLib
+  OrderedCollectionLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+
+[Protocols]
+  gEfiAcpiTableProtocolGuid                     # PROTOCOL ALWAYS_CONSUMED
+  gEfiPciIoProtocolGuid                         # PROTOCOL SOMETIMES_CONSUMED

[SAMI] gEfiPciIoProtocolGuidis not used in this module.

 
+
+[Guids]
+  gRootBridgesConnectedEventGroupGuid

[SAMI] gRootBridgesConnectedEventGroupGuid not used in this module.

 
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration

[SAMI] PcdPciDisableBusEnumerationis not used in this module.

 
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiRsdpBaseAddress
+
+[Depex]
+  gEfiAcpiTableProtocolGuid
diff --git a/ArmVirtPkg/CloudHvPlatformHasAcpiDtDxe/CloudHvHasAcpiDtDxe.inf b/ArmVirtPkg/CloudHvPlatformHasAcpiDtDxe/CloudHvHasAcpiDtDxe.inf
new file mode 100644
index 000000000000..f511a4f5064c
--- /dev/null
+++ b/ArmVirtPkg/CloudHvPlatformHasAcpiDtDxe/CloudHvHasAcpiDtDxe.inf
@@ -0,0 +1,43 @@
+## @file
+# Decide whether the firmware should expose an ACPI- and/or a Device Tree-based
+# hardware description to the operating system.
+#
+# Copyright (c) 2017, Red Hat, Inc.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION                    = 1.25
+  BASE_NAME                      = ClhPlatformHasAcpiDtDxe

[SAMI] Is it possible to change the Clh prefix to CloudHv. Same comment for other places in this patch series.

 
+  FILE_GUID                      = 71fe72f9-6dc1-199d-5054-13b4200ee88d
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = PlatformHasAcpiDt
+
+[Sources]
+  CloudHvHasAcpiDtDxe.c
+
+[Packages]
+  ArmVirtPkg/ArmVirtPkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  PcdLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+
+[Guids]
+  gEdkiiPlatformHasAcpiGuid       ## SOMETIMES_PRODUCES ## PROTOCOL
+  gEdkiiPlatformHasDeviceTreeGuid ## SOMETIMES_PRODUCES ## PROTOCOL
+
+[Pcd]
+  gArmVirtTokenSpaceGuid.PcdForceNoAcpi
+
+[Depex]
+  gEfiVariableArchProtocolGuid
diff --git a/ArmVirtPkg/CloudHvAcpiPlatformDxe/CloudHvAcpi.c b/ArmVirtPkg/CloudHvAcpiPlatformDxe/CloudHvAcpi.c
new file mode 100644
index 000000000000..c2344e7b29fa
--- /dev/null
+++ b/ArmVirtPkg/CloudHvAcpiPlatformDxe/CloudHvAcpi.c
@@ -0,0 +1,73 @@

[SAMI] File license header is missing.

 
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <IndustryStandard/Acpi63.h>
+#include <Protocol/AcpiTable.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+
+#define ACPI_ENTRY_SIZE 8
+#define XSDT_LEN 36
+
+STATIC
+EFI_ACPI_TABLE_PROTOCOL *
+FindAcpiTableProtocol (
+  VOID
+  )

[SAMI] Please add doxygen header for function. Same comment for other functions introduced in this series.

 
+{
+  EFI_STATUS              Status;
+  EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+
+  Status = gBS->LocateProtocol (
+                  &gEfiAcpiTableProtocolGuid,
+                  NULL,
+                  (VOID**)&AcpiTable
+                  );
+  ASSERT_EFI_ERROR (Status);
+  return AcpiTable;
+}
+
+EFI_STATUS
+EFIAPI
+InstallCloudHvAcpiTables (
+ IN     EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol
+ )
+{
+  UINTN InstalledKey, TableSize;
+  UINT64 Rsdp, Xsdt, table_offset, PointerValue;

[SAMI] Please have a look at variable naming conventions in EDKII coding standard at https://edk2-docs.gitbook.io/edk-ii-c-coding-standards-specification/4_naming_conventions

 
+  EFI_STATUS Status = 0;

[SAMI] Status = EFI_SUCCESS.

 
+  int size;

[SAMI] UINTN should be used instead of 'int'. Also variable name does not confirm to coding standard.

 
+
+  Rsdp = PcdGet64 (PcdAcpiRsdpBaseAddress);
+  Xsdt = ((EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER *)Rsdp)->XsdtAddress;
+  PointerValue = Xsdt;
+  table_offset = Xsdt;
+  size = ((EFI_ACPI_COMMON_HEADER *)PointerValue)->Length - XSDT_LEN;
+  table_offset += XSDT_LEN;

[SAMI] I think the macro name XSDT_LEN is a bit misleading. 'sizeof (EFI_ACPI_DESCRIPTION_HEADER)' should be used instead of XSDT_LEN.

 
+
+  while(!Status && size > 0) {

[SAMI] Status is not boolean, use 'EFI_ERROR (Status)' instead. Also use paranthesis to add clarity.

 
+    PointerValue = *(UINT64 *)table_offset;
+    TableSize = ((EFI_ACPI_COMMON_HEADER *)PointerValue)->Length;
+    Status = AcpiProtocol->InstallAcpiTable (AcpiProtocol,
+             (VOID *)(UINT64)PointerValue, TableSize,
+             &InstalledKey);

[SAMI] See coding convention for spacing rules at https://edk2-docs.gitbook.io/edk-ii-c-coding-standards-specification/5_source_files/52_spacing

 
+    table_offset += ACPI_ENTRY_SIZE;
+    size -= ACPI_ENTRY_SIZE;
+  }

[SAMI] Can you look at simplifying the code in this function, please? You could refer to https://github.com/tianocore/edk2/blob/master/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Xsdt/XsdtParser.c#L131..L139


 
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+CloudHvAcpiPlatformEntryPoint (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_STATUS                         Status;
+
+  Status = InstallCloudHvAcpiTables (FindAcpiTableProtocol ());
+  return Status;
+}
+
diff --git a/ArmVirtPkg/CloudHvPlatformHasAcpiDtDxe/CloudHvHasAcpiDtDxe.c b/ArmVirtPkg/CloudHvPlatformHasAcpiDtDxe/CloudHvHasAcpiDtDxe.c
new file mode 100644
index 000000000000..ae07c91f5705
--- /dev/null
+++ b/ArmVirtPkg/CloudHvPlatformHasAcpiDtDxe/CloudHvHasAcpiDtDxe.c
@@ -0,0 +1,69 @@
+/** @file
+  Decide whether the firmware should expose an ACPI- and/or a Device Tree-based
+  hardware description to the operating system.
+
+  Copyright (c) 2017, Red Hat, Inc.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Guid/PlatformHasAcpi.h>
+#include <Guid/PlatformHasDeviceTree.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+EFI_STATUS
+EFIAPI
+PlatformHasAcpiDt (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  EFI_STATUS           Status;
+
+  //
+  // If we fail to install any of the necessary protocols below, the OS will be
+  // unbootable anyway (due to lacking hardware description), so tolerate no
+  // errors here.
+  //
+  if (MAX_UINTN == MAX_UINT64 &&
+      !PcdGetBool (PcdForceNoAcpi))
+  {
+    Status = gBS->InstallProtocolInterface (
+                    &ImageHandle,
+                    &gEdkiiPlatformHasAcpiGuid,
+                    EFI_NATIVE_INTERFACE,
+                    NULL
+                    );
+    if (EFI_ERROR (Status)) {
+      goto Failed;
+    }
+
+    return Status;
+  }
+
+  //
+  // Expose the Device Tree otherwise.
+  //
+  Status = gBS->InstallProtocolInterface (
+                  &ImageHandle,
+                  &gEdkiiPlatformHasDeviceTreeGuid,
+                  EFI_NATIVE_INTERFACE,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Failed;
+  }
+
+  return Status;
+
+Failed:
+  ASSERT_EFI_ERROR (Status);
+  CpuDeadLoop ();
+  //
+  // Keep compilers happy.
+  //
+  return Status;
+}

 


[PATCH] IntelSiliconPkg/VTd: Support Queued Invalidation Interface

Sheng Wei
 

Add queued invalidation interface support for VTd core driver.
For software to invalidate the various caching structures, the architecture
supports the following two types of invalidation interfaces.
1. Register-based invalidation interface
2. Queued invalidation interface.
BIOS shall check VER_REG to determine if register based invalidation can
be used. Only for Major Version 6 or lower can support register based
invalidation. For any version newer than that should use queue
invalidation interface instead.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3366

Signed-off-by: Sheng Wei <w.sheng@intel.com>
Cc: Jenny Huang <jenny.huang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@intel.com>
Reviewed-by: Jenny Huang <jenny.huang@intel.com>
---
.../Feature/VTd/IntelVTdDmarPei/DmarTable.c | 2 +
.../Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c | 560 +++++++++++++++++----
.../Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.c | 15 +
.../Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h | 19 +
.../Feature/VTd/IntelVTdDmarPei/TranslationTable.c | 2 -
.../Feature/VTd/IntelVTdDxe/DmaProtection.h | 29 ++
.../Feature/VTd/IntelVTdDxe/VtdReg.c | 315 +++++++++++-
.../IntelSiliconPkg/Include/IndustryStandard/Vtd.h | 57 +++
8 files changed, 876 insertions(+), 123 deletions(-)

diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c
index d188f917..2154690d 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c
@@ -561,6 +561,8 @@ ProcessDhrd (
DEBUG ((DEBUG_INFO," VTD BaseAddress - 0x%016lx\n", DmarDrhd->RegisterBaseAddress));
VTdUnitInfo->VtdUnitBaseAddress = (UINT32) DmarDrhd->RegisterBaseAddress;

+ VTdUnitInfo->EnableQueuedInvalidation = 0;
+
DEBUG ((DEBUG_INFO," VTD Segment - %d\n", DmarDrhd->SegmentNumber));
VTdUnitInfo->Segment = DmarDrhd->SegmentNumber;

diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c
index 9ad2a494..c3a939c9 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c
@@ -66,30 +66,269 @@ FlushWriteBuffer (
}

/**
- Invalidate VTd context cache.
+ Perpare cache invalidation interface.

- @param[in] VtdUnitBaseAddress The base address of the VTd engine.
+ @param[in] VTdUnitInfo The VTd engine unit information.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_UNSUPPORTED Invalidation method is not supported.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
**/
EFI_STATUS
-InvalidateContextCache (
- IN UINTN VtdUnitBaseAddress
+PerpareCacheInvalidationInterface (
+ IN VTD_UNIT_INFO *VTdUnitInfo
)
{
- UINT64 Reg64;
+ UINT16 QueueSize;
+ UINT64 Reg64;
+ UINT32 Reg32;
+ VTD_ECAP_REG ECapReg;
+
+
+ if (VTdUnitInfo->VerReg.Bits.Major <= 6) {
+ VTdUnitInfo->EnableQueuedInvalidation = 0;
+ DEBUG ((DEBUG_INFO, "Use Register-based Invalidation Interface for engine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress));
+ return EFI_SUCCESS;
+ }
+
+ ECapReg.Uint64 = MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_ECAP_REG);
+ if (ECapReg.Bits.QI == 0) {
+ DEBUG ((DEBUG_ERROR, "Hardware does not support queued invalidations interface for engine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress));
+ return EFI_UNSUPPORTED;
+ }
+
+ VTdUnitInfo->EnableQueuedInvalidation = 1;
+ DEBUG ((DEBUG_INFO, "Use Queued Invalidation Interface for engine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress));
+
+ Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
+ if ((Reg32 & B_GSTS_REG_QIES) != 0) {
+ DEBUG ((DEBUG_INFO,"Queued Invalidation Interface was enabled.\n"));
+ Reg32 &= (~B_GSTS_REG_QIES);
+ MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32);
+ do {
+ Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
+ } while ((Reg32 & B_GSTS_REG_QIES) != 0);
+ MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQA_REG, 0);
+
+ if (VTdUnitInfo->QiDesc != NULL) {
+ FreePages(VTdUnitInfo->QiDesc, EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * VTdUnitInfo->QiDescLength));
+ VTdUnitInfo->QiDesc = NULL;
+ VTdUnitInfo->QiDescLength = 0;
+ }
+ }
+
+ //
+ // Initialize the Invalidation Queue Tail Register to zero.
+ //
+ MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQT_REG, 0);
+
+ //
+ // Setup the IQ address, size and descriptor width through the Invalidation Queue Address Register
+ //
+ QueueSize = 0;
+ VTdUnitInfo->QiDescLength = 1 << (QueueSize + 8);
+ VTdUnitInfo->QiDesc = (QI_DESC *) AllocatePages (EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * VTdUnitInfo->QiDescLength));
+
+ if (VTdUnitInfo->QiDesc == NULL) {
+ VTdUnitInfo->QiDescLength = 0;
+ DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG ((DEBUG_INFO, "Invalidation Queue Length : %d\n", VTdUnitInfo->QiDescLength));
+ Reg64 = (UINT64)(UINTN)VTdUnitInfo->QiDesc;
+ Reg64 |= QueueSize;
+ MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQA_REG, Reg64);
+
+ //
+ // Enable the queued invalidation interface through the Global Command Register.
+ // When enabled, hardware sets the QIES field in the Global Status Register.
+ //
+ Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
+ Reg32 |= B_GMCD_REG_QIE;
+ MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32);
+ DEBUG ((DEBUG_INFO, "Enable Queued Invalidation Interface. GCMD_REG = 0x%x\n", Reg32));
+ do {
+ Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
+ } while ((Reg32 & B_GSTS_REG_QIES) == 0);

- Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
- if ((Reg64 & B_CCMD_REG_ICC) != 0) {
- DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%x)\n",VtdUnitBaseAddress));
- return EFI_DEVICE_ERROR;
+ VTdUnitInfo->QiFreeHead = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Disable queued invalidation interface.
+
+ @param[in] VTdUnitInfo The VTd engine unit information.
+**/
+VOID
+DisableQueuedInvalidationInterface (
+ IN VTD_UNIT_INFO *VTdUnitInfo
+ )
+{
+ UINT32 Reg32;
+
+ if (VTdUnitInfo->EnableQueuedInvalidation != 0) {
+ Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
+ Reg32 &= (~B_GMCD_REG_QIE);
+ MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32);
+ DEBUG ((DEBUG_INFO, "Disable Queued Invalidation Interface. GCMD_REG = 0x%x\n", Reg32));
+ do {
+ Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
+ } while ((Reg32 & B_GSTS_REG_QIES) != 0);
+
+ if (VTdUnitInfo->QiDesc != NULL) {
+ FreePages(VTdUnitInfo->QiDesc, EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * VTdUnitInfo->QiDescLength));
+ VTdUnitInfo->QiDesc = NULL;
+ VTdUnitInfo->QiDescLength = 0;
+ }
+
+ VTdUnitInfo->EnableQueuedInvalidation = 0;
+ }
+}
+
+/**
+ Check Queued Invalidation Fault.
+
+ @param[in] VTdUnitInfo The VTd engine unit information.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval RETURN_DEVICE_ERROR A fault is detected.
+**/
+EFI_STATUS
+QueuedInvalidationCheckFault (
+ IN VTD_UNIT_INFO *VTdUnitInfo
+ )
+{
+ UINT32 FaultReg;
+
+ FaultReg = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG);
+
+ if (FaultReg & B_FSTS_REG_IQE) {
+ DEBUG((DEBUG_ERROR, "Detect Invalidation Queue Error [0x%08x]\n", FaultReg));
+ FaultReg |= B_FSTS_REG_IQE;
+ MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
+ return RETURN_DEVICE_ERROR;
+ }
+
+ if (FaultReg & B_FSTS_REG_ITE) {
+ DEBUG((DEBUG_ERROR, "Detect Invalidation Time-out Error [0x%08x]\n", FaultReg));
+ FaultReg |= B_FSTS_REG_ITE;
+ MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
+ return RETURN_DEVICE_ERROR;
+ }
+
+ if (FaultReg & B_FSTS_REG_ICE) {
+ DEBUG((DEBUG_ERROR, "Detect Invalidation Completion Error [0x%08x]\n", FaultReg));
+ FaultReg |= B_FSTS_REG_ICE;
+ MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
+ return RETURN_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Submit the queued invalidation descriptor to the remapping
+ hardware unit and wait for its completion.
+
+ @param[in] VTdUnitInfo The VTd engine unit information.
+ @param[in] Desc The invalidate descriptor
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval RETURN_DEVICE_ERROR A fault is detected.
+ @retval EFI_INVALID_PARAMETER Parameter is invalid.
+**/
+EFI_STATUS
+SubmitQueuedInvalidationDescriptor (
+ IN VTD_UNIT_INFO *VTdUnitInfo,
+ IN QI_DESC *Desc
+ )
+{
+ EFI_STATUS Status;
+ UINT16 QiDescLength;
+ QI_DESC *BaseDesc;
+ UINT64 Reg64Iqt;
+ UINT64 Reg64Iqh;
+
+ if (Desc == NULL) {
+ return EFI_INVALID_PARAMETER;
}

- Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));
- Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);
- MmioWrite64 (VtdUnitBaseAddress + R_CCMD_REG, Reg64);
+ QiDescLength = VTdUnitInfo->QiDescLength;
+ BaseDesc = VTdUnitInfo->QiDesc;

+ DEBUG((DEBUG_INFO, "[0x%x] Submit QI Descriptor [0x%08x, 0x%08x]\n", VTdUnitInfo->VtdUnitBaseAddress, Desc->Low, Desc->High));
+
+ BaseDesc[VTdUnitInfo->QiFreeHead].Low = Desc->Low;
+ BaseDesc[VTdUnitInfo->QiFreeHead].High = Desc->High;
+ FlushPageTableMemory(VTdUnitInfo, (UINTN) &BaseDesc[VTdUnitInfo->QiFreeHead], sizeof(QI_DESC));
+
+ DEBUG((DEBUG_INFO,"QI Free Head=0x%x\n", VTdUnitInfo->QiFreeHead));
+ VTdUnitInfo->QiFreeHead = (VTdUnitInfo->QiFreeHead + 1) % QiDescLength;
+
+ Reg64Iqh = MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQH_REG);
+ //
+ // Update the HW tail register indicating the presence of new descriptors.
+ //
+ Reg64Iqt = VTdUnitInfo->QiFreeHead << DMAR_IQ_SHIFT;
+ MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQT_REG, Reg64Iqt);
+
+ Status = EFI_SUCCESS;
do {
- Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
- } while ((Reg64 & B_CCMD_REG_ICC) != 0);
+ Status = QueuedInvalidationCheckFault(VTdUnitInfo);
+ if (Status != EFI_SUCCESS) {
+ DEBUG((DEBUG_ERROR,"Detect Queued Invalidation Fault.\n"));
+ break;
+ }
+
+ Reg64Iqh = MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQH_REG);
+ } while (Reg64Iqt != Reg64Iqh);
+
+ DEBUG((DEBUG_ERROR,"SubmitQueuedInvalidationDescriptor end\n"));
+ return Status;
+}
+
+/**
+ Invalidate VTd context cache.
+
+ @param[in] VTdUnitInfo The VTd engine unit information.
+**/
+EFI_STATUS
+InvalidateContextCache (
+ IN VTD_UNIT_INFO *VTdUnitInfo
+ )
+{
+ UINT64 Reg64;
+ QI_DESC QiDesc;
+
+ if (VTdUnitInfo->EnableQueuedInvalidation == 0) {
+ //
+ // Register-based Invalidation
+ //
+ Reg64 = MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_CCMD_REG);
+ if ((Reg64 & B_CCMD_REG_ICC) != 0) {
+ DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%x)\n", (UINTN)VTdUnitInfo->VtdUnitBaseAddress));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));
+ Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);
+ MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_CCMD_REG, Reg64);
+
+ do {
+ Reg64 = MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_CCMD_REG);
+ } while ((Reg64 & B_CCMD_REG_ICC) != 0);
+ } else {
+ //
+ // Queued Invalidation
+ //
+ QiDesc.Low = QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(1) | QI_CC_TYPE;
+ QiDesc.High = 0;
+
+ return SubmitQueuedInvalidationDescriptor(VTdUnitInfo, &QiDesc);
+ }

return EFI_SUCCESS;
}
@@ -97,31 +336,102 @@ InvalidateContextCache (
/**
Invalidate VTd IOTLB.

- @param[in] VtdUnitBaseAddress The base address of the VTd engine.
+ @param[in] VTdUnitInfo The VTd engine unit information.
**/
EFI_STATUS
InvalidateIOTLB (
- IN UINTN VtdUnitBaseAddress
+ IN VTD_UNIT_INFO *VTdUnitInfo
)
{
UINT64 Reg64;
VTD_ECAP_REG ECapReg;
+ QI_DESC QiDesc;
+
+ if (VTdUnitInfo->EnableQueuedInvalidation == 0) {
+ //
+ // Register-based Invalidation
+ //
+ ECapReg.Uint64 = MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_ECAP_REG);
+
+ Reg64 = MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+ if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
+ DEBUG ((DEBUG_ERROR, "ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%x)\n", (UINTN)VTdUnitInfo->VtdUnitBaseAddress));
+ return EFI_DEVICE_ERROR;
+ }

- ECapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_ECAP_REG);
+ Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
+ Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);
+ MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);

- Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
- if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
- DEBUG ((DEBUG_ERROR, "ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%x)\n", VtdUnitBaseAddress));
- return EFI_DEVICE_ERROR;
+ do {
+ Reg64 = MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+ } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
+ } else {
+ //
+ // Queued Invalidation
+ //
+ ECapReg.Uint64 = MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_ECAP_REG);
+ QiDesc.Low = QI_IOTLB_DID(0) | QI_IOTLB_DR(CAP_READ_DRAIN(ECapReg.Uint64)) | QI_IOTLB_DW(CAP_WRITE_DRAIN(ECapReg.Uint64)) | QI_IOTLB_GRAN(1) | QI_IOTLB_TYPE;
+ QiDesc.High = QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0);
+
+ return SubmitQueuedInvalidationDescriptor(VTdUnitInfo, &QiDesc);
}

- Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
- Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);
- MmioWrite64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
+ return EFI_SUCCESS;
+}

+/**
+ Enable DMAR translation inpre-mem phase.
+
+ @param[in] VtdUnitBaseAddress The base address of the VTd engine.
+ @param[in] RootEntryTable The address of the VTd RootEntryTable.
+
+ @retval EFI_SUCCESS DMAR translation is enabled.
+ @retval EFI_DEVICE_ERROR DMAR translation is not enabled.
+**/
+EFI_STATUS
+EnableDmarPreMem (
+ IN UINTN VtdUnitBaseAddress,
+ IN UINTN RootEntryTable
+ )
+{
+ UINT32 Reg32;
+
+ DEBUG ((DEBUG_INFO, ">>>>>>EnableDmarPreMem() for engine [%x] \n", VtdUnitBaseAddress));
+
+ DEBUG ((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));
+ MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64) (UINTN) RootEntryTable);
+
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+ MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_SRTP);
+
+ DEBUG ((DEBUG_INFO, "EnableDmarPreMem: waiting for RTPS bit to be set... \n"));
do {
- Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
- } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+ } while((Reg32 & B_GSTS_REG_RTPS) == 0);
+ DEBUG ((DEBUG_INFO, "EnableDmarPreMem: R_GSTS_REG = 0x%x \n", Reg32));
+
+ //
+ // Init DMAr Fault Event and Data registers
+ //
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);
+
+ //
+ // Write Buffer Flush before invalidation
+ //
+ FlushWriteBuffer (VtdUnitBaseAddress);
+
+ //
+ // Enable VTd
+ //
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+ MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_TE);
+ DEBUG ((DEBUG_INFO, "EnableDmarPreMem: Waiting B_GSTS_REG_TE ...\n"));
+ do {
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+ } while ((Reg32 & B_GSTS_REG_TE) == 0);
+
+ DEBUG ((DEBUG_INFO, "VTD () enabled!<<<<<<\n"));

return EFI_SUCCESS;
}
@@ -129,59 +439,62 @@ InvalidateIOTLB (
/**
Enable DMAR translation.

- @param[in] VtdUnitBaseAddress The base address of the VTd engine.
- @param[in] RootEntryTable The address of the VTd RootEntryTable.
+ @param[in] VTdUnitInfo The VTd engine unit information.
+ @param[in] RootEntryTable The address of the VTd RootEntryTable.

@retval EFI_SUCCESS DMAR translation is enabled.
@retval EFI_DEVICE_ERROR DMAR translation is not enabled.
**/
EFI_STATUS
EnableDmar (
- IN UINTN VtdUnitBaseAddress,
+ IN VTD_UNIT_INFO *VTdUnitInfo,
IN UINTN RootEntryTable
)
{
UINT32 Reg32;

- DEBUG ((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%x] \n", VtdUnitBaseAddress));
+ DEBUG ((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%x] \n", VTdUnitInfo->VtdUnitBaseAddress));

DEBUG ((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));
- MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64) (UINTN) RootEntryTable);
+ MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_RTADDR_REG, (UINT64) (UINTN) RootEntryTable);

- MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+ Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
+ MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_SRTP);

DEBUG ((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
do {
- Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+ Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
} while((Reg32 & B_GSTS_REG_RTPS) == 0);
+ DEBUG ((DEBUG_INFO, "EnableDmar: R_GSTS_REG = 0x%x \n", Reg32));

//
// Init DMAr Fault Event and Data registers
//
- Reg32 = MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);
+ Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FEDATA_REG);

//
// Write Buffer Flush before invalidation
//
- FlushWriteBuffer (VtdUnitBaseAddress);
+ FlushWriteBuffer ((UINTN)VTdUnitInfo->VtdUnitBaseAddress);

//
// Invalidate the context cache
//
- InvalidateContextCache (VtdUnitBaseAddress);
+ InvalidateContextCache (VTdUnitInfo);

//
// Invalidate the IOTLB cache
//
- InvalidateIOTLB (VtdUnitBaseAddress);
+ InvalidateIOTLB (VTdUnitInfo);

//
// Enable VTd
//
- MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);
+ Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
+ MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_TE);
DEBUG ((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));
do {
- Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+ Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG);
} while ((Reg32 & B_GSTS_REG_TE) == 0);

DEBUG ((DEBUG_INFO, "VTD () enabled!<<<<<<\n"));
@@ -252,6 +565,86 @@ DisableDmar (
return EFI_SUCCESS;
}

+/**
+ Dump VTd version registers.
+
+ @param[in] VerReg The version register.
+**/
+VOID
+DumpVtdVerRegs (
+ IN VTD_VER_REG *VerReg
+ )
+{
+ DEBUG ((DEBUG_INFO, " VerReg:\n", VerReg->Uint32));
+ DEBUG ((DEBUG_INFO, " Major - 0x%x\n", VerReg->Bits.Major));
+ DEBUG ((DEBUG_INFO, " Minor - 0x%x\n", VerReg->Bits.Minor));
+}
+
+/**
+ Dump VTd capability registers.
+
+ @param[in] CapReg The capability register.
+**/
+VOID
+DumpVtdCapRegs (
+ IN VTD_CAP_REG *CapReg
+ )
+{
+ DEBUG ((DEBUG_INFO, " CapReg:\n", CapReg->Uint64));
+ DEBUG ((DEBUG_INFO, " ND - 0x%x\n", CapReg->Bits.ND));
+ DEBUG ((DEBUG_INFO, " AFL - 0x%x\n", CapReg->Bits.AFL));
+ DEBUG ((DEBUG_INFO, " RWBF - 0x%x\n", CapReg->Bits.RWBF));
+ DEBUG ((DEBUG_INFO, " PLMR - 0x%x\n", CapReg->Bits.PLMR));
+ DEBUG ((DEBUG_INFO, " PHMR - 0x%x\n", CapReg->Bits.PHMR));
+ DEBUG ((DEBUG_INFO, " CM - 0x%x\n", CapReg->Bits.CM));
+ DEBUG ((DEBUG_INFO, " SAGAW - 0x%x\n", CapReg->Bits.SAGAW));
+ DEBUG ((DEBUG_INFO, " MGAW - 0x%x\n", CapReg->Bits.MGAW));
+ DEBUG ((DEBUG_INFO, " ZLR - 0x%x\n", CapReg->Bits.ZLR));
+ DEBUG ((DEBUG_INFO, " FRO - 0x%x\n", CapReg->Bits.FRO));
+ DEBUG ((DEBUG_INFO, " SLLPS - 0x%x\n", CapReg->Bits.SLLPS));
+ DEBUG ((DEBUG_INFO, " PSI - 0x%x\n", CapReg->Bits.PSI));
+ DEBUG ((DEBUG_INFO, " NFR - 0x%x\n", CapReg->Bits.NFR));
+ DEBUG ((DEBUG_INFO, " MAMV - 0x%x\n", CapReg->Bits.MAMV));
+ DEBUG ((DEBUG_INFO, " DWD - 0x%x\n", CapReg->Bits.DWD));
+ DEBUG ((DEBUG_INFO, " DRD - 0x%x\n", CapReg->Bits.DRD));
+ DEBUG ((DEBUG_INFO, " FL1GP - 0x%x\n", CapReg->Bits.FL1GP));
+ DEBUG ((DEBUG_INFO, " PI - 0x%x\n", CapReg->Bits.PI));
+}
+
+/**
+ Dump VTd extended capability registers.
+
+ @param[in] ECapReg The extended capability register.
+**/
+VOID
+DumpVtdECapRegs (
+ IN VTD_ECAP_REG *ECapReg
+ )
+{
+ DEBUG ((DEBUG_INFO, " ECapReg:\n", ECapReg->Uint64));
+ DEBUG ((DEBUG_INFO, " C - 0x%x\n", ECapReg->Bits.C));
+ DEBUG ((DEBUG_INFO, " QI - 0x%x\n", ECapReg->Bits.QI));
+ DEBUG ((DEBUG_INFO, " DT - 0x%x\n", ECapReg->Bits.DT));
+ DEBUG ((DEBUG_INFO, " IR - 0x%x\n", ECapReg->Bits.IR));
+ DEBUG ((DEBUG_INFO, " EIM - 0x%x\n", ECapReg->Bits.EIM));
+ DEBUG ((DEBUG_INFO, " PT - 0x%x\n", ECapReg->Bits.PT));
+ DEBUG ((DEBUG_INFO, " SC - 0x%x\n", ECapReg->Bits.SC));
+ DEBUG ((DEBUG_INFO, " IRO - 0x%x\n", ECapReg->Bits.IRO));
+ DEBUG ((DEBUG_INFO, " MHMV - 0x%x\n", ECapReg->Bits.MHMV));
+ DEBUG ((DEBUG_INFO, " ECS - 0x%x\n", ECapReg->Bits.ECS));
+ DEBUG ((DEBUG_INFO, " MTS - 0x%x\n", ECapReg->Bits.MTS));
+ DEBUG ((DEBUG_INFO, " NEST - 0x%x\n", ECapReg->Bits.NEST));
+ DEBUG ((DEBUG_INFO, " DIS - 0x%x\n", ECapReg->Bits.DIS));
+ DEBUG ((DEBUG_INFO, " PASID - 0x%x\n", ECapReg->Bits.PASID));
+ DEBUG ((DEBUG_INFO, " PRS - 0x%x\n", ECapReg->Bits.PRS));
+ DEBUG ((DEBUG_INFO, " ERS - 0x%x\n", ECapReg->Bits.ERS));
+ DEBUG ((DEBUG_INFO, " SRS - 0x%x\n", ECapReg->Bits.SRS));
+ DEBUG ((DEBUG_INFO, " NWFS - 0x%x\n", ECapReg->Bits.NWFS));
+ DEBUG ((DEBUG_INFO, " EAFS - 0x%x\n", ECapReg->Bits.EAFS));
+ DEBUG ((DEBUG_INFO, " PSS - 0x%x\n", ECapReg->Bits.PSS));
+}
+
+
/**
Enable VTd translation table protection for all.

@@ -286,7 +679,15 @@ EnableVTdTranslationProtectionAll (
if ((EngineMask & LShiftU64(1, Index)) == 0) {
continue;
}
- EnableDmar ((UINTN) VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress, (UINTN) *RootEntryTable);
+
+ VTdInfo->VtdUnitInfo[Index].VerReg.Uint32 = MmioRead32 (VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress + R_VER_REG);
+ DumpVtdVerRegs (&VTdInfo->VtdUnitInfo[Index].VerReg);
+ VTdInfo->VtdUnitInfo[Index].CapReg.Uint64 = MmioRead64 (VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress + R_CAP_REG);
+ DumpVtdCapRegs (&VTdInfo->VtdUnitInfo[Index].CapReg);
+ VTdInfo->VtdUnitInfo[Index].ECapReg.Uint64 = MmioRead64 (VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress + R_ECAP_REG);
+ DumpVtdECapRegs (&VTdInfo->VtdUnitInfo[Index].ECapReg);
+
+ EnableDmarPreMem (VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress, (UINTN) *RootEntryTable);
}

return;
@@ -311,10 +712,10 @@ EnableVTdTranslationProtection (
for (VtdIndex = 0; VtdIndex < VTdInfo->VTdEngineCount; VtdIndex++) {
if (VTdInfo->VtdUnitInfo[VtdIndex].ExtRootEntryTable != 0) {
DEBUG ((DEBUG_INFO, "EnableVtdDmar (%d) ExtRootEntryTable 0x%x\n", VtdIndex, VTdInfo->VtdUnitInfo[VtdIndex].ExtRootEntryTable));
- Status = EnableDmar (VTdInfo->VtdUnitInfo[VtdIndex].VtdUnitBaseAddress, VTdInfo->VtdUnitInfo[VtdIndex].ExtRootEntryTable);
+ Status = EnableDmar (&VTdInfo->VtdUnitInfo[VtdIndex], VTdInfo->VtdUnitInfo[VtdIndex].ExtRootEntryTable);
} else {
DEBUG ((DEBUG_INFO, "EnableVtdDmar (%d) RootEntryTable 0x%x\n", VtdIndex, VTdInfo->VtdUnitInfo[VtdIndex].RootEntryTable));
- Status = EnableDmar (VTdInfo->VtdUnitInfo[VtdIndex].VtdUnitBaseAddress, VTdInfo->VtdUnitInfo[VtdIndex].RootEntryTable);
+ Status = EnableDmar (&VTdInfo->VtdUnitInfo[VtdIndex], VTdInfo->VtdUnitInfo[VtdIndex].RootEntryTable);
}
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "EnableVtdDmar (%d) Failed !\n", VtdIndex));
@@ -345,73 +746,36 @@ DisableVTdTranslationProtection (
continue;
}
DisableDmar ((UINTN) VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress);
+
+ DisableQueuedInvalidationInterface(&VTdInfo->VtdUnitInfo[Index]);
}

return;
}

/**
- Dump VTd capability registers.
+ Prepare VTD cache invalidation configuration.

- @param[in] CapReg The capability register.
+ @param[in] VTdInfo The VTd engine context information.
+
+ @retval EFI_SUCCESS Prepare Vtd config success
**/
-VOID
-DumpVtdCapRegs (
- IN VTD_CAP_REG *CapReg
+EFI_STATUS
+PrepareVtdCacheInvalidationConfig (
+ IN VTD_INFO *VTdInfo
)
{
- DEBUG ((DEBUG_INFO, " CapReg:\n", CapReg->Uint64));
- DEBUG ((DEBUG_INFO, " ND - 0x%x\n", CapReg->Bits.ND));
- DEBUG ((DEBUG_INFO, " AFL - 0x%x\n", CapReg->Bits.AFL));
- DEBUG ((DEBUG_INFO, " RWBF - 0x%x\n", CapReg->Bits.RWBF));
- DEBUG ((DEBUG_INFO, " PLMR - 0x%x\n", CapReg->Bits.PLMR));
- DEBUG ((DEBUG_INFO, " PHMR - 0x%x\n", CapReg->Bits.PHMR));
- DEBUG ((DEBUG_INFO, " CM - 0x%x\n", CapReg->Bits.CM));
- DEBUG ((DEBUG_INFO, " SAGAW - 0x%x\n", CapReg->Bits.SAGAW));
- DEBUG ((DEBUG_INFO, " MGAW - 0x%x\n", CapReg->Bits.MGAW));
- DEBUG ((DEBUG_INFO, " ZLR - 0x%x\n", CapReg->Bits.ZLR));
- DEBUG ((DEBUG_INFO, " FRO - 0x%x\n", CapReg->Bits.FRO));
- DEBUG ((DEBUG_INFO, " SLLPS - 0x%x\n", CapReg->Bits.SLLPS));
- DEBUG ((DEBUG_INFO, " PSI - 0x%x\n", CapReg->Bits.PSI));
- DEBUG ((DEBUG_INFO, " NFR - 0x%x\n", CapReg->Bits.NFR));
- DEBUG ((DEBUG_INFO, " MAMV - 0x%x\n", CapReg->Bits.MAMV));
- DEBUG ((DEBUG_INFO, " DWD - 0x%x\n", CapReg->Bits.DWD));
- DEBUG ((DEBUG_INFO, " DRD - 0x%x\n", CapReg->Bits.DRD));
- DEBUG ((DEBUG_INFO, " FL1GP - 0x%x\n", CapReg->Bits.FL1GP));
- DEBUG ((DEBUG_INFO, " PI - 0x%x\n", CapReg->Bits.PI));
-}
+ UINTN Index;
+ EFI_STATUS Status;

-/**
- Dump VTd extended capability registers.
+ for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+ Status = PerpareCacheInvalidationInterface(&VTdInfo->VtdUnitInfo[Index]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }

- @param[in] ECapReg The extended capability register.
-**/
-VOID
-DumpVtdECapRegs (
- IN VTD_ECAP_REG *ECapReg
- )
-{
- DEBUG ((DEBUG_INFO, " ECapReg:\n", ECapReg->Uint64));
- DEBUG ((DEBUG_INFO, " C - 0x%x\n", ECapReg->Bits.C));
- DEBUG ((DEBUG_INFO, " QI - 0x%x\n", ECapReg->Bits.QI));
- DEBUG ((DEBUG_INFO, " DT - 0x%x\n", ECapReg->Bits.DT));
- DEBUG ((DEBUG_INFO, " IR - 0x%x\n", ECapReg->Bits.IR));
- DEBUG ((DEBUG_INFO, " EIM - 0x%x\n", ECapReg->Bits.EIM));
- DEBUG ((DEBUG_INFO, " PT - 0x%x\n", ECapReg->Bits.PT));
- DEBUG ((DEBUG_INFO, " SC - 0x%x\n", ECapReg->Bits.SC));
- DEBUG ((DEBUG_INFO, " IRO - 0x%x\n", ECapReg->Bits.IRO));
- DEBUG ((DEBUG_INFO, " MHMV - 0x%x\n", ECapReg->Bits.MHMV));
- DEBUG ((DEBUG_INFO, " ECS - 0x%x\n", ECapReg->Bits.ECS));
- DEBUG ((DEBUG_INFO, " MTS - 0x%x\n", ECapReg->Bits.MTS));
- DEBUG ((DEBUG_INFO, " NEST - 0x%x\n", ECapReg->Bits.NEST));
- DEBUG ((DEBUG_INFO, " DIS - 0x%x\n", ECapReg->Bits.DIS));
- DEBUG ((DEBUG_INFO, " PASID - 0x%x\n", ECapReg->Bits.PASID));
- DEBUG ((DEBUG_INFO, " PRS - 0x%x\n", ECapReg->Bits.PRS));
- DEBUG ((DEBUG_INFO, " ERS - 0x%x\n", ECapReg->Bits.ERS));
- DEBUG ((DEBUG_INFO, " SRS - 0x%x\n", ECapReg->Bits.SRS));
- DEBUG ((DEBUG_INFO, " NWFS - 0x%x\n", ECapReg->Bits.NWFS));
- DEBUG ((DEBUG_INFO, " EAFS - 0x%x\n", ECapReg->Bits.EAFS));
- DEBUG ((DEBUG_INFO, " PSS - 0x%x\n", ECapReg->Bits.PSS));
+ return EFI_SUCCESS;
}

/**
@@ -431,6 +795,8 @@ PrepareVtdConfig (

for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
DEBUG ((DEBUG_ERROR, "Dump VTd Capability (%d)\n", Index));
+ VTdInfo->VtdUnitInfo[Index].VerReg.Uint32 = MmioRead32 (VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress + R_VER_REG);
+ DumpVtdVerRegs (&VTdInfo->VtdUnitInfo[Index].VerReg);
VTdInfo->VtdUnitInfo[Index].CapReg.Uint64 = MmioRead64 (VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress + R_CAP_REG);
DumpVtdCapRegs (&VTdInfo->VtdUnitInfo[Index].CapReg);
VTdInfo->VtdUnitInfo[Index].ECapReg.Uint64 = MmioRead64 (VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress + R_ECAP_REG);
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.c
index f3c4a2bc..a8f7bfee 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.c
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.c
@@ -482,6 +482,7 @@ InitVTdDmarForAll (
VOID *Hob;
VTD_INFO *VTdInfo;
UINT64 EngineMask;
+ EFI_STATUS Status;

Hob = GetFirstGuidHob (&mVTdInfoGuid);
if (Hob == NULL) {
@@ -491,6 +492,13 @@ InitVTdDmarForAll (
VTdInfo = GET_GUID_HOB_DATA (Hob);
EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;

+ DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));
+ Status = PrepareVtdConfig (VTdInfo);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
EnableVTdTranslationProtectionAll (VTdInfo, EngineMask);

return EFI_SUCCESS;
@@ -596,6 +604,13 @@ InitVTdDmarForDma (
return Status;
}

+ DEBUG ((DEBUG_INFO, "PrepareVtdCacheInvalidationConfig\n"));
+ Status = PrepareVtdCacheInvalidationConfig (VTdInfo);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
// create root entry table
DEBUG ((DEBUG_INFO, "SetupTranslationTable\n"));
Status = SetupTranslationTable (VTdInfo);
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h
index a3bb8827..e23a6c8e 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h
@@ -11,6 +11,8 @@

#define MAX_VTD_PCI_DATA_NUMBER 0x100

+#define VTD_64BITS_ADDRESS(Lo, Hi) (LShiftU64 (Lo, 12) | LShiftU64 (Hi, 32))
+
typedef struct {
UINT8 DeviceType;
VTD_SOURCE_ID PciSourceId;
@@ -27,6 +29,7 @@ typedef struct {
typedef struct {
UINT32 VtdUnitBaseAddress;
UINT16 Segment;
+ VTD_VER_REG VerReg;
VTD_CAP_REG CapReg;
VTD_ECAP_REG ECapReg;
BOOLEAN Is5LevelPaging;
@@ -37,6 +40,10 @@ typedef struct {
UINT16 RootEntryTablePageSize;
UINT16 ExtRootEntryTablePageSize;
PEI_PCI_DEVICE_INFORMATION PciDeviceInfo;
+ UINT8 EnableQueuedInvalidation;
+ UINT16 QiDescLength;
+ QI_DESC *QiDesc;
+ UINT16 QiFreeHead;
} VTD_UNIT_INFO;

typedef struct {
@@ -123,6 +130,18 @@ DumpAcpiDMAR (
IN EFI_ACPI_DMAR_HEADER *Dmar
);

+/**
+ Prepare VTD cache invalidation configuration.
+
+ @param[in] VTdInfo The VTd engine context information.
+
+ @retval EFI_SUCCESS Prepare Vtd config success
+**/
+EFI_STATUS
+PrepareVtdCacheInvalidationConfig (
+ IN VTD_INFO *VTdInfo
+ );
+
/**
Prepare VTD configuration.

diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/TranslationTable.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/TranslationTable.c
index d417f5af..341e2beb 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/TranslationTable.c
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/TranslationTable.c
@@ -26,8 +26,6 @@
#define ALIGN_VALUE_UP(Value, Alignment) (((Value) + (Alignment) - 1) & (~((Alignment) - 1)))
#define ALIGN_VALUE_LOW(Value, Alignment) ((Value) & (~((Alignment) - 1)))

-#define VTD_64BITS_ADDRESS(Lo, Hi) (LShiftU64 (Lo, 12) | LShiftU64 (Hi, 32))
-
/**
Allocate zero pages.

diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h
index f641cea0..a24fbc37 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h
@@ -69,6 +69,7 @@ typedef struct {
typedef struct {
UINTN VtdUnitBaseAddress;
UINT16 Segment;
+ VTD_VER_REG VerReg;
VTD_CAP_REG CapReg;
VTD_ECAP_REG ECapReg;
VTD_ROOT_ENTRY *RootEntryTable;
@@ -78,6 +79,10 @@ typedef struct {
BOOLEAN HasDirtyPages;
PCI_DEVICE_INFORMATION PciDeviceInfo;
BOOLEAN Is5LevelPaging;
+ UINT8 EnableQueuedInvalidation;
+ UINT16 QiDescLength;
+ QI_DESC *QiDesc;
+ UINT16 QiFreeHead;
} VTD_UNIT_INFORMATION;

//
@@ -179,6 +184,20 @@ FlushWriteBuffer (
IN UINTN VtdIndex
);

+/**
+ Perpare cache invalidation interface.
+
+ @param[in] VtdIndex The index used to identify a VTd engine.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_UNSUPPORTED Invalidation method is not supported.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+PerpareCacheInvalidationInterface (
+ IN UINTN VtdIndex
+ );
+
/**
Invalidate VTd context cache.

@@ -230,6 +249,16 @@ DumpVtdRegsAll (
VOID
);

+/**
+ Dump VTd version registers.
+
+ @param[in] VerReg The version register.
+**/
+VOID
+DumpVtdVerRegs (
+ IN VTD_VER_REG *VerReg
+ );
+
/**
Dump VTd capability registers.

diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c
index 686d235f..1ce9c1c0 100644
--- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c
@@ -55,59 +55,298 @@ FlushWriteBuffer (
}

/**
- Invalidate VTd context cache.
+ Perpare cache invalidation interface.

@param[in] VtdIndex The index used to identify a VTd engine.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_UNSUPPORTED Invalidation method is not supported.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
**/
EFI_STATUS
-InvalidateContextCache (
+PerpareCacheInvalidationInterface (
IN UINTN VtdIndex
)
{
+ UINT16 QueueSize;
UINT64 Reg64;
+ UINT32 Reg32;

- Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
- if ((Reg64 & B_CCMD_REG_ICC) != 0) {
- DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%d)\n",VtdIndex));
- return EFI_DEVICE_ERROR;
+ if (mVtdUnitInformation[VtdIndex].VerReg.Bits.Major <= 6) {
+ mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation = 0;
+ DEBUG ((DEBUG_INFO, "Use Register-based Invalidation Interface for engine [%d]\n", VtdIndex));
+ return EFI_SUCCESS;
+ }
+
+ if (mVtdUnitInformation[VtdIndex].ECapReg.Bits.QI == 0) {
+ DEBUG ((DEBUG_ERROR, "Hardware does not support queued invalidations interface for engine [%d]\n", VtdIndex));
+ return EFI_UNSUPPORTED;
+ }
+
+ mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation = 1;
+ DEBUG ((DEBUG_INFO, "Use Queued Invalidation Interface for engine [%d]\n", VtdIndex));
+
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+ if ((Reg32 & B_GSTS_REG_QIES) != 0) {
+ DEBUG ((DEBUG_ERROR,"Queued Invalidation Interface was enabled.\n"));
+ Reg32 &= (~B_GSTS_REG_QIES);
+ MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, Reg32);
+ do {
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+ } while ((Reg32 & B_GSTS_REG_QIES) != 0);
}

- Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));
- Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);
- MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG, Reg64);
+ //
+ // Initialize the Invalidation Queue Tail Register to zero.
+ //
+ MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQT_REG, 0);

+ //
+ // Setup the IQ address, size and descriptor width through the Invalidation Queue Address Register
+ //
+ QueueSize = 0;
+ mVtdUnitInformation[VtdIndex].QiDescLength = 1 << (QueueSize + 8);
+ mVtdUnitInformation[VtdIndex].QiDesc = (QI_DESC *) AllocatePages (EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * mVtdUnitInformation[VtdIndex].QiDescLength));
+
+ if (mVtdUnitInformation[VtdIndex].QiDesc == NULL) {
+ mVtdUnitInformation[VtdIndex].QiDescLength = 0;
+ DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG ((DEBUG_INFO, "Invalidation Queue Length : %d\n", mVtdUnitInformation[VtdIndex].QiDescLength));
+ Reg64 = (UINT64)(UINTN)mVtdUnitInformation[VtdIndex].QiDesc;
+ Reg64 |= QueueSize;
+ MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQA_REG, Reg64);
+
+ //
+ // Enable the queued invalidation interface through the Global Command Register.
+ // When enabled, hardware sets the QIES field in the Global Status Register.
+ //
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+ Reg32 |= B_GMCD_REG_QIE;
+ MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, Reg32);
+ DEBUG ((DEBUG_INFO, "Enable Queued Invalidation Interface. GCMD_REG = 0x%x\n", Reg32));
do {
- Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
- } while ((Reg64 & B_CCMD_REG_ICC) != 0);
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+ } while ((Reg32 & B_GSTS_REG_QIES) == 0);
+
+ mVtdUnitInformation[VtdIndex].QiFreeHead = 0;

return EFI_SUCCESS;
}

/**
- Invalidate VTd IOTLB.
+ Disable queued invalidation interface.
+
+ @param[in] VtdIndex The index used to identify a VTd engine.
+**/
+VOID
+DisableQueuedInvalidationInterface (
+ IN UINTN VtdIndex
+ )
+{
+ UINT32 Reg32;
+
+ if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation != 0) {
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+ Reg32 &= (~B_GMCD_REG_QIE);
+ MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, Reg32);
+ DEBUG ((DEBUG_INFO, "Disable Queued Invalidation Interface. GCMD_REG = 0x%x\n", Reg32));
+ do {
+ Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+ } while ((Reg32 & B_GSTS_REG_QIES) != 0);
+
+ if (mVtdUnitInformation[VtdIndex].QiDesc != NULL) {
+ FreePages(mVtdUnitInformation[VtdIndex].QiDesc, EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * mVtdUnitInformation[VtdIndex].QiDescLength));
+ mVtdUnitInformation[VtdIndex].QiDesc = NULL;
+ mVtdUnitInformation[VtdIndex].QiDescLength = 0;
+ }
+
+ mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation = 0;
+ }
+}
+
+/**
+ Check Queued Invalidation Fault.

@param[in] VtdIndex The index used to identify a VTd engine.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval RETURN_DEVICE_ERROR A fault is detected.
**/
EFI_STATUS
-InvalidateIOTLB (
+QueuedInvalidationCheckFault (
IN UINTN VtdIndex
)
{
- UINT64 Reg64;
+ UINT32 FaultReg;

- Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
- if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
- DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%d)\n", VtdIndex));
- return EFI_DEVICE_ERROR;
+ FaultReg = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG);
+
+ if (FaultReg & B_FSTS_REG_IQE) {
+ DEBUG((DEBUG_ERROR, "Detect Invalidation Queue Error [0x%08x]\n", FaultReg));
+ FaultReg |= B_FSTS_REG_IQE;
+ MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
+ return RETURN_DEVICE_ERROR;
}

- Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
- Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);
- MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
+ if (FaultReg & B_FSTS_REG_ITE) {
+ DEBUG((DEBUG_ERROR, "Detect Invalidation Time-out Error [0x%08x]\n", FaultReg));
+ FaultReg |= B_FSTS_REG_ITE;
+ MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
+ return RETURN_DEVICE_ERROR;
+ }
+
+ if (FaultReg & B_FSTS_REG_ICE) {
+ DEBUG((DEBUG_ERROR, "Detect Invalidation Completion Error [0x%08x]\n", FaultReg));
+ FaultReg |= B_FSTS_REG_ICE;
+ MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG, FaultReg);
+ return RETURN_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Submit the queued invalidation descriptor to the remapping
+ hardware unit and wait for its completion.
+
+ @param[in] VtdIndex The index used to identify a VTd engine.
+ @param[in] Desc The invalidate descriptor
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval RETURN_DEVICE_ERROR A fault is detected.
+ @retval EFI_INVALID_PARAMETER Parameter is invalid.
+**/
+EFI_STATUS
+SubmitQueuedInvalidationDescriptor (
+ IN UINTN VtdIndex,
+ IN QI_DESC *Desc
+ )
+{
+ EFI_STATUS Status;
+ UINT16 QiDescLength;
+ QI_DESC *BaseDesc;
+ UINT64 Reg64Iqt;
+ UINT64 Reg64Iqh;
+
+ if (Desc == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ QiDescLength = mVtdUnitInformation[VtdIndex].QiDescLength;
+ BaseDesc = mVtdUnitInformation[VtdIndex].QiDesc;
+
+ DEBUG((DEBUG_INFO, "[%d] Submit QI Descriptor [0x%08x, 0x%08x] Free Head (%d)\n", VtdIndex, Desc->Low, Desc->High, mVtdUnitInformation[VtdIndex].QiFreeHead));

+ BaseDesc[mVtdUnitInformation[VtdIndex].QiFreeHead].Low = Desc->Low;
+ BaseDesc[mVtdUnitInformation[VtdIndex].QiFreeHead].High = Desc->High;
+ FlushPageTableMemory(VtdIndex, (UINTN) &BaseDesc[mVtdUnitInformation[VtdIndex].QiFreeHead], sizeof(QI_DESC));
+
+ mVtdUnitInformation[VtdIndex].QiFreeHead = (mVtdUnitInformation[VtdIndex].QiFreeHead + 1) % QiDescLength;
+
+ //
+ // Update the HW tail register indicating the presence of new descriptors.
+ //
+ Reg64Iqt = mVtdUnitInformation[VtdIndex].QiFreeHead << DMAR_IQ_SHIFT;
+ MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQT_REG, Reg64Iqt);
+
+ Status = EFI_SUCCESS;
do {
+ Status = QueuedInvalidationCheckFault(VtdIndex);
+ if (Status != EFI_SUCCESS) {
+ DEBUG((DEBUG_ERROR,"Detect Queued Invalidation Fault.\n"));
+ break;
+ }
+
+ Reg64Iqh = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQH_REG);
+ } while (Reg64Iqt != Reg64Iqh);
+
+ return Status;
+}
+
+/**
+ Invalidate VTd context cache.
+
+ @param[in] VtdIndex The index used to identify a VTd engine.
+**/
+EFI_STATUS
+InvalidateContextCache (
+ IN UINTN VtdIndex
+ )
+{
+ UINT64 Reg64;
+ QI_DESC QiDesc;
+
+ if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation == 0) {
+ //
+ // Register-based Invalidation
+ //
+ Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
+ if ((Reg64 & B_CCMD_REG_ICC) != 0) {
+ DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%d)\n",VtdIndex));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));
+ Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);
+ MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG, Reg64);
+
+ do {
+ Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
+ } while ((Reg64 & B_CCMD_REG_ICC) != 0);
+ } else {
+ //
+ // Queued Invalidation
+ //
+ QiDesc.Low = QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(1) | QI_CC_TYPE;
+ QiDesc.High = 0;
+
+ return SubmitQueuedInvalidationDescriptor(VtdIndex, &QiDesc);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Invalidate VTd IOTLB.
+
+ @param[in] VtdIndex The index used to identify a VTd engine.
+**/
+EFI_STATUS
+InvalidateIOTLB (
+ IN UINTN VtdIndex
+ )
+{
+ UINT64 Reg64;
+ QI_DESC QiDesc;
+
+ if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation == 0) {
+ //
+ // Register-based Invalidation
+ //
Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
- } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
+ if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
+ DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%d)\n", VtdIndex));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
+ Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);
+ MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
+
+ do {
+ Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+ } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
+ } else {
+ //
+ // Queued Invalidation
+ //
+ QiDesc.Low = QI_IOTLB_DID(0) | QI_IOTLB_DR(CAP_READ_DRAIN(mVtdUnitInformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_DW(CAP_WRITE_DRAIN(mVtdUnitInformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_GRAN(1) | QI_IOTLB_TYPE;
+ QiDesc.High = QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0);
+
+ return SubmitQueuedInvalidationDescriptor(VtdIndex, &QiDesc);
+ }

return EFI_SUCCESS;
}
@@ -163,9 +402,12 @@ PrepareVtdConfig (
{
UINTN Index;
UINTN DomainNumber;
+ EFI_STATUS Status;

for (Index = 0; Index < mVtdUnitNumber; Index++) {
DEBUG ((DEBUG_INFO, "Dump VTd Capability (%d)\n", Index));
+ mVtdUnitInformation[Index].VerReg.Uint32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_VER_REG);
+ DumpVtdVerRegs (&mVtdUnitInformation[Index].VerReg);
mVtdUnitInformation[Index].CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CAP_REG);
DumpVtdCapRegs (&mVtdUnitInformation[Index].CapReg);
mVtdUnitInformation[Index].ECapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_ECAP_REG);
@@ -190,6 +432,12 @@ PrepareVtdConfig (
DEBUG((DEBUG_ERROR, "!!!! Pci device Number(0x%x) >= DomainNumber(0x%x) !!!!\n", mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceDataNumber, DomainNumber));
return ;
}
+
+ Status = PerpareCacheInvalidationInterface(Index);
+ if (EFI_ERROR (Status)) {
+ ASSERT(FALSE);
+ return;
+ }
}
return ;
}
@@ -252,7 +500,8 @@ EnableDmar (
MmioWrite64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)mVtdUnitInformation[Index].RootEntryTable);
}

- MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+ Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);
+ MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_SRTP);

DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
do {
@@ -282,7 +531,8 @@ EnableDmar (
//
// Enable VTd
//
- MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);
+ Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);
+ MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_TE);
DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));
do {
Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);
@@ -360,6 +610,8 @@ DisableDmar (
DEBUG((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));

DEBUG ((DEBUG_INFO,"VTD (%d) Disabled!<<<<<<\n",Index));
+
+ DisableQueuedInvalidationInterface(Index);
}

mVtdEnabled = FALSE;
@@ -380,6 +632,21 @@ DisableDmar (
return EFI_SUCCESS;
}

+/**
+ Dump VTd version registers.
+
+ @param[in] VerReg The version register.
+**/
+VOID
+DumpVtdVerRegs (
+ IN VTD_VER_REG *VerReg
+ )
+{
+ DEBUG ((DEBUG_INFO, " VerReg:\n", VerReg->Uint32));
+ DEBUG ((DEBUG_INFO, " Major - 0x%x\n", VerReg->Bits.Major));
+ DEBUG ((DEBUG_INFO, " Minor - 0x%x\n", VerReg->Bits.Minor));
+}
+
/**
Dump VTd capability registers.

diff --git a/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
index b2f745bd..a759ca10 100644
--- a/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
+++ b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
@@ -206,10 +206,12 @@ typedef union {
#define B_CAP_REG_RWBF BIT4
#define R_ECAP_REG 0x10
#define R_GCMD_REG 0x18
+#define B_GMCD_REG_QIE BIT26
#define B_GMCD_REG_WBF BIT27
#define B_GMCD_REG_SRTP BIT30
#define B_GMCD_REG_TE BIT31
#define R_GSTS_REG 0x1C
+#define B_GSTS_REG_QIES BIT26
#define B_GSTS_REG_WBF BIT27
#define B_GSTS_REG_RTPS BIT30
#define B_GSTS_REG_TE BIT31
@@ -221,6 +223,9 @@ typedef union {
#define V_CCMD_REG_CIRG_DEVICE (BIT62|BIT61)
#define B_CCMD_REG_ICC BIT63
#define R_FSTS_REG 0x34
+#define B_FSTS_REG_IQE BIT4
+#define B_FSTS_REG_ICE BIT5
+#define B_FSTS_REG_ITE BIT6
#define R_FECTL_REG 0x38
#define R_FEDATA_REG 0x3C
#define R_FEADDR_REG 0x40
@@ -247,6 +252,58 @@ typedef union {
#define R_PMEN_HIGH_BASE_REG 0x70
#define R_PMEN_HIGH_LIMITE_REG 0x78

+#define R_IQH_REG 0x80
+#define R_IQT_REG 0x88
+#define DMAR_IQ_SHIFT 4 /* Invalidation queue head/tail shift */
+
+#define R_IQA_REG 0x90
+
+#define VTD_PAGE_SHIFT (12)
+#define VTD_PAGE_SIZE (1UL << VTD_PAGE_SHIFT)
+#define VTD_PAGE_MASK (((UINT64)-1) << VTD_PAGE_SHIFT)
+
+#define QI_CC_TYPE 0x1
+#define QI_IOTLB_TYPE 0x2
+#define QI_DIOTLB_TYPE 0x3
+#define QI_IEC_TYPE 0x4
+#define QI_IWD_TYPE 0x5
+
+#define QI_CC_FM(fm) (((UINT64)fm) << 48)
+#define QI_CC_SID(sid) (((UINT64)sid) << 32)
+#define QI_CC_DID(did) (((UINT64)did) << 16)
+#define QI_CC_GRAN(gran) (((UINT64)gran) << 4)
+
+#define QI_IOTLB_DID(did) (((UINT64)did) << 16)
+#define QI_IOTLB_DR(dr) (((UINT64)dr) << 7)
+#define QI_IOTLB_DW(dw) (((UINT64)dw) << 6)
+#define QI_IOTLB_GRAN(gran) (((UINT64)gran) << 4)
+#define QI_IOTLB_ADDR(addr) (((UINT64)addr) & VTD_PAGE_MASK)
+#define QI_IOTLB_IH(ih) (((UINT64)ih) << 6)
+#define QI_IOTLB_AM(am) (((UINT8)am))
+
+#define CAP_READ_DRAIN(c) (((c) >> 55) & 1)
+#define CAP_WRITE_DRAIN(c) (((c) >> 54) & 1)
+
+#define QI_IWD_STATUS_DATA(d) (((UINT64)d) << 32)
+#define QI_IWD_STATUS_WRITE (((UINT64)1) << 5)
+
+//
+// This is the queued invalidate descriptor.
+//
+typedef struct {
+ UINT64 Low;
+ UINT64 High;
+} QI_DESC;
+
+typedef union {
+ struct {
+ UINT8 Minor:4;
+ UINT8 Major:4;
+ UINT32 Rsvd:24;
+ } Bits;
+ UINT32 Uint32;
+} VTD_VER_REG;
+
typedef union {
struct {
UINT8 ND:3; // Number of domains supported
--
2.16.2.windows.1


Re: [PATCH v2 2/5] MdeMoudlePkg: introduce new PCD for Acpi/rsdp

Jianyong Wu
 

Hi Laszlo,

-----Original Message-----
From: Laszlo Ersek <lersek@redhat.com>
Sent: Wednesday, May 19, 2021 2:17 PM
To: devel@edk2.groups.io; Jianyong Wu <Jianyong.Wu@arm.com>;
ardb+tianocore@kernel.org; Sami Mujawar <Sami.Mujawar@arm.com>
Cc: hao.a.wu@intel.com; Justin He <Justin.He@arm.com>; Jian J Wang
<jian.j.wang@intel.com>
Subject: Re: [edk2-devel] [PATCH v2 2/5] MdeMoudlePkg: introduce new
PCD for Acpi/rsdp

On 05/17/21 08:50, Jianyong Wu wrote:
As there is lack of a machnism in Cloud Hypervisor to pass the base
address of Rsdp in Acpi, so a PCD varialbe is introduced here to feed
it.

Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
MdeModulePkg/MdeModulePkg.dec | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/MdeModulePkg/MdeModulePkg.dec
b/MdeModulePkg/MdeModulePkg.dec index
148395511034..4c8baac35a9e
100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -910,6 +910,13 @@ [PcdsFixedAtBuild]
# @Expression 0x80000001 |
(gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable
== 0xFFFFFFFFFFFFFFFF ||
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable <=
0x0FFFFFFFFFFFFFFF)

gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable|0|
UINT6
4|0x30001015

+ ##
+ # This is the physical address of rsdp which is the core struct of Acpi.
+ # Some hypervisor may has no way to pass rsdp address to the guest,
+ so a PCD # is worth for those.
+ #
+
+
gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiRsdpBaseAddress|0x0|UINT64
|0x3
+ 0001056
+
## Progress Code for OS Loader LoadImage start.<BR><BR>
# PROGRESS_CODE_OS_LOADER_LOAD =
(EFI_SOFTWARE_DXE_BS_DRIVER | (EFI_OEM_SPECIFIC | 0x00000000)) =
0x03058000<BR>
# @Prompt Progress Code for OS Loader LoadImage start.
This PCD is not useful enough to be placed in MdeModulePkg -- it is only
used in the next two patches, which are for ArmVirtPkg.

(1) Therefore, please add the PCD to the "ArmVirtPkg.dec" file.

(2) The PCD should arguably refer to "CloudHv" in the name.

(3) In my opinion, this patch (once reimplemented for ArmVirtPkg.dec)
should be squashed into the CloudHvAcpiPlatformDxe patch. The PCD is
being introduced *for* CloudHvAcpiPlatformDxe, and *only* for that driver.
In such cases, we usually keep the DEC modifications in the same patch as
the driver addition, assuming the PCD goes in the same package as the driver.

(4) "some hypervisor" in the DEC comment is bogus. Please be as explicit
about the use case as possible.
OK, that's better.

Thanks
Jianyong


Thanks
Laszlo
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.


回复: [edk2-devel] [edk2-devel202105 PATCH v2 1/1] ArmPkg/ArmGic: Fix maximum number of interrupts in GICv3

gaoliming
 

If no objection, I will merge this patch today. Then, tomorrow, I will create stable tag 202105.

Thanks
Liming

-----邮件原件-----
发件人: devel@edk2.groups.io <devel@edk2.groups.io> 代表 gaoliming
发送时间: 2021年5月26日 10:22
收件人: devel@edk2.groups.io; lersek@redhat.com;
sami.mujawar@arm.com
抄送: ardb@kernel.org; leif@nuviainc.com; Matteo.Carlini@arm.com;
Andreas.Sandberg@arm.com; joey.gouly@arm.com; nd@arm.com
主题: 回复: [edk2-devel] [edk2-devel202105 PATCH v2 1/1] ArmPkg/ArmGic:
Fix maximum number of interrupts in GICv3

Laszlo, Ard, Sami:
I am OK to merge this patch for stable tag 202105.

Thanks
Liming
-----邮件原件-----
发件人: devel@edk2.groups.io <devel@edk2.groups.io> 代表 Laszlo
Ersek
发送时间: 2021年5月25日 19:55
收件人: devel@edk2.groups.io; sami.mujawar@arm.com
抄送: ardb@kernel.org; leif@nuviainc.com; Matteo.Carlini@arm.com;
Andreas.Sandberg@arm.com; joey.gouly@arm.com; nd@arm.com
主题: Re: [edk2-devel] [edk2-devel202105 PATCH v2 1/1] ArmPkg/ArmGic:
Fix maximum number of interrupts in GICv3

Hi Sami,

On 05/24/21 15:01, Sami Mujawar wrote:
From: Andreas Sandberg <andreas.sandberg@arm.com>

Bugzilla: 3415 (https://bugzilla.tianocore.org/show_bug.cgi?id=3415)

The GICv3 architecture supports up to 1020 ordinary interrupt
lines. The actual number of interrupts supported is described by the
ITLinesNumber field in the GICD_TYPER register. The total number of
implemented registers is normally calculated as
32*(ITLinesNumber+1). However, maximum value (0x1f) is a special case
since that would indicate that 1024 interrupts are implemented.

Add handling for this special case in ArmGicGetMaxNumInterrupts.

Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
---
The changes can be seen at:
https://github.com/samimujawar/edk2/tree/1396_gic_max_num_intr_v2

Notes:
v2:
- Fix comment style.
[Laszlo]
- Updated comment style.
[Sami]

ArmPkg/Drivers/ArmGic/ArmGicLib.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
I think this patch should be merged really soon, as long as Ard agrees.

Thanks,
Laszlo


diff --git a/ArmPkg/Drivers/ArmGic/ArmGicLib.c
b/ArmPkg/Drivers/ArmGic/ArmGicLib.c
index
6b01c88206ad8adef3100dd44c0d57660db77783..bd4b5edb903f3846f4f0e43
1f93e001f01cd9e7d 100644
--- a/ArmPkg/Drivers/ArmGic/ArmGicLib.c
+++ b/ArmPkg/Drivers/ArmGic/ArmGicLib.c
@@ -1,6 +1,6 @@
/** @file
*
-* Copyright (c) 2011-2018, ARM Limited. All rights reserved.
+* Copyright (c) 2011-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -120,7 +120,14 @@ ArmGicGetMaxNumInterrupts (
IN INTN GicDistributorBase
)
{
- return 32 * ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) &
0x1F) + 1);
+ UINTN ItLines;
+
+ ItLines = MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) &
0x1F;
+
+ //
+ // Interrupt ID 1020-1023 are reserved.
+ //
+ return (ItLines == 0x1f) ? 1020 : 32 * (ItLines + 1);
}

VOID









Re: [PATCH v2 2/5] MdeMoudlePkg: introduce new PCD for Acpi/rsdp

Jianyong Wu
 

Hi Sami,

-----Original Message-----
From: Sami Mujawar <Sami.Mujawar@arm.com>
Sent: Wednesday, May 19, 2021 4:26 AM
To: Jianyong Wu <Jianyong.Wu@arm.com>; devel@edk2.groups.io;
lersek@redhat.com; ardb+tianocore@kernel.org
Cc: hao.a.wu@intel.com; Justin He <Justin.He@arm.com>; Jian J Wang
<jian.j.wang@intel.com>; nd <nd@arm.com>
Subject: Re: [PATCH v2 2/5] MdeMoudlePkg: introduce new PCD for
Acpi/rsdp

Hi Jianyon,

Thank you for this patch.

Please find my response inline marked [SAMI].

Regards,

Sami Mujawar


On 17/05/2021 07:50 AM, Jianyong Wu wrote:
As there is lack of a machnism in Cloud Hypervisor to pass the base
address of Rsdp in Acpi, so a PCD varialbe is introduced here to
[SAMI] Please fix the following typos: 'machnism' & 'varialbe'
feed it.

Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
MdeModulePkg/MdeModulePkg.dec | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/MdeModulePkg/MdeModulePkg.dec
b/MdeModulePkg/MdeModulePkg.dec index
148395511034..4c8baac35a9e
100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -910,6 +910,13 @@ [PcdsFixedAtBuild]
# @Expression 0x80000001 |
(gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable
== 0xFFFFFFFFFFFFFFFF ||
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable <=
0x0FFFFFFFFFFFFFFF)

gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable|0|
UINT6
4|0x30001015

+ ##
+ # This is the physical address of rsdp which is the core struct of Acpi.
+ # Some hypervisor may has no way to pass rsdp address to the guest,
+ so a PCD # is worth for those.
+ #
+
+
gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiRsdpBaseAddress|0x0|UINT64
|0x3
+ 0001056
[SAMI] Can this PCD be defined in ArmVirtPkg\ArmVirtPkg.dec ?
Ok, It's better to do this change.

Thanks
Jianyong
+
## Progress Code for OS Loader LoadImage start.<BR><BR>
# PROGRESS_CODE_OS_LOADER_LOAD =
(EFI_SOFTWARE_DXE_BS_DRIVER | (EFI_OEM_SPECIFIC | 0x00000000)) =
0x03058000<BR>
# @Prompt Progress Code for OS Loader LoadImage start.


Re: [PATCH v2 1/5] ArmVirtPkg: Library: Memory initialization for Cloud Hypervisor

Jianyong Wu
 

Hi Sami,

-----Original Message-----
From: Sami Mujawar <Sami.Mujawar@arm.com>
Sent: Wednesday, May 19, 2021 4:21 AM
To: Jianyong Wu <Jianyong.Wu@arm.com>; devel@edk2.groups.io;
lersek@redhat.com; ardb+tianocore@kernel.org
Cc: hao.a.wu@intel.com; Justin He <Justin.He@arm.com>; Leif Lindholm
<leif@nuviainc.com>; nd <nd@arm.com>
Subject: Re: [PATCH v2 1/5] ArmVirtPkg: Library: Memory initialization for
Cloud Hypervisor

Hi Jianyon,

Thank you for this patch.

Please find my response inline marked [SAMI].

Regards,

Sami Mujawar

On 17/05/2021 07:50 AM, Jianyong Wu wrote:
Cloud Hypervisor is kvm based VMM implemented in rust.

This library populates the system memory map for the Cloud Hypervisor
virtual platform.

Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <leif@nuviainc.com>
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
.../CloudHvVirtMemInfoPeiLib.inf | 47 ++++++++
.../CloudHvVirtMemInfoLib.c | 94 ++++++++++++++++
.../CloudHvVirtMemInfoPeiLibConstructor.c | 100
++++++++++++++++++
3 files changed, 241 insertions(+)
create mode 100644
ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoPeiLib.inf
create mode 100644
ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoLib.c
create mode 100644
ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoPeiLibCon
st
ructor.c

diff --git
a/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoPeiLib.i
n
f
b/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoPeiLib.i
n
f
new file mode 100644
index 000000000000..71dbf9c06ccc
--- /dev/null
+++
b/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoPeiLi
+++ b.inf
@@ -0,0 +1,47 @@
+#/* @file
+#
+# Copyright (c) 2011-2015, ARM Limited. All rights reserved.
+# Copyright (c) 2014-2017, Linaro Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent # #*/
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = ClhVirtMemInfoPeiLib
+ FILE_GUID = 3E29D940-0591-EE6A-CAD4-223A9CF55E75
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ArmVirtMemInfoLib|PEIM
+ CONSTRUCTOR = CloudHvVirtMemInfoPeiLibConstructor
+
+[Sources]
+ CloudHvVirtMemInfoLib.c
+ CloudHvVirtMemInfoPeiLibConstructor.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ ArmVirtPkg/ArmVirtPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ ArmLib
+ BaseMemoryLib
+ DebugLib
+ FdtLib
+ PcdLib
+ MemoryAllocationLib
+
+[Pcd]
+ gArmTokenSpaceGuid.PcdFdBaseAddress
+ gArmTokenSpaceGuid.PcdFvBaseAddress
+ gArmTokenSpaceGuid.PcdSystemMemoryBase
+ gArmTokenSpaceGuid.PcdSystemMemorySize
+
+[FixedPcd]
+ gArmTokenSpaceGuid.PcdFdSize
+ gArmTokenSpaceGuid.PcdFvSize
+ gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
diff --git
a/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoLib.c
b/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoLib.c
new file mode 100644
index 000000000000..69f4e6ab6cc4
--- /dev/null
+++
b/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoLib.c
@@ -0,0 +1,94 @@
+/** @file
+
+ Copyright (c) 2014-2017, Linaro Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+// Number of Virtual Memory Map Descriptors
+#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 5
+
+//
+// mach-virt's core peripherals such as the UART, the GIC and the RTC
+are // all mapped in the 'miscellaneous device I/O' region, which we
+just map // in its entirety rather than device by device. Note that
+it does not // cover any of the NOR flash banks or PCI resource windows.
+//
+#define MACH_VIRT_PERIPH_BASE 0x08000000
+#define MACH_VIRT_PERIPH_SIZE SIZE_128MB
+
+//
+// in cloud-hypervisor, 0x0 ~ 0x8000000 is reserved as normal memory
+for UEFI //
+#define CLOUDHV_UEFI_MEM_BASE 0x0
+#define CLOUDHV_UEFI_MEM_SIZE 0x08000000
[SAMI] The above macros are not used anywhere. Can these be removed?
If so, the code in this patch would be very similar to
ArmVirtPkg\Library\QemuVirtMemInfoLib. To avoid code duplication, would
it be possible to use QemuVirtMemInfoPeiLib.inf instead?
[/SAMI]
Yeah, these 2 lines of code should be removed and this file is copied from qemu part.
We changed Cloud Hypervisor and its memory layout is very similar with qemu now.
Maybe we can reuse the qemu code for now and rebuild it if need in the future, as the Cloud Hypervisor
are in fast developing.

thanks
Jianyong

+
+/**
+ Return the Virtual Memory Map of your platform
+
+ This Virtual Memory Map is used by MemoryInitPei Module to
+ initialize the MMU on your platform.
+
+ @param[out] VirtualMemoryMap Array of
ARM_MEMORY_REGION_DESCRIPTOR
+ describing a Physical-to-Virtual Memory
+ mapping. This array must be ended by a
+ zero-filled entry. The allocated memory
+ will not be freed.
+
+**/
+VOID
+ArmVirtGetMemoryMap (
+ OUT ARM_MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap
+ )
+{
+ ARM_MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable;
+
+ ASSERT (VirtualMemoryMap != NULL);
+
+ VirtualMemoryTable = AllocatePool (sizeof
(ARM_MEMORY_REGION_DESCRIPTOR) *
+
+ MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS);
+
+ if (VirtualMemoryTable == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Error: Failed AllocatePool()\n",
__FUNCTION__));
+ return;
+ }
+
+ // System DRAM
+ VirtualMemoryTable[0].PhysicalBase = PcdGet64
+ (PcdSystemMemoryBase); VirtualMemoryTable[0].VirtualBase =
VirtualMemoryTable[0].PhysicalBase;
+ VirtualMemoryTable[0].Length = PcdGet64 (PcdSystemMemorySize);
+ VirtualMemoryTable[0].Attributes =
ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
+
+ DEBUG ((DEBUG_INFO, "%a: Dumping System DRAM Memory Map:\n"
+ "\tPhysicalBase: 0x%lX\n"
+ "\tVirtualBase: 0x%lX\n"
+ "\tLength: 0x%lX\n",
+ __FUNCTION__,
+ VirtualMemoryTable[0].PhysicalBase,
+ VirtualMemoryTable[0].VirtualBase,
+ VirtualMemoryTable[0].Length));
+
+ // Memory mapped peripherals (UART, RTC, GIC, virtio-mmio, etc)
+ VirtualMemoryTable[1].PhysicalBase = MACH_VIRT_PERIPH_BASE;
+ VirtualMemoryTable[1].VirtualBase = MACH_VIRT_PERIPH_BASE;
+ VirtualMemoryTable[1].Length = MACH_VIRT_PERIPH_SIZE;
+ VirtualMemoryTable[1].Attributes =
ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
+
+ // Map the FV region as normal executable memory
+ VirtualMemoryTable[2].PhysicalBase = PcdGet64 (PcdFvBaseAddress);
+ VirtualMemoryTable[2].VirtualBase =
VirtualMemoryTable[2].PhysicalBase;
+ VirtualMemoryTable[2].Length = FixedPcdGet32 (PcdFvSize);
+ VirtualMemoryTable[2].Attributes =
ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
+
+ // End of Table
+ ZeroMem (&VirtualMemoryTable[3], sizeof
+ (ARM_MEMORY_REGION_DESCRIPTOR));
+
+ *VirtualMemoryMap = VirtualMemoryTable; }
diff --git
a/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoPeiLibC
on
structor.c
b/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoPeiLibC
on
structor.c
new file mode 100644
index 000000000000..062dfcee1d66
--- /dev/null
+++
b/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoPeiLi
+++ bConstructor.c
@@ -0,0 +1,100 @@
+/** @file
+
+ Copyright (c) 2014-2017, Linaro Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <libfdt.h>
+
+RETURN_STATUS
+EFIAPI
+CloudHvVirtMemInfoPeiLibConstructor (
+ VOID
+ )
+{
+ VOID *DeviceTreeBase;
+ INT32 Node, Prev;
+ UINT64 NewBase, CurBase;
+ UINT64 NewSize, CurSize;
+ CONST CHAR8 *Type;
+ INT32 Len;
+ CONST UINT64 *RegProp;
+ RETURN_STATUS PcdStatus;
+
+ NewBase = 0;
+ NewSize = 0;
+
+ DeviceTreeBase = (VOID *)(UINTN)PcdGet64
+ (PcdDeviceTreeInitialBaseAddress);
+ ASSERT (DeviceTreeBase != NULL);
+
+ //
+ // Make sure we have a valid device tree blob // ASSERT
+ (fdt_check_header (DeviceTreeBase) == 0);
+
+ //
+ // Look for the lowest memory node
+ //
+ for (Prev = 0;; Prev = Node) {
+ Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
+ if (Node < 0) {
+ break;
+ }
+
+ //
+ // Check for memory node
+ //
+ Type = fdt_getprop (DeviceTreeBase, Node, "device_type", &Len);
+ if (Type && AsciiStrnCmp (Type, "memory", Len) == 0) {
+ //
+ // Get the 'reg' property of this node. For now, we will assume
+ // two 8 byte quantities for base and size, respectively.
+ //
+ RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
+ if (RegProp != 0 && Len == (2 * sizeof (UINT64))) {
+
+ CurBase = fdt64_to_cpu (ReadUnaligned64 (RegProp));
+ CurSize = fdt64_to_cpu (ReadUnaligned64 (RegProp + 1));
+
+ DEBUG ((DEBUG_INFO, "%a: System RAM @ 0x%lx - 0x%lx\n",
+ __FUNCTION__, CurBase, CurBase + CurSize - 1));
+
+ if (NewBase > CurBase || NewBase == 0) {
+ NewBase = CurBase;
+ NewSize = CurSize;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to parse FDT memory node\n",
+ __FUNCTION__));
+ }
+ }
+ }
+
+ //
+ // Make sure the start of DRAM matches our expectation // ASSERT
+ (FixedPcdGet64 (PcdSystemMemoryBase) == NewBase); PcdStatus =
+ PcdSet64S (PcdSystemMemorySize, NewSize); ASSERT_RETURN_ERROR
+ (PcdStatus);
+
+ //
+ // We need to make sure that the machine we are running on has at
+ least // 128 MB of memory configured, and is currently executing
+ this binary from // NOR flash. This prevents a device tree image in
+ DRAM from getting // clobbered when our caller installs permanent
+ PEI RAM, before we have a // chance of marking its location as
+ reserved or copy it to a freshly // allocated block in the permanent PEI
RAM in the platform PEIM.
+ //
+ ASSERT (NewSize >= SIZE_128MB);
+ ASSERT (
+ (((UINT64)PcdGet64 (PcdFdBaseAddress) +
+ (UINT64)PcdGet32 (PcdFdSize)) <= NewBase) ||
+ ((UINT64)PcdGet64 (PcdFdBaseAddress) >= (NewBase + NewSize)));
+
+ return RETURN_SUCCESS;
+}


Re: [PATCH 8/9] MdeModulePkg/ACPI: Install ACPI table from HOB.

Wu, Hao A
 

Some inline comments below:

-----Original Message-----
From: Liu, Zhiguang <zhiguang.liu@intel.com>
Sent: Monday, May 24, 2021 3:13 PM
To: devel@edk2.groups.io
Cc: Wang, Jian J <jian.j.wang@intel.com>; Wu, Hao A <hao.a.wu@intel.com>;
Bi, Dandan <dandan.bi@intel.com>; Liming Gao
<gaoliming@byosoft.com.cn>; Ni, Ray <ray.ni@intel.com>
Subject: [PATCH 8/9] MdeModulePkg/ACPI: Install ACPI table from HOB.

If HOB contains APCI table information, entry point of AcpiTableDxe.inf
should parse the APCI table from HOB, and install these tables.
We assume the whole ACPI table (starting with
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER)
is contained by a single gEfiAcpiTableGuid HOB.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Ray Ni <ray.ni@intel.com>
Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com>
---
MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h | 4 +++-
MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf | 4 +++-
MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c | 144
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++--------
3 files changed, 142 insertions(+), 10 deletions(-)

diff --git a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
index 9d7cf7ccfc..7fd393aab3 100644
--- a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
+++ b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
@@ -1,7 +1,7 @@
/** @file

ACPI Table Protocol Driver



- Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>

+ Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>

SPDX-License-Identifier: BSD-2-Clause-Patent



**/

@@ -24,6 +24,8 @@
#include <Library/MemoryAllocationLib.h>

#include <Library/UefiBootServicesTableLib.h>

#include <Library/PcdLib.h>

+#include <Library/HobLib.h>

+#include <UniversalPayload/AcpiTable.h>



//

// Statements that include other files

diff --git a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
index d341df439e..df80c4db35 100644
--- a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
+++ b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
@@ -4,7 +4,7 @@
# This driver initializes ACPI tables (Rsdp, Rsdt and Xsdt) and produces
UEFI/PI

# services to install/uninstall/manage ACPI tables.

#

-# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>

# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>

# SPDX-License-Identifier: BSD-2-Clause-Patent

#

@@ -51,10 +51,12 @@
DebugLib

BaseLib

PcdLib

+ HobLib



[Guids]

gEfiAcpi10TableGuid ## PRODUCES ## SystemTable

gEfiAcpiTableGuid ## PRODUCES ## SystemTable

+ gPldAcpiTableGuid

Please help to add "## SOMETIMES_CONSUMES ## HOB" as simple description of the GUID usage.





[FeaturePcd]

gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol ##
CONSUMES

diff --git
a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
index 5a2afdff27..24962843a1 100644
--- a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
+++ b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
@@ -1,7 +1,7 @@
/** @file

ACPI Table Protocol Implementation



- Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>

+ Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>

Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>

SPDX-License-Identifier: BSD-2-Clause-Patent



@@ -30,6 +30,7 @@ STATIC EFI_ALLOCATE_TYPE mAcpiTableAllocType;
@param Table Table to add.

@param Checksum Does the table require checksumming.

@param Version The version of the list to add the table to.

+ @param IsFromHob True, if add Apci Table from Hob List.

@param Handle Pointer for returning the handle.



@return EFI_SUCCESS The function completed successfully.

@@ -44,6 +45,7 @@ AddTableToList (
IN VOID *Table,

IN BOOLEAN Checksum,

IN EFI_ACPI_TABLE_VERSION Version,

+ IN BOOLEAN IsFromHob,

OUT UINTN *Handle

);



@@ -238,6 +240,7 @@ InstallAcpiTable (
AcpiTableBufferConst,

TRUE,

Version,

+ FALSE,

TableKey

);

if (!EFI_ERROR (Status)) {

@@ -472,6 +475,7 @@ FreeTableMemory (
@param Table Table to add.

@param Checksum Does the table require checksumming.

@param Version The version of the list to add the table to.

+ @param IsFromHob True, if add Apci Table from Hob List.

@param Handle Pointer for returning the handle.



@return EFI_SUCCESS The function completed successfully.

@@ -487,6 +491,7 @@ AddTableToList (
IN VOID *Table,

IN BOOLEAN Checksum,

IN EFI_ACPI_TABLE_VERSION Version,

+ IN BOOLEAN IsFromHob,

OUT UINTN *Handle

)

{

@@ -552,13 +557,16 @@ AddTableToList (
// could be updated by OS present agent. For example, BufferPtrAddress
in

// SMM communication ACPI table.

//

- ASSERT ((EFI_PAGE_SIZE % 64) == 0);

Is there any special consideration for removing the above check when the table is not from HOB?
Also, will the tables from HOB violate the rule mentioned in the below comment?
// Allocate memory for the FACS. This structure must be aligned
// on a 64 byte boundary and must be ACPI NVS memory.



- Status = gBS->AllocatePages (

- AllocateMaxAddress,

- EfiACPIMemoryNVS,

- EFI_SIZE_TO_PAGES (CurrentTableList->TableSize),

- &AllocPhysAddress

- );

+ if (IsFromHob){

+ AllocPhysAddress = (UINTN)Table;

+ } else {

+ Status = gBS->AllocatePages (

+ AllocateMaxAddress,

+ EfiACPIMemoryNVS,

+ EFI_SIZE_TO_PAGES (CurrentTableList->TableSize),

+ &AllocPhysAddress

+ );

+ }

} else if (mAcpiTableAllocType == AllocateAnyPages) {

//

// If there is no allocation limit, there is also no need to use page

@@ -1689,6 +1697,124 @@ ChecksumCommonTables (
return EFI_SUCCESS;

}



+/**

+ This function will find gPldAcpiTableGuid Guid Hob, and install Acpi table
from it.

+

+ @param AcpiTableInstance Protocol instance private data.

+

+ @return EFI_SUCCESS The function completed successfully.

+ @return EFI_NOT_FOUND The function doesn't find the
gEfiAcpiTableGuid Guid Hob.

+ @return EFI_ABORTED The function could not complete successfully.

+

+**/

+EFI_STATUS

+InstallAcpiTableFromHob (

+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance

+ )

+{

+ EFI_HOB_GUID_TYPE *GuidHob;

+ EFI_ACPI_TABLE_VERSION Version;

+ EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;

+ EFI_ACPI_DESCRIPTION_HEADER *Rsdt;

+ EFI_ACPI_DESCRIPTION_HEADER *ChildTable;

+ UINT64 ChildTableAddress;

+ UINTN Count;

+ UINTN Index;

+ UINTN TableKey;

+ EFI_STATUS Status;

+ UINTN EntrySize;

+ PLD_ACPI_TABLE *AcpiTableAdress;

+ VOID *TableToInstall;

+ PLD_GENERIC_HEADER *GenericHeader;

+

+ TableKey = 0;

+ Version = PcdGet32 (PcdAcpiExposedTableVersions);

+

+ //

+ // HOB only contains the ACPI table in 2.0+ format.

+ //

+ GuidHob = GetFirstGuidHob (&gPldAcpiTableGuid);

+ if (GuidHob == NULL) {

+ return EFI_NOT_FOUND;

+ }

+

+ GenericHeader = (PLD_GENERIC_HEADER *) GET_GUID_HOB_DATA
(GuidHob);

+ if ((sizeof (PLD_GENERIC_HEADER) > GET_GUID_HOB_DATA_SIZE
(GuidHob)) || (GenericHeader->Length > GET_GUID_HOB_DATA_SIZE
(GuidHob))) {

+ return EFI_NOT_FOUND;

+ }

+ if (GenericHeader->Revision == PLD_ACPI_TABLE_REVISION) {

+ //

+ // PLD_ACPI_TABLE structure is used when Revision equals to
PLD_ACPI_TABLE_REVISION

+ //

+ AcpiTableAdress = (PLD_ACPI_TABLE *) GET_GUID_HOB_DATA
(GuidHob);

+ if (GenericHeader->Length < PLD_SIZEOF_THROUGH_FIELD
(PLD_ACPI_TABLE, Rsdp)) {

+ //

+ // Retrun if can't find the ACPI Info Hob with enough length

+ //

+ return EFI_NOT_FOUND;

+ }

+ Rsdp = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) (UINTN)
(AcpiTableAdress->Rsdp);

+

+ //

+ // An ACPI-compatible OS must use the XSDT if present.

+ // It shouldn't happen that XsdtAddress points beyond 4G range in 32-bit
environment.

+ //

+ ASSERT ((UINTN) Rsdp->XsdtAddress == Rsdp->XsdtAddress);

+

+ EntrySize = sizeof (UINT64);

+ Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress;

+ if (Rsdt == NULL) {

+ //

+ // XsdtAddress is zero, then we use Rsdt which has 32 bit entry

+ //

+ Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;

+ EntrySize = sizeof (UINT32);

+ }

+ Count = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) /
EntrySize;

Do we need a check on the validity of 'Rsdt->Length'?
If 'Dsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)' underflows,
I think it is possible to consume invalid content.



+

+ for (Index = 0; Index < Count; Index++){

+ ChildTableAddress = 0;

+ CopyMem (&ChildTableAddress, (UINT8 *) (Rsdt + 1) + EntrySize * Index,
EntrySize);

+ //

+ // If the address is of UINT64 while this module runs at 32 bits,

+ // make sure the upper bits are all-zeros.

+ //

+ ASSERT (ChildTableAddress == (UINTN) ChildTableAddress);

Sorry for a question, is the condition in the above ASSERT a case that will never happen or
the above ASSERT is used for table content check?

If it is a check, please help to add error handling logic.



+

+ ChildTable = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN)
ChildTableAddress;

+ Status = AddTableToList (AcpiTableInstance, ChildTable, TRUE, Version,
TRUE, &TableKey);

+ if (EFI_ERROR (Status)) {

+ DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromHob: Fail to add ACPI
table at 0x%p\n", ChildTable));

+ ASSERT_EFI_ERROR (Status);

For a single ChildTable, if the installation fails here, is it still needed to install the FACS and DSDT within the ChildTable?



+ }

+ if (ChildTable->Signature ==
EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE){

+ //

+ // Add the FACS and DSDT tables if it is not NULL.

+ //

+ if (((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)-
FirmwareCtrl != 0) {
+ TableToInstall = (VOID *) (UINTN)
((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)-
FirmwareCtrl;
+ Status = AddTableToList (AcpiTableInstance, TableToInstall, TRUE,
Version, TRUE, &TableKey);

+ if (EFI_ERROR (Status)) {

+ DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromHob: Fail to add ACPI
table FACS\n"));

+ ASSERT_EFI_ERROR (Status);

If the installation of FACS fails, is it still needed to install the DSDT below?



+ }

+ }

+

+ if (((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)-
Dsdt != 0) {
+ TableToInstall = (VOID *) (UINTN)
((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)->Dsdt;

+ Status = AddTableToList (AcpiTableInstance, TableToInstall, TRUE,
Version, TRUE, &TableKey);

+ if (EFI_ERROR (Status)) {

+ DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromHob: Fail to add ACPI
table DSDT\n"));

+ ASSERT_EFI_ERROR (Status);

+ }

+ }

+ }

+ }

+ }

+ Status = PublishTables (AcpiTableInstance, Version);

If there are errors occurred during the parse of the tables, do we still need to publish them anyway?

Best Regards,
Hao Wu



+ ASSERT_EFI_ERROR (Status);

+ return Status;

+}



/**

Constructor for the ACPI table protocol. Initializes instance

@@ -1918,6 +2044,8 @@ AcpiTableAcpiTableConstructor (


ChecksumCommonTables (AcpiTableInstance);



+ InstallAcpiTableFromHob (AcpiTableInstance);

+

//

// Completed successfully

//

--
2.30.0.windows.2


Re: [edk2-platforms][PATCH v2 00/35] Consolidate SpiFlashCommonLib instances

Nate DeSimone
 

Hi Michael,

I have been thinking about this more from a long-term maintainability standpoint. The IFWI region enum FLASH_REGION_TYPE looks pretty ripe for causing issues years from now. We should probably convert each member of that enum into a EFI_GUID so that regions can be added/removed as needed. Some of those enum types probably don't belong in IntelSiliconPkg either, like FlashRegion10Gbe_B for example.

Thanks,
Nate

-----Original Message-----
From: mikuback@linux.microsoft.com <mikuback@linux.microsoft.com>
Sent: Tuesday, May 18, 2021 8:59 PM
To: devel@edk2.groups.io
Cc: Agyeman, Prince <prince.agyeman@intel.com>; Chiu, Chasel <chasel.chiu@intel.com>; Kethi Reddy, Deepika <deepika.kethi.reddy@intel.com>; Dong, Eric <eric.dong@intel.com>; Luo, Heng <heng.luo@intel.com>; Jeremy Soller <jeremy@system76.com>; Esakkithevar, Kathappan <kathappan.esakkithevar@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>; Desimone, Nathaniel L <nathaniel.l.desimone@intel.com>; Chaganty, Rangasai V <rangasai.v.chaganty@intel.com>
Subject: [edk2-platforms][PATCH v2 00/35] Consolidate SpiFlashCommonLib instances

From: Michael Kubacki <michael.kubacki@microsoft.com>

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3307

SpiFlashCommonLib is duplicated in multiple places across the MinPlatform design in edk2-platforms. I'm planning to build some additional functionality on top of SpiFlashCommonLib and, ideally, this duplication will be consolidated into a single instance usable across all current library consumers.

This patch series focuses on consolidating the various SpiFlashCommonLib instances as agreed upon in https://edk2.groups.io/g/devel/message/71701.

Read the BZ for more general background around this series.

I only have an UpXtreme board on hand so maintainers/reviewers of other board packages should test these changes on those boards.

V2 changes:
- Rebased patch series on current edk2-platforms master (32183bdaa91)

Note: Patch series only received a couple review comments after being on the mailing list for over 1 month. Please be more prompt with v2.

Cc: Agyeman Prince <prince.agyeman@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Cc: Deepika Kethi Reddy <deepika.kethi.reddy@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Heng Luo <heng.luo@intel.com>
Cc: Jeremy Soller <jeremy@system76.com>
Cc: Kathappan Esakkithevar <kathappan.esakkithevar@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@intel.com>
Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>

Michael Kubacki (35):
CometlakeOpenBoardPkg: Remove redundant IntelSiliconPkg.dec entry
WhiskeylakeOpenBoardPkg: Remove redundant IntelSiliconPkg.dec entry
CometlakeOpenBoardPkg/PeiPolicyUpdateLib: Add missing GUID to INF
IntelSiliconPkg: Add BIOS area base address and size PCDs
IntelSiliconPkg: Add microcode FV PCDs
IntelSiliconPkg: Add PCH SPI PPI
IntelSiliconPkg: Add PCH SPI Protocol
IntelSiliconPkg: Add SpiFlashCommonLib
IntelSiliconPkg: Add SmmSpiFlashCommonLib
IntelSiliconPkg: Add MM SPI FVB services
CometlakeOpenBoardPkg: Use IntelSiliconPkg BIOS area and ucode PCDs
KabylakeOpenBoardPkg: Use IntelSiliconPkg BIOS area and ucode PCDs
SimicsOpenBoardPkg: Use IntelSiliconPkg BIOS area and ucode PCDs
TigerlakeOpenBoardPkg: Use IntelSiliconPkg BIOS area and ucode PCDs
WhiskeylakeOpenBoardPkg: Use IntelSiliconPkg BIOS area and ucode PCDs
CoffeelakeSiliconPkg: Use IntelSiliconPkg BIOS area and ucode PCDs
KabylakeSiliconPkg: Use IntelSiliconPkg BIOS area and ucode PCDs
SimicsIch10Pkg: Use IntelSiliconPkg BIOS area and ucode PCDs
TigerlakeSiliconPkg: Use IntelSiliconPkg BIOS are and ucode PCDs
CometlakeOpenBoardPkg: Update SpiFvbService & SpiFlashCommonLib
KabylakeOpenBoardPkg: Update SpiFvbService & SpiFlashCommonLib
SimicsOpenBoardPkg: Update SpiFvbService & SpiFlashCommonLib
TigerlakeOpenBoardPkg: Update SpiFvbService & SpiFlashCommonLib
WhiskeylakeOpenBoardPkg: Update SpiFvbService & SpiFlashCommonLib
MinPlatformPkg: Remove SpiFvbService modules
CoffeelakeSiliconPkg: Remove SmmSpiFlashCommonLib
KabylakeSiliconPkg: Remove SmmSpiFlashCommonLib
SimicsIch10Pkg: Remove SmmSpiFlashCommonLib
TigerlakeOpenBoardPkg: Remove SmmSpiFlashCommonLib
MinPlatformPkg: Remove SpiFlashCommonLibNull
KabylakeOpenBoardPkg/PeiSerialPortLibSpiFlash: Add IntelSiliconPkg.dec
CoffeelakeSiliconPkg: Remove PCH SPI PPI and Protocol from package
KabylakeSiliconPkg: Remove PCH SPI PPI and Protocol from package
SimicsIch10Pkg: Remove PCH SPI SMM Protocol from package
TigerlakeSiliconPkg: Remove PCH SPI PPI and Protocol from package

Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommon.c | 196 -------------
Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommonSmmLib.c | 54 ----
{Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/FvbInfo.c | 0
{Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceCommon.c | 4 +-
{Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceMm.c | 8 +-
{Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceStandaloneMm.c | 0
{Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceTraditionalMm.c | 0
Platform/Intel/TigerlakeOpenBoardPkg/Library/SmmSpiFlashCommonLib/SpiFlashCommonSmmLib.c => Silicon/Intel/IntelSiliconPkg/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.c | 0
{Platform/Intel/TigerlakeOpenBoardPkg => Silicon/Intel/IntelSiliconPkg}/Library/SmmSpiFlashCommonLib/SpiFlashCommon.c | 3 +-
{Platform/Intel/MinPlatformPkg/Flash => Silicon/Intel/IntelSiliconPkg}/Library/SpiFlashCommonLibNull/SpiFlashCommonLibNull.c | 12 +-
Silicon/Intel/KabylakeSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommon.c | 196 -------------
Silicon/Intel/KabylakeSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommonSmmLib.c | 54 ----
Silicon/Intel/SimicsIch10Pkg/Library/SmmSpiFlashCommonLib/SpiFlashCommon.c | 194 -------------
Silicon/Intel/SimicsIch10Pkg/Library/SmmSpiFlashCommonLib/SpiFlashCommonSmmLib.c | 54 ----
Silicon/Intel/SimicsIch10Pkg/LibraryPrivate/BasePchSpiCommonLib/SpiCommon.c | 26 +-
Silicon/Intel/SimicsIch10Pkg/Spi/Smm/PchSpi.c | 4 +-
Platform/Intel/CometlakeOpenBoardPkg/BiosInfo/BiosInfo.inf | 4 +-
Platform/Intel/CometlakeOpenBoardPkg/CometlakeURvp/Include/Fdf/FlashMapInclude.fdf | 4 +-
Platform/Intel/CometlakeOpenBoardPkg/CometlakeURvp/OpenBoardPkg.dsc | 7 +-
Platform/Intel/CometlakeOpenBoardPkg/CometlakeURvp/OpenBoardPkg.fdf | 38 +--
Platform/Intel/CometlakeOpenBoardPkg/Policy/Library/PeiPolicyUpdateLib/PeiPolicyUpdateLib.inf | 2 +-
Platform/Intel/CometlakeOpenBoardPkg/Policy/PolicyInitDxe/PolicyInitDxe.inf | 4 +-
Platform/Intel/KabylakeOpenBoardPkg/BiosInfo/BiosInfo.inf | 4 +-
Platform/Intel/KabylakeOpenBoardPkg/GalagoPro3/Include/Fdf/FlashMapInclude.fdf | 4 +-
Platform/Intel/KabylakeOpenBoardPkg/GalagoPro3/OpenBoardPkg.dsc | 7 +-
Platform/Intel/KabylakeOpenBoardPkg/GalagoPro3/OpenBoardPkg.fdf | 40 +--
Platform/Intel/KabylakeOpenBoardPkg/KabylakeRvp3/Include/Fdf/FlashMapInclude.fdf | 4 +-
Platform/Intel/KabylakeOpenBoardPkg/KabylakeRvp3/OpenBoardPkg.dsc | 7 +-
Platform/Intel/KabylakeOpenBoardPkg/KabylakeRvp3/OpenBoardPkg.fdf | 40 +--
Platform/Intel/KabylakeOpenBoardPkg/KabylakeRvp3/Policy/Library/PeiSiliconPolicyUpdateLib/PeiSiliconPolicyUpdateLib.inf | 4 +-
Platform/Intel/KabylakeOpenBoardPkg/Library/PeiSerialPortLibSpiFlash/PeiSerialPortLibSpiFlash.inf | 1 +
Platform/Intel/MinPlatformPkg/Include/Library/SpiFlashCommonLib.h | 98 -------
Platform/Intel/MinPlatformPkg/MinPlatformPkg.dec | 2 -
Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc | 6 -
Platform/Intel/SimicsOpenBoardPkg/BoardX58Ich10/OpenBoardPkg.dsc | 6 +-
Platform/Intel/SimicsOpenBoardPkg/BoardX58Ich10/OpenBoardPkg.fdf | 2 +-
Platform/Intel/SimicsOpenBoardPkg/BoardX58Ich10/OpenBoardPkg.fdf.inc | 8 +-
Platform/Intel/TigerlakeOpenBoardPkg/BiosInfo/BiosInfo.inf | 8 +-
Platform/Intel/TigerlakeOpenBoardPkg/TigerlakeURvp/Include/Fdf/FlashMapInclude.fdf | 4 +-
Platform/Intel/TigerlakeOpenBoardPkg/TigerlakeURvp/OpenBoardPkg.dsc | 7 +-
Platform/Intel/TigerlakeOpenBoardPkg/TigerlakeURvp/OpenBoardPkg.fdf | 40 +--
Platform/Intel/WhiskeylakeOpenBoardPkg/BiosInfo/BiosInfo.inf | 4 +-
Platform/Intel/WhiskeylakeOpenBoardPkg/Policy/Library/PeiPolicyUpdateLib/PeiPolicyUpdateLib.inf | 1 -
Platform/Intel/WhiskeylakeOpenBoardPkg/Policy/PolicyInitDxe/PolicyInitDxe.inf | 4 +-
Platform/Intel/WhiskeylakeOpenBoardPkg/UpXtreme/Include/Fdf/FlashMapInclude.fdf | 4 +-
Platform/Intel/WhiskeylakeOpenBoardPkg/UpXtreme/Library/BoardInitLib/PeiMultiBoardInitPreMemLib.inf | 2 +-
Platform/Intel/WhiskeylakeOpenBoardPkg/UpXtreme/OpenBoardPkg.dsc | 7 +-
Platform/Intel/WhiskeylakeOpenBoardPkg/UpXtreme/OpenBoardPkg.fdf | 38 +--
Platform/Intel/WhiskeylakeOpenBoardPkg/WhiskeylakeURvp/Include/Fdf/FlashMapInclude.fdf | 4 +-
Platform/Intel/WhiskeylakeOpenBoardPkg/WhiskeylakeURvp/OpenBoardPkg.dsc | 7 +-
Platform/Intel/WhiskeylakeOpenBoardPkg/WhiskeylakeURvp/OpenBoardPkg.fdf | 38 +--
Silicon/Intel/CoffeelakeSiliconPkg/Cpu/Library/PeiCpuPolicyLib/PeiCpuPolicyLib.inf | 4 +-
Silicon/Intel/CoffeelakeSiliconPkg/Pch/Include/Protocol/Spi.h | 295 --------------------
Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/PeiSpiLib/PeiSpiLib.inf | 1 +
Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/BasePchSpiCommonLib/BasePchSpiCommonLib.inf | 1 +
Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.inf | 51 ----
Silicon/Intel/CoffeelakeSiliconPkg/Pch/Spi/Smm/PchSpiSmm.inf | 1 +
Silicon/Intel/CoffeelakeSiliconPkg/SiPkg.dec | 8 -
{Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceCommon.h | 0
{Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceMm.h | 0
{Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceSmm.inf | 6 +-
{Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceStandaloneMm.inf | 6 +-
Silicon/Intel/{CoffeelakeSiliconPkg/Pch => IntelSiliconPkg}/Include/Library/SpiFlashCommonLib.h | 2 +-
Silicon/Intel/{CoffeelakeSiliconPkg/Pch => IntelSiliconPkg}/Include/Ppi/Spi.h | 4 +-
Silicon/Intel/{TigerlakeSiliconPkg => IntelSiliconPkg}/Include/Protocol/Spi.h | 0
Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dec | 19 ++
Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dsc | 17 ++
{Platform/Intel/TigerlakeOpenBoardPkg => Silicon/Intel/IntelSiliconPkg}/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.inf | 21 +-
{Platform/Intel/MinPlatformPkg/Flash => Silicon/Intel/IntelSiliconPkg}/Library/SpiFlashCommonLibNull/SpiFlashCommonLibNull.inf | 3 +-
Silicon/Intel/KabylakeSiliconPkg/Cpu/Library/PeiCpuPolicyLib/PeiCpuPolicyLib.inf | 4 +-
Silicon/Intel/KabylakeSiliconPkg/Hsti/Dxe/HstiSiliconDxe.inf | 3 +-
Silicon/Intel/KabylakeSiliconPkg/Pch/Include/Library/SpiFlashCommonLib.h | 98 -------
Silicon/Intel/KabylakeSiliconPkg/Pch/Include/Ppi/Spi.h | 26 --
Silicon/Intel/KabylakeSiliconPkg/Pch/Include/Protocol/Spi.h | 293 -------------------
Silicon/Intel/KabylakeSiliconPkg/Pch/Library/PeiSpiLib/PeiSpiLib.inf | 1 +
Silicon/Intel/KabylakeSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.inf | 53 ----
Silicon/Intel/KabylakeSiliconPkg/Pch/Spi/Smm/PchSpiSmm.inf | 1 +
Silicon/Intel/KabylakeSiliconPkg/SiPkg.dec | 13 +-
Silicon/Intel/SimicsIch10Pkg/Ich10Pkg.dec | 11 -
Silicon/Intel/SimicsIch10Pkg/Include/Library/SpiFlashCommonLib.h | 98 -------
Silicon/Intel/SimicsIch10Pkg/Include/Protocol/Spi.h | 295 --------------------
Silicon/Intel/SimicsIch10Pkg/IncludePrivate/Library/PchSpiCommonLib.h | 26 +-
Silicon/Intel/SimicsIch10Pkg/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.inf | 50 ----
Silicon/Intel/SimicsIch10Pkg/LibraryPrivate/BasePchSpiCommonLib/BasePchSpiCommonLib.inf | 5 +-
Silicon/Intel/SimicsIch10Pkg/Spi/Smm/PchSpiSmm.inf | 3 +-
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Spi/LibraryPrivate/BaseSpiCommonLib/BaseSpiCommonLib.inf | 1 +
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Spi/Smm/SpiSmm.inf | 1 +
Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf | 1 +
Silicon/Intel/TigerlakeSiliconPkg/SiPkg.dec | 8 -
89 files changed, 303 insertions(+), 2392 deletions(-) delete mode 100644 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommon.c
delete mode 100644 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommonSmmLib.c
rename {Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/FvbInfo.c (100%) rename {Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceCommon.c (96%) rename {Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceMm.c (94%) rename {Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceStandaloneMm.c (100%) rename {Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceTraditionalMm.c (100%) rename Platform/Intel/TigerlakeOpenBoardPkg/Library/SmmSpiFlashCommonLib/SpiFlashCommonSmmLib.c => Silicon/Intel/IntelSiliconPkg/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.c (100%) rename {Platform/Intel/TigerlakeOpenBoardPkg => Silicon/Intel/IntelSiliconPkg}/Library/SmmSpiFlashCommonLib/SpiFlashCommon.c (95%) rename {Platform/Intel/MinPlatformPkg/Flash => Silicon/Intel/IntelSiliconPkg}/Library/SpiFlashCommonLibNull/SpiFlashCommonLibNull.c (83%) delete mode 100644 Silicon/Intel/KabylakeSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommon.c
delete mode 100644 Silicon/Intel/KabylakeSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommonSmmLib.c
delete mode 100644 Silicon/Intel/SimicsIch10Pkg/Library/SmmSpiFlashCommonLib/SpiFlashCommon.c
delete mode 100644 Silicon/Intel/SimicsIch10Pkg/Library/SmmSpiFlashCommonLib/SpiFlashCommonSmmLib.c
delete mode 100644 Platform/Intel/MinPlatformPkg/Include/Library/SpiFlashCommonLib.h
delete mode 100644 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Include/Protocol/Spi.h
delete mode 100644 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.inf
rename {Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceCommon.h (100%) rename {Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceMm.h (100%) rename {Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceSmm.inf (88%) rename {Platform/Intel/MinPlatformPkg => Silicon/Intel/IntelSiliconPkg/Feature}/Flash/SpiFvbService/SpiFvbServiceStandaloneMm.inf (88%) rename Silicon/Intel/{CoffeelakeSiliconPkg/Pch => IntelSiliconPkg}/Include/Library/SpiFlashCommonLib.h (96%) rename Silicon/Intel/{CoffeelakeSiliconPkg/Pch => IntelSiliconPkg}/Include/Ppi/Spi.h (85%) rename Silicon/Intel/{TigerlakeSiliconPkg => IntelSiliconPkg}/Include/Protocol/Spi.h (100%) rename {Platform/Intel/TigerlakeOpenBoardPkg => Silicon/Intel/IntelSiliconPkg}/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.inf (69%) rename {Platform/Intel/MinPlatformPkg/Flash => Silicon/Intel/IntelSiliconPkg}/Library/SpiFlashCommonLibNull/SpiFlashCommonLibNull.inf (91%) delete mode 100644 Silicon/Intel/KabylakeSiliconPkg/Pch/Include/Library/SpiFlashCommonLib.h
delete mode 100644 Silicon/Intel/KabylakeSiliconPkg/Pch/Include/Ppi/Spi.h
delete mode 100644 Silicon/Intel/KabylakeSiliconPkg/Pch/Include/Protocol/Spi.h
delete mode 100644 Silicon/Intel/KabylakeSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.inf
delete mode 100644 Silicon/Intel/SimicsIch10Pkg/Include/Library/SpiFlashCommonLib.h
delete mode 100644 Silicon/Intel/SimicsIch10Pkg/Include/Protocol/Spi.h
delete mode 100644 Silicon/Intel/SimicsIch10Pkg/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.inf

--
2.28.0.windows.1


[PATCH RFC v3 22/22] MdePkg/GHCB: increase the GHCB protocol max version

Brijesh Singh
 

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: 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: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.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 4d1ee29e0a5e..191fd0876060 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


[PATCH RFC v3 21/22] UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs

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: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 3 +
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 5 +-
UefiCpuPkg/Library/MpInitLib/MpLib.h | 17 ++
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 11 +-
.../MpInitLib/Ia32/SevSnpRmpAdjustInternal.c | 31 ++
UefiCpuPkg/Library/MpInitLib/MpLib.c | 274 ++++++++++++++++--
.../MpInitLib/X64/SevSnpRmpAdjustInternal.c | 44 +++
7 files changed, 360 insertions(+), 25 deletions(-)
create mode 100644 UefiCpuPkg/Library/MpInitLib/Ia32/SevSnpRmpAdjustInternal.c
create mode 100644 UefiCpuPkg/Library/MpInitLib/X64/SevSnpRmpAdjustInternal.c

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index 48d7dfa4450f..b9ce05e81b54 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -23,9 +23,11 @@ [Defines]

[Sources.IA32]
Ia32/MpFuncs.nasm
+ Ia32/SevSnpRmpAdjustInternal.c

[Sources.X64]
X64/MpFuncs.nasm
+ X64/SevSnpRmpAdjustInternal.c

[Sources.common]
MpEqu.inc
@@ -72,6 +74,7 @@ [Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index ab8279df596f..35057ac07cbb 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -23,9 +23,11 @@ [Defines]

[Sources.IA32]
Ia32/MpFuncs.nasm
+ Ia32/SevSnpRmpAdjustInternal.c

[Sources.X64]
X64/MpFuncs.nasm
+ X64/SevSnpRmpAdjustInternal.c

[Sources.common]
MpEqu.inc
@@ -62,10 +64,11 @@ [Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ## SOMETIMES_CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdSevSnpIsEnabled ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES

[Ppis]
gEdkiiPeiShadowMicrocodePpiGuid ## SOMETIMES_CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 4abaa2243d0a..b49a60ac0ce5 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>
@@ -146,6 +147,7 @@ typedef struct {
UINT8 PlatformId;
UINT64 MicrocodeEntryAddr;
UINT32 MicrocodeRevision;
+ SEV_ES_SAVE_AREA *SevEsSaveArea;
} CPU_AP_DATA;

//
@@ -289,6 +291,7 @@ struct _CPU_MP_DATA {

BOOLEAN SevEsIsEnabled;
BOOLEAN SevSnpIsEnabled;
+ BOOLEAN UseSevEsAPMethod;
UINTN SevEsAPBuffer;
UINTN SevEsAPResetStackStart;
CPU_MP_DATA *NewCpuMpData;
@@ -743,5 +746,19 @@ PlatformShadowMicrocode (
IN OUT CPU_MP_DATA *CpuMpData
);

+/**
+ Issue RMPADJUST to adjust the attributes 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
+ );
+
#endif

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 7839c249760e..1e3e71766611 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -88,7 +88,12 @@ GetWakeupBuffer (
EFI_PHYSICAL_ADDRESS StartAddress;
EFI_MEMORY_TYPE MemoryType;

- if (PcdGetBool (PcdSevEsIsEnabled)) {
+ //
+ // 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.
+ //
+ if (PcdGetBool (PcdSevEsIsEnabled) && !PcdGetBool (PcdSevSnpIsEnabled)) {
MemoryType = EfiReservedMemoryType;
} else {
MemoryType = EfiBootServicesData;
@@ -356,7 +361,7 @@ RelocateApLoop (
MpInitLibWhoAmI (&ProcessorNumber);
CpuMpData = GetCpuMpData ();
MwaitSupport = IsMwaitSupport ();
- if (CpuMpData->SevEsIsEnabled) {
+ if (CpuMpData->UseSevEsAPMethod) {
StackStart = CpuMpData->SevEsAPResetStackStart;
} else {
StackStart = mReservedTopOfApStack;
@@ -405,7 +410,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/SevSnpRmpAdjustInternal.c b/UefiCpuPkg/Library/MpInitLib/Ia32/SevSnpRmpAdjustInternal.c
new file mode 100644
index 000000000000..167628b696f2
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/Ia32/SevSnpRmpAdjustInternal.c
@@ -0,0 +1,31 @@
+/** @file
+
+ RMPADJUST helper function.
+
+ Copyright (c) 2021, AMD Incorporated. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+/**
+ Issue RMPADJUST to adjust the attributes 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 7cbcce101414..5a06e21a2830 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -15,7 +15,6 @@

EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;

-
/**
The function will check if BSP Execute Disable is enabled.

@@ -297,8 +296,8 @@ GetApLoopMode (

if (PcdGetBool (PcdSevEsIsEnabled)) {
//
- // 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 +868,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 +882,7 @@ ApWakeupFunction (
//
while (TRUE) {
DisableInterrupts ();
- if (CpuMpData->SevEsIsEnabled) {
+ if (CpuMpData->UseSevEsAPMethod) {
MSR_SEV_ES_GHCB_REGISTER Msr;
GHCB *Ghcb;
UINT64 Status;
@@ -1167,9 +1166,11 @@ GetApResetVectorSize (

//
// The AP reset stack is only used by SEV-ES guests. Do not add to the
- // allocation if SEV-ES is not enabled.
+ // allocation 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 (PcdGetBool (PcdSevEsIsEnabled)) {
+ if (PcdGetBool (PcdSevEsIsEnabled) && !PcdGetBool (PcdSevSnpIsEnabled)) {
//
// Stack location is based on APIC ID, so use the total number of
// processors for calculating the total stack area.
@@ -1231,7 +1232,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);
}
}
@@ -1248,7 +1249,7 @@ AllocateSevEsAPMemory (
{
if (CpuMpData->SevEsAPBuffer == (UINTN) -1) {
CpuMpData->SevEsAPBuffer =
- CpuMpData->SevEsIsEnabled ? GetSevEsAPMemory () : 0;
+ CpuMpData->UseSevEsAPMethod ? GetSevEsAPMemory () : 0;
}
}

@@ -1301,6 +1302,222 @@ SetSevEsJumpTable (
JmpFar->Segment = (UINT16) (SipiVector >> 4);
}

+/**
+ 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
+**/
+STATIC
+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)
+**/
+STATIC
+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);
+ }
+}
+
/**
This function will be called by BSP to wakeup AP.

@@ -1332,7 +1549,7 @@ WakeUpAP (
ResetVectorRequired = FALSE;

if (CpuMpData->WakeUpByInitSipiSipi ||
- CpuMpData->InitFlag != ApInitDone) {
+ CpuMpData->InitFlag != ApInitDone) {
ResetVectorRequired = TRUE;
AllocateResetVector (CpuMpData);
AllocateSevEsAPMemory (CpuMpData);
@@ -1373,7 +1590,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.
//
@@ -1383,8 +1600,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) {
@@ -1474,7 +1697,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.
//
@@ -1482,10 +1705,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
@@ -2016,10 +2243,15 @@ MpInitLibInitialize (
CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);
CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
InitializeSpinLock(&CpuMpData->MpLock);
- CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
- CpuMpData->SevSnpIsEnabled = PcdGetBool (PcdSevSnpIsEnabled);
- CpuMpData->SevEsAPBuffer = (UINTN) -1;
- CpuMpData->GhcbBase = PcdGet64 (PcdGhcbBase);
+ CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
+ CpuMpData->SevSnpIsEnabled = PcdGetBool (PcdSevSnpIsEnabled);
+ 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/SevSnpRmpAdjustInternal.c b/UefiCpuPkg/Library/MpInitLib/X64/SevSnpRmpAdjustInternal.c
new file mode 100644
index 000000000000..0716a4623e38
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/X64/SevSnpRmpAdjustInternal.c
@@ -0,0 +1,44 @@
+/** @file
+
+ RMPADJUST helper function.
+
+ Copyright (c) 2021, AMD Incorporated. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+/**
+ Issue RMPADJUST to adjust the attributes 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;
+ UINT8 Vmpl;
+ UINT8 PermissionMask;
+
+ //
+ // Use the highest VMPL level.
+ //
+ PermissionMask = 0;
+ Vmpl = RMPADJUST_VMPL_MAX;
+
+ Rdx = (Vmpl & RMPADJUST_VMPL_MASK) << RMPADJUST_VMPL_SHIFT;
+ Rdx |= (PermissionMask & RMPADJUST_PERMISSION_MASK_MASK) << RMPADJUST_PERMISSION_MASK_SHIFT;
+ if (VmsaPage) {
+ Rdx |= RMPADJUST_VMSA_PAGE_BIT;
+ }
+
+ return AsmRmpAdjust ((UINT64) PageAddress, 0, Rdx);
+}
--
2.17.1


[PATCH RFC v3 20/22] OvmfPkg/AmdSev: expose the SNP reserved pages through configuration table

Brijesh Singh
 

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: 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: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
OvmfPkg/OvmfPkg.dec | 1 +
OvmfPkg/AmdSev/SecretDxe/SecretDxe.inf | 4 ++++
.../Guid/ConfidentialComputingSecret.h | 18 +++++++++++++++
OvmfPkg/AmdSev/SecretDxe/SecretDxe.c | 22 +++++++++++++++++++
4 files changed, 45 insertions(+)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 4da2d2de9df0..89476c6a68d2 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -126,6 +126,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}}
+ gConfidentialComputingBlobGuid = {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/AmdSev/SecretDxe/SecretDxe.inf b/OvmfPkg/AmdSev/SecretDxe/SecretDxe.inf
index 40bda7ff846c..d15194b368f5 100644
--- a/OvmfPkg/AmdSev/SecretDxe/SecretDxe.inf
+++ b/OvmfPkg/AmdSev/SecretDxe/SecretDxe.inf
@@ -23,13 +23,17 @@ [Packages]
MdePkg/MdePkg.dec

[LibraryClasses]
+ MemEncryptSevLib
UefiBootServicesTableLib
UefiDriverEntryPoint

[Guids]
gConfidentialComputingSecretGuid
+ gConfidentialComputingBlobGuid

[FixedPcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidSize
gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretBase
gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretSize

diff --git a/OvmfPkg/Include/Guid/ConfidentialComputingSecret.h b/OvmfPkg/Include/Guid/ConfidentialComputingSecret.h
index 7026fc5b089f..aa1a3b015437 100644
--- a/OvmfPkg/Include/Guid/ConfidentialComputingSecret.h
+++ b/OvmfPkg/Include/Guid/ConfidentialComputingSecret.h
@@ -18,11 +18,29 @@
{ 0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47 }, \
}

+#define CONFIDENTIAL_COMPUTING_BLOB_GUID \
+ { 0x067b1f5f, \
+ 0xcf26, \
+ 0x44c5, \
+ { 0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42 }, \
+ }
+
typedef struct {
UINT64 Base;
UINT64 Size;
} CONFIDENTIAL_COMPUTING_SECRET_LOCATION;

+typedef struct {
+ UINT32 Header;
+ UINT16 Version;
+ UINT16 Reserved1;
+ UINT64 SecretsPhysicalAddress;
+ UINT32 SecretsSize;
+ UINT64 CpuidPhysicalAddress;
+ UINT32 CpuidLSize;
+} CONFIDENTIAL_COMPUTING_BLOB_LOCATION;
+
extern EFI_GUID gConfidentialComputingSecretGuid;
+extern EFI_GUID gConfidentialComputingBlobGuid;

#endif // SEV_LAUNCH_SECRET_H_
diff --git a/OvmfPkg/AmdSev/SecretDxe/SecretDxe.c b/OvmfPkg/AmdSev/SecretDxe/SecretDxe.c
index 308022b5b25e..0c0f511d4ca0 100644
--- a/OvmfPkg/AmdSev/SecretDxe/SecretDxe.c
+++ b/OvmfPkg/AmdSev/SecretDxe/SecretDxe.c
@@ -6,6 +6,7 @@
**/
#include <PiDxe.h>
#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemEncryptSevLib.h>
#include <Guid/ConfidentialComputingSecret.h>

STATIC CONFIDENTIAL_COMPUTING_SECRET_LOCATION mSecretDxeTable = {
@@ -13,6 +14,16 @@ STATIC CONFIDENTIAL_COMPUTING_SECRET_LOCATION mSecretDxeTable = {
FixedPcdGet32 (PcdSevLaunchSecretSize),
};

+STATIC CONFIDENTIAL_COMPUTING_BLOB_LOCATION mSnpBootDxeTable = {
+ SIGNATURE_32('A','M','D','E'),
+ 1,
+ 0,
+ (UINT64)(UINTN) FixedPcdGet32 (PcdSevLaunchSecretBase),
+ FixedPcdGet32 (PcdSevLaunchSecretSize),
+ (UINT64)(UINTN) FixedPcdGet32 (PcdOvmfSnpCpuidBase),
+ FixedPcdGet32 (PcdOvmfSnpCpuidSize),
+};
+
EFI_STATUS
EFIAPI
InitializeSecretDxe(
@@ -20,6 +31,17 @@ InitializeSecretDxe(
IN EFI_SYSTEM_TABLE *SystemTable
)
{
+ //
+ // If its SEV-SNP active guest then install the CONFIDENTIAL_COMPUTING_BLOB.
+ // It contains the location for both the Secrets and CPUID page.
+ //
+ if (MemEncryptSevSnpIsEnabled ()) {
+ return gBS->InstallConfigurationTable (
+ &gConfidentialComputingBlobGuid,
+ &mSnpBootDxeTable
+ );
+ }
+
return gBS->InstallConfigurationTable (
&gConfidentialComputingSecretGuid,
&mSecretDxeTable
--
2.17.1


[PATCH RFC v3 19/22] OvmfPkg/MemEncryptSevLib: skip page state change for Mmio address

Brijesh Singh
 

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: 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: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.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


[PATCH RFC v3 18/22] OvmfPkg/MemEncryptSevLib: Change the page state in the RMP table

Brijesh Singh
 

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: 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: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.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


[PATCH RFC v3 17/22] OvmfPkg/PlatformPei: validate the system RAM when SNP is active

Brijesh Singh
 

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: 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: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
OvmfPkg/PlatformPei/AmdSev.c | 33 +++++++++++++++++++++++++++------
1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 54b07622b4dd..9a20165db79e 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -34,7 +34,9 @@ AmdSevSnpInitialize (
VOID
)
{
- RETURN_STATUS PcdStatus;
+ RETURN_STATUS PcdStatus;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;

if (!MemEncryptSevSnpIsEnabled ()) {
return;
@@ -42,6 +44,22 @@ AmdSevSnpInitialize (

PcdStatus = PcdSetBoolS (PcdSevSnpIsEnabled, TRUE);
ASSERT_RETURN_ERROR (PcdStatus);
+
+ //
+ // 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)
+ );
+ }
+ }
+ }
}

/**
@@ -204,6 +222,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 current page table. 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
//
@@ -264,9 +290,4 @@ AmdSevInitialize (
// Check and perform SEV-ES initialization if required.
//
AmdSevEsInitialize ();
-
- //
- // Check and perform SEV-SNP initialization if required.
- //
- AmdSevSnpInitialize ();
}
--
2.17.1


[PATCH RFC v3 16/22] OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv

Brijesh Singh
 

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: 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: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
OvmfPkg/OvmfPkg.dec | 5 ++++
.../PeiMemEncryptSevLib.inf | 2 ++
OvmfPkg/Sec/SecMain.inf | 3 +++
.../X64/PeiSnpSystemRamValidate.c | 5 ++++
OvmfPkg/Sec/SecMain.c | 27 +++++++++++++++++++
OvmfPkg/FvmainCompactScratchEnd.fdf.inc | 5 ++++
6 files changed, 47 insertions(+)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 3886d43bd3de..4da2d2de9df0 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -336,6 +336,11 @@ [PcdsFixedAtBuild]
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedStart|0x0|UINT32|0x49
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedEnd|0x0|UINT32|0x50

+ ## 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|0x51
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd|0|UINT32|0x52
+
[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 f4058911e7b6..2b60920f4b25 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
@@ -58,5 +58,7 @@ [FeaturePcd]

[FixedPcd]
gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedStart
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedEnd
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedStart
diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index 7f78dcee2772..8144b1d115cf 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -50,6 +50,7 @@ [LibraryClasses]
PeCoffExtraActionLib
ExtractGuidedSectionLib
LocalApicLib
+ MemEncryptSevLib
CpuExceptionHandlerLib

[Ppis]
@@ -70,6 +71,8 @@ [Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd
gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedStart
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd

[FeaturePcd]
gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
index 69ffb79633c4..253d42073907 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
@@ -27,6 +27,11 @@ STATIC SNP_PRE_VALIDATED_RANGE mPreValidatedRange[] = {
{
FixedPcdGet32 (PcdOvmfSnpHypervisorPreValidatedStart),
FixedPcdGet32 (PcdOvmfSnpHypervisorPreValidatedEnd)
+ },
+ // This range is pre-validated by the Sec/SecMain.c
+ {
+ FixedPcdGet32 (PcdOvmfSnpSecPreValidatedStart),
+ FixedPcdGet32 (PcdOvmfSnpSecPreValidatedEnd)
}
};

diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index faa6891cca79..532574fa3095 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -910,6 +910,26 @@ SevEsIsEnabled (
return ((SevEsWorkArea != NULL) && (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.
+
+**/
+STATIC
+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));
+}
+
VOID
EFIAPI
SecCoreStartupWithStack (
@@ -1041,6 +1061,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


[PATCH RFC v3 15/22] OvmfPkg/MemEncryptSevLib: add support to validate > 4GB memory in PEI phase

Brijesh Singh
 

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: 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: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.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 3e692a3b869d..69ffb79633c4 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;
@@ -68,6 +71,7 @@ MemEncryptSevSnpPreValidateSystemRam (
{
PHYSICAL_ADDRESS EndAddress;
SNP_PRE_VALIDATED_RANGE OverlapRange;
+ EFI_STATUS Status;

if (!MemEncryptSevSnpIsEnabled ()) {
return;
@@ -75,6 +79,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


[PATCH RFC v3 14/22] OvmfPkg/BaseMemEncryptSevLib: skip the pre-validated system RAM

Brijesh Singh
 

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: 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: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
.../PeiMemEncryptSevLib.inf | 2 +
.../X64/PeiSnpSystemRamValidate.c | 65 ++++++++++++++++++-
2 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
index 0402e49a1028..f4058911e7b6 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
@@ -58,3 +58,5 @@ [FeaturePcd]

[FixedPcd]
gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedEnd
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedStart
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
index 64aab7f45b6d..3e692a3b869d 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
@@ -14,6 +14,44 @@

#include "SnpPageStateChange.h"

+typedef struct {
+ UINT64 StartAddress;
+ UINT64 EndAddress;
+} SNP_PRE_VALIDATED_RANGE;
+
+STATIC SNP_PRE_VALIDATED_RANGE mPreValidatedRange[] = {
+ // This range is pre-validated by the Hypervisor.
+ {
+ FixedPcdGet32 (PcdOvmfSnpHypervisorPreValidatedStart),
+ FixedPcdGet32 (PcdOvmfSnpHypervisorPreValidatedEnd)
+ }
+};
+
+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 +66,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


[PATCH RFC v3 13/22] OvmfPkg/MemEncryptSevLib: add support to validate system RAM

Brijesh Singh
 

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: 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: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.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 | 230 ++++++++++++++++++
12 files changed, 415 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 7cbef8e82282..9ffe9e3159d4 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -267,6 +267,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 75f87d311454..aeb603d87f13 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -271,6 +271,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 dd1c97d4a9a3..eec80474c8fb 100644
--- a/OvmfPkg/Include/Library/MemEncryptSevLib.h
+++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h
@@ -237,4 +237,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..fb8b50eab661
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c
@@ -0,0 +1,230 @@
+/** @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 ();
+ }
+ }
+}
+
+/**
+ 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
+ )
+{
+ EFI_STATUS Status;
+ GHCB *Ghcb;
+ EFI_PHYSICAL_ADDRESS NextAddress, EndAddress;
+ MSR_SEV_ES_GHCB_REGISTER Msr;
+ BOOLEAN InterruptState;
+ SNP_PAGE_STATE_CHANGE_INFO *Info;
+ UINTN i, RmpPageSize;
+
+ 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
+ ));
+
+ for (; BaseAddress < EndAddress; BaseAddress = NextAddress) {
+ //
+ // Initialize the GHCB and setup scratch sw to point to shared buffer.
+ //
+ VmgInit (Ghcb, &InterruptState);
+ Info = (SNP_PAGE_STATE_CHANGE_INFO *) Ghcb->SharedBuffer;
+
+ SetMem (Info, sizeof (*Info), 0);
+
+ //
+ // Build page state change buffer
+ //
+ for (i = 0; (EndAddress > BaseAddress) && i < SNP_PAGE_STATE_MAX_ENTRY;
+ BaseAddress = NextAddress, i++) {
+ //
+ // 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.CurrentEntry = 0;
+ Info->Header.EndEntry = i - 1;
+
+ //
+ // If the request page state change is shared then invalidate the pages before
+ // adding the page in the RMP table.
+ //
+ if (State == SevSnpPageShared) {
+ PvalidateRange (Info, 0, i, FALSE);
+ }
+
+ //
+ // Issue the VMGEXIT and retry if hypervisor failed to process all the entries.
+ //
+ 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);
+ if ((Status != 0) || (Ghcb->SaveArea.SwExitInfo2)) {
+ SnpPageStateFailureTerminate ();
+ }
+ }
+
+ //
+ // If the request page state change is shared then invalidate the pages before
+ // adding the page in the RMP table.
+ //
+ if (State == SevSnpPagePrivate) {
+ PvalidateRange (Info, 0, i, TRUE);
+ }
+
+ VmgDone (Ghcb, InterruptState);
+ }
+}
--
2.17.1


[PATCH RFC v3 12/22] OvmfPkg/AmdSevDxe: do not use extended PCI config space

Brijesh Singh
 

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: 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: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.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 66bbbc80cd18..4ef3d71877fa 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -814,7 +814,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 7d9e88040000..b8a7128b310e 100644
--- a/OvmfPkg/Bhyve/BhyveX64.dsc
+++ b/OvmfPkg/Bhyve/BhyveX64.dsc
@@ -824,7 +824,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 6b0bc02bd536..75f87d311454 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -967,7 +967,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 8d9a0a077601..7f72f4150440 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -966,7 +966,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
OvmfPkg/AmdSev/SecretDxe/SecretDxe.inf

diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index e535503e385d..d549f1b14378 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -727,7 +727,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


[PATCH RFC v3 11/22] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled

Brijesh Singh
 

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 for the futher detail.

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: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 1 +
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 1 +
UefiCpuPkg/Library/MpInitLib/MpLib.h | 2 +
UefiCpuPkg/Library/MpInitLib/MpLib.c | 2 +
UefiCpuPkg/Library/MpInitLib/MpEqu.inc | 1 +
UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 51 +++++++++++++++++++
6 files changed, 58 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index d34419c2a524..48d7dfa4450f 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -76,3 +76,4 @@ [Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdSevSnpIsEnabled ## CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 36fcb96b5852..ab8279df596f 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -65,6 +65,7 @@ [Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdSevSnpIsEnabled ## CONSUMES

[Ppis]
gEdkiiPeiShadowMicrocodePpiGuid ## SOMETIMES_CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index e88a5355c983..4abaa2243d0a 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -218,6 +218,7 @@ typedef struct {
//
BOOLEAN Enable5LevelPaging;
BOOLEAN SevEsIsEnabled;
+ BOOLEAN SevSnpIsEnabled;
UINTN GhcbBase;
} MP_CPU_EXCHANGE_INFO;

@@ -287,6 +288,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 dc2a54aa31e8..7cbcce101414 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;

//
@@ -2016,6 +2017,7 @@ MpInitLibInitialize (
CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
InitializeSpinLock(&CpuMpData->MpLock);
CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
+ CpuMpData->SevSnpIsEnabled = PcdGetBool (PcdSevSnpIsEnabled);
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..19939c093d2e 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -194,9 +194,60 @@ LongModeStart:
mov rdx, rax
shr rdx, 32
mov rcx, 0xc0010130
+
+ ;
+ ; Register GHCB GPA when SEV-SNP is enabled
+ ;
+ lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]
+ cmp byte [edi], 1 ; SevSnpIsEnabled
+ jne SetGhcbAddress
+
+ ; 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
+
+ ;
+ ; Program GHCB
+ ;
+SetGhcbAddress:
wrmsr
jmp CProcedureInvoke

+ ;
+ ; 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
+
GetApicId:
lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]
cmp byte [edi], 1 ; SevEsIsEnabled
--
2.17.1

5241 - 5260 of 80912