[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