[edk2-devel] [PATCH V2 07/10] OvmfPkg/IntelTdx: Add Sec to bring up both Legacy and Tdx guest

Min Xu min.m.xu at intel.com
Tue Jan 25 06:33:15 UTC 2022


RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

OvmfPkg/IntelTdx/Sec is a simplied version of OvmfPkg/Sec. There
are below differences between these 2 Sec
 - IntelTdx/Sec only supports Legacy guest and Tdx guest.
 - IntelTdx/Sec calls TdxStartup () to jump from SEC to DXE directly.
 - IntelTdx/Sec only supports X64.
 - IntelTdx/Sec uses MemoryAllocationLib / HobLib / PrePiLib in
   EmbeddedPkg.

Cc: Michael D Kinney <michael.d.kinney at intel.com>
Cc: Brijesh Singh <brijesh.singh at amd.com>
Cc: Erdem Aktas <erdemaktas at google.com>
Cc: James Bottomley <jejb at linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao at intel.com>
Cc: Tom Lendacky <thomas.lendacky at amd.com>
Cc: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: Min Xu <min.m.xu at intel.com>
---
 OvmfPkg/IntelTdx/Sec/IntelTdx.c        | 508 +++++++++++++++++++++++++
 OvmfPkg/IntelTdx/Sec/IntelTdx.h        |  46 +++
 OvmfPkg/IntelTdx/Sec/SecMain.c         | 200 ++++++++++
 OvmfPkg/IntelTdx/Sec/SecMain.inf       |  73 ++++
 OvmfPkg/IntelTdx/Sec/X64/SecEntry.nasm | 151 ++++++++
 5 files changed, 978 insertions(+)
 create mode 100644 OvmfPkg/IntelTdx/Sec/IntelTdx.c
 create mode 100644 OvmfPkg/IntelTdx/Sec/IntelTdx.h
 create mode 100644 OvmfPkg/IntelTdx/Sec/SecMain.c
 create mode 100644 OvmfPkg/IntelTdx/Sec/SecMain.inf
 create mode 100644 OvmfPkg/IntelTdx/Sec/X64/SecEntry.nasm

diff --git a/OvmfPkg/IntelTdx/Sec/IntelTdx.c b/OvmfPkg/IntelTdx/Sec/IntelTdx.c
new file mode 100644
index 000000000000..aae64fd155e2
--- /dev/null
+++ b/OvmfPkg/IntelTdx/Sec/IntelTdx.c
@@ -0,0 +1,508 @@
+/** @file
+
+  Copyright (c) 2008, Intel Corporation. All rights reserved.<BR>
+  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Uefi/UefiSpec.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrePiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/TdxLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <IndustryStandard/IntelTdx.h>
+#include <WorkArea.h>
+#include "IntelTdx.h"
+
+#define ALIGNED_2MB_MASK  0x1fffff
+
+#define GET_HOB_TYPE(Hob)     ((Hob).Header->HobType)
+#define GET_HOB_LENGTH(Hob)   ((Hob).Header->HobLength)
+#define GET_NEXT_HOB(Hob)     ((Hob).Raw + GET_HOB_LENGTH (Hob))
+#define END_OF_HOB_LIST(Hob)  (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_END_OF_HOB_LIST)
+
+/**
+  Check TDX is enabled.
+
+  @retval    TRUE   TDX is enabled
+  @retval    FALSE  TDX is not enabled
+**/
+BOOLEAN
+SecTdxIsEnabled (
+  VOID
+  )
+{
+  CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER  *CcWorkAreaHeader;
+
+  CcWorkAreaHeader = (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER *)FixedPcdGet32 (PcdOvmfWorkAreaBase);
+  return (CcWorkAreaHeader != NULL && CcWorkAreaHeader->GuestType == GUEST_TYPE_INTEL_TDX);
+}
+
+/**
+  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
+**/
+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 ((AcceptPageSize == SIZE_4KB) || (TotalLength <= SIZE_2MB)) {
+    //
+    // if total length is less than 2M, then we accept pages in 4k
+    //
+    StartAddress2  = PhysicalAddress;
+    Length2        = PhysicalEnd - PhysicalAddress;
+    AcceptPageSize = SIZE_4KB;
+  } else if (AcceptPageSize == SIZE_2MB) {
+    //
+    // Total length is bigger than 2M and Page Accept size 2M is supported.
+    //
+    if ((PhysicalAddress & ALIGNED_2MB_MASK) == 0) {
+      //
+      // Start address is 2M aligned
+      //
+      StartAddress2 = PhysicalAddress;
+      Length2       = TotalLength & ~(UINT64)ALIGNED_2MB_MASK;
+
+      if (TotalLength > Length2) {
+        //
+        // There is remaining part 3)
+        //
+        StartAddress3 = StartAddress2 + Length2;
+        Length3       = TotalLength - Length2;
+        ASSERT (Length3 < SIZE_2MB);
+      }
+    } else {
+      //
+      // Start address is not 2M aligned and total length is bigger than 2M.
+      //
+      StartAddress1 = PhysicalAddress;
+      ASSERT (TotalLength > SIZE_2MB);
+      Length1 = SIZE_2MB - (PhysicalAddress & ALIGNED_2MB_MASK);
+      if (TotalLength - Length1 < SIZE_2MB) {
+        //
+        // The Part 2) length is less than 2MB, so let's accept all the
+        // memory in 4K
+        //
+        Length1 = TotalLength;
+      } else {
+        StartAddress2 = PhysicalAddress + Length1;
+        Length2       = (TotalLength - Length1) & ~(UINT64)ALIGNED_2MB_MASK;
+        Length3       = TotalLength - Length1 - Length2;
+        StartAddress3 = Length3 > 0 ? StartAddress2 + Length2 : 0;
+        ASSERT (Length3 < SIZE_2MB);
+      }
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "TdAccept: 0x%llx - 0x%llx\n", PhysicalAddress, TotalLength));
+  DEBUG ((DEBUG_INFO, "   Part1: 0x%llx - 0x%llx\n", StartAddress1, Length1));
+  DEBUG ((DEBUG_INFO, "   Part2: 0x%llx - 0x%llx\n", StartAddress2, Length2));
+  DEBUG ((DEBUG_INFO, "   Part3: 0x%llx - 0x%llx\n", StartAddress3, Length3));
+  DEBUG ((DEBUG_INFO, "   Page : 0x%x\n", AcceptPageSize));
+
+  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;
+}
+
+/**
+  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.
+
+**/
+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.
+
+**/
+BOOLEAN
+EFIAPI
+ValidateHobList (
+  IN CONST VOID  *VmmHobList
+  )
+{
+  EFI_PEI_HOB_POINTERS  Hob;
+  UINT32                EFI_BOOT_MODE_LIST[12] = {
+    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[8] = {
+    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,
+    EFI_RESOURCE_MAX_MEMORY_TYPE
+  };
+
+  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, 12) == 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, 8) == 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 |
+                                                            EFI_RESOURCE_ATTRIBUTE_ENCRYPTED))) != 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
+
+**/
+EFI_STATUS
+EFIAPI
+ProcessHobList (
+  IN CONST VOID  *VmmHobList
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PEI_HOB_POINTERS  Hob;
+  EFI_PHYSICAL_ADDRESS  PhysicalEnd;
+
+  Status = EFI_SUCCESS;
+  ASSERT (VmmHobList != NULL);
+  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->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+      DEBUG ((DEBUG_INFO, "\nResourceType: 0x%x\n", Hob.ResourceDescriptor->ResourceType));
+
+      if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
+        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));
+
+        PhysicalEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
+
+        Status = BspAcceptMemoryResourceRange (
+                   Hob.ResourceDescriptor->PhysicalStart,
+                   PhysicalEnd
+                   );
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+    }
+
+    Hob.Raw = GET_NEXT_HOB (Hob);
+  }
+
+  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 HobList which is described in TdxMetadata.
+
+  Information in HobList is treated as external input. From the security
+  perspective before it is consumed, it should be validated.
+
+  @retval   EFI_SUCCESS   Successfully process the hoblist
+  @retval   Others        Other error as indicated
+**/
+EFI_STATUS
+EFIAPI
+ProcessTdxHobList (
+  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;
+}
diff --git a/OvmfPkg/IntelTdx/Sec/IntelTdx.h b/OvmfPkg/IntelTdx/Sec/IntelTdx.h
new file mode 100644
index 000000000000..ddd09eff34cd
--- /dev/null
+++ b/OvmfPkg/IntelTdx/Sec/IntelTdx.h
@@ -0,0 +1,46 @@
+/** @file
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SEC_INTEL_TDX_H_
+#define SEC_INTEL_TDX_H_
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Uefi/UefiSpec.h>
+#include <Uefi/UefiBaseType.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+
+/**
+  Check TDX is enabled.
+
+  @retval    TRUE   TDX is enabled
+  @retval    FALSE  TDX is not enabled
+**/
+BOOLEAN
+SecTdxIsEnabled (
+  VOID
+  );
+
+/**
+  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 HobList which is described in TdxMetadata.
+
+  Information in HobList is treated as external input. From the security
+  perspective before it is consumed, it should be validated.
+
+  @retval   EFI_SUCCESS   Successfully process the hoblist
+  @retval   Others        Other error as indicated
+**/
+EFI_STATUS
+EFIAPI
+ProcessTdxHobList (
+  VOID
+  );
+
+#endif
diff --git a/OvmfPkg/IntelTdx/Sec/SecMain.c b/OvmfPkg/IntelTdx/Sec/SecMain.c
new file mode 100644
index 000000000000..374e7cc7eeb6
--- /dev/null
+++ b/OvmfPkg/IntelTdx/Sec/SecMain.c
@@ -0,0 +1,200 @@
+/** @file
+  Main SEC phase code.  Transitions to PEI.
+
+  Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
+  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiCpuLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/IoLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/LocalApicLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
+
+#include "IntelTdx.h"
+
+#include <Library/TdxStartupLib.h>
+
+#define SEC_IDT_ENTRY_COUNT  34
+
+typedef struct _SEC_IDT_TABLE {
+  EFI_PEI_SERVICES            *PeiService;
+  IA32_IDT_GATE_DESCRIPTOR    IdtTable[SEC_IDT_ENTRY_COUNT];
+} SEC_IDT_TABLE;
+
+//
+// Template of an IDT entry pointing to 10:FFFFFFE4h.
+//
+IA32_IDT_GATE_DESCRIPTOR  mIdtEntryTemplate = {
+  {                                      // Bits
+    0xffe4,                              // OffsetLow
+    0x10,                                // Selector
+    0x0,                                 // Reserved_0
+    IA32_IDT_GATE_TYPE_INTERRUPT_32,     // GateType
+    0xffff                               // OffsetHigh
+  }
+};
+
+VOID
+EFIAPI
+SecCoreStartupWithStack (
+  IN EFI_FIRMWARE_VOLUME_HEADER  *BootFv,
+  IN VOID                        *TopOfCurrentStack
+  )
+{
+  EFI_SEC_PEI_HAND_OFF  SecCoreData;
+  SEC_IDT_TABLE         IdtTableInStack;
+  IA32_DESCRIPTOR       IdtDescriptor;
+  UINT32                Index;
+  volatile UINT8        *Table;
+
+  if (SecTdxIsEnabled ()) {
+    //
+    // For Td guests, the memory map info is in TdHobLib. It should be processed
+    // first so that the memory is accepted. Otherwise access to the unaccepted
+    // memory will trigger tripple fault.
+    //
+    if (ProcessTdxHobList () != EFI_SUCCESS) {
+      CpuDeadLoop ();
+    }
+  }
+
+  //
+  // To ensure SMM can't be compromised on S3 resume, we must force re-init of
+  // the BaseExtractGuidedSectionLib. Since this is before library contructors
+  // are called, we must use a loop rather than SetMem.
+  //
+  Table = (UINT8 *)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress);
+  for (Index = 0;
+       Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize);
+       ++Index)
+  {
+    Table[Index] = 0;
+  }
+
+  //
+  // Initialize IDT - Since this is before library constructors are called,
+  // we use a loop rather than CopyMem.
+  //
+  IdtTableInStack.PeiService = NULL;
+
+  for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index++) {
+    //
+    // Declare the local variables that actually move the data elements as
+    // volatile to prevent the optimizer from replacing this function with
+    // the intrinsic memcpy()
+    //
+    CONST UINT8     *Src;
+    volatile UINT8  *Dst;
+    UINTN           Byte;
+
+    Src = (CONST UINT8 *)&mIdtEntryTemplate;
+    Dst = (volatile UINT8 *)&IdtTableInStack.IdtTable[Index];
+
+    for (Byte = 0; Byte < sizeof (mIdtEntryTemplate); Byte++) {
+      Dst[Byte] = Src[Byte];
+    }
+  }
+
+  IdtDescriptor.Base  = (UINTN)&IdtTableInStack.IdtTable;
+  IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
+
+  ProcessLibraryConstructorList (NULL, NULL);
+
+  //
+  // Load the IDTR.
+  //
+  AsmWriteIdtr (&IdtDescriptor);
+
+  if (SecTdxIsEnabled ()) {
+    //
+    // InitializeCpuExceptionHandlers () should be called in Td guests so that
+    // #VE exceptions can be handled correctly.
+    //
+    InitializeCpuExceptionHandlers (NULL);
+  }
+
+  DEBUG ((
+    DEBUG_INFO,
+    "SecCoreStartupWithStack(0x%x, 0x%x)\n",
+    (UINT32)(UINTN)BootFv,
+    (UINT32)(UINTN)TopOfCurrentStack
+    ));
+
+  //
+  // Initialize floating point operating environment
+  // to be compliant with UEFI spec.
+  //
+  InitializeFloatingPointUnits ();
+
+  //
+  // ASSERT that the Page Tables were set by the reset vector code to
+  // the address we expect.
+  //
+  ASSERT (AsmReadCr3 () == (UINTN)PcdGet32 (PcdOvmfSecPageTablesBase));
+
+  //
+  // |-------------|       <-- TopOfCurrentStack
+  // |   Stack     | 32k
+  // |-------------|
+  // |    Heap     | 32k
+  // |-------------|       <-- SecCoreData.TemporaryRamBase
+  //
+
+  ASSERT (
+    (UINTN)(PcdGet32 (PcdOvmfSecPeiTempRamBase) +
+            PcdGet32 (PcdOvmfSecPeiTempRamSize)) ==
+    (UINTN)TopOfCurrentStack
+    );
+
+  //
+  // Initialize SEC hand-off state
+  //
+  SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
+
+  SecCoreData.TemporaryRamSize = (UINTN)PcdGet32 (PcdOvmfSecPeiTempRamSize);
+  SecCoreData.TemporaryRamBase = (VOID *)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize);
+
+  SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;
+  SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize >> 1;
+
+  SecCoreData.StackBase = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
+  SecCoreData.StackSize = SecCoreData.TemporaryRamSize >> 1;
+
+  SecCoreData.BootFirmwareVolumeBase = BootFv;
+  SecCoreData.BootFirmwareVolumeSize = (UINTN)BootFv->FvLength;
+
+  //
+  // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
+  //
+  IoWrite8 (0x21, 0xff);
+  IoWrite8 (0xA1, 0xff);
+
+  //
+  // Initialize Local APIC Timer hardware and disable Local APIC Timer
+  // interrupts before initializing the Debug Agent and the debug timer is
+  // enabled.
+  //
+  InitializeApicTimer (0, MAX_UINT32, TRUE, 5);
+  DisableApicTimerInterrupt ();
+
+  TdxStartup (&SecCoreData);
+
+  ASSERT (FALSE);
+  CpuDeadLoop ();
+}
diff --git a/OvmfPkg/IntelTdx/Sec/SecMain.inf b/OvmfPkg/IntelTdx/Sec/SecMain.inf
new file mode 100644
index 000000000000..7815d6ba77cf
--- /dev/null
+++ b/OvmfPkg/IntelTdx/Sec/SecMain.inf
@@ -0,0 +1,73 @@
+## @file
+#  SEC Driver
+#
+#  Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SecMain
+  FILE_GUID                      = 69d96630-eb64-4b33-8491-13a5cf023dcf
+  MODULE_TYPE                    = SEC
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = SecMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = X64
+#
+
+[Sources]
+  SecMain.c
+  IntelTdx.c
+  X64/SecEntry.nasm
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+  OvmfPkg/OvmfPkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  BaseMemoryLib
+  PcdLib
+  UefiCpuLib
+  DebugAgentLib
+  IoLib
+  PeCoffLib
+  PeCoffGetEntryPointLib
+  PeCoffExtraActionLib
+  ExtractGuidedSectionLib
+  LocalApicLib
+  MemEncryptSevLib
+  CpuExceptionHandlerLib
+  TdxLib
+  TdxStartupLib
+
+[Pcd]
+  gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+  gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
+  gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd
+  gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfConfidentialComputingWorkAreaHeader
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecValidatedStart
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecValidatedEnd
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
diff --git a/OvmfPkg/IntelTdx/Sec/X64/SecEntry.nasm b/OvmfPkg/IntelTdx/Sec/X64/SecEntry.nasm
new file mode 100644
index 000000000000..4528fec309a0
--- /dev/null
+++ b/OvmfPkg/IntelTdx/Sec/X64/SecEntry.nasm
@@ -0,0 +1,151 @@
+;------------------------------------------------------------------------------
+;*
+;*   Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+;*   SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*    CpuAsm.asm
+;*
+;*   Abstract:
+;*
+;------------------------------------------------------------------------------
+
+#include <Base.h>
+%include "TdxCommondefs.inc"
+
+DEFAULT REL
+SECTION .text
+
+extern ASM_PFX(SecCoreStartupWithStack)
+
+%macro  tdcall  0
+  db  0x66, 0x0f, 0x01, 0xcc
+%endmacro
+
+;
+; SecCore Entry Point
+;
+; Processor is in flat protected mode
+;
+; @param[in]  RAX   Initial value of the EAX register (BIST: Built-in Self Test)
+; @param[in]  DI    'BP': boot-strap processor, or 'AP': application processor
+; @param[in]  RBP   Pointer to the start of the Boot Firmware Volume
+; @param[in]  DS    Selector allowing flat access to all addresses
+; @param[in]  ES    Selector allowing flat access to all addresses
+; @param[in]  FS    Selector allowing flat access to all addresses
+; @param[in]  GS    Selector allowing flat access to all addresses
+; @param[in]  SS    Selector allowing flat access to all addresses
+;
+; @return     None  This routine does not return
+;
+global ASM_PFX(_ModuleEntryPoint)
+ASM_PFX(_ModuleEntryPoint):
+
+    ;
+    ; Guest type is stored in OVMF_WORK_AREA
+    ;
+    %define OVMF_WORK_AREA        FixedPcdGet32 (PcdOvmfWorkAreaBase)
+    %define VM_GUEST_TYPE_TDX     2
+    mov     eax, OVMF_WORK_AREA
+    cmp     byte[eax], VM_GUEST_TYPE_TDX
+    jne     InitStack
+
+    mov     rax, TDCALL_TDINFO
+    tdcall
+
+    ;
+    ; R8  [31:0]  NUM_VCPUS
+    ;     [63:32] MAX_VCPUS
+    ; R9  [31:0]  VCPU_INDEX
+    ; Td Guest set the VCPU0 as the BSP, others are the APs
+    ; APs jump to spinloop and get released by DXE's MpInitLib
+    ;
+    mov     rax, r9
+    and     rax, 0xffff
+    test    rax, rax
+    jne     ParkAp
+
+InitStack:
+
+    ;
+    ; Fill the temporary RAM with the initial stack value.
+    ; The loop below will seed the heap as well, but that's harmless.
+    ;
+    mov     rax, (FixedPcdGet32 (PcdInitValueInTempStack) << 32) | FixedPcdGet32 (PcdInitValueInTempStack)
+                                                              ; qword to store
+    mov     rdi, FixedPcdGet32 (PcdOvmfSecPeiTempRamBase)     ; base address,
+                                                              ;   relative to
+                                                              ;   ES
+    mov     rcx, FixedPcdGet32 (PcdOvmfSecPeiTempRamSize) / 8 ; qword count
+    cld                                                       ; store from base
+                                                              ;   up
+    rep stosq
+
+    ;
+    ; Load temporary RAM stack based on PCDs
+    ;
+    %define SEC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + \
+                          FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
+    mov     rsp, SEC_TOP_OF_STACK
+    nop
+
+    ;
+    ; Setup parameters and call SecCoreStartupWithStack
+    ;   rcx: BootFirmwareVolumePtr
+    ;   rdx: TopOfCurrentStack
+    ;
+    mov     rcx, rbp
+    mov     rdx, rsp
+    sub     rsp, 0x20
+    call    ASM_PFX(SecCoreStartupWithStack)
+
+    ;
+    ; Note: BSP never gets here. APs will be unblocked by DXE
+    ;
+    ; R8  [31:0]  NUM_VCPUS
+    ;     [63:32] MAX_VCPUS
+    ; R9  [31:0]  VCPU_INDEX
+    ;
+ParkAp:
+
+    mov     rbp,  r9
+
+.do_wait_loop:
+    mov     rsp, FixedPcdGet32 (PcdOvmfSecGhcbBackupBase)
+
+    ;
+    ; register itself in [rsp + CpuArrivalOffset]
+    ;
+    mov       rax, 1
+    lock xadd dword [rsp + CpuArrivalOffset], eax
+    inc       eax
+
+.check_arrival_cnt:
+    cmp       eax, r8d
+    je        .check_command
+    mov       eax, dword[rsp + CpuArrivalOffset]
+    jmp       .check_arrival_cnt
+
+.check_command:
+    mov     eax, dword[rsp + CommandOffset]
+    cmp     eax, MpProtectedModeWakeupCommandNoop
+    je      .check_command
+
+    cmp     eax, MpProtectedModeWakeupCommandWakeup
+    je      .do_wakeup
+
+    ; Don't support this command, so ignore
+    jmp     .check_command
+
+.do_wakeup:
+    ;
+    ; BSP sets these variables before unblocking APs
+    ;   RAX:  WakeupVectorOffset
+    ;   RBX:  Relocated mailbox address
+    ;   RBP:  vCpuId
+    ;
+    mov     rax, 0
+    mov     eax, dword[rsp + WakeupVectorOffset]
+    mov     rbx, [rsp + WakeupArgsRelocatedMailBox]
+    nop
+    jmp     rax
+    jmp     $
-- 
2.29.2.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#86045): https://edk2.groups.io/g/devel/message/86045
Mute This Topic: https://groups.io/mt/88666805/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list