[edk2-devel] [PATCH V2 03/10] OvmfPkg/IntelTdx: Add SecTdxHelperLib

Min Xu posted 10 patches 3 years ago
There is a newer version of this series
[edk2-devel] [PATCH V2 03/10] OvmfPkg/IntelTdx: Add SecTdxHelperLib
Posted by Min Xu 3 years ago
From: Min M Xu <min.m.xu@intel.com>

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

TdxHelperLib provides below helper functions for a td-guest.
 - TdxHelperProcessTdHob
 - TdxHelperMeasureTdHob
 - TdxHelperMeasureCfvImage
 - TdxHelperBuildGuidHobForTdxMeasurement

SecTdxHelperLib is the SEC instance of TdxHelperLib. It implements 4
functions for tdx in SEC phase:
 - TdxHelperProcessTdHob consumes TdHob to accept un-accepted memories.
   Before the TdHob is consumed, it is first validated.

 - TdxHelperMeasureTdHob measure/extend TdHob and store the measurement
   value in workarea.

 - TdxHelperMeasureCfvImage measure/extend the Configuration FV image and
   store the measurement value in workarea.

 - TdxHelperBuildGuidHobForTdxMeasurement builds GuidHob for tdx
   measurement.

In this patch only TdxHelperProcessTdHob is implemented. Other 3 functions
are to be implemented in the following patch. This is because the code of
TdxHelperProcessTdHob is copied from PlatformInitLib/IntelTdx.c.
TdxHelperProcessTdHob is corresponding to ProcessTdxHobList. To make the
patch reviewable, we sperate the SecTdxHelperLib into several patches. The
duplicated code in PlatformInitLib/IntelTdx.c will be deleted later. This
is to prevent the build from broken.

Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Michael Roth <michael.roth@amd.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelper.c  | 845 ++++++++++++++++++
 .../IntelTdx/TdxHelperLib/SecTdxHelperLib.inf |  52 ++
 2 files changed, 897 insertions(+)
 create mode 100644 OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelper.c
 create mode 100644 OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelperLib.inf

diff --git a/OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelper.c b/OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelper.c
new file mode 100644
index 000000000000..4fb2d2a8acad
--- /dev/null
+++ b/OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelper.c
@@ -0,0 +1,845 @@
+/** @file
+  TdxHelper Functions which are used in SEC phase
+
+  Copyright (c) 2022 - 2023, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <IndustryStandard/IntelTdx.h>
+#include <IndustryStandard/Tpm20.h>
+#include <Library/TdxLib.h>
+#include <Library/TdxMailboxLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Pi/PrePiHob.h>
+#include <WorkArea.h>
+#include <ConfidentialComputingGuestAttr.h>
+#include <Library/TdxHelperLib.h>
+
+#define ALIGNED_2MB_MASK  0x1fffff
+#define MEGABYTE_SHIFT    20
+
+#define ACCEPT_CHUNK_SIZE  SIZE_32MB
+#define AP_STACK_SIZE      SIZE_16KB
+#define APS_STACK_SIZE(CpusNum)  (ALIGN_VALUE(CpusNum*AP_STACK_SIZE, SIZE_2MB))
+
+/**
+  This function will be called to accept pages. Only BSP accepts pages.
+
+  TDCALL(ACCEPT_PAGE) supports the accept page size of 4k and 2M. To
+  simplify the implementation, the Memory to be accpeted is splitted
+  into 3 parts:
+  -----------------  <-- StartAddress1 (not 2M aligned)
+  |  part 1       |      Length1 < 2M
+  |---------------|  <-- StartAddress2 (2M aligned)
+  |               |      Length2 = Integer multiples of 2M
+  |  part 2       |
+  |               |
+  |---------------|  <-- StartAddress3
+  |  part 3       |      Length3 < 2M
+  |---------------|
+
+  @param[in] PhysicalAddress   Start physical adress
+  @param[in] PhysicalEnd       End physical address
+
+  @retval    EFI_SUCCESS       Accept memory successfully
+  @retval    Others            Other errors as indicated
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BspAcceptMemoryResourceRange (
+  IN EFI_PHYSICAL_ADDRESS  PhysicalAddress,
+  IN EFI_PHYSICAL_ADDRESS  PhysicalEnd
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      AcceptPageSize;
+  UINT64      StartAddress1;
+  UINT64      StartAddress2;
+  UINT64      StartAddress3;
+  UINT64      TotalLength;
+  UINT64      Length1;
+  UINT64      Length2;
+  UINT64      Length3;
+  UINT64      Pages;
+
+  AcceptPageSize = FixedPcdGet32 (PcdTdxAcceptPageSize);
+  TotalLength    = PhysicalEnd - PhysicalAddress;
+  StartAddress1  = 0;
+  StartAddress2  = 0;
+  StartAddress3  = 0;
+  Length1        = 0;
+  Length2        = 0;
+  Length3        = 0;
+
+  if (TotalLength == 0) {
+    return EFI_SUCCESS;
+  }
+
+  if (ALIGN_VALUE (PhysicalAddress, SIZE_2MB) != PhysicalAddress) {
+    StartAddress1 = PhysicalAddress;
+    Length1       = ALIGN_VALUE (PhysicalAddress, SIZE_2MB) - PhysicalAddress;
+    if (Length1 >= TotalLength) {
+      Length1 = TotalLength;
+    }
+
+    PhysicalAddress += Length1;
+    TotalLength     -= Length1;
+  }
+
+  if (TotalLength > SIZE_2MB) {
+    StartAddress2    = PhysicalAddress;
+    Length2          = TotalLength & ~(UINT64)ALIGNED_2MB_MASK;
+    PhysicalAddress += Length2;
+    TotalLength     -= Length2;
+  }
+
+  if (TotalLength) {
+    StartAddress3 = PhysicalAddress;
+    Length3       = TotalLength;
+  }
+
+  Status = EFI_SUCCESS;
+  if (Length1 > 0) {
+    Pages  = Length1 / SIZE_4KB;
+    Status = TdAcceptPages (StartAddress1, Pages, SIZE_4KB);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  if (Length2 > 0) {
+    Pages  = Length2 / AcceptPageSize;
+    Status = TdAcceptPages (StartAddress2, Pages, AcceptPageSize);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  if (Length3 > 0) {
+    Pages  = Length3 / SIZE_4KB;
+    Status = TdAcceptPages (StartAddress3, Pages, SIZE_4KB);
+    ASSERT (!EFI_ERROR (Status));
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  return Status;
+}
+
+/**
+ * This function is called by BSP and APs to accept memory.
+ * Note:
+ * The input PhysicalStart/PhysicalEnd indicates the whole memory region
+ * to be accepted. BSP or AP only accepts one piece in the whole memory region.
+ *
+ * @param CpuIndex        vCPU index
+ * @param CpusNum         Total vCPU number of a Tdx guest
+ * @param PhysicalStart   Start address of a memory region which is to be accepted
+ * @param PhysicalEnd     End address of a memory region which is to be accepted
+ *
+ * @retval EFI_SUCCESS    Successfully accept the memory
+ * @retval Other          Other errors as indicated
+ */
+STATIC
+EFI_STATUS
+EFIAPI
+BspApAcceptMemoryResourceRange (
+  UINT32                CpuIndex,
+  UINT32                CpusNum,
+  EFI_PHYSICAL_ADDRESS  PhysicalStart,
+  EFI_PHYSICAL_ADDRESS  PhysicalEnd
+  )
+{
+  UINT64                Status;
+  UINT64                Pages;
+  UINT64                Stride;
+  UINT64                AcceptPageSize;
+  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
+
+  AcceptPageSize = (UINT64)(UINTN)FixedPcdGet32 (PcdTdxAcceptPageSize);
+
+  Status          = EFI_SUCCESS;
+  Stride          = (UINTN)CpusNum * ACCEPT_CHUNK_SIZE;
+  PhysicalAddress = PhysicalStart + ACCEPT_CHUNK_SIZE * (UINTN)CpuIndex;
+
+  while (!EFI_ERROR (Status) && PhysicalAddress < PhysicalEnd) {
+    Pages  = MIN (ACCEPT_CHUNK_SIZE, PhysicalEnd - PhysicalAddress) / AcceptPageSize;
+    Status = TdAcceptPages (PhysicalAddress, Pages, (UINT32)(UINTN)AcceptPageSize);
+    ASSERT (!EFI_ERROR (Status));
+    PhysicalAddress += Stride;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+ * This function is called by APs to accept memory.
+ *
+ * @param CpuIndex        vCPU index of an AP
+ * @param PhysicalStart   Start address of a memory region which is to be accepted
+ * @param PhysicalEnd     End address of a memory region which is to be accepted
+ *
+ * @retval EFI_SUCCESS    Successfully accept the memory
+ * @retval Others         Other errors as indicated
+ */
+STATIC
+EFI_STATUS
+EFIAPI
+ApAcceptMemoryResourceRange (
+  UINT32                CpuIndex,
+  EFI_PHYSICAL_ADDRESS  PhysicalStart,
+  EFI_PHYSICAL_ADDRESS  PhysicalEnd
+  )
+{
+  UINT64          Status;
+  TD_RETURN_DATA  TdReturnData;
+
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+  if (Status != TDX_EXIT_REASON_SUCCESS) {
+    ASSERT (FALSE);
+    return EFI_ABORTED;
+  }
+
+  if ((CpuIndex == 0) || (CpuIndex >= TdReturnData.TdInfo.NumVcpus)) {
+    ASSERT (FALSE);
+    return EFI_ABORTED;
+  }
+
+  return BspApAcceptMemoryResourceRange (CpuIndex, TdReturnData.TdInfo.NumVcpus, PhysicalStart, PhysicalEnd);
+}
+
+/**
+ * This function is called by BSP. It coordinates BSP/APs to accept memory together.
+ *
+ * @param PhysicalStart     Start address of a memory region which is to be accepted
+ * @param PhysicalEnd       End address of a memory region which is to be accepted
+ * @param APsStackAddress   APs stack address
+ * @param CpusNum           Total vCPU number of the Tdx guest
+ *
+ * @retval EFI_SUCCESS      Successfully accept the memory
+ * @retval Others           Other errors as indicated
+ */
+STATIC
+EFI_STATUS
+EFIAPI
+MpAcceptMemoryResourceRange (
+  IN EFI_PHYSICAL_ADDRESS      PhysicalStart,
+  IN EFI_PHYSICAL_ADDRESS      PhysicalEnd,
+  IN OUT EFI_PHYSICAL_ADDRESS  APsStackAddress,
+  IN UINT32                    CpusNum
+  )
+{
+  UINT64      Length;
+  EFI_STATUS  Status;
+
+  Length = PhysicalEnd - PhysicalStart;
+
+  DEBUG ((DEBUG_INFO, "MpAccept : 0x%llx - 0x%llx (0x%llx)\n", PhysicalStart, PhysicalEnd, Length));
+
+  if (Length == 0) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // The start address is not 2M aligned. BSP first accept the part which is not 2M aligned.
+  //
+  if (ALIGN_VALUE (PhysicalStart, SIZE_2MB) != PhysicalStart) {
+    Length = MIN (ALIGN_VALUE (PhysicalStart, SIZE_2MB) - PhysicalStart, Length);
+    Status = BspAcceptMemoryResourceRange (PhysicalStart, PhysicalStart + Length);
+    ASSERT (Status == EFI_SUCCESS);
+
+    PhysicalStart += Length;
+    Length         = PhysicalEnd - PhysicalStart;
+  }
+
+  if (Length == 0) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // BSP will accept the memory by itself if the memory is not big enough compared with a chunk.
+  //
+  if (Length <= ACCEPT_CHUNK_SIZE) {
+    return BspAcceptMemoryResourceRange (PhysicalStart, PhysicalEnd);
+  }
+
+  //
+  // Now APs are asked to accept the memory together.
+  //
+  MpSerializeStart ();
+
+  MpSendWakeupCommand (
+    MpProtectedModeWakeupCommandAcceptPages,
+    (UINT64)(UINTN)ApAcceptMemoryResourceRange,
+    PhysicalStart,
+    PhysicalEnd,
+    APsStackAddress,
+    AP_STACK_SIZE
+    );
+
+  //
+  // Now BSP does its job.
+  //
+  BspApAcceptMemoryResourceRange (0, CpusNum, PhysicalStart, PhysicalEnd);
+
+  MpSerializeEnd ();
+
+  return EFI_SUCCESS;
+}
+
+/**
+  BSP accept a small piece of memory which will be used as APs stack.
+
+  @param[in] VmmHobList    The Hoblist pass the firmware
+  @param[in] APsStackSize  APs stack size
+  @param[out] PhysicalAddressEnd    The physical end address of accepted memory in phase-1
+
+  @retval  EFI_SUCCESS     Process the HobList successfully
+  @retval  Others          Other errors as indicated
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AcceptMemoryForAPsStack (
+  IN CONST VOID             *VmmHobList,
+  IN UINT32                 APsStackSize,
+  OUT EFI_PHYSICAL_ADDRESS  *PhysicalAddressEnd
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PEI_HOB_POINTERS  Hob;
+  EFI_PHYSICAL_ADDRESS  PhysicalEnd;
+  EFI_PHYSICAL_ADDRESS  PhysicalStart;
+  UINT64                ResourceLength;
+  BOOLEAN               MemoryRegionFound;
+
+  ASSERT (VmmHobList != NULL);
+
+  Status            = EFI_SUCCESS;
+  Hob.Raw           = (UINT8 *)VmmHobList;
+  MemoryRegionFound = FALSE;
+
+  DEBUG ((DEBUG_INFO, "AcceptMemoryForAPsStack with APsStackSize=0x%x\n", APsStackSize));
+
+  //
+  // Parse the HOB list until end of list or matching type is found.
+  //
+  while (!END_OF_HOB_LIST (Hob) && !MemoryRegionFound) {
+    if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+      DEBUG ((DEBUG_INFO, "\nResourceType: 0x%x\n", Hob.ResourceDescriptor->ResourceType));
+
+      if (Hob.ResourceDescriptor->ResourceType == BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED) {
+        ResourceLength = Hob.ResourceDescriptor->ResourceLength;
+        PhysicalStart  = Hob.ResourceDescriptor->PhysicalStart;
+        PhysicalEnd    = PhysicalStart + ResourceLength;
+
+        DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));
+        DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", PhysicalStart));
+        DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", ResourceLength));
+        DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));
+
+        if (ResourceLength >= APsStackSize) {
+          MemoryRegionFound = TRUE;
+          if (ResourceLength > ACCEPT_CHUNK_SIZE) {
+            PhysicalEnd = Hob.ResourceDescriptor->PhysicalStart + APsStackSize;
+          }
+        }
+
+        Status = BspAcceptMemoryResourceRange (
+                   Hob.ResourceDescriptor->PhysicalStart,
+                   PhysicalEnd
+                   );
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+    }
+
+    Hob.Raw = GET_NEXT_HOB (Hob);
+  }
+
+  ASSERT (MemoryRegionFound);
+  *PhysicalAddressEnd = PhysicalEnd;
+
+  return Status;
+}
+
+/**
+  BSP and APs work togeter to accept memory which is under the address of 4G.
+
+  @param[in] VmmHobList           The Hoblist pass the firmware
+  @param[in] CpusNum              Number of vCPUs
+  @param[in] APsStackStartAddres  Start address of APs stack
+  @param[in] PhysicalAddressStart Start physical address which to be accepted
+
+  @retval  EFI_SUCCESS     Process the HobList successfully
+  @retval  Others          Other errors as indicated
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AcceptMemory (
+  IN CONST VOID            *VmmHobList,
+  IN UINT32                CpusNum,
+  IN EFI_PHYSICAL_ADDRESS  APsStackStartAddress,
+  IN EFI_PHYSICAL_ADDRESS  PhysicalAddressStart
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PEI_HOB_POINTERS  Hob;
+  EFI_PHYSICAL_ADDRESS  PhysicalStart;
+  EFI_PHYSICAL_ADDRESS  PhysicalEnd;
+  EFI_PHYSICAL_ADDRESS  AcceptMemoryEndAddress;
+
+  Status                 = EFI_SUCCESS;
+  AcceptMemoryEndAddress = BASE_4GB;
+
+  ASSERT (VmmHobList != NULL);
+  Hob.Raw = (UINT8 *)VmmHobList;
+
+  DEBUG ((DEBUG_INFO, "AcceptMemory under address of 4G\n"));
+
+  //
+  // Parse the HOB list until end of list or matching type is found.
+  //
+  while (!END_OF_HOB_LIST (Hob)) {
+    if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+      if (Hob.ResourceDescriptor->ResourceType == BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED) {
+        PhysicalStart = Hob.ResourceDescriptor->PhysicalStart;
+        PhysicalEnd   = PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
+
+        if (PhysicalEnd <= PhysicalAddressStart) {
+          // this memory region has been accepted. Skipped it.
+          Hob.Raw = GET_NEXT_HOB (Hob);
+          continue;
+        }
+
+        if (PhysicalStart >= AcceptMemoryEndAddress) {
+          // this memory region is not to be accepted. And we're done.
+          break;
+        }
+
+        if (PhysicalStart >= PhysicalAddressStart) {
+          // this memory region has not been acceted.
+        } else if ((PhysicalStart < PhysicalAddressStart) && (PhysicalEnd > PhysicalAddressStart)) {
+          // part of the memory region has been accepted.
+          PhysicalStart = PhysicalAddressStart;
+        }
+
+        // then compare the PhysicalEnd with AcceptMemoryEndAddress
+        if (PhysicalEnd >= AcceptMemoryEndAddress) {
+          PhysicalEnd = AcceptMemoryEndAddress;
+        }
+
+        DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));
+        DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", Hob.ResourceDescriptor->PhysicalStart));
+        DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", Hob.ResourceDescriptor->ResourceLength));
+        DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));
+
+        // Now we're ready to accept memory [PhysicalStart, PhysicalEnd)
+        if (CpusNum == 1) {
+          Status = BspAcceptMemoryResourceRange (PhysicalStart, PhysicalEnd);
+        } else {
+          Status = MpAcceptMemoryResourceRange (
+                     PhysicalStart,
+                     PhysicalEnd,
+                     APsStackStartAddress,
+                     CpusNum
+                     );
+        }
+
+        if (EFI_ERROR (Status)) {
+          ASSERT (FALSE);
+          break;
+        }
+
+        if (PhysicalEnd == AcceptMemoryEndAddress) {
+          break;
+        }
+      }
+    }
+
+    Hob.Raw = GET_NEXT_HOB (Hob);
+  }
+
+  return Status;
+}
+
+/**
+  Check the value whether in the valid list.
+
+  @param[in] Value             A value
+  @param[in] ValidList         A pointer to valid list
+  @param[in] ValidListLength   Length of valid list
+
+  @retval  TRUE   The value is in valid list.
+  @retval  FALSE  The value is not in valid list.
+
+**/
+STATIC
+BOOLEAN
+EFIAPI
+IsInValidList (
+  IN UINT32  Value,
+  IN UINT32  *ValidList,
+  IN UINT32  ValidListLength
+  )
+{
+  UINT32  index;
+
+  if (ValidList == NULL) {
+    return FALSE;
+  }
+
+  for (index = 0; index < ValidListLength; index++) {
+    if (ValidList[index] == Value) {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+  Check the integrity of VMM Hob List.
+
+  @param[in] VmmHobList   A pointer to Hob List
+
+  @retval  TRUE     The Hob List is valid.
+  @retval  FALSE    The Hob List is invalid.
+
+**/
+STATIC
+BOOLEAN
+EFIAPI
+ValidateHobList (
+  IN CONST VOID  *VmmHobList
+  )
+{
+  EFI_PEI_HOB_POINTERS  Hob;
+  UINT32                EFI_BOOT_MODE_LIST[] = {
+    BOOT_WITH_FULL_CONFIGURATION,
+    BOOT_WITH_MINIMAL_CONFIGURATION,
+    BOOT_ASSUMING_NO_CONFIGURATION_CHANGES,
+    BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS,
+    BOOT_WITH_DEFAULT_SETTINGS,
+    BOOT_ON_S4_RESUME,
+    BOOT_ON_S5_RESUME,
+    BOOT_WITH_MFG_MODE_SETTINGS,
+    BOOT_ON_S2_RESUME,
+    BOOT_ON_S3_RESUME,
+    BOOT_ON_FLASH_UPDATE,
+    BOOT_IN_RECOVERY_MODE
+  };
+
+  UINT32  EFI_RESOURCE_TYPE_LIST[] = {
+    EFI_RESOURCE_SYSTEM_MEMORY,
+    EFI_RESOURCE_MEMORY_MAPPED_IO,
+    EFI_RESOURCE_IO,
+    EFI_RESOURCE_FIRMWARE_DEVICE,
+    EFI_RESOURCE_MEMORY_MAPPED_IO_PORT,
+    EFI_RESOURCE_MEMORY_RESERVED,
+    EFI_RESOURCE_IO_RESERVED,
+    BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED
+  };
+
+  if (VmmHobList == NULL) {
+    DEBUG ((DEBUG_ERROR, "HOB: HOB data pointer is NULL\n"));
+    return FALSE;
+  }
+
+  Hob.Raw = (UINT8 *)VmmHobList;
+
+  //
+  // Parse the HOB list until end of list or matching type is found.
+  //
+  while (!END_OF_HOB_LIST (Hob)) {
+    if (Hob.Header->Reserved != (UINT32)0) {
+      DEBUG ((DEBUG_ERROR, "HOB: Hob header Reserved filed should be zero\n"));
+      return FALSE;
+    }
+
+    if (Hob.Header->HobLength == 0) {
+      DEBUG ((DEBUG_ERROR, "HOB: Hob header LEANGTH should not be zero\n"));
+      return FALSE;
+    }
+
+    switch (Hob.Header->HobType) {
+      case EFI_HOB_TYPE_HANDOFF:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_HANDOFF_INFO_TABLE)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_HANDOFF));
+          return FALSE;
+        }
+
+        if (IsInValidList (Hob.HandoffInformationTable->BootMode, EFI_BOOT_MODE_LIST, ARRAY_SIZE (EFI_BOOT_MODE_LIST)) == FALSE) {
+          DEBUG ((DEBUG_ERROR, "HOB: Unknow HandoffInformationTable BootMode type. Type: 0x%08x\n", Hob.HandoffInformationTable->BootMode));
+          return FALSE;
+        }
+
+        if ((Hob.HandoffInformationTable->EfiFreeMemoryTop % 4096) != 0) {
+          DEBUG ((DEBUG_ERROR, "HOB: HandoffInformationTable EfiFreeMemoryTop address must be 4-KB aligned to meet page restrictions of UEFI.\
+                               Address: 0x%016lx\n", Hob.HandoffInformationTable->EfiFreeMemoryTop));
+          return FALSE;
+        }
+
+        break;
+
+      case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_RESOURCE_DESCRIPTOR));
+          return FALSE;
+        }
+
+        if (IsInValidList (Hob.ResourceDescriptor->ResourceType, EFI_RESOURCE_TYPE_LIST, ARRAY_SIZE (EFI_RESOURCE_TYPE_LIST)) == FALSE) {
+          DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceType type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceType));
+          return FALSE;
+        }
+
+        if ((Hob.ResourceDescriptor->ResourceAttribute & (~(EFI_RESOURCE_ATTRIBUTE_PRESENT |
+                                                            EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+                                                            EFI_RESOURCE_ATTRIBUTE_TESTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_PERSISTENT |
+                                                            EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC |
+                                                            EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC |
+                                                            EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 |
+                                                            EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 |
+                                                            EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_16_BIT_IO |
+                                                            EFI_RESOURCE_ATTRIBUTE_32_BIT_IO |
+                                                            EFI_RESOURCE_ATTRIBUTE_64_BIT_IO |
+                                                            EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_PERSISTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE))) != 0)
+        {
+          DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceAttribute type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceAttribute));
+          return FALSE;
+        }
+
+        break;
+
+      // EFI_HOB_GUID_TYPE is variable length data, so skip check
+      case EFI_HOB_TYPE_GUID_EXTENSION:
+        break;
+
+      case EFI_HOB_TYPE_FV:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV));
+          return FALSE;
+        }
+
+        break;
+
+      case EFI_HOB_TYPE_FV2:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME2)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV2));
+          return FALSE;
+        }
+
+        break;
+
+      case EFI_HOB_TYPE_FV3:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME3)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV3));
+          return FALSE;
+        }
+
+        break;
+
+      case EFI_HOB_TYPE_CPU:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_CPU)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_CPU));
+          return FALSE;
+        }
+
+        for (UINT32 index = 0; index < 6; index++) {
+          if (Hob.Cpu->Reserved[index] != 0) {
+            DEBUG ((DEBUG_ERROR, "HOB: Cpu Reserved field will always be set to zero.\n"));
+            return FALSE;
+          }
+        }
+
+        break;
+
+      default:
+        DEBUG ((DEBUG_ERROR, "HOB: Hob type is not know. Type: 0x%04x\n", Hob.Header->HobType));
+        return FALSE;
+    }
+
+    // Get next HOB
+    Hob.Raw = (UINT8 *)(Hob.Raw + Hob.Header->HobLength);
+  }
+
+  return TRUE;
+}
+
+/**
+  Processing the incoming HobList for the TDX
+
+  Firmware must parse list, and accept the pages of memory before their can be
+  use by the guest.
+
+  @param[in] VmmHobList    The Hoblist pass the firmware
+
+  @retval  EFI_SUCCESS     Process the HobList successfully
+  @retval  Others          Other errors as indicated
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ProcessHobList (
+  IN CONST VOID  *VmmHobList
+  )
+{
+  EFI_STATUS            Status;
+  UINT32                CpusNum;
+  EFI_PHYSICAL_ADDRESS  PhysicalEnd;
+  EFI_PHYSICAL_ADDRESS  APsStackStartAddress;
+
+  CpusNum = GetCpusNum ();
+
+  //
+  // If there are mutli-vCPU in a TDX guest, accept memory is split into 2 phases.
+  // Phase-1 accepts a small piece of memory by BSP. This piece of memory
+  // is used to setup AP's stack.
+  // After that phase-2 accepts a big piece of memory by BSP/APs.
+  //
+  // TDVF supports 4K and 2M accept-page-size. The memory which can be accpeted
+  // in 2M accept-page-size must be 2M aligned and multiple 2M. So we align
+  // APsStackSize to 2M size aligned.
+  //
+  if (CpusNum > 1) {
+    Status = AcceptMemoryForAPsStack (VmmHobList, APS_STACK_SIZE (CpusNum), &PhysicalEnd);
+    ASSERT (Status == EFI_SUCCESS);
+    APsStackStartAddress = PhysicalEnd - APS_STACK_SIZE (CpusNum);
+  } else {
+    PhysicalEnd          = 0;
+    APsStackStartAddress = 0;
+  }
+
+  Status = AcceptMemory (VmmHobList, CpusNum, APsStackStartAddress, PhysicalEnd);
+  ASSERT (Status == EFI_SUCCESS);
+
+  return Status;
+}
+
+/**
+  In Tdx guest, some information need to be passed from host VMM to guest
+  firmware. For example, the memory resource, etc. These information are
+  prepared by host VMM and put in TdHob which is described in TdxMetadata.
+  TDVF processes the TdHob to accept memories.
+
+  @retval   EFI_SUCCESS   Successfully process the TdHob
+  @retval   Others        Other error as indicated
+**/
+EFI_STATUS
+EFIAPI
+TdxHelperProcessTdHob (
+  VOID
+  )
+{
+  EFI_STATUS      Status;
+  VOID            *TdHob;
+  TD_RETURN_DATA  TdReturnData;
+
+  TdHob  = (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase);
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  DEBUG ((
+    DEBUG_INFO,
+    "Intel Tdx Started with (GPAW: %d, Cpus: %d)\n",
+    TdReturnData.TdInfo.Gpaw,
+    TdReturnData.TdInfo.NumVcpus
+    ));
+
+  //
+  // Validate HobList
+  //
+  if (ValidateHobList (TdHob) == FALSE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Process Hoblist to accept memory
+  //
+  Status = ProcessHobList (TdHob);
+
+  return Status;
+}
+
+/**
+  In Tdx guest, TdHob is passed from host VMM to guest firmware and it contains
+  the information of the memory resource. From the security perspective before
+  it is consumed, it should be measured and extended.
+ *
+ * @retval EFI_SUCCESS Successfully measure the TdHob
+ * @retval Others      Other error as indicated
+ */
+EFI_STATUS
+EFIAPI
+TdxHelperMeasureTdHob (
+  VOID
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+ * In Tdx guest, Configuration FV (CFV) is treated as external input because it
+ * may contain the data provided by VMM. From the sucurity perspective Cfv image
+ * should be measured before it is consumed.
+ *
+ * @retval EFI_SUCCESS Successfully measure the CFV image
+ * @retval Others      Other error as indicated
+ */
+EFI_STATUS
+EFIAPI
+TdxHelperMeasureCfvImage (
+  VOID
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+/**
+  Build the GuidHob for tdx measurements which were done in SEC phase.
+  The measurement values are stored in WorkArea.
+
+  @retval EFI_SUCCESS  The GuidHob is built successfully
+  @retval Others       Other errors as indicated
+**/
+EFI_STATUS
+EFIAPI
+TdxHelperBuildGuidHobForTdxMeasurement (
+  VOID
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelperLib.inf b/OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelperLib.inf
new file mode 100644
index 000000000000..3c6b96f7759a
--- /dev/null
+++ b/OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelperLib.inf
@@ -0,0 +1,52 @@
+## @file
+#  TdxHelperLib SEC instance
+#
+#  This module provides Tdx helper functions in SEC phase.
+#  Copyright (c) 2021 - 2023, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SecTdxHelperLib
+  FILE_GUID                      = ba69ac6b-0c59-4472-899d-b684590ec1e9
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = TdxHelperLib|SEC
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = X64
+#
+
+[Sources]
+  SecTdxHelper.c
+
+[Packages]
+  CryptoPkg/CryptoPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+  SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseCryptLib
+  DebugLib
+  HobLib
+  PcdLib
+  TdxMailboxLib
+  TdxLib
+
+[FixedPcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageVariableBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize
+
+[Guids]
+  gCcEventEntryHobGuid
-- 
2.29.2.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#98848): https://edk2.groups.io/g/devel/message/98848
Mute This Topic: https://groups.io/mt/96370897/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH V2 03/10] OvmfPkg/IntelTdx: Add SecTdxHelperLib
Posted by Gerd Hoffmann 3 years ago
  Hi,

> TdxHelperLib provides below helper functions for a td-guest.
>  - TdxHelperProcessTdHob

This is moved over from PlatformInitLib.

>  - TdxHelperMeasureTdHob
>  - TdxHelperMeasureCfvImage
>  - TdxHelperBuildGuidHobForTdxMeasurement

This is new.

> In this patch only TdxHelperProcessTdHob is implemented. Other 3 functions
> are to be implemented in the following patch. This is because the code of
> TdxHelperProcessTdHob is copied from PlatformInitLib/IntelTdx.c.

Why copy?  You should be able to move the code over in one patch.  Maybe
it's easier to do so at the end of the series, i.e. drop this patch and
the last patch moves the code instead of deleting it.

take care,
  Gerd



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#98878): https://edk2.groups.io/g/devel/message/98878
Mute This Topic: https://groups.io/mt/96370897/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-