diff --git a/ArmVirtPkg/ArmVirt.dsc.inc b/ArmVirtPkg/ArmVirt.dsc.inc
index 9ec92930472d..d9abadbe708c 100644
--- a/ArmVirtPkg/ArmVirt.dsc.inc
+++ b/ArmVirtPkg/ArmVirt.dsc.inc
@@ -290,7 +290,7 @@
[PcdsFixedAtBuild.common]
gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength|1000000
gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength|1000000
- gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|1000000
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|0
gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout|10000000
gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|320
diff --git a/CryptoPkg/Library/BaseCryptLib/SecCryptLib.inf b/CryptoPkg/Library/BaseCryptLib/SecCryptLib.inf
new file mode 100644
index 000000000000..fb792616921e
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLib/SecCryptLib.inf
@@ -0,0 +1,68 @@
+## @file
+# Cryptographic Library Instance for SEC.
+#
+# Caution: This module requires additional review when modified.
+# This library will have external input - signature.
+# This external input must be validated carefully to avoid security issues such as
+# buffer overflow or integer overflow.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SecCryptLib
+ MODULE_UNI_FILE = SecCryptLib.uni
+ FILE_GUID = 3689D343-0D32-4284-8053-BF10537990E8
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = BaseCryptLib|SEC
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ InternalCryptLib.h
+ Hash/CryptSha512.c
+
+ SysCall/CrtWrapper.c
+ SysCall/ConstantTimeClock.c
+ SysCall/BaseMemAllocation.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ DebugLib
+ OpensslLib
+ IntrinsicLib
+
+#
+# Remove these [BuildOptions] after this library is cleaned up
+#
+[BuildOptions]
+ #
+ # suppress the following warnings so we do not break the build with warnings-as-errors:
+ # C4090: 'function' : different 'const' qualifiers
+ # C4718: 'function call' : recursive call has no side effects, deleting
+ #
+ MSFT:*_*_*_CC_FLAGS = /wd4090 /wd4718
+
+ # -JCryptoPkg/Include : To disable the use of the system includes provided by RVCT
+ # --diag_remark=1 : Reduce severity of "#1-D: last line of file ends without a newline"
+ RVCT:*_*_ARM_CC_FLAGS = -JCryptoPkg/Include --diag_remark=1
+
+ GCC:*_CLANG35_*_CC_FLAGS = -std=c99
+ GCC:*_CLANG38_*_CC_FLAGS = -std=c99
+ GCC:*_CLANGPDB_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types
+
+ XCODE:*_*_*_CC_FLAGS = -std=c99
diff --git a/CryptoPkg/Library/BaseCryptLib/SecCryptLib.uni b/CryptoPkg/Library/BaseCryptLib/SecCryptLib.uni
new file mode 100644
index 000000000000..aa25c8ce7027
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLib/SecCryptLib.uni
@@ -0,0 +1,25 @@
+// /** @file
+// Cryptographic Library Instance for PEIM.
+//
+// Caution: This module requires additional review when modified.
+// This library will have external input - signature.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Note: AES
+// functions, RSA external functions, PKCS#7 SignedData sign functions,
+// Diffie-Hellman functions, X.509 certificate handler functions, authenticode
+// signature verification functions, PEM handler functions, and pseudorandom number
+// generator functions are not supported in this instance.
+//
+// Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Cryptographic Library Instance for PEIM"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Caution: This module requires additional review when modified. This library will have external input - signature. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow. Note: AES functions, RSA external functions, PKCS#7 SignedData sign functions, Diffie-Hellman functions, X.509 certificate handler functions, authenticode signature verification functions, PEM handler functions, and pseudorandom number generator functions are not supported in this instance."
+
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
index e317169d9c57..91bfcdaa38bc 100644
--- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
@@ -73,6 +73,7 @@
BaseLib
UefiDriverEntryPoint
DebugLib
+ TdxProbeLib
[Protocols]
gEfiPciHotPlugRequestProtocolGuid ## SOMETIMES_PRODUCES
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c
index 8db1ebf8ec41..a1e6db17b702 100644
--- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c
@@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include "PciBus.h"
+#include
+
/**
This routine is used to enumerate entire pci bus system
in a given platform.
@@ -533,6 +535,9 @@ GetMaxOptionRomSize (
UINT32 TempOptionRomSize;
MaxOptionRomSize = 0;
+ if(ProbeTdGuest()) {
+ return 0;
+ }
//
// Go through bridges to reach all devices
diff --git a/MdeModulePkg/Core/Dxe/DxeMain.h b/MdeModulePkg/Core/Dxe/DxeMain.h
index 9bd3c0d08411..3562d833e707 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.h
+++ b/MdeModulePkg/Core/Dxe/DxeMain.h
@@ -289,6 +289,8 @@ extern EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate;
extern EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable;
extern BOOLEAN gLoadFixedAddressCodeMemoryReady;
+
+extern BOOLEAN gTdGuest;
//
// Service Initialization Functions
//
diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/DxeMain.inf
index e4bca895773d..fb2218e062c4 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.inf
+++ b/MdeModulePkg/Core/Dxe/DxeMain.inf
@@ -94,6 +94,7 @@
DebugAgentLib
CpuExceptionHandlerLib
PcdLib
+ TdxProbeLib
[Guids]
gEfiEventMemoryMapChangeGuid ## PRODUCES ## Event
diff --git a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
index db21311f9352..e124a5d8428f 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
+++ b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
@@ -7,6 +7,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "DxeMain.h"
+#include
+
+BOOLEAN gTdGuest = FALSE;
//
// DXE Core Global Variables for Protocols from PEI
@@ -244,6 +247,11 @@ DxeMain (
EFI_VECTOR_HANDOFF_INFO *VectorInfo;
VOID *EntryPoint;
+ //
+ // Check whether it is of Td guest
+ //
+ gTdGuest = ProbeTdGuest();
+
//
// Setup the default exception handlers
//
diff --git a/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c b/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c
index 8dcbbeb5ee5a..09cf88c200b4 100644
--- a/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c
+++ b/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c
@@ -1,7 +1,7 @@
/** @file
Implements functions to read firmware file
-Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -128,6 +128,7 @@ FvGetNextFile (
UINTN *KeyValue;
LIST_ENTRY *Link;
FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ UINTN MaxFileType;
FvDevice = FV_DEVICE_FROM_THIS (This);
@@ -143,7 +144,16 @@ FvGetNextFile (
return EFI_ACCESS_DENIED;
}
- if (*FileType > EFI_FV_FILETYPE_MM_CORE_STANDALONE) {
+ //
+ // Td guest doesn't support SMM
+ //
+ if(gTdGuest) {
+ MaxFileType = EFI_FV_FILETYPE_SMM_CORE;
+ } else {
+ MaxFileType = EFI_FV_FILETYPE_MM_CORE_STANDALONE;
+ }
+
+ if (*FileType > MaxFileType) {
//
// File type needs to be in 0 - 0x0F
//
diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
index 51b082b7e7eb..1b9d591754c7 100644
--- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
+++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
@@ -35,6 +35,14 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)
+// TDX
+#define EXCLUSIVE_MEMORY_ATTRIBUTES (EFI_MEMORY_UC | EFI_MEMORY_WC | \
+ EFI_MEMORY_WT | EFI_MEMORY_WB | \
+ EFI_MEMORY_WP | EFI_MEMORY_UCE)
+
+#define NONEXCLUSIVE_MEMORY_ATTRIBUTES (EFI_MEMORY_XP | EFI_MEMORY_RP | \
+ EFI_MEMORY_RO)
+
//
// Module Variables
//
@@ -74,6 +82,9 @@ EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = {
NULL,
NULL
};
+// TD
+#define EFI_RESOURCE_ATTRIBUTE_ENCRYPTED 0x04000000
+
GCD_ATTRIBUTE_CONVERSION_ENTRY mAttributeConversionTable[] = {
{ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE, EFI_MEMORY_UC, TRUE },
@@ -90,6 +101,7 @@ GCD_ATTRIBUTE_CONVERSION_ENTRY mAttributeConversionTable[] = {
{ EFI_RESOURCE_ATTRIBUTE_TESTED, EFI_MEMORY_TESTED, FALSE },
{ EFI_RESOURCE_ATTRIBUTE_PERSISTABLE, EFI_MEMORY_NV, TRUE },
{ EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE, EFI_MEMORY_MORE_RELIABLE, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_ENCRYPTED, EFI_MEMORY_CPU_CRYPTO, TRUE }, // TDX
{ 0, 0, FALSE }
};
@@ -658,7 +670,11 @@ ConverToCpuArchAttributes (
{
UINT64 CpuArchAttributes;
- CpuArchAttributes = Attributes & EFI_MEMORY_ATTRIBUTE_MASK;
+ if(gTdGuest) {
+ CpuArchAttributes = Attributes & NONEXCLUSIVE_MEMORY_ATTRIBUTES;
+ } else {
+ CpuArchAttributes = Attributes & EFI_MEMORY_ATTRIBUTE_MASK;
+ }
if ( (Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) {
CpuArchAttributes |= EFI_MEMORY_UC;
@@ -944,7 +960,11 @@ CoreConvertSpace (
// Keep original CPU arch attributes when caller just calls
// SetMemorySpaceAttributes() with none CPU arch attributes (for example, RUNTIME).
//
- Attributes |= (Entry->Attributes & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+ if(gTdGuest) {
+ Attributes |= (Entry->Attributes & (EXCLUSIVE_MEMORY_ATTRIBUTES | NONEXCLUSIVE_MEMORY_ATTRIBUTES));
+ } else {
+ Attributes |= (Entry->Attributes & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+ }
}
Entry->Attributes = Attributes;
break;
@@ -2289,7 +2309,9 @@ CoreInitializeMemoryServices (
Attributes = PhitResourceHob->ResourceAttribute;
BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);
Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);
- FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
+ if(!gTdGuest) {
+ FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
+ }
if (Length < MinimalMemorySizeNeeded) {
//
// If that range is not large enough to intialize the DXE Core, then
@@ -2305,7 +2327,9 @@ CoreInitializeMemoryServices (
//
BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
Length = PageAlignLength ((UINT64)((UINTN)*HobStart - BaseAddress));
- FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
+ if(!gTdGuest) {
+ FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
+ }
}
}
break;
@@ -2369,7 +2393,9 @@ CoreInitializeMemoryServices (
//
TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
TestedMemoryLength = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress);
- FindLargestFreeRegion (&TestedMemoryBaseAddress, &TestedMemoryLength, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
+ if(!gTdGuest) {
+ FindLargestFreeRegion (&TestedMemoryBaseAddress, &TestedMemoryLength, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
+ }
if (TestedMemoryLength < MinimalMemorySizeNeeded) {
continue;
}
diff --git a/MdeModulePkg/Core/Dxe/Mem/Page.c b/MdeModulePkg/Core/Dxe/Mem/Page.c
index 731bf08bc959..a749ffd6e32e 100644
--- a/MdeModulePkg/Core/Dxe/Mem/Page.c
+++ b/MdeModulePkg/Core/Dxe/Mem/Page.c
@@ -1856,8 +1856,14 @@ CoreGetMemoryMap (
MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
MemoryMap->VirtualStart = 0;
MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
- MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
+ if(gTdGuest) {
+ MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
+ (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
+ EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
+ } else {
+ MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
(MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+ }
if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
MemoryMap->Type = EfiReservedMemoryType;
@@ -1890,8 +1896,14 @@ CoreGetMemoryMap (
MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
MemoryMap->VirtualStart = 0;
MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
- MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
+ if(gTdGuest) {
+ MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
+ (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
+ EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
+ } else {
+ MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
(MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+ }
MemoryMap->Type = EfiPersistentMemory;
//
@@ -1933,7 +1945,12 @@ CoreGetMemoryMap (
MemoryMapEnd = MemoryMap;
MemoryMap = MemoryMapStart;
while (MemoryMap < MemoryMapEnd) {
- MemoryMap->Attribute &= ~(UINT64)EFI_MEMORY_ACCESS_MASK;
+ if(gTdGuest) {
+ MemoryMap->Attribute &= ~(UINT64)(EFI_MEMORY_RP | EFI_MEMORY_RO |
+ EFI_MEMORY_XP);
+ } else {
+ MemoryMap->Attribute &= ~(UINT64)EFI_MEMORY_ACCESS_MASK;
+ }
MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
}
MergeMemoryMap (MemoryMapStart, &BufferSize, Size);
diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
index 7d1daf0b1938..dfa69cd6d3a1 100644
--- a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
+++ b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
@@ -42,6 +42,10 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include "DxeMain.h"
#include "Mem/HeapGuard.h"
+// TD
+#define CACHE_ATTRIBUTE_MASK (EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP)
+#define MEMORY_ATTRIBUTE_MASK (EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RO)
+
//
// Image type definitions
//
@@ -218,7 +222,11 @@ SetUefiImageMemoryAttributes (
Status = CoreGetMemorySpaceDescriptor(BaseAddress, &Descriptor);
ASSERT_EFI_ERROR(Status);
- FinalAttributes = (Descriptor.Attributes & EFI_CACHE_ATTRIBUTE_MASK) | (Attributes & EFI_MEMORY_ATTRIBUTE_MASK);
+ if(gTdGuest) {
+ FinalAttributes = (Descriptor.Attributes & CACHE_ATTRIBUTE_MASK) | (Attributes & MEMORY_ATTRIBUTE_MASK);
+ } else {
+ FinalAttributes = (Descriptor.Attributes & EFI_CACHE_ATTRIBUTE_MASK) | (Attributes & EFI_MEMORY_ATTRIBUTE_MASK);
+ }
DEBUG ((DEBUG_INFO, "SetUefiImageMemoryAttributes - 0x%016lx - 0x%016lx (0x%016lx)\n", BaseAddress, Length, FinalAttributes));
@@ -920,8 +928,13 @@ InitializeDxeNxMemoryProtectionPolicy (
(Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
- Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |
+ if(gTdGuest) {
+ Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |
+ (Entry->Attributes & CACHE_ATTRIBUTE_MASK);
+ } else {
+ Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |
(Entry->Attributes & EFI_CACHE_ATTRIBUTE_MASK);
+ }
DEBUG ((DEBUG_INFO,
"Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n",
diff --git a/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c b/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c
index 3cdb0b1ed74f..0afa80823c00 100644
--- a/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c
+++ b/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c
@@ -8,7 +8,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "SmbiosDxe.h"
-
+#include
//
// Module Global:
// Since this driver will only ever produce one instance of the
@@ -1428,6 +1428,10 @@ SmbiosDriverEntryPoint (
{
EFI_STATUS Status;
+ if(ProbeTdGuest()) {
+ return EFI_UNSUPPORTED;
+ }
+
mPrivateData.Signature = SMBIOS_INSTANCE_SIGNATURE;
mPrivateData.Smbios.Add = SmbiosAdd;
mPrivateData.Smbios.UpdateString = SmbiosUpdateString;
diff --git a/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf b/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
index f6c036e1dcbc..91b9321d544b 100644
--- a/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
+++ b/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
@@ -41,6 +41,7 @@
UefiDriverEntryPoint
DebugLib
PcdLib
+ TdxProbeLib
[Protocols]
gEfiSmbiosProtocolGuid ## PRODUCES
diff --git a/MdePkg/Include/IndustryStandard/Tdx.h b/MdePkg/Include/IndustryStandard/Tdx.h
new file mode 100644
index 000000000000..106c4daef686
--- /dev/null
+++ b/MdePkg/Include/IndustryStandard/Tdx.h
@@ -0,0 +1,199 @@
+/** @file
+ Intel Trust Domain Extension definitions
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _TDX_H_
+#define _TDX_H_
+
+#define EXIT_REASON_EXTERNAL_INTERRUPT 1
+#define EXIT_REASON_TRIPLE_FAULT 2
+
+#define EXIT_REASON_PENDING_INTERRUPT 7
+#define EXIT_REASON_NMI_WINDOW 8
+#define EXIT_REASON_TASK_SWITCH 9
+#define EXIT_REASON_CPUID 10
+#define EXIT_REASON_HLT 12
+#define EXIT_REASON_INVD 13
+#define EXIT_REASON_INVLPG 14
+#define EXIT_REASON_RDPMC 15
+#define EXIT_REASON_RDTSC 16
+#define EXIT_REASON_VMCALL 18
+#define EXIT_REASON_VMCLEAR 19
+#define EXIT_REASON_VMLAUNCH 20
+#define EXIT_REASON_VMPTRLD 21
+#define EXIT_REASON_VMPTRST 22
+#define EXIT_REASON_VMREAD 23
+#define EXIT_REASON_VMRESUME 24
+#define EXIT_REASON_VMWRITE 25
+#define EXIT_REASON_VMOFF 26
+#define EXIT_REASON_VMON 27
+#define EXIT_REASON_CR_ACCESS 28
+#define EXIT_REASON_DR_ACCESS 29
+#define EXIT_REASON_IO_INSTRUCTION 30
+#define EXIT_REASON_MSR_READ 31
+#define EXIT_REASON_MSR_WRITE 32
+#define EXIT_REASON_INVALID_STATE 33
+#define EXIT_REASON_MSR_LOAD_FAIL 34
+#define EXIT_REASON_MWAIT_INSTRUCTION 36
+#define EXIT_REASON_MONITOR_TRAP_FLAG 37
+#define EXIT_REASON_MONITOR_INSTRUCTION 39
+#define EXIT_REASON_PAUSE_INSTRUCTION 40
+#define EXIT_REASON_MCE_DURING_VMENTRY 41
+#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
+#define EXIT_REASON_APIC_ACCESS 44
+#define EXIT_REASON_EOI_INDUCED 45
+#define EXIT_REASON_GDTR_IDTR 46
+#define EXIT_REASON_LDTR_TR 47
+#define EXIT_REASON_EPT_VIOLATION 48
+#define EXIT_REASON_EPT_MISCONFIG 49
+#define EXIT_REASON_INVEPT 50
+#define EXIT_REASON_RDTSCP 51
+#define EXIT_REASON_PREEMPTION_TIMER 52
+#define EXIT_REASON_INVVPID 53
+#define EXIT_REASON_WBINVD 54
+#define EXIT_REASON_XSETBV 55
+#define EXIT_REASON_APIC_WRITE 56
+#define EXIT_REASON_RDRAND 57
+#define EXIT_REASON_INVPCID 58
+#define EXIT_REASON_VMFUNC 59
+#define EXIT_REASON_ENCLS 60
+#define EXIT_REASON_RDSEED 61
+#define EXIT_REASON_PML_FULL 62
+#define EXIT_REASON_XSAVES 63
+#define EXIT_REASON_XRSTORS 64
+
+// TDCALL API Function Completion Status Codes
+#define TDX_EXIT_REASON_SUCCESS 0x0000000000000000
+#define TDX_EXIT_REASON_PAGE_ALREADY_ACCEPTED 0x00000B0A00000000
+#define TDX_EXIT_REASON_OPERAND_INVALID 0xC000010000000000
+#define TDX_EXIT_REASON_OPERAND_BUSY 0x8000020000000000
+
+// TDCALL [TDG.MEM.PAGE.ACCEPT] page size
+#define TDCALL_ACCEPT_PAGE_SIZE_4K 0
+#define TDCALL_ACCEPT_PAGE_SIZE_2M 1
+#define TDCALL_ACCEPT_PAGE_SIZE_1G 2
+
+#define TDCALL_TDVMCALL 0
+#define TDCALL_TDINFO 1
+#define TDCALL_TDEXTENDRTMR 2
+#define TDCALL_TDGETVEINFO 3
+#define TDCALL_TDREPORT 4
+#define TDCALL_TDSETCPUIDVE 5
+#define TDCALL_TDACCEPTPAGE 6
+
+#define TDVMCALL_CPUID 0x0000a
+#define TDVMCALL_HALT 0x0000c
+#define TDVMCALL_IO 0x0001e
+#define TDVMCALL_RDMSR 0x0001f
+#define TDVMCALL_WRMSR 0x00020
+#define TDVMCALL_MMIO 0x00030
+#define TDVMCALL_PCONFIG 0x00041
+
+#define TDVMCALL_GET_TDVMCALL_INFO 0x10000
+#define TDVMCALL_MAPGPA 0x10001
+#define TDVMCALL_GET_QUOTE 0x10002
+#define TDVMCALL_REPORT_FATAL_ERR 0x10003
+#define TDVMCALL_SETUP_EVENT_NOTIFY 0x10004
+
+#pragma pack(1)
+typedef struct {
+ UINT64 Data[6];
+} TDCALL_GENERIC_RETURN_DATA;
+
+typedef struct {
+ UINT64 Gpaw;
+ UINT64 Attributes;
+ UINT32 MaxVcpus;
+ UINT32 NumVcpus;
+ UINT64 Resv[3];
+} TDCALL_INFO_RETURN_DATA;
+
+typedef union {
+ UINT64 Val;
+ struct {
+ UINT32 Size:3;
+ UINT32 Direction:1;
+ UINT32 String:1;
+ UINT32 Rep:1;
+ UINT32 Encoding:1;
+ UINT32 Resv:9;
+ UINT32 Port:16;
+ UINT32 Resv2;
+ } Io;
+} VMX_EXIT_QUALIFICATION;
+
+typedef struct {
+ UINT32 ExitReason;
+ UINT32 Resv;
+ VMX_EXIT_QUALIFICATION ExitQualification;
+ UINT64 GuestLA;
+ UINT64 GuestPA;
+ UINT32 ExitInstructionLength;
+ UINT32 ExitInstructionInfo;
+ UINT32 Resv1;
+} TDCALL_VEINFO_RETURN_DATA;
+
+typedef union {
+ TDCALL_GENERIC_RETURN_DATA Generic;
+ TDCALL_INFO_RETURN_DATA TdInfo;
+ TDCALL_VEINFO_RETURN_DATA VeInfo;
+} TD_RETURN_DATA;
+
+/* data structure used in TDREPORT_STRUCT */
+typedef struct {
+ UINT8 Type;
+ UINT8 Subtype;
+ UINT8 Version;
+ UINT8 Rsvd;
+} TD_REPORT_TYPE;
+
+typedef struct {
+ TD_REPORT_TYPE ReportType;
+ UINT8 Rsvd1[12];
+ UINT8 CpuSvn[16];
+ UINT8 TeeTcbInfoHash[48];
+ UINT8 TeeInfoHash[48];
+ UINT8 ReportData[64];
+ UINT8 Rsvd2[32];
+ UINT8 Mac[32];
+} REPORTMACSTRUCT;
+
+typedef struct {
+ UINT8 Seam[2];
+ UINT8 Rsvd[14];
+} TEE_TCB_SVN;
+
+typedef struct {
+ UINT8 Valid[8];
+ TEE_TCB_SVN TeeTcbSvn;
+ UINT8 Mrseam[48];
+ UINT8 Mrsignerseam[48];
+ UINT8 Attributes[8];
+ UINT8 Rsvd[111];
+} TEE_TCB_INFO;
+
+typedef struct {
+ UINT8 Attributes[8];
+ UINT8 Xfam[8];
+ UINT8 Mrtd[48];
+ UINT8 Mrconfigid[48];
+ UINT8 Mrowner[48];
+ UINT8 Mrownerconfig[48];
+ UINT8 Rtmrs[4][48];
+ UINT8 Rsvd[112];
+} TDINFO;
+
+typedef struct {
+ REPORTMACSTRUCT ReportMacStruct;
+ TEE_TCB_INFO TeeTcbInfo;
+ UINT8 Rsvd[17];
+ TDINFO Tdinfo;
+} TDREPORT_STRUCT;
+
+#pragma pack()
+
+#endif
diff --git a/MdePkg/Include/Library/HobLib.h b/MdePkg/Include/Library/HobLib.h
index 517365eae594..9e3801103ebb 100644
--- a/MdePkg/Include/Library/HobLib.h
+++ b/MdePkg/Include/Library/HobLib.h
@@ -473,6 +473,105 @@ BuildMemoryAllocationHob (
IN EFI_MEMORY_TYPE MemoryType
);
+
+VOID *
+EFIAPI
+PrePeiGetHobList(
+ VOID
+);
+
+EFI_STATUS
+EFIAPI
+PrePeiSetHobList(
+ IN VOID *HobList
+ );
+
+/**
+ Builds a Firmware Volume HOB and a resource descriptor hob
+
+ This function builds a Firmware Volume HOB.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+
+**/
+VOID
+EFIAPI
+BuildFvHobs (
+ IN EFI_PHYSICAL_ADDRESS PhysicalStart,
+ IN UINT64 NumberOfBytes,
+ IN EFI_RESOURCE_ATTRIBUTE_TYPE *ResourceAttribute OPTIONAL
+ );
+
+
+/**
+ Updates the pointer to the HOB list.
+
+ @param HobList Hob list pointer to store
+
+**/
+EFI_STATUS
+EFIAPI
+SetHobList (
+ IN VOID *HobList
+ );
+
+EFI_HOB_HANDOFF_INFO_TABLE*
+HobConstructor (
+ IN VOID *EfiMemoryBegin,
+ IN UINTN EfiMemoryLength,
+ IN VOID *EfiFreeMemoryBottom,
+ IN VOID *EfiFreeMemoryTop
+ );
+
+/**
+ This service enables PEIMs to create various types of HOBs.
+
+ @param Type The type of HOB to be installed.
+ @param Length The length of the HOB to be added.
+
+ @retval !NULL The HOB was successfully created.
+ @retval NULL There is no additional space for HOB creation.
+
+**/
+VOID *
+CreateHob (
+ IN UINT16 HobType,
+ IN UINT16 HobLenght
+ );
+
+
+/**
+ This service enables PEIMs to update the boot mode variable.
+
+ @param BootMode The value of the boot mode to set.
+
+ @retval EFI_SUCCESS The value was successfully updated
+
+**/
+EFI_STATUS
+EFIAPI
+SetBootMode (
+ IN EFI_BOOT_MODE BootMode
+ );
+
+/**
+ Update the Stack Hob if the stack has been moved
+
+ @param BaseAddress The 64 bit physical address of the Stack.
+ @param Length The length of the stack in bytes.
+
+**/
+VOID
+UpdateStackHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+
/**
Returns the type of a HOB.
diff --git a/MdePkg/Include/Library/MemoryAllocationLib.h b/MdePkg/Include/Library/MemoryAllocationLib.h
index 65a30cf146dd..8f0fae6c73e1 100644
--- a/MdePkg/Include/Library/MemoryAllocationLib.h
+++ b/MdePkg/Include/Library/MemoryAllocationLib.h
@@ -484,4 +484,26 @@ FreePool (
IN VOID *Buffer
);
+/**
+ Allocates one or more 4KB pages of given type MemoryType.
+
+ Allocates the number of 4KB pages of MemoryType and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param MemoryType Type of memory to use for this allocation.
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePagesWithMemoryType (
+ IN UINTN MemoryType,
+ IN UINTN Pages
+ );
+
+
#endif
diff --git a/MdePkg/Include/Library/TdxLib.h b/MdePkg/Include/Library/TdxLib.h
new file mode 100644
index 000000000000..5c089ed2262a
--- /dev/null
+++ b/MdePkg/Include/Library/TdxLib.h
@@ -0,0 +1,145 @@
+/** @file
+ TdxLib definitions
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _TDX_LIB_H_
+#define _TDX_LIB_H_
+
+#include
+#include
+#include
+#include
+
+/**
+ This function accepts a pending private page, and initialize the page to
+ all-0 using the TD ephemeral private key.
+
+ @param[in] StartAddress Guest physical address of the private page
+ to accept.
+ @param[in] NumberOfPages Number of the pages to be accepted.
+ @param[in] PageSize GPA page size. Accept 1G/2M/4K page size.
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+TdAcceptPages (
+ IN UINT64 StartAddress,
+ IN UINT64 NumberOfPages,
+ IN UINT64 PageSize
+ );
+
+/**
+ This function extends one of the RTMR measurement register
+ in TDCS with the provided extension data in memory.
+ RTMR extending supports SHA384 which length is 48 bytes.
+
+ @param[in] Data Point to the data to be extended
+ @param[in] DataLen Length of the data. Must be 48
+ @param[in] Index RTMR index
+
+ @return EFI_SUCCESS
+ @return EFI_INVALID_PARAMETER
+ @return EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+TdExtendRtmr (
+ IN UINT32 *Data,
+ IN UINT32 DataLen,
+ IN UINT8 Index
+ );
+
+
+/**
+ This function ges the Td guest shared page mask.
+
+ The guest indicates if a page is shared using the Guest Physical Address
+ (GPA) Shared (S) bit. If the GPA Width(GPAW) is 48, the S-bit is bit-47.
+ If the GPAW is 52, the S-bit is bit-51.
+
+ @return Shared page bit mask
+**/
+UINT64
+EFIAPI
+TdSharedPageMask (
+ VOID
+ );
+
+
+/**
+ The TDCALL instruction causes a VM exit to the Intel TDX module. It is
+ used to call guest-side Intel TDX functions, either local or a TD exit
+ to the host VMM, as selected by Leaf.
+ Leaf functions are described at
+
+ @param[in] Leaf Leaf number of TDCALL instruction
+ @param[in] Arg1 Arg1
+ @param[in] Arg2 Arg2
+ @param[in] Arg3 Arg3
+ @param[in,out] Results Returned result of the Leaf function
+
+ @return EFI_SUCCESS
+ @return Other See individual leaf functions
+**/
+EFI_STATUS
+EFIAPI
+TdCall (
+ IN UINT64 Leaf,
+ IN UINT64 Arg1,
+ IN UINT64 Arg2,
+ IN UINT64 Arg3,
+ IN OUT VOID *Results
+ );
+
+/**
+ TDVMALL is a leaf function 0 for TDCALL. It helps invoke services from the
+ host VMM to pass/receive information.
+
+ @param[in] Leaf Number of sub-functions
+ @param[in] Arg1 Arg1
+ @param[in] Arg2 Arg2
+ @param[in] Arg3 Arg3
+ @param[in] Arg4 Arg4
+ @param[in,out] Results Returned result of the sub-function
+
+ @return EFI_SUCCESS
+ @return Other See individual sub-functions
+
+**/
+EFI_STATUS
+EFIAPI
+TdVmCall (
+ IN UINT64 Leaf,
+ IN UINT64 Arg1,
+ IN UINT64 Arg2,
+ IN UINT64 Arg3,
+ IN UINT64 Arg4,
+ IN OUT VOID *Results
+ );
+
+/**
+ This function enable the TD guest to request the VMM to emulate CPUID
+ operation, especially for non-architectural, CPUID leaves.
+
+ @param[in] Eax Main leaf of the CPUID
+ @param[in] Ecx Sub-leaf of the CPUID
+ @param[out] Results Returned result of CPUID operation
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+TdVmCallCpuid (
+ IN UINT64 Eax,
+ IN UINT64 Ecx,
+ OUT VOID *Results
+ );
+
+#endif
diff --git a/MdePkg/Include/Library/TdxProbeLib.h b/MdePkg/Include/Library/TdxProbeLib.h
new file mode 100644
index 000000000000..177c684f5622
--- /dev/null
+++ b/MdePkg/Include/Library/TdxProbeLib.h
@@ -0,0 +1,25 @@
+/** @file
+ TdxProbeLib definitions
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _TDX_PROBE_LIB_H_
+#define _TDX_PROBE_LIB_H_
+
+#include
+
+/**
+ Check whether it is TD guest or Non-TD guest
+
+ @return TRUE TD guest
+ @return FALSE Non-TD guest
+**/
+BOOLEAN
+EFIAPI
+ProbeTdGuest (
+ VOID);
+
+#endif
diff --git a/MdePkg/Include/Protocol/Tdx.h b/MdePkg/Include/Protocol/Tdx.h
new file mode 100644
index 000000000000..0c09feb6fd4d
--- /dev/null
+++ b/MdePkg/Include/Protocol/Tdx.h
@@ -0,0 +1,28 @@
+/** @file
+ If TD-Guest firmware supports measurement and an event is created, TD-Guest
+ firmware is designed to report the event log with the same data structure
+ in TCG-Platform-Firmware-Profile specification with
+ EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 format.
+
+ The TD-Guest firmware supports measurement, the TD Guest Firmware is designed
+ to produce EFI_TD_PROTOCOL with new GUID EFI_TD_PROTOCOL_GUID to report
+ event log and provides hash capability.
+
+Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef __EFI_TDX_PROTOCOL_H__
+#define __EFI_TDX_PROTOCOL_H__
+
+#include
+
+#define EFI_TD_PROTOCOL_GUID \
+ {0x96751a3d, 0x72f4, 0x41a6, { 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b }}
+
+extern EFI_GUID gTdTcg2ProtocolGuid;
+
+
+#endif
diff --git a/MdePkg/Include/Protocol/TdxAcpi.h b/MdePkg/Include/Protocol/TdxAcpi.h
new file mode 100644
index 000000000000..f7cd2eac5d4f
--- /dev/null
+++ b/MdePkg/Include/Protocol/TdxAcpi.h
@@ -0,0 +1,29 @@
+/** @file
+ TBD
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef __TDX_ACPI_H__
+#define __TDX_ACPI_H__
+
+#include
+
+#define EFI_TDX_EVENTLOG_ACPI_TABLE_SIGNATURE SIGNATURE_32('T', 'D', 'E', 'L')
+#define EFI_TDX_EVENTLOG_ACPIT_TABLE_REVISION 1
+
+#pragma pack(1)
+
+typedef struct {
+ EFI_ACPI_DESCRIPTION_HEADER Header;
+ UINT32 Rsvd;
+ UINT64 Laml;
+ UINT64 Lasa;
+} EFI_TDX_EVENTLOG_ACPI_TABLE;
+
+#pragma pack()
+
+#endif
\ No newline at end of file
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
index 86a07e60f838..84fdf6adb79c 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
@@ -1,52 +1,52 @@
-## @file
-# Instance of I/O Library using compiler intrinsics.
-#
-# I/O Library that uses compiler intrinsics to perform IN and OUT instructions
-# for IA-32 and x64.
-#
-# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
-# Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
-# Copyright (c) 2017, AMD Incorporated. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = BaseIoLibIntrinsicSev
- MODULE_UNI_FILE = BaseIoLibIntrinsic.uni
- FILE_GUID = 93742f95-6e71-4581-b600-8e1da443f95a
- MODULE_TYPE = BASE
- VERSION_STRING = 1.0
- LIBRARY_CLASS = IoLib
-
-
-#
-# VALID_ARCHITECTURES = IA32 X64
-#
-
-[Sources]
- IoLibMmioBuffer.c
- BaseIoLibIntrinsicInternal.h
- IoHighLevel.c
-
-[Sources.IA32]
- IoLibGcc.c | GCC
- IoLibMsc.c | MSFT
- IoLib.c
- Ia32/IoFifoSev.nasm
-
-[Sources.X64]
- IoLibGcc.c | GCC
- IoLibMsc.c | MSFT
- IoLib.c
- X64/IoFifoSev.nasm
-
-[Packages]
- MdePkg/MdePkg.dec
-
-[LibraryClasses]
- DebugLib
- BaseLib
-
+## @file
+# Instance of I/O Library using compiler intrinsics.
+#
+# I/O Library that uses compiler intrinsics to perform IN and OUT instructions
+# for IA-32 and x64.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+# Copyright (c) 2017, AMD Incorporated. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseIoLibIntrinsicSev
+ MODULE_UNI_FILE = BaseIoLibIntrinsic.uni
+ FILE_GUID = 93742f95-6e71-4581-b600-8e1da443f95a
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IoLib
+
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ IoLibMmioBuffer.c
+ BaseIoLibIntrinsicInternal.h
+ IoHighLevel.c
+
+[Sources.IA32]
+ IoLibGcc.c | GCC
+ IoLibMsc.c | MSFT
+ IoLib.c
+ Ia32/IoFifoSev.nasm
+
+[Sources.X64]
+ IoLibGcc.c | GCC
+ IoLibMsc.c | MSFT
+ IoLib.c
+ X64/IoFifoSev.nasm
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseLib
+
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicTdx.inf b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicTdx.inf
new file mode 100644
index 000000000000..3032460dfadc
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicTdx.inf
@@ -0,0 +1,53 @@
+## @file
+# Instance of I/O Library compatible for both Td guest and Non-Td guest.
+#
+# For Non-Td guest this I/O Library uses compiler intrinsics to perform
+# IN and OUT instructions for X64.
+#
+# For Td guest this I/O Library uses TDVMCALL to perform IN and OUT
+# instruction for X64.
+#
+# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.
+# Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+# Copyright (c) 2017, AMD Incorporated. All rights reserved.
+# Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseIoLibIntrinsicTdx
+ MODULE_UNI_FILE = BaseIoLibIntrinsic.uni
+ FILE_GUID = 681b9f30-fc2d-11ea-8b6e-0800200c9a66
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IoLib
+
+
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ IoLibMmioBuffer.c
+ BaseIoLibIntrinsicInternal.h
+ IoHighLevel.c
+
+[Sources.X64]
+ IoLibGccTdx.c | GCC
+ IoLibMscTdx.c | MSFT
+ IoLibInternalTdx.c
+ IoLibTdx.c
+ X64/IoFifoSev.nasm
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseLib
+ TdxLib
+ TdxProbeLib
+
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGccTdx.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGccTdx.c
new file mode 100644
index 000000000000..a8e4295f8767
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGccTdx.c
@@ -0,0 +1,231 @@
+/** @file
+ I/O Library. This file has compiler specifics for GCC as there is no
+ ANSI C standard for doing IO.
+
+ GCC - uses EFIAPI assembler. __asm__ calls GAS. __volatile__ makes sure the
+ compiler puts the assembler in this exact location. The complex GNUC
+ operations are not optimzed. It would be possible to also write these
+ with EFIAPI assembler.
+
+ We don't advocate putting compiler specifics in libraries or drivers but there
+ is no other way to make this work.
+
+ Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "BaseIoLibIntrinsicInternal.h"
+#include
+#include "IoLibTdx.h"
+
+/**
+ Reads an 8-bit I/O port.
+
+ Reads the 8-bit I/O port specified by Port. The 8-bit read value is returned.
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT()
+
+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+IoRead8 (
+ IN UINTN Port
+ )
+{
+ UINT8 Data;
+
+ if (ProbeTdGuest ()) {
+ Data = TdIoRead8 (Port);
+ return Data;
+ }
+
+ __asm__ __volatile__ ("inb %w1,%b0" : "=a" (Data) : "d" ((UINT16)Port));
+ return Data;
+}
+
+/**
+ Writes an 8-bit I/O port.
+
+ Writes the 8-bit I/O port specified by Port with the value specified by Value
+ and returns Value. This function must guarantee that all I/O read and write
+ operations are serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT8
+EFIAPI
+IoWrite8 (
+ IN UINTN Port,
+ IN UINT8 Value
+ )
+{
+ if (ProbeTdGuest ()) {
+ TdIoWrite8 (Port, Value);
+ return Value;
+ }
+ __asm__ __volatile__ ("outb %b0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ return Value;;
+}
+
+/**
+ Reads a 16-bit I/O port.
+
+ Reads the 16-bit I/O port specified by Port. The 16-bit read value is returned.
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 16-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT16
+EFIAPI
+IoRead16 (
+ IN UINTN Port
+ )
+{
+ UINT16 Data;
+
+ ASSERT ((Port & 1) == 0);
+
+ if (ProbeTdGuest ()) {
+ Data = TdIoRead16 (Port);
+ return Data;
+ }
+
+ __asm__ __volatile__ ("inw %w1,%w0" : "=a" (Data) : "d" ((UINT16)Port));
+ return Data;
+}
+
+/**
+ Writes a 16-bit I/O port.
+
+ Writes the 16-bit I/O port specified by Port with the value specified by Value
+ and returns Value. This function must guarantee that all I/O read and write
+ operations are serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 16-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT16
+EFIAPI
+IoWrite16 (
+ IN UINTN Port,
+ IN UINT16 Value
+ )
+{
+ ASSERT ((Port & 1) == 0);
+
+ if (ProbeTdGuest ()) {
+ TdIoWrite16 (Port, Value);
+ return Value;
+ }
+
+ __asm__ __volatile__ ("outw %w0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ return Value;;
+}
+
+/**
+ Reads a 32-bit I/O port.
+
+ Reads the 32-bit I/O port specified by Port. The 32-bit read value is returned.
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 32-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT32
+EFIAPI
+IoRead32 (
+ IN UINTN Port
+ )
+{
+ UINT32 Data;
+
+ ASSERT ((Port & 3) == 0);
+
+ if (ProbeTdGuest ()) {
+ Data = TdIoRead32 (Port);
+ return Data;
+ }
+
+ __asm__ __volatile__ ("inl %w1,%0" : "=a" (Data) : "d" ((UINT16)Port));
+ return Data;
+}
+
+/**
+ Writes a 32-bit I/O port.
+
+ Writes the 32-bit I/O port specified by Port with the value specified by Value
+ and returns Value. This function must guarantee that all I/O read and write
+ operations are serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 32-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT32
+EFIAPI
+IoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ )
+{
+ ASSERT ((Port & 3) == 0);
+
+ if (ProbeTdGuest ()) {
+ TdIoWrite32 (Port, Value);
+ return Value;
+ }
+
+ __asm__ __volatile__ ("outl %0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ return Value;
+}
+
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
new file mode 100644
index 000000000000..eec490ac3816
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
@@ -0,0 +1,456 @@
+/** @file
+ TDX I/O Library routines.
+
+ Copyright (c) 2020-2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "IoLibTdx.h"
+#include
+#include
+
+// Size of TDVMCALL Access, including IO and MMIO
+#define TDVMCALL_ACCESS_SIZE_1 1
+#define TDVMCALL_ACCESS_SIZE_2 2
+#define TDVMCALL_ACCESS_SIZE_4 4
+#define TDVMCALL_ACCESS_SIZE_8 8
+
+// Direction of TDVMCALL Access, including IO and MMIO
+#define TDVMCALL_ACCESS_READ 0
+#define TDVMCALL_ACCESS_WRITE 1
+
+/**
+ Reads an 8-bit I/O port.
+
+ TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdIoRead8 (
+ IN UINTN Port
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Port, 0, &Val);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ return (UINT8)Val;
+}
+
+/**
+ Reads a 16-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdIoRead16 (
+ IN UINTN Port
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ ASSERT ((Port & 1) == 0);
+
+ Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_READ, Port, 0, &Val);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ return (UINT16)Val;
+}
+
+/**
+ Reads a 32-bit I/O port.
+
+ TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdIoRead32 (
+ IN UINTN Port
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ ASSERT ((Port & 3) == 0);
+
+ Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_READ, Port, 0, &Val);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ return (UINT32)Val;
+}
+
+/**
+ Writes an 8-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT8
+EFIAPI
+TdIoWrite8 (
+ IN UINTN Port,
+ IN UINT8 Value
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_WRITE, Port, Val, 0);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ return Value;;
+}
+
+/**
+ Writes a 16-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT16
+EFIAPI
+TdIoWrite16 (
+ IN UINTN Port,
+ IN UINT16 Value
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ ASSERT ((Port & 1) == 0);
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_WRITE, Port, Val, 0);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ return Value;;
+}
+
+/**
+ Writes a 32-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT32
+EFIAPI
+TdIoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ ASSERT ((Port & 3) == 0);
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_WRITE, Port, Val, 0);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ return Value;;
+}
+
+/**
+ Reads an 8-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdMmioRead8 (
+ IN UINTN Address
+ )
+{
+ UINT64 Value;
+ UINT64 Status;
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+ if (Status != 0) {
+ Value = *(volatile UINT64*)Address;
+ }
+ MemoryFence ();
+
+ return (UINT8)Value;
+}
+
+/**
+ Writes an 8-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read write registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT8
+EFIAPI
+TdMmioWrite8 (
+ IN UINTN Address,
+ IN UINT8 Val
+ )
+{
+ UINT64 Value;
+ UINT64 Status;
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Value = Val;
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_WRITE, Address, Value, 0);
+ if (Status != 0) {
+ *(volatile UINT8*)Address = Val;
+ }
+ MemoryFence ();
+
+ return Val;
+}
+
+/**
+ Reads a 16-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdMmioRead16 (
+ IN UINTN Address
+ )
+{
+ UINT64 Value;
+ UINT64 Status;
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+ if (Status != 0) {
+ Value = *(volatile UINT64*)Address;
+ }
+ MemoryFence ();
+
+ return (UINT16)Value;
+}
+
+/**
+ Writes a 16-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT16
+EFIAPI
+TdMmioWrite16 (
+ IN UINTN Address,
+ IN UINT16 Val
+ )
+{
+ UINT64 Value;
+ UINT64 Status;
+
+ ASSERT ((Address & 1) == 0);
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Value = Val;
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_WRITE, Address, Value, 0);
+ if (Status != 0) {
+ *(volatile UINT16*)Address = Val;
+ }
+ MemoryFence ();
+
+ return Val;
+}
+
+/**
+ Reads a 32-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdMmioRead32 (
+ IN UINTN Address
+ )
+{
+ UINT64 Value;
+ UINT64 Status;
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+ if (Status != 0) {
+ Value = *(volatile UINT64*)Address;
+ }
+ MemoryFence ();
+
+ return (UINT32)Value;
+}
+
+/**
+ Writes a 32-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT32
+EFIAPI
+TdMmioWrite32 (
+ IN UINTN Address,
+ IN UINT32 Val
+ )
+{
+ UINT64 Value;
+ UINT64 Status;
+
+ ASSERT ((Address & 3) == 0);
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Value = Val;
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_WRITE, Address, Value, 0);
+ if (Status != 0) {
+ *(volatile UINT32*)Address = Val;
+ }
+ MemoryFence ();
+
+ return Val;
+}
+
+/**
+ Reads a 64-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT64
+EFIAPI
+TdMmioRead64 (
+ IN UINTN Address
+ )
+{
+ UINT64 Value;
+ UINT64 Status;
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+ if (Status != 0) {
+ Value = *(volatile UINT64*)Address;
+ }
+ MemoryFence ();
+
+ return Value;
+}
+
+/**
+ Writes a 64-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+**/
+UINT64
+EFIAPI
+TdMmioWrite64 (
+ IN UINTN Address,
+ IN UINT64 Value
+ )
+{
+ UINT64 Status;
+
+ ASSERT ((Address & 7) == 0);
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_WRITE, Address, Value, 0);
+ if (Status != 0) {
+ *(volatile UINT64*)Address = Value;
+ }
+ MemoryFence ();
+ return Value;
+}
+
+
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibMscTdx.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMscTdx.c
new file mode 100644
index 000000000000..247a6bdafa2a
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMscTdx.c
@@ -0,0 +1,271 @@
+/** @file
+ I/O Library. This file has compiler specifics for Microsft C as there is no
+ ANSI C standard for doing IO.
+
+ MSC - uses intrinsic functions and the optimize will remove the function call
+ overhead.
+
+ We don't advocate putting compiler specifics in libraries or drivers but there
+ is no other way to make this work.
+
+ Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#include "BaseIoLibIntrinsicInternal.h"
+#include
+#include "IoLibTdx.h"
+
+//
+// Microsoft Visual Studio 7.1 Function Prototypes for I/O Intrinsics.
+//
+
+int _inp (unsigned short port);
+unsigned short _inpw (unsigned short port);
+unsigned long _inpd (unsigned short port);
+int _outp (unsigned short port, int databyte );
+unsigned short _outpw (unsigned short port, unsigned short dataword );
+unsigned long _outpd (unsigned short port, unsigned long dataword );
+void _ReadWriteBarrier (void);
+
+#pragma intrinsic(_inp)
+#pragma intrinsic(_inpw)
+#pragma intrinsic(_inpd)
+#pragma intrinsic(_outp)
+#pragma intrinsic(_outpw)
+#pragma intrinsic(_outpd)
+#pragma intrinsic(_ReadWriteBarrier)
+
+//
+// _ReadWriteBarrier() forces memory reads and writes to complete at the point
+// in the call. This is only a hint to the compiler and does emit code.
+// In past versions of the compiler, _ReadWriteBarrier was enforced only
+// locally and did not affect functions up the call tree. In Visual C++
+// 2005, _ReadWriteBarrier is enforced all the way up the call tree.
+//
+
+/**
+ Reads an 8-bit I/O port.
+
+ Reads the 8-bit I/O port specified by Port. The 8-bit read value is returned.
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+IoRead8 (
+ IN UINTN Port
+ )
+{
+ UINT8 Value;
+
+ if (ProbeTdGuest ()) {
+ Value = TdIoRead8 (Port);
+ return Value;
+ }
+
+ _ReadWriteBarrier ();
+ Value = (UINT8)_inp ((UINT16)Port);
+ _ReadWriteBarrier ();
+ return Value;
+}
+
+/**
+ Writes an 8-bit I/O port.
+
+ Writes the 8-bit I/O port specified by Port with the value specified by Value
+ and returns Value. This function must guarantee that all I/O read and write
+ operations are serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written to the I/O port.
+
+**/
+UINT8
+EFIAPI
+IoWrite8 (
+ IN UINTN Port,
+ IN UINT8 Value
+ )
+{
+
+ if (ProbeTdGuest ()) {
+ TdIoWrite8 (Port, Value);
+ return Value;
+ }
+
+ _ReadWriteBarrier ();
+ (UINT8)_outp ((UINT16)Port, Value);
+ _ReadWriteBarrier ();
+ return Value;
+}
+
+/**
+ Reads a 16-bit I/O port.
+
+ Reads the 16-bit I/O port specified by Port. The 16-bit read value is returned.
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 16-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT16
+EFIAPI
+IoRead16 (
+ IN UINTN Port
+ )
+{
+ UINT16 Value;
+
+ ASSERT ((Port & 1) == 0);
+
+ if (ProbeTdGuest ()) {
+ Value = TdIoRead16 (Port);
+ return Value;
+ }
+
+ _ReadWriteBarrier ();
+ Value = _inpw ((UINT16)Port);
+ _ReadWriteBarrier ();
+ return Value;
+}
+
+/**
+ Writes a 16-bit I/O port.
+
+ Writes the 16-bit I/O port specified by Port with the value specified by Value
+ and returns Value. This function must guarantee that all I/O read and write
+ operations are serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 16-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written to the I/O port.
+
+**/
+UINT16
+EFIAPI
+IoWrite16 (
+ IN UINTN Port,
+ IN UINT16 Value
+ )
+{
+ ASSERT ((Port & 1) == 0);
+
+ if (ProbeTdGuest ()) {
+ TdIoWrite16 (Port, Value);
+ return Value;
+ }
+
+ _ReadWriteBarrier ();
+ _outpw ((UINT16)Port, Value);
+ _ReadWriteBarrier ();
+ return Value;
+}
+
+/**
+ Reads a 32-bit I/O port.
+
+ Reads the 32-bit I/O port specified by Port. The 32-bit read value is returned.
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 32-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT32
+EFIAPI
+IoRead32 (
+ IN UINTN Port
+ )
+{
+ UINT32 Value;
+
+ ASSERT ((Port & 3) == 0);
+
+ if (ProbeTdGuest ()) {
+ Value = TdIoRead32 (Port);
+ return Value;
+ }
+
+ _ReadWriteBarrier ();
+ Value = _inpd ((UINT16)Port);
+ _ReadWriteBarrier ();
+ return Value;
+}
+
+/**
+ Writes a 32-bit I/O port.
+
+ Writes the 32-bit I/O port specified by Port with the value specified by Value
+ and returns Value. This function must guarantee that all I/O read and write
+ operations are serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 32-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written to the I/O port.
+
+**/
+UINT32
+EFIAPI
+IoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ )
+{
+ ASSERT ((Port & 3) == 0);
+
+ if (ProbeTdGuest ()) {
+ TdIoWrite32 (Port, Value);
+ return Value;
+ }
+
+ _ReadWriteBarrier ();
+ _outpd ((UINT16)Port, Value);
+ _ReadWriteBarrier ();
+ return Value;
+}
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.c
new file mode 100644
index 000000000000..db208f74a600
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.c
@@ -0,0 +1,369 @@
+/** @file
+ Common I/O Library routines.
+
+ Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BaseIoLibIntrinsicInternal.h"
+#include
+#include "IoLibTdx.h"
+
+/**
+ Reads a 64-bit I/O port.
+
+ Reads the 64-bit I/O port specified by Port. The 64-bit read value is returned.
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 64-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 64-bit boundary, then ASSERT().
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT64
+EFIAPI
+IoRead64 (
+ IN UINTN Port
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Writes a 64-bit I/O port.
+
+ Writes the 64-bit I/O port specified by Port with the value specified by Value
+ and returns Value. This function must guarantee that all I/O read and write
+ operations are serialized.
+
+ If 64-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 64-bit boundary, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT64
+EFIAPI
+IoWrite64 (
+ IN UINTN Port,
+ IN UINT64 Value
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+
+/**
+ Reads an 8-bit MMIO register.
+
+ Reads the 8-bit MMIO register specified by Address. The 8-bit read value is
+ returned. This function must guarantee that all MMIO read and write
+ operations are serialized.
+
+ If 8-bit MMIO register operations are not supported, then ASSERT().
+
+ For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+MmioRead8 (
+ IN UINTN Address
+ )
+{
+ UINT8 Value;
+
+ if (ProbeTdGuest ()) {
+ Value = TdMmioRead8 (Address);
+ return Value;
+ }
+
+ MemoryFence ();
+ Value = *(volatile UINT8*)Address;
+ MemoryFence ();
+
+ return Value;
+}
+
+/**
+ Writes an 8-bit MMIO register.
+
+ Writes the 8-bit MMIO register specified by Address with the value specified
+ by Value and returns Value. This function must guarantee that all MMIO read
+ and write operations are serialized.
+
+ If 8-bit MMIO register operations are not supported, then ASSERT().
+
+ For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT8
+EFIAPI
+MmioWrite8 (
+ IN UINTN Address,
+ IN UINT8 Value
+ )
+{
+ if (ProbeTdGuest ()) {
+ TdMmioWrite8 (Address, Value);
+ return Value;
+ }
+
+ MemoryFence ();
+ *(volatile UINT8*)Address = Value;
+ MemoryFence ();
+
+ return Value;
+}
+
+/**
+ Reads a 16-bit MMIO register.
+
+ Reads the 16-bit MMIO register specified by Address. The 16-bit read value is
+ returned. This function must guarantee that all MMIO read and write
+ operations are serialized.
+
+ If 16-bit MMIO register operations are not supported, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT16
+EFIAPI
+MmioRead16 (
+ IN UINTN Address
+ )
+{
+ UINT16 Value;
+
+ ASSERT ((Address & 1) == 0);
+
+ if (ProbeTdGuest ()) {
+ Value = TdMmioRead16 (Address);
+ return Value;
+ }
+
+ MemoryFence ();
+ Value = *(volatile UINT16*)Address;
+ MemoryFence ();
+
+ return Value;
+}
+
+/**
+ Writes a 16-bit MMIO register.
+
+ Writes the 16-bit MMIO register specified by Address with the value specified
+ by Value and returns Value. This function must guarantee that all MMIO read
+ and write operations are serialized.
+
+ If 16-bit MMIO register operations are not supported, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT16
+EFIAPI
+MmioWrite16 (
+ IN UINTN Address,
+ IN UINT16 Value
+ )
+{
+ ASSERT ((Address & 1) == 0);
+
+ if (ProbeTdGuest ()) {
+ TdMmioWrite16 (Address, Value);
+ return Value;
+ }
+
+ MemoryFence ();
+ *(volatile UINT16*)Address = Value;
+ MemoryFence ();
+
+ return Value;
+}
+
+/**
+ Reads a 32-bit MMIO register.
+
+ Reads the 32-bit MMIO register specified by Address. The 32-bit read value is
+ returned. This function must guarantee that all MMIO read and write
+ operations are serialized.
+
+ If 32-bit MMIO register operations are not supported, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT32
+EFIAPI
+MmioRead32 (
+ IN UINTN Address
+ )
+{
+ UINT32 Value;
+
+ ASSERT ((Address & 3) == 0);
+
+ if (ProbeTdGuest ()) {
+ Value = TdMmioRead32 (Address);
+ return Value;
+ }
+
+ MemoryFence ();
+ Value = *(volatile UINT32*)Address;
+ MemoryFence ();
+
+ return Value;
+}
+
+/**
+ Writes a 32-bit MMIO register.
+
+ Writes the 32-bit MMIO register specified by Address with the value specified
+ by Value and returns Value. This function must guarantee that all MMIO read
+ and write operations are serialized.
+
+ If 32-bit MMIO register operations are not supported, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT32
+EFIAPI
+MmioWrite32 (
+ IN UINTN Address,
+ IN UINT32 Value
+ )
+{
+ ASSERT ((Address & 3) == 0);
+
+ if (ProbeTdGuest ()) {
+ TdMmioWrite32 (Address, Value);
+ return Value;
+ }
+
+ MemoryFence ();
+ *(volatile UINT32*)Address = Value;
+ MemoryFence ();
+
+ return Value;
+}
+
+/**
+ Reads a 64-bit MMIO register.
+
+ Reads the 64-bit MMIO register specified by Address. The 64-bit read value is
+ returned. This function must guarantee that all MMIO read and write
+ operations are serialized.
+
+ If 64-bit MMIO register operations are not supported, then ASSERT().
+ If Address is not aligned on a 64-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT64
+EFIAPI
+MmioRead64 (
+ IN UINTN Address
+ )
+{
+ UINT64 Value;
+
+ ASSERT ((Address & 7) == 0);
+
+ if (ProbeTdGuest ()) {
+ Value = TdMmioRead64 (Address);
+ return Value;
+ }
+
+ MemoryFence ();
+ Value = *(volatile UINT64*)Address;
+ MemoryFence ();
+
+ return Value;
+}
+
+/**
+ Writes a 64-bit MMIO register.
+
+ Writes the 64-bit MMIO register specified by Address with the value specified
+ by Value and returns Value. This function must guarantee that all MMIO read
+ and write operations are serialized.
+
+ If 64-bit MMIO register operations are not supported, then ASSERT().
+ If Address is not aligned on a 64-bit boundary, then ASSERT().
+
+ For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+**/
+UINT64
+EFIAPI
+MmioWrite64 (
+ IN UINTN Address,
+ IN UINT64 Value
+ )
+{
+ ASSERT ((Address & 7) == 0);
+
+ if (ProbeTdGuest ()) {
+ TdMmioWrite64 (Address, Value);
+ return Value;
+ }
+
+ MemoryFence ();
+ *(volatile UINT64*)Address = Value;
+ MemoryFence ();
+
+ return Value;
+}
+
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
new file mode 100644
index 000000000000..551e239c6976
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
@@ -0,0 +1,102 @@
+/** @file
+ Header file for Tdx IO library.
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __IOLIB_TDX_H__
+#define __IOLIB_TDX_H__
+
+UINT8
+EFIAPI
+TdIoRead8 (
+ IN UINTN Port
+ );
+
+UINT16
+EFIAPI
+TdIoRead16 (
+ IN UINTN Port
+ );
+
+UINT32
+EFIAPI
+TdIoRead32 (
+ IN UINTN Port
+ );
+
+UINT8
+EFIAPI
+TdIoWrite8 (
+ IN UINTN Port,
+ IN UINT8 Value
+ );
+
+UINT16
+EFIAPI
+TdIoWrite16 (
+ IN UINTN Port,
+ IN UINT16 Value
+ );
+
+UINT32
+EFIAPI
+TdIoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ );
+
+UINT8
+EFIAPI
+TdMmioRead8 (
+ IN UINTN Address
+ );
+
+UINT8
+EFIAPI
+TdMmioWrite8 (
+ IN UINTN Address,
+ IN UINT8 Val
+ );
+
+UINT16
+EFIAPI
+TdMmioRead16 (
+ IN UINTN Address
+ );
+
+UINT16
+EFIAPI
+TdMmioWrite16 (
+ IN UINTN Address,
+ IN UINT16 Val
+ );
+
+UINT32
+EFIAPI
+TdMmioRead32 (
+ IN UINTN Address
+ );
+
+UINT32
+EFIAPI
+TdMmioWrite32 (
+ IN UINTN Address,
+ IN UINT32 Val
+ );
+
+UINT64
+EFIAPI
+TdMmioRead64 (
+ IN UINTN Address
+ );
+
+UINT64
+EFIAPI
+TdMmioWrite64 (
+ IN UINTN Address,
+ IN UINT64 Value
+ );
+
+#endif
diff --git a/MdePkg/Library/SecHobLib/HobLib.c b/MdePkg/Library/SecHobLib/HobLib.c
new file mode 100644
index 000000000000..5923be7c2b20
--- /dev/null
+++ b/MdePkg/Library/SecHobLib/HobLib.c
@@ -0,0 +1,996 @@
+/** @file
+ Provide Hob Library functions for SEC phase.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+VOID *mHobList = NULL;
+
+VOID *
+EFIAPI
+PrePeiGetHobList(
+ VOID
+)
+{
+ return mHobList;
+}
+
+EFI_STATUS
+EFIAPI
+PrePeiSetHobList(
+ IN VOID *HobList
+ )
+{
+ mHobList = HobList;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Returns the pointer to the HOB list.
+
+ This function returns the pointer to first HOB in the list.
+ For PEI phase, the PEI service GetHobList() can be used to retrieve the pointer
+ to the HOB list. For the DXE phase, the HOB list pointer can be retrieved through
+ the EFI System Table by looking up theHOB list GUID in the System Configuration Table.
+ Since the System Configuration Table does not exist that the time the DXE Core is
+ launched, the DXE Core uses a global variable from the DXE Core Entry Point Library
+ to manage the pointer to the HOB list.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+
+ @return The pointer to the HOB list.
+
+**/
+VOID *
+EFIAPI
+GetHobList (
+ VOID
+ )
+{
+ VOID *HobList;
+
+ HobList = PrePeiGetHobList();
+ ASSERT (HobList != NULL);
+
+ return HobList;
+}
+
+EFI_STATUS
+EFIAPI
+SetHobList (
+ IN VOID *HobList
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PrePeiSetHobList(HobList);
+
+ return Status;
+}
+
+EFI_HOB_HANDOFF_INFO_TABLE*
+HobConstructor (
+ IN VOID *EfiMemoryBegin,
+ IN UINTN EfiMemoryLength,
+ IN VOID *EfiFreeMemoryBottom,
+ IN VOID *EfiFreeMemoryTop
+ )
+{
+ EFI_HOB_HANDOFF_INFO_TABLE *Hob;
+ EFI_HOB_GENERIC_HEADER *HobEnd;
+
+ Hob = EfiFreeMemoryBottom;
+ HobEnd = (EFI_HOB_GENERIC_HEADER *)(Hob+1);
+
+ Hob->Header.HobType = EFI_HOB_TYPE_HANDOFF;
+ Hob->Header.HobLength = sizeof(EFI_HOB_HANDOFF_INFO_TABLE);
+ Hob->Header.Reserved = 0;
+
+ HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
+ HobEnd->HobLength = sizeof(EFI_HOB_GENERIC_HEADER);
+ HobEnd->Reserved = 0;
+
+ Hob->Version = EFI_HOB_HANDOFF_TABLE_VERSION;
+ Hob->BootMode = BOOT_WITH_FULL_CONFIGURATION;
+
+ Hob->EfiMemoryTop = (UINTN)EfiMemoryBegin + EfiMemoryLength;
+ Hob->EfiMemoryBottom = (UINTN)EfiMemoryBegin;
+ Hob->EfiFreeMemoryTop = (UINTN)EfiFreeMemoryTop;
+ Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS)(UINTN)(HobEnd+1);
+ Hob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS)(UINTN)HobEnd;
+
+ return Hob;
+
+}
+
+VOID *
+CreateHob (
+ IN UINT16 HobType,
+ IN UINT16 HobLength
+ )
+{
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+ EFI_HOB_GENERIC_HEADER *HobEnd;
+ EFI_PHYSICAL_ADDRESS FreeMemory;
+ VOID *Hob;
+
+ HandOffHob = GetHobList ();
+
+ HobLength = (UINT16)((HobLength + 0x7) & (~0x7));
+
+ FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom;
+
+ if (FreeMemory < HobLength) {
+ return NULL;
+ }
+
+ Hob = (VOID*) (UINTN) HandOffHob->EfiEndOfHobList;
+ ((EFI_HOB_GENERIC_HEADER*) Hob)->HobType = HobType;
+ ((EFI_HOB_GENERIC_HEADER*) Hob)->HobLength = HobLength;
+ ((EFI_HOB_GENERIC_HEADER*) Hob)->Reserved = 0;
+
+ HobEnd = (EFI_HOB_GENERIC_HEADER*) ((UINTN)Hob + HobLength);
+ HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
+ HobEnd->HobLength = sizeof(EFI_HOB_GENERIC_HEADER);
+ HobEnd->Reserved = 0;
+ HobEnd++;
+ HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ return Hob;
+}
+
+
+/**
+ Returns the next instance of a HOB type from the starting HOB.
+
+ This function searches the first instance of a HOB type from the starting HOB pointer.
+ If there does not exist such HOB type from the starting HOB pointer, it will return NULL.
+ In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer
+ unconditionally: it returns HobStart back if HobStart itself meets the requirement;
+ caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart.
+
+ If HobStart is NULL, then ASSERT().
+
+ @param Type The HOB type to return.
+ @param HobStart The starting HOB pointer to search from.
+
+ @return The next instance of a HOB type from the starting HOB.
+
+**/
+VOID *
+EFIAPI
+GetNextHob (
+ IN UINT16 Type,
+ IN CONST VOID *HobStart
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+
+ Hob.Raw = (UINT8 *) HobStart;
+ //
+ // Parse the HOB list until end of list or matching type is found.
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == Type) {
+ return Hob.Raw;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+ return NULL;
+}
+
+/**
+ Returns the first instance of a HOB type among the whole HOB list.
+
+ This function searches the first instance of a HOB type among the whole HOB list.
+ If there does not exist such HOB type in the HOB list, it will return NULL.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+
+ @param Type The HOB type to return.
+
+ @return The next instance of a HOB type from the starting HOB.
+
+**/
+VOID *
+EFIAPI
+GetFirstHob (
+ IN UINT16 Type
+ )
+{
+ VOID *HobList;
+
+ HobList = GetHobList ();
+ return GetNextHob (Type, HobList);
+}
+
+/**
+ Returns the next instance of the matched GUID HOB from the starting HOB.
+
+ This function searches the first instance of a HOB from the starting HOB pointer.
+ Such HOB should satisfy two conditions:
+ its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid.
+ If there does not exist such HOB from the starting HOB pointer, it will return NULL.
+ Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE ()
+ to extract the data section and its size information, respectively.
+ In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer
+ unconditionally: it returns HobStart back if HobStart itself meets the requirement;
+ caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart.
+
+ If Guid is NULL, then ASSERT().
+ If HobStart is NULL, then ASSERT().
+
+ @param Guid The GUID to match with in the HOB list.
+ @param HobStart A pointer to a Guid.
+
+ @return The next instance of the matched GUID HOB from the starting HOB.
+
+**/
+VOID *
+EFIAPI
+GetNextGuidHob (
+ IN CONST EFI_GUID *Guid,
+ IN CONST VOID *HobStart
+ )
+{
+ EFI_PEI_HOB_POINTERS GuidHob;
+
+ GuidHob.Raw = (UINT8 *) HobStart;
+ while ((GuidHob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GuidHob.Raw)) != NULL) {
+ if (CompareGuid (Guid, &GuidHob.Guid->Name)) {
+ break;
+ }
+ GuidHob.Raw = GET_NEXT_HOB (GuidHob);
+ }
+ return GuidHob.Raw;
+}
+
+/**
+ Returns the first instance of the matched GUID HOB among the whole HOB list.
+
+ This function searches the first instance of a HOB among the whole HOB list.
+ Such HOB should satisfy two conditions:
+ its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid.
+ If there does not exist such HOB from the starting HOB pointer, it will return NULL.
+ Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE ()
+ to extract the data section and its size information, respectively.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+ If Guid is NULL, then ASSERT().
+
+ @param Guid The GUID to match with in the HOB list.
+
+ @return The first instance of the matched GUID HOB among the whole HOB list.
+
+**/
+VOID *
+EFIAPI
+GetFirstGuidHob (
+ IN CONST EFI_GUID *Guid
+ )
+{
+ VOID *HobList;
+
+ HobList = GetHobList ();
+ return GetNextGuidHob (Guid, HobList);
+}
+
+/**
+ Get the system boot mode from the HOB list.
+
+ This function returns the system boot mode information from the
+ PHIT HOB in HOB list.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+
+ @param VOID.
+
+ @return The Boot Mode.
+
+**/
+EFI_BOOT_MODE
+EFIAPI
+GetBootModeHob (
+ VOID
+ )
+{
+ EFI_BOOT_MODE BootMode;
+ EFI_PEI_HOB_POINTERS Hob;
+
+ Hob.Raw = GetHobList ();
+ BootMode = Hob.HandoffInformationTable->BootMode;
+
+ return BootMode;
+}
+
+EFI_STATUS
+EFIAPI
+SetBootMode (
+ IN EFI_BOOT_MODE BootMode
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+
+ Hob.Raw = GetHobList ();
+ Hob.HandoffInformationTable->BootMode = BootMode;
+ return BootMode;
+}
+
+/**
+ Builds a HOB for a loaded PE32 module.
+
+ This function builds a HOB for a loaded PE32 module.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If ModuleName is NULL, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ModuleName The GUID File Name of the module.
+ @param MemoryAllocationModule The 64 bit physical address of the module.
+ @param ModuleLength The length of the module in bytes.
+ @param EntryPoint The 64 bit physical address of the module entry point.
+
+**/
+VOID
+EFIAPI
+BuildModuleHob (
+ IN CONST EFI_GUID *ModuleName,
+ IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule,
+ IN UINT64 ModuleLength,
+ IN EFI_PHYSICAL_ADDRESS EntryPoint
+ )
+{
+ EFI_HOB_MEMORY_ALLOCATION_MODULE *Hob;
+
+ ASSERT (((MemoryAllocationModule & (EFI_PAGE_SIZE - 1)) == 0) &&
+ ((ModuleLength & (EFI_PAGE_SIZE - 1)) == 0));
+
+ Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, (UINT16) sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE));
+
+ if (Hob == NULL) {
+ ASSERT(FALSE);
+ return;
+ }
+
+ CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid);
+ Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule;
+ Hob->MemoryAllocationHeader.MemoryLength = ModuleLength;
+ Hob->MemoryAllocationHeader.MemoryType = EfiBootServicesCode;
+
+ //
+ // Zero the reserved space to match HOB spec
+ //
+ ZeroMem (Hob->MemoryAllocationHeader.Reserved, sizeof (Hob->MemoryAllocationHeader.Reserved));
+
+ CopyGuid (&Hob->ModuleName, ModuleName);
+ Hob->EntryPoint = EntryPoint;
+}
+
+/**
+ Builds a HOB that describes a chunk of system memory with Owner GUID.
+
+ This function builds a HOB that describes a chunk of system memory.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ResourceType The type of resource described by this HOB.
+ @param ResourceAttribute The resource attributes of the memory described by this HOB.
+ @param PhysicalStart The 64 bit physical address of memory described by this HOB.
+ @param NumberOfBytes The length of the memory described by this HOB in bytes.
+ @param OwnerGUID GUID for the owner of this resource.
+
+**/
+VOID
+EFIAPI
+BuildResourceDescriptorWithOwnerHob (
+ IN EFI_RESOURCE_TYPE ResourceType,
+ IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute,
+ IN EFI_PHYSICAL_ADDRESS PhysicalStart,
+ IN UINT64 NumberOfBytes,
+ IN EFI_GUID *OwnerGUID
+ )
+{
+ EFI_HOB_RESOURCE_DESCRIPTOR *Hob;
+ Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, (UINT16) sizeof (EFI_HOB_RESOURCE_DESCRIPTOR));
+
+ if (Hob == NULL) {
+ ASSERT(FALSE);
+ return;
+ }
+
+ Hob->ResourceType = ResourceType;
+ Hob->ResourceAttribute = ResourceAttribute;
+ Hob->PhysicalStart = PhysicalStart;
+ Hob->ResourceLength = NumberOfBytes;
+
+ CopyGuid (&Hob->Owner, OwnerGUID);
+}
+
+/**
+ Builds a HOB that describes a chunk of system memory.
+
+ This function builds a HOB that describes a chunk of system memory.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ResourceType The type of resource described by this HOB.
+ @param ResourceAttribute The resource attributes of the memory described by this HOB.
+ @param PhysicalStart The 64 bit physical address of memory described by this HOB.
+ @param NumberOfBytes The length of the memory described by this HOB in bytes.
+
+**/
+VOID
+EFIAPI
+BuildResourceDescriptorHob (
+ IN EFI_RESOURCE_TYPE ResourceType,
+ IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute,
+ IN EFI_PHYSICAL_ADDRESS PhysicalStart,
+ IN UINT64 NumberOfBytes
+ )
+{
+ EFI_HOB_RESOURCE_DESCRIPTOR *Hob;
+
+ Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, (UINT16) sizeof (EFI_HOB_RESOURCE_DESCRIPTOR));
+
+ if (Hob == NULL) {
+ ASSERT(FALSE);
+ return;
+ }
+
+ Hob->ResourceType = ResourceType;
+ Hob->ResourceAttribute = ResourceAttribute;
+ Hob->PhysicalStart = PhysicalStart;
+ Hob->ResourceLength = NumberOfBytes;
+ ZeroMem (&(Hob->Owner), sizeof (EFI_GUID));
+}
+
+/**
+ Builds a customized HOB tagged with a GUID for identification and returns
+ the start address of GUID HOB data.
+
+ This function builds a customized HOB tagged with a GUID for identification
+ and returns the start address of GUID HOB data so that caller can fill the customized data.
+ The HOB Header and Name field is already stripped.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If Guid is NULL, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+ If DataLength > (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT().
+ HobLength is UINT16 and multiples of 8 bytes, so the max HobLength is 0xFFF8.
+
+ @param Guid The GUID to tag the customized HOB.
+ @param DataLength The size of the data payload for the GUID HOB.
+
+ @retval NULL The GUID HOB could not be allocated.
+ @retval others The start address of GUID HOB data.
+
+**/
+VOID *
+EFIAPI
+BuildGuidHob (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN DataLength
+ )
+{
+ EFI_HOB_GUID_TYPE *Hob;
+
+ //
+ // Make sure Guid is valid
+ //
+ ASSERT (Guid != NULL);
+
+ //
+ // Make sure that data length is not too long.
+ //
+ ASSERT (DataLength <= (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE)));
+
+ Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16) (sizeof (EFI_HOB_GUID_TYPE) + DataLength));
+
+ if (Hob == NULL) {
+ ASSERT(FALSE);
+ return Hob;
+ }
+ CopyGuid (&Hob->Name, Guid);
+ return Hob + 1;
+}
+
+/**
+ Builds a customized HOB tagged with a GUID for identification, copies the input data to the HOB
+ data field, and returns the start address of the GUID HOB data.
+
+ This function builds a customized HOB tagged with a GUID for identification and copies the input
+ data to the HOB data field and returns the start address of the GUID HOB data. It can only be
+ invoked during PEI phase; for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+ The HOB Header and Name field is already stripped.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If Guid is NULL, then ASSERT().
+ If Data is NULL and DataLength > 0, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+ If DataLength > (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT().
+ HobLength is UINT16 and multiples of 8 bytes, so the max HobLength is 0xFFF8.
+
+ @param Guid The GUID to tag the customized HOB.
+ @param Data The data to be copied into the data field of the GUID HOB.
+ @param DataLength The size of the data payload for the GUID HOB.
+
+ @retval NULL The GUID HOB could not be allocated.
+ @retval others The start address of GUID HOB data.
+
+**/
+VOID *
+EFIAPI
+BuildGuidDataHob (
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN UINTN DataLength
+ )
+{
+ VOID *HobData;
+
+ ASSERT (Data != NULL || DataLength == 0);
+
+ HobData = BuildGuidHob (Guid, DataLength);
+ if (HobData == NULL) {
+ return HobData;
+ }
+
+ return CopyMem (HobData, Data, DataLength);
+}
+
+/**
+ Check FV alignment.
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+
+ @retval TRUE FvImage buffer is at its required alignment.
+ @retval FALSE FvImage buffer is not at its required alignment.
+
+**/
+BOOLEAN
+InternalCheckFvAlignment (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINT32 FvAlignment;
+
+ FvAlignment = 0;
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
+
+ //
+ // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
+ // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
+ // its initial linked location and maintain its alignment.
+ //
+ if ((FwVolHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
+ //
+ // Get FvHeader alignment
+ //
+ FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
+ //
+ // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
+ //
+ if (FvAlignment < 8) {
+ FvAlignment = 8;
+ }
+ if ((UINTN)BaseAddress % FvAlignment != 0) {
+ //
+ // FvImage buffer is not at its required alignment.
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "Unaligned FvImage found at 0x%lx:0x%lx, the required alignment is 0x%x\n",
+ BaseAddress,
+ Length,
+ FvAlignment
+ ));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+VOID
+EFIAPI
+BuildFvHobs (
+ IN EFI_PHYSICAL_ADDRESS PhysicalStart,
+ IN UINT64 NumberOfBytes,
+ IN EFI_RESOURCE_ATTRIBUTE_TYPE *ResourceAttribute OPTIONAL
+ )
+{
+
+ EFI_RESOURCE_ATTRIBUTE_TYPE Resource;
+
+ BuildFvHob (PhysicalStart, NumberOfBytes);
+
+ if (ResourceAttribute == NULL) {
+ Resource = (EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_TESTED |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE);
+ } else {
+ Resource = *ResourceAttribute;
+ }
+
+ BuildResourceDescriptorHob (EFI_RESOURCE_FIRMWARE_DEVICE, Resource, PhysicalStart, NumberOfBytes);
+}
+
+
+/**
+ Builds a Firmware Volume HOB.
+
+ This function builds a Firmware Volume HOB.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+ If the FvImage buffer is not at its required alignment, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+
+**/
+VOID
+EFIAPI
+BuildFvHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ EFI_HOB_FIRMWARE_VOLUME *Hob;
+
+ if (!InternalCheckFvAlignment (BaseAddress, Length)) {
+ ASSERT (FALSE);
+ return;
+ }
+
+ Hob = CreateHob (EFI_HOB_TYPE_FV, (UINT16) sizeof (EFI_HOB_FIRMWARE_VOLUME));
+
+ if (Hob == NULL) {
+ ASSERT(FALSE);
+ return;
+ }
+
+ Hob->BaseAddress = BaseAddress;
+ Hob->Length = Length;
+}
+
+/**
+ Builds a EFI_HOB_TYPE_FV2 HOB.
+
+ This function builds a EFI_HOB_TYPE_FV2 HOB.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+ If the FvImage buffer is not at its required alignment, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+ @param FvName The name of the Firmware Volume.
+ @param FileName The name of the file.
+
+**/
+VOID
+EFIAPI
+BuildFv2Hob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN CONST EFI_GUID *FvName,
+ IN CONST EFI_GUID *FileName
+ )
+{
+ EFI_HOB_FIRMWARE_VOLUME2 *Hob;
+
+ if (!InternalCheckFvAlignment (BaseAddress, Length)) {
+ ASSERT (FALSE);
+ return;
+ }
+
+ Hob = CreateHob (EFI_HOB_TYPE_FV2, (UINT16) sizeof (EFI_HOB_FIRMWARE_VOLUME2));
+
+ if (Hob == NULL) {
+ ASSERT(FALSE);
+ return;
+ }
+
+ Hob->BaseAddress = BaseAddress;
+ Hob->Length = Length;
+ CopyGuid (&Hob->FvName, FvName);
+ CopyGuid (&Hob->FileName, FileName);
+}
+
+/**
+ Builds a EFI_HOB_TYPE_FV3 HOB.
+
+ This function builds a EFI_HOB_TYPE_FV3 HOB.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+ If the FvImage buffer is not at its required alignment, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+ @param AuthenticationStatus The authentication status.
+ @param ExtractedFv TRUE if the FV was extracted as a file within
+ another firmware volume. FALSE otherwise.
+ @param FvName The name of the Firmware Volume.
+ Valid only if IsExtractedFv is TRUE.
+ @param FileName The name of the file.
+ Valid only if IsExtractedFv is TRUE.
+
+**/
+VOID
+EFIAPI
+BuildFv3Hob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT32 AuthenticationStatus,
+ IN BOOLEAN ExtractedFv,
+ IN CONST EFI_GUID *FvName, OPTIONAL
+ IN CONST EFI_GUID *FileName OPTIONAL
+ )
+{
+ EFI_HOB_FIRMWARE_VOLUME3 *Hob;
+
+ if (!InternalCheckFvAlignment (BaseAddress, Length)) {
+ ASSERT (FALSE);
+ return;
+ }
+
+ Hob = CreateHob (EFI_HOB_TYPE_FV3, (UINT16) sizeof (EFI_HOB_FIRMWARE_VOLUME3));
+
+ if (Hob == NULL) {
+ ASSERT(FALSE);
+ return;
+ }
+
+ Hob->BaseAddress = BaseAddress;
+ Hob->Length = Length;
+ Hob->AuthenticationStatus = AuthenticationStatus;
+ Hob->ExtractedFv = ExtractedFv;
+ if (ExtractedFv) {
+ CopyGuid (&Hob->FvName, FvName);
+ CopyGuid (&Hob->FileName, FileName);
+ }
+}
+
+/**
+ Builds a Capsule Volume HOB.
+
+ This function builds a Capsule Volume HOB.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If the platform does not support Capsule Volume HOBs, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The base address of the Capsule Volume.
+ @param Length The size of the Capsule Volume in bytes.
+
+**/
+VOID
+EFIAPI
+BuildCvHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ ASSERT(FALSE);
+}
+
+/**
+ Builds a HOB for the CPU.
+
+ This function builds a HOB for the CPU.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param SizeOfMemorySpace The maximum physical memory addressability of the processor.
+ @param SizeOfIoSpace The maximum physical I/O addressability of the processor.
+
+**/
+VOID
+EFIAPI
+BuildCpuHob (
+ IN UINT8 SizeOfMemorySpace,
+ IN UINT8 SizeOfIoSpace
+ )
+{
+ EFI_HOB_CPU *Hob;
+
+ Hob = CreateHob (EFI_HOB_TYPE_CPU, (UINT16) sizeof (EFI_HOB_CPU));
+
+ if (Hob == NULL) {
+ ASSERT(FALSE);
+ return;
+ }
+
+ Hob->SizeOfMemorySpace = SizeOfMemorySpace;
+ Hob->SizeOfIoSpace = SizeOfIoSpace;
+
+ //
+ // Zero the reserved space to match HOB spec
+ //
+ ZeroMem (Hob->Reserved, sizeof (Hob->Reserved));
+}
+
+/**
+ Builds a HOB for the Stack.
+
+ This function builds a HOB for the stack.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the Stack.
+ @param Length The length of the stack in bytes.
+
+**/
+VOID
+EFIAPI
+BuildStackHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ EFI_HOB_MEMORY_ALLOCATION_STACK *Hob;
+
+ ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) &&
+ ((Length & (EFI_PAGE_SIZE - 1)) == 0));
+
+ Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, (UINT16) sizeof (EFI_HOB_MEMORY_ALLOCATION_STACK));
+
+ if (Hob == NULL) {
+ ASSERT(FALSE);
+ return;
+ }
+
+ CopyGuid (&(Hob->AllocDescriptor.Name), &gEfiHobMemoryAllocStackGuid);
+ Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress;
+ Hob->AllocDescriptor.MemoryLength = Length;
+ Hob->AllocDescriptor.MemoryType = EfiBootServicesData;
+
+ //
+ // Zero the reserved space to match HOB spec
+ //
+ ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved));
+}
+
+/**
+ Builds a HOB for the BSP store.
+
+ This function builds a HOB for BSP store.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the BSP.
+ @param Length The length of the BSP store in bytes.
+ @param MemoryType The type of memory allocated by this HOB.
+
+**/
+VOID
+EFIAPI
+BuildBspStoreHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ ASSERT(FALSE);
+}
+
+/**
+ Update the Stack Hob if the stack has been moved
+
+ @param BaseAddress The 64 bit physical address of the Stack.
+ @param Length The length of the stack in bytes.
+
+**/
+VOID
+UpdateStackHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+
+ Hob.Raw = GetHobList ();
+ while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
+ if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &(Hob.MemoryAllocationStack->AllocDescriptor.Name))) {
+ //
+ // Build a new memory allocation HOB with old stack info with EfiConventionalMemory type
+ // to be reclaimed by DXE core.
+ //
+ BuildMemoryAllocationHob (
+ Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress,
+ Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength,
+ EfiConventionalMemory
+ );
+ //
+ // Update the BSP Stack Hob to reflect the new stack info.
+ //
+ Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress = BaseAddress;
+ Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength = Length;
+ break;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+}
+
+
+/**
+ Builds a HOB for the memory allocation.
+
+ This function builds a HOB for the memory allocation.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the memory.
+ @param Length The length of the memory allocation in bytes.
+ @param MemoryType The type of memory allocated by this HOB.
+
+**/
+VOID
+EFIAPI
+BuildMemoryAllocationHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ EFI_HOB_MEMORY_ALLOCATION *Hob;
+
+ ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) &&
+ ((Length & (EFI_PAGE_SIZE - 1)) == 0));
+
+ Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, (UINT16) sizeof (EFI_HOB_MEMORY_ALLOCATION));
+
+ if (Hob == NULL) {
+ ASSERT(FALSE);
+ return;
+ }
+
+ ZeroMem (&(Hob->AllocDescriptor.Name), sizeof (EFI_GUID));
+ Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress;
+ Hob->AllocDescriptor.MemoryLength = Length;
+ Hob->AllocDescriptor.MemoryType = MemoryType;
+ //
+ // Zero the reserved space to match HOB spec
+ //
+ ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved));
+}
diff --git a/MdePkg/Library/SecHobLib/SecHobLib.inf b/MdePkg/Library/SecHobLib/SecHobLib.inf
new file mode 100644
index 000000000000..95117bcf9ae4
--- /dev/null
+++ b/MdePkg/Library/SecHobLib/SecHobLib.inf
@@ -0,0 +1,50 @@
+## @file
+# Instance of HOB Library using PEI Services.
+#
+# HOB Library implementation that uses PEI Services to retrieve the HOB List.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SecHobLib
+ MODULE_UNI_FILE = SecHobLib.uni
+ FILE_GUID = 95A20151-9407-401A-89B3-5B4D9CDB932A
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = HobLib|SEC
+
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
+#
+
+[Sources]
+ HobLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ #OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+
+[Guids]
+ gEfiHobMemoryAllocStackGuid ## SOMETIMES_PRODUCES ## HOB # MemoryAllocation StackHob
+ gEfiHobMemoryAllocBspStoreGuid ## SOMETIMES_PRODUCES ## HOB # MemoryAllocation BspStoreHob
+ gEfiHobMemoryAllocModuleGuid ## SOMETIMES_PRODUCES ## HOB # MemoryAllocation ModuleHob
+
+#
+# [Hob]
+# MEMORY_ALLOCATION ## SOMETIMES_PRODUCES
+# RESOURCE_DESCRIPTOR ## SOMETIMES_PRODUCES
+# FIRMWARE_VOLUME ## SOMETIMES_PRODUCES
+#
+
diff --git a/MdePkg/Library/SecHobLib/SecHobLib.uni b/MdePkg/Library/SecHobLib/SecHobLib.uni
new file mode 100644
index 000000000000..071ac1c2cac9
--- /dev/null
+++ b/MdePkg/Library/SecHobLib/SecHobLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Instance of HOB Library using PEI Services.
+//
+// HOB Library implementation that retrieve the HOB List in SEC phase.
+//
+// Copyright (c) 2021, Intel Corporation. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Instance of HOB Library in SEC Phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "HOB Library implementation that retrieve the HOB List in SEC Phase."
+
diff --git a/MdePkg/Library/SecMemoryAllocationLib/MemoryAllocationLib.c b/MdePkg/Library/SecMemoryAllocationLib/MemoryAllocationLib.c
new file mode 100644
index 000000000000..19245e3f6963
--- /dev/null
+++ b/MdePkg/Library/SecMemoryAllocationLib/MemoryAllocationLib.c
@@ -0,0 +1,827 @@
+/** @file
+ Support routines for memory allocation routines
+ based on PeiService for PEI phase drivers.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include
+
+
+#include
+#include
+#include
+#include
+#include
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData.
+
+ Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePages (
+ IN UINTN Pages
+ )
+{
+ return AllocatePagesWithMemoryType(EfiBootServicesData, Pages);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePages (
+ IN UINTN Pages
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType.
+
+ Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPages (
+ IN UINTN Pages
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the page allocation
+ functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
+ then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer The pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreePages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ ASSERT(FALSE);
+}
+
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation.
+ Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ VOID *Memory;
+ UINTN AlignmentMask;
+
+ //
+ // Alignment must be a power of two or zero.
+ //
+ ASSERT ((Alignment & (Alignment - 1)) == 0);
+
+ if (Pages == 0) {
+ return NULL;
+ }
+ //
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
+ //
+ ASSERT (Pages <= (MAX_ADDRESS - EFI_SIZE_TO_PAGES (Alignment)));
+ //
+ // We would rather waste some memory to save PEI code size.
+ //
+ Memory = (VOID *)(UINTN)AllocatePages (Pages + EFI_SIZE_TO_PAGES (Alignment));
+ if (Alignment == 0) {
+ AlignmentMask = Alignment;
+ } else {
+ AlignmentMask = Alignment - 1;
+ }
+ return (VOID *) (UINTN) (((UINTN) Memory + AlignmentMask) & ~AlignmentMask);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation.
+ Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedRuntimePages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation.
+ Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedReservedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the aligned page
+ allocation functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the aligned page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
+ Library, then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer The pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreeAlignedPages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ ASSERT(FALSE);
+}
+
+/**
+ Allocates a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePool (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN AllocationSize
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Allocates a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+TdAllocatePool (
+ IN UINTN AllocationSize
+ )
+{
+ EFI_HOB_MEMORY_POOL *Hob;
+
+ Hob = GetHobList ();
+
+ //
+ // Verify that there is sufficient memory to satisfy the allocation
+ //
+ if (AllocationSize > 0x10000) {
+ // Please call AllocatePages for big allocations
+ return 0;
+ } else {
+
+ Hob = (EFI_HOB_MEMORY_POOL *)CreateHob (EFI_HOB_TYPE_MEMORY_POOL, (UINT16)(sizeof (EFI_HOB_TYPE_MEMORY_POOL) + AllocationSize));
+ return (VOID *)(Hob + 1);
+ }
+}
+
+/**
+ Allocates a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePool (
+ IN UINTN AllocationSize
+ )
+{
+ EFI_HOB_MEMORY_POOL *Hob;
+
+ Hob = GetHobList ();
+
+ //
+ // Verify that there is sufficient memory to satisfy the allocation
+ //
+ if (AllocationSize > 0x10000) {
+ // Please call AllocatePages for big allocations
+ return 0;
+ } else {
+ Hob = (EFI_HOB_MEMORY_POOL *)CreateHob (EFI_HOB_TYPE_MEMORY_POOL, (UINT16)(sizeof (EFI_HOB_TYPE_MEMORY_POOL) + AllocationSize));
+ return (VOID *)(Hob + 1);
+ }
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePool (
+ IN UINTN AllocationSize
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Allocates a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPool (
+ IN UINTN AllocationSize
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Allocates and zeros a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, clears the buffer
+ with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a valid
+ buffer of 0 size is returned. If there is not enough memory remaining to satisfy the request,
+ then NULL is returned.
+
+ @param PoolType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateZeroPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Memory;
+
+ Memory = AllocatePool (AllocationSize);
+ if (Memory != NULL) {
+ Memory = ZeroMem (Memory, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Copies a buffer to an allocated buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateCopyPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *Memory;
+
+ ASSERT (Buffer != NULL);
+ ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));
+
+ Memory = AllocatePool (AllocationSize);
+ if (Memory != NULL) {
+ Memory = CopyMem (Memory, Buffer, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Reallocates a buffer of a specified memory type.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of the type
+ specified by PoolType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an
+ optional parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalReallocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Reallocates a buffer of type EfiBootServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateRuntimePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Reallocates a buffer of type EfiReservedMemoryType.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an
+ optional parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateReservedPool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer The pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+ IN VOID *Buffer
+ )
+{
+ //
+ // PEI phase does not support to free pool, so leave it as NOP.
+ //
+}
+
+/**
+ Allocates one or more 4KB pages of given type MemoryType.
+
+ Allocates the number of 4KB pages of MemoryType and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param MemoryType Type of memory to use for this allocation.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePagesWithMemoryType (
+ IN UINTN MemoryType,
+ IN UINTN Pages
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PHYSICAL_ADDRESS Offset;
+
+ Hob.Raw = GetHobList ();
+
+ // Check to see if on 4k boundary
+ Offset = Hob.HandoffInformationTable->EfiFreeMemoryTop & 0xFFF;
+ if (Offset != 0) {
+ // If not aligned, make the allocation aligned.
+ Hob.HandoffInformationTable->EfiFreeMemoryTop -= Offset;
+ }
+
+ //
+ // Verify that there is sufficient memory to satisfy the allocation
+ //
+ if (Hob.HandoffInformationTable->EfiFreeMemoryTop - ((Pages * EFI_PAGE_SIZE) + sizeof (EFI_HOB_MEMORY_ALLOCATION)) < Hob.HandoffInformationTable->EfiFreeMemoryBottom) {
+ return 0;
+ } else {
+ //
+ // Update the PHIT to reflect the memory usage
+ //
+ Hob.HandoffInformationTable->EfiFreeMemoryTop -= Pages * EFI_PAGE_SIZE;
+
+ // This routine used to create a memory allocation HOB a la PEI, but that's not
+ // necessary for us.
+
+ //
+ // Create a memory allocation HOB.
+ //
+ BuildMemoryAllocationHob (
+ Hob.HandoffInformationTable->EfiFreeMemoryTop,
+ Pages * EFI_PAGE_SIZE,
+ (EFI_MEMORY_TYPE)MemoryType
+ );
+ return (VOID *)(UINTN)Hob.HandoffInformationTable->EfiFreeMemoryTop;
+ }
+}
+
+
diff --git a/MdePkg/Library/SecMemoryAllocationLib/SecMemoryAllocationLib.inf b/MdePkg/Library/SecMemoryAllocationLib/SecMemoryAllocationLib.inf
new file mode 100644
index 000000000000..243ef1de5303
--- /dev/null
+++ b/MdePkg/Library/SecMemoryAllocationLib/SecMemoryAllocationLib.inf
@@ -0,0 +1,40 @@
+## @file
+# Instance of Memory Allocation Library using PEI Services.
+#
+# Memory Allocation Library that uses PEI Services to allocate memory.
+# Free operations are ignored.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SecMemoryAllocationLib
+ MODULE_UNI_FILE = SecMemoryAllocationLib.uni
+ FILE_GUID = 9435C171-D3F0-47AB-B45C-E51D5411EDE2
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemoryAllocationLib|SEC
+
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
+#
+
+[Sources]
+ MemoryAllocationLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ #OvmfPkg/OvmfPkg.dec
+
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+ #PeiServicesLib
+ HobLib
\ No newline at end of file
diff --git a/MdePkg/Library/SecMemoryAllocationLib/SecMemoryAllocationLib.uni b/MdePkg/Library/SecMemoryAllocationLib/SecMemoryAllocationLib.uni
new file mode 100644
index 000000000000..f492b6240a88
--- /dev/null
+++ b/MdePkg/Library/SecMemoryAllocationLib/SecMemoryAllocationLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Instance of Memory Allocation Library using PEI Services.
+//
+// Memory Allocation Library that uses PEI Services to allocate memory.
+// Free operations are ignored.
+//
+// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Instance of Memory Allocation Library using PEI Services"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Memory Allocation Library that uses PEI Services to allocate memory. Free operations are ignored."
+
diff --git a/MdePkg/Library/TdxLib/AcceptPages.c b/MdePkg/Library/TdxLib/AcceptPages.c
new file mode 100644
index 000000000000..358a39b572f3
--- /dev/null
+++ b/MdePkg/Library/TdxLib/AcceptPages.c
@@ -0,0 +1,74 @@
+/** @file
+
+ There are 4 defined types in TD memory.
+ Unaccepted memory is a special type of private memory. The guest
+ firmware must invoke TDCALL [TDG.MEM.PAGE.ACCEPT] the unaccepted
+ memory before use it.
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+
+UINT64 mNumberOfDuplicatedAcceptedPages;
+
+/**
+ This function accept a pending private page, and initialize the page to
+ all-0 using the TD ephemeral private key.
+
+ @param[in] StartAddress Guest physical address of the private
+ page to accept.
+ @param[in] NumberOfPages Number of the pages to be accepted.
+ @param[in] PageSize GPA page size. Only accept 1G/2M/4K size.
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+TdAcceptPages (
+ IN UINT64 StartAddress,
+ IN UINT64 NumberOfPages,
+ IN UINT64 PageSize
+ )
+{
+ UINT64 Address;
+ UINT64 Status;
+ UINT64 Index;
+ UINT64 GpaPageSize;
+
+ Address = StartAddress;
+
+ if (PageSize == SIZE_4KB) {
+ GpaPageSize = TDCALL_ACCEPT_PAGE_SIZE_4K;
+ } else if (PageSize == SIZE_2MB) {
+ GpaPageSize = TDCALL_ACCEPT_PAGE_SIZE_2M;
+ } else if (PageSize == SIZE_1GB) {
+ GpaPageSize = TDCALL_ACCEPT_PAGE_SIZE_1G;
+ } else {
+ DEBUG ((DEBUG_ERROR, "Accept page size must be 4K/2M/1G. Invalid page size - 0x%llx\n", PageSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Index = 0; Index < NumberOfPages; Index++) {
+ Status = TdCall (TDCALL_TDACCEPTPAGE,Address, GpaPageSize, 0, 0);
+ if (Status != TDX_EXIT_REASON_SUCCESS) {
+ if ((Status & ~0xFFULL) == TDX_EXIT_REASON_PAGE_ALREADY_ACCEPTED) {
+ mNumberOfDuplicatedAcceptedPages++;
+ DEBUG ((DEBUG_VERBOSE, "Address %llx already accepted. Total number of already accepted pages %ld\n",
+ Address, mNumberOfDuplicatedAcceptedPages));
+ } else {
+ DEBUG ((DEBUG_ERROR, "Address %llx failed to be accepted. Error = %ld\n",
+ Address, Status));
+ ASSERT (Status == TDX_EXIT_REASON_SUCCESS);
+ }
+ }
+ Address += PageSize;
+ }
+ return EFI_SUCCESS;
+}
diff --git a/MdePkg/Library/TdxLib/Rtmr.c b/MdePkg/Library/TdxLib/Rtmr.c
new file mode 100644
index 000000000000..9c60d3c65e0e
--- /dev/null
+++ b/MdePkg/Library/TdxLib/Rtmr.c
@@ -0,0 +1,118 @@
+/** @file
+
+ Extends one of the RTMR measurement registers in TDCS with the provided
+ extension data in memory.
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define RTMR_COUNT 4
+#define TD_EXTEND_BUFFER_LEN (64 + 64)
+#define EXTEND_BUFFER_ADDRESS_MASK 0x3f
+
+
+#pragma pack(16)
+typedef struct {
+ UINT8 Buffer[TD_EXTEND_BUFFER_LEN];
+} TDX_EXTEND_BUFFER;
+#pragma pack()
+
+UINT8 *mExtendBufferAddress = NULL;
+TDX_EXTEND_BUFFER mExtendBuffer;
+
+/**
+ TD.RTMR.EXTEND requires 64B-aligned guest physical address of
+ 48B-extension data. In runtime we walk thru the Buffer to find
+ out a 64B-aligned start address.
+
+ @return Start address of the extend buffer
+
+**/
+UINT8 *
+EFIAPI
+GetExtendBuffer (
+ VOID
+ )
+{
+ UINT8 *ExtendBufferAddress;
+ UINT64 Gap;
+
+ if (mExtendBufferAddress != NULL) {
+ return mExtendBufferAddress;
+ }
+
+ ExtendBufferAddress = mExtendBuffer.Buffer;
+
+ Gap = 0x40 - ((UINT64)(UINTN)ExtendBufferAddress & EXTEND_BUFFER_ADDRESS_MASK);
+ mExtendBufferAddress = (UINT8*)((UINT64)(UINTN)ExtendBufferAddress + Gap);
+
+ DEBUG ((DEBUG_VERBOSE, "ExtendBufferAddress: 0x%p, Gap: 0x%x\n", ExtendBufferAddress, Gap));
+ DEBUG ((DEBUG_VERBOSE, "mExtendBufferAddress: 0x%p\n", mExtendBufferAddress));
+
+ ASSERT (mExtendBufferAddress + 64 <= ExtendBufferAddress + TD_EXTEND_BUFFER_LEN);
+
+ return mExtendBufferAddress;
+}
+
+
+/**
+ This function extends one of the RTMR measurement register
+ in TDCS with the provided extension data in memory.
+ RTMR extending supports SHA384 which length is 48 bytes.
+
+ @param[in] Data Point to the data to be extended
+ @param[in] DataLen Length of the data. Must be 48
+ @param[in] Index RTMR index
+
+ @return EFI_SUCCESS
+ @return EFI_INVALID_PARAMETER
+ @return EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+TdExtendRtmr (
+ IN UINT32 *Data,
+ IN UINT32 DataLen,
+ IN UINT8 Index
+ )
+{
+ EFI_STATUS Status;
+ UINT64 TdCallStatus;
+ UINT8 *ExtendBuffer;
+
+ Status = EFI_SUCCESS;
+
+ ASSERT (Index >= 0 && Index < RTMR_COUNT);
+ ASSERT (DataLen == SHA384_DIGEST_SIZE);
+
+ ExtendBuffer = GetExtendBuffer();
+ ASSERT (ExtendBuffer != NULL);
+ ZeroMem (ExtendBuffer, SHA384_DIGEST_SIZE);
+ CopyMem (ExtendBuffer, Data, SHA384_DIGEST_SIZE);
+
+ TdCallStatus = TdCall (TDCALL_TDEXTENDRTMR, (UINT64)(UINTN)ExtendBuffer, Index, 0, 0);
+
+ if (TdCallStatus == TDX_EXIT_REASON_SUCCESS) {
+ Status = EFI_SUCCESS;
+ } else if (TdCallStatus == TDX_EXIT_REASON_OPERAND_INVALID) {
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Error returned from TdExtendRtmr call - 0x%lx\n", TdCallStatus));
+ }
+
+ return Status;
+}
diff --git a/MdePkg/Library/TdxLib/TdSharedPageMask.c b/MdePkg/Library/TdxLib/TdSharedPageMask.c
new file mode 100644
index 000000000000..e6cbad322145
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdSharedPageMask.c
@@ -0,0 +1,46 @@
+/** @file
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+
+UINT64 mTdSharedPageMask = 0;
+
+/**
+ This function ges the Td guest shared page mask.
+
+ The guest indicates if a page is shared using the Guest Physical Address
+ (GPA) Shared (S) bit. If the GPA Width(GPAW) is 48, the S-bit is bit-47.
+ If the GPAW is 52, the S-bit is bit-51.
+
+ @return Shared page bit mask
+**/
+UINT64
+EFIAPI
+TdSharedPageMask (
+ VOID
+ )
+{
+ UINT64 Status;
+ UINT8 Gpaw;
+ TD_RETURN_DATA TdReturnData;
+
+ if (mTdSharedPageMask != 0) {
+ return mTdSharedPageMask;
+ }
+
+ Status = TdCall (TDCALL_TDINFO, 0,0,0, &TdReturnData);
+ ASSERT (Status == TDX_EXIT_REASON_SUCCESS);
+
+ Gpaw = (UINT8)(TdReturnData.TdInfo.Gpaw & 0x3f);
+ mTdSharedPageMask = 1ULL << (Gpaw - 1);
+ ASSERT(Gpaw == 48 || Gpaw == 52);
+ return mTdSharedPageMask;
+}
diff --git a/MdePkg/Library/TdxLib/TdxLib.inf b/MdePkg/Library/TdxLib/TdxLib.inf
new file mode 100644
index 000000000000..08951fc95b70
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdxLib.inf
@@ -0,0 +1,40 @@
+## @file
+# Tdx library
+#
+# Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TdxLib
+ FILE_GUID = 032A8E0D-0C27-40C0-9CAA-23B731C1B223
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TdxLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ AcceptPages.c
+ Rtmr.c
+ TdSharedPageMask.c
+ X64/Tdcall.nasm
+ X64/Tdvmcall.nasm
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdUseTdxEmulation
diff --git a/MdePkg/Library/TdxLib/X64/Tdcall.nasm b/MdePkg/Library/TdxLib/X64/Tdcall.nasm
new file mode 100644
index 000000000000..e5bbdca3df08
--- /dev/null
+++ b/MdePkg/Library/TdxLib/X64/Tdcall.nasm
@@ -0,0 +1,124 @@
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+%macro tdcall 0
+%if (FixedPcdGet32 (PcdUseTdxEmulation) != 0)
+ vmcall
+%else
+ db 0x66,0x0f,0x01,0xcc
+%endif
+%endmacro
+
+%macro tdcall_push_regs 0
+ push rbp
+ mov rbp, rsp
+ push r15
+ push r14
+ push r13
+ push r12
+ push rbx
+ push rsi
+ push rdi
+%endmacro
+
+%macro tdcall_pop_regs 0
+ pop rdi
+ pop rsi
+ pop rbx
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+ pop rbp
+%endmacro
+
+%define number_of_regs_pushed 8
+%define number_of_parameters 4
+
+;
+; Keep these in sync for push_regs/pop_regs, code below
+; uses them to find 5th or greater parameters
+;
+%define first_variable_on_stack_offset \
+ ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)
+%define second_variable_on_stack_offset \
+ ((first_variable_on_stack_offset) + 8)
+
+%macro tdcall_regs_preamble 2
+ mov rax, %1
+
+ mov ecx, %2
+
+ ; R10 = 0 (standard TDVMCALL)
+
+ xor r10d, r10d
+
+ ; Zero out unused (for standard TDVMCALL) registers to avoid leaking
+ ; secrets to the VMM.
+
+ xor ebx, ebx
+ xor esi, esi
+ xor edi, edi
+
+ xor edx, edx
+ xor ebp, ebp
+ xor r8d, r8d
+ xor r9d, r9d
+%endmacro
+
+%macro tdcall_regs_postamble 0
+ xor ebx, ebx
+ xor esi, esi
+ xor edi, edi
+
+ xor ecx, ecx
+ xor edx, edx
+ xor r8d, r8d
+ xor r9d, r9d
+ xor r10d, r10d
+ xor r11d, r11d
+%endmacro
+
+; TdCall (
+; UINT64 Leaf, // Rcx
+; UINT64 P1, // Rdx
+; UINT64 P2, // R8
+; UINT64 P3, // R9
+; UINT64 Results, // rsp + 0x28
+; )
+global ASM_PFX(TdCall)
+ASM_PFX(TdCall):
+ tdcall_push_regs
+
+ mov rax, rcx
+ mov rcx, rdx
+ mov rdx, r8
+ mov r8, r9
+
+ tdcall
+
+ ; exit if tdcall reports failure.
+ test rax, rax
+ jnz .exit
+
+ ; test if caller wanted results
+ mov r12, [rsp + first_variable_on_stack_offset ]
+ test r12, r12
+ jz .exit
+ mov [r12 + 0 ], rcx
+ mov [r12 + 8 ], rdx
+ mov [r12 + 16], r8
+ mov [r12 + 24], r9
+ mov [r12 + 32], r10
+ mov [r12 + 40], r11
+.exit:
+ tdcall_pop_regs
+ ret
diff --git a/MdePkg/Library/TdxLib/X64/Tdvmcall.nasm b/MdePkg/Library/TdxLib/X64/Tdvmcall.nasm
new file mode 100644
index 000000000000..12de700ff6ff
--- /dev/null
+++ b/MdePkg/Library/TdxLib/X64/Tdvmcall.nasm
@@ -0,0 +1,210 @@
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+%define TDVMCALL_EXPOSE_REGS_MASK 0xffec
+%define TDVMCALL 0x0
+%define EXIT_REASON_CPUID 0xa
+
+%macro tdcall 0
+%if (FixedPcdGet32 (PcdUseTdxEmulation) != 0)
+ vmcall
+%else
+ db 0x66,0x0f,0x01,0xcc
+%endif
+%endmacro
+
+%macro tdcall_push_regs 0
+ push rbp
+ mov rbp, rsp
+ push r15
+ push r14
+ push r13
+ push r12
+ push rbx
+ push rsi
+ push rdi
+%endmacro
+
+%macro tdcall_pop_regs 0
+ pop rdi
+ pop rsi
+ pop rbx
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+ pop rbp
+%endmacro
+
+%define number_of_regs_pushed 8
+%define number_of_parameters 4
+
+;
+; Keep these in sync for push_regs/pop_regs, code below
+; uses them to find 5th or greater parameters
+;
+%define first_variable_on_stack_offset \
+ ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)
+%define second_variable_on_stack_offset \
+ ((first_variable_on_stack_offset) + 8)
+
+%macro tdcall_regs_preamble 2
+ mov rax, %1
+
+ mov ecx, %2
+
+ ; R10 = 0 (standard TDVMCALL)
+
+ xor r10d, r10d
+
+ ; Zero out unused (for standard TDVMCALL) registers to avoid leaking
+ ; secrets to the VMM.
+
+ xor ebx, ebx
+ xor esi, esi
+ xor edi, edi
+
+ xor edx, edx
+ xor ebp, ebp
+ xor r8d, r8d
+ xor r9d, r9d
+%endmacro
+
+%macro tdcall_regs_postamble 0
+ xor ebx, ebx
+ xor esi, esi
+ xor edi, edi
+
+ xor ecx, ecx
+ xor edx, edx
+ xor r8d, r8d
+ xor r9d, r9d
+ xor r10d, r10d
+ xor r11d, r11d
+%endmacro
+
+;------------------------------------------------------------------------------
+; 0 => RAX = TDCALL leaf
+; M => RCX = TDVMCALL register behavior
+; 1 => R10 = standard vs. vendor
+; RDI => R11 = TDVMCALL function / nr
+; RSI = R12 = p1
+; RDX => R13 = p2
+; RCX => R14 = p3
+; R8 => R15 = p4
+
+; UINT64
+; EFIAPI
+; TdVmCall (
+; UINT64 Leaf, // Rcx
+; UINT64 P1, // Rdx
+; UINT64 P2, // R8
+; UINT64 P3, // R9
+; UINT64 P4, // rsp + 0x28
+; UINT64 *Val // rsp + 0x30
+; )
+global ASM_PFX(TdVmCall)
+ASM_PFX(TdVmCall):
+ tdcall_push_regs
+
+ mov r11, rcx
+ mov r12, rdx
+ mov r13, r8
+ mov r14, r9
+ mov r15, [rsp + first_variable_on_stack_offset ]
+
+ tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK
+
+ tdcall
+
+ ; ignore return dataif TDCALL reports failure.
+ test rax, rax
+ jnz .no_return_data
+
+ ; Propagate TDVMCALL success/failure to return value.
+ mov rax, r10
+
+ ; Retrieve the Val pointer.
+ mov r9, [rsp + second_variable_on_stack_offset ]
+ test r9, r9
+ jz .no_return_data
+
+ ; On success, propagate TDVMCALL output value to output param
+ test rax, rax
+ jnz .no_return_data
+ mov [r9], r11
+.no_return_data:
+ tdcall_regs_postamble
+
+ tdcall_pop_regs
+
+ ret
+
+;------------------------------------------------------------------------------
+; 0 => RAX = TDCALL leaf
+; M => RCX = TDVMCALL register behavior
+; 1 => R10 = standard vs. vendor
+; RDI => R11 = TDVMCALL function / nr
+; RSI = R12 = p1
+; RDX => R13 = p2
+; RCX => R14 = p3
+; R8 => R15 = p4
+
+; UINT64
+; EFIAPI
+; TdVmCallCpuid (
+; UINT64 EaxIn, // Rcx
+; UINT64 EcxIn, // Rdx
+; UINT64 *Results // R8
+; )
+global ASM_PFX(TdVmCallCpuid)
+ASM_PFX(TdVmCallCpuid):
+ tdcall_push_regs
+
+ mov r11, EXIT_REASON_CPUID
+ mov r12, rcx
+ mov r13, rdx
+
+ tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK
+
+ ; Save *results pointers
+ push r8
+
+ tdcall
+
+ ; Panic if TDCALL reports failure.
+ test rax, rax
+ jnz .no_return_data
+
+ ; Propagate TDVMCALL success/failure to return value.
+ mov rax, r10
+ test rax, rax
+ jnz .no_return_data
+
+ ; Retrieve *Results
+ pop r8
+ test r8, r8
+ jnz .no_return_data
+ ; Caller pass in buffer so store results r12-r15 contains eax-edx
+ mov [r8 + 0], r12
+ mov [r8 + 8], r13
+ mov [r8 + 16], r14
+ mov [r8 + 24], r15
+
+.no_return_data:
+ tdcall_regs_postamble
+
+ tdcall_pop_regs
+
+ ret
+
+.panic:
+ ud2
diff --git a/MdePkg/Library/TdxProbeLib/TdxProbeLibNull.c b/MdePkg/Library/TdxProbeLib/TdxProbeLibNull.c
new file mode 100644
index 000000000000..631f51ebf79b
--- /dev/null
+++ b/MdePkg/Library/TdxProbeLib/TdxProbeLibNull.c
@@ -0,0 +1,25 @@
+/** @file
+ Null instance of TdxProbeLib.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include
+#include
+
+/**
+ Probe whether it is TD guest or Non-TD guest.
+
+ @return TRUE TD guest
+ @return FALSE Non-TD guest
+**/
+BOOLEAN
+EFIAPI
+ProbeTdGuest (
+ VOID )
+{
+ return FALSE;
+}
diff --git a/MdePkg/Library/TdxProbeLib/TdxProbeLibNull.inf b/MdePkg/Library/TdxProbeLib/TdxProbeLibNull.inf
new file mode 100644
index 000000000000..f3d5eb69ae15
--- /dev/null
+++ b/MdePkg/Library/TdxProbeLib/TdxProbeLibNull.inf
@@ -0,0 +1,27 @@
+## @file
+# Null Tdx Probe library instance
+#
+# Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TdxProbeLibNull
+ FILE_GUID = D0DCCD86-FC42-4EE3-9132-53827C77661C
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TdxProbeLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = X64 IA32
+#
+
+[Sources]
+ TdxProbeLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index 3928db65d188..888d92086a49 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -983,6 +983,9 @@
gEfiPeiDelayedDispatchPpiGuid = { 0x869c711d, 0x649c, 0x44fe, { 0x8b, 0x9e, 0x2c, 0xbb, 0x29, 0x11, 0xc3, 0xe6 }}
[Protocols]
+ ## Include/Protocol/Tdx.h
+ gTdTcg2ProtocolGuid = {0x96751a3d, 0x72f4, 0x41a6, {0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b}}
+
## Include/Protocol/Pcd.h
gPcdProtocolGuid = { 0x11B34006, 0xD85B, 0x4D0A, { 0xA2, 0x90, 0xD5, 0xA5, 0x71, 0x31, 0x0E, 0xF7 }}
diff --git a/OvmfPkg/8254TimerDxe/8254Timer.inf b/OvmfPkg/8254TimerDxe/8254Timer.inf
index 8a07c8247ebe..007e3f405c0a 100644
--- a/OvmfPkg/8254TimerDxe/8254Timer.inf
+++ b/OvmfPkg/8254TimerDxe/8254Timer.inf
@@ -26,6 +26,7 @@
DebugLib
UefiDriverEntryPoint
IoLib
+ TdxProbeLib
[Sources]
Timer.h
diff --git a/OvmfPkg/8254TimerDxe/Timer.c b/OvmfPkg/8254TimerDxe/Timer.c
index fd1691beb3c7..701cc65a303e 100644
--- a/OvmfPkg/8254TimerDxe/Timer.c
+++ b/OvmfPkg/8254TimerDxe/Timer.c
@@ -7,6 +7,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Timer.h"
+#include
//
// The handle onto which the Timer Architectural Protocol will be installed
@@ -340,6 +341,10 @@ TimerDriverInitialize (
EFI_STATUS Status;
UINT32 TimerVector;
+ if(ProbeTdGuest()) {
+ return EFI_UNSUPPORTED;
+ }
+
//
// Initialize the pointer to our notify function.
//
diff --git a/OvmfPkg/8259InterruptControllerDxe/8259.c b/OvmfPkg/8259InterruptControllerDxe/8259.c
index 1c2ac1039d40..94b7cb83c90e 100644
--- a/OvmfPkg/8259InterruptControllerDxe/8259.c
+++ b/OvmfPkg/8259InterruptControllerDxe/8259.c
@@ -8,6 +8,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include "8259.h"
+#include
//
// Global for the Legacy 8259 Protocol that is produced by this driver
//
@@ -586,6 +587,9 @@ Install8259 (
EFI_STATUS Status;
EFI_8259_IRQ Irq;
+ if(ProbeTdGuest()) {
+ return EFI_UNSUPPORTED;
+ }
//
// Initialze mask values from PCDs
//
diff --git a/OvmfPkg/8259InterruptControllerDxe/8259.inf b/OvmfPkg/8259InterruptControllerDxe/8259.inf
index 7320ff2490a7..09a4b41996af 100644
--- a/OvmfPkg/8259InterruptControllerDxe/8259.inf
+++ b/OvmfPkg/8259InterruptControllerDxe/8259.inf
@@ -29,6 +29,7 @@
UefiDriverEntryPoint
IoLib
PcdLib
+ TdxProbeLib
[Protocols]
gEfiLegacy8259ProtocolGuid ## PRODUCES
diff --git a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
index e486b8afa56d..91918c8f5533 100644
--- a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
+++ b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
@@ -51,14 +51,17 @@
DxeServicesTableLib
OrderedCollectionLib
XenPlatformLib
+ TdxProbeLib
[Protocols]
gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiFirmwareVolume2ProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
gEfiPciIoProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
+ gTdTcg2ProtocolGuid # PROTOCOL SOMETIMES_CONSUMES
[Guids]
gRootBridgesConnectedEventGroupGuid
+ gUefiOvmfPkgTdxPlatformGuid
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiTableStorageFile
@@ -66,6 +69,7 @@
gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
gUefiOvmfPkgTokenSpaceGuid.Pcd8259LegacyModeEdgeLevel
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdRelocatedMailboxBase
[Depex]
gEfiAcpiTableProtocolGuid
diff --git a/OvmfPkg/AcpiPlatformDxe/Qemu.c b/OvmfPkg/AcpiPlatformDxe/Qemu.c
index 7fb42270043f..3e1da8ef1037 100644
--- a/OvmfPkg/AcpiPlatformDxe/Qemu.c
+++ b/OvmfPkg/AcpiPlatformDxe/Qemu.c
@@ -17,6 +17,10 @@
#include
#include
#include
+#include
+#include
+
+STATIC EFI_HOB_PLATFORM_INFO *mPlatformInfoHob = NULL;
BOOLEAN
QemuDetected (
@@ -30,28 +34,6 @@ QemuDetected (
return TRUE;
}
-
-STATIC
-UINTN
-CountBits16 (
- UINT16 Mask
- )
-{
- //
- // For all N >= 1, N bits are enough to represent the number of bits set
- // among N bits. It's true for N == 1. When adding a new bit (N := N+1),
- // the maximum number of possibly set bits increases by one, while the
- // representable maximum doubles.
- //
- Mask = ((Mask & 0xAAAA) >> 1) + (Mask & 0x5555);
- Mask = ((Mask & 0xCCCC) >> 2) + (Mask & 0x3333);
- Mask = ((Mask & 0xF0F0) >> 4) + (Mask & 0x0F0F);
- Mask = ((Mask & 0xFF00) >> 8) + (Mask & 0x00FF);
-
- return Mask;
-}
-
-
STATIC
EFI_STATUS
EFIAPI
@@ -63,7 +45,6 @@ QemuInstallAcpiMadtTable (
)
{
UINTN CpuCount;
- UINTN PciLinkIsoCount;
UINTN NewBufferSize;
EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic;
@@ -73,6 +54,7 @@ QemuInstallAcpiMadtTable (
VOID *Ptr;
UINTN Loop;
EFI_STATUS Status;
+ ACPI_MADT_MPWK_STRUCT *MadtMpWk;
ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
@@ -80,19 +62,15 @@ QemuInstallAcpiMadtTable (
CpuCount = QemuFwCfgRead16 ();
ASSERT (CpuCount >= 1);
- //
- // Set Level-tiggered, Active High for these identity mapped IRQs. The bitset
- // corresponds to the union of all possible interrupt assignments for the LNKA,
- // LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT.
- //
- PciLinkIsoCount = CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel));
-
+#define NUM_8259_IRQS 16
NewBufferSize = 1 * sizeof (*Madt) +
CpuCount * sizeof (*LocalApic) +
1 * sizeof (*IoApic) +
- (1 + PciLinkIsoCount) * sizeof (*Iso) +
+ NUM_8259_IRQS * sizeof (*Iso) +
1 * sizeof (*LocalApicNmi);
+ NewBufferSize += sizeof(ACPI_MADT_MPWK_STRUCT);
+
Madt = AllocatePool (NewBufferSize);
if (Madt == NULL) {
return EFI_OUT_OF_RESOURCES;
@@ -130,31 +108,21 @@ QemuInstallAcpiMadtTable (
Iso = Ptr;
Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
Iso->Length = sizeof (*Iso);
- Iso->Bus = 0x00; // ISA
- Iso->Source = 0x00; // IRQ0
+ Iso->Bus = 0x00; // ISA
+ Iso->Source = 0x00; // IRQ0
Iso->GlobalSystemInterruptVector = 0x00000002;
- Iso->Flags = 0x0000; // Conforms to specs of the bus
+ Iso->Flags = 0x0005; // Edge-triggered, Active High
++Iso;
- //
- // Set Level-triggered, Active High for all possible PCI link targets.
- //
- for (Loop = 0; Loop < 16; ++Loop) {
- if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel) & (1 << Loop)) == 0) {
- continue;
- }
+ for (Loop = 1; Loop < NUM_8259_IRQS; ++Loop) {
Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
Iso->Length = sizeof (*Iso);
Iso->Bus = 0x00; // ISA
Iso->Source = (UINT8) Loop;
Iso->GlobalSystemInterruptVector = (UINT32) Loop;
- Iso->Flags = 0x000D; // Level-triggered, Active High
+ Iso->Flags = 0x0005; // Edge-triggered, Active High
++Iso;
}
- ASSERT (
- (UINTN) (Iso - (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *)Ptr) ==
- 1 + PciLinkIsoCount
- );
Ptr = Iso;
LocalApicNmi = Ptr;
@@ -172,6 +140,17 @@ QemuInstallAcpiMadtTable (
LocalApicNmi->LocalApicInti = 0x01;
Ptr = LocalApicNmi + 1;
+ MadtMpWk = Ptr;
+ MadtMpWk->Type = ACPI_MADT_MPWK_STRUCT_TYPE;
+ MadtMpWk->Length = sizeof(ACPI_MADT_MPWK_STRUCT);
+ MadtMpWk->MailBoxVersion = 1;
+ MadtMpWk->Reserved2 = 0;
+ MadtMpWk->MailBoxAddress = PcdGet64 (PcdTdRelocatedMailboxBase);
+ Ptr = MadtMpWk + 1;
+
+ DEBUG ((DEBUG_INFO, "%a:%d:ACPI setting mailbox to 0x%x 0x%x\n", __func__, __LINE__,
+ MadtMpWk->MailBoxAddress, PcdGet64 (PcdTdRelocatedMailboxBase)));
+
ASSERT ((UINTN) ((UINT8 *)Ptr - (UINT8 *)Madt) == NewBufferSize);
Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
@@ -355,13 +334,18 @@ GetSuspendStates (
//
// check for overrides
//
- Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize);
- if (Status != RETURN_SUCCESS || FwCfgSize != sizeof SystemStates) {
- DEBUG ((DEBUG_INFO, "ACPI using S3/S4 defaults\n"));
- return;
+ if (mPlatformInfoHob) {
+ CopyMem(SystemStates, mPlatformInfoHob->SystemStates, sizeof SystemStates);
+ DEBUG ((DEBUG_INFO, ">>>> GetSuspendStates mPlatformInfoHob\n"));
+ } else {
+ Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize);
+ if (Status != RETURN_SUCCESS || FwCfgSize != sizeof SystemStates) {
+ DEBUG ((DEBUG_INFO, "ACPI using S3/S4 defaults\n"));
+ return;
+ }
+ QemuFwCfgSelectItem (FwCfgItem);
+ QemuFwCfgReadBytes (sizeof SystemStates, SystemStates);
}
- QemuFwCfgSelectItem (FwCfgItem);
- QemuFwCfgReadBytes (sizeof SystemStates, SystemStates);
//
// Each byte corresponds to a system state. In each byte, the MSB tells us
@@ -489,6 +473,12 @@ QemuInstallAcpiTable (
{
EFI_ACPI_DESCRIPTION_HEADER *Hdr;
EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ GuidHob = GetFirstGuidHob(&gUefiOvmfPkgTdxPlatformGuid);
+ if (GuidHob) {
+ mPlatformInfoHob = (EFI_HOB_PLATFORM_INFO *)GET_GUID_HOB_DATA (GuidHob);
+ }
Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AcpiTableBuffer;
switch (Hdr->Signature) {
diff --git a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
index b62027db6e66..b679e6b44ec6 100644
--- a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
+++ b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
@@ -18,7 +18,11 @@
#include
#include
#include
+#include
+#include
+#include
+EFI_TCG2_PROTOCOL *mTdTcg2Protocol = NULL;
//
// The user structure for the ordered collection that will track the fw_cfg
@@ -35,6 +39,71 @@ typedef struct {
// part of ACPI tables.
} BLOB;
+/**
+ Mesure firmware acpi configuration data from qemu.
+ @param[in] EventData Pointer to the event data.
+ @param[in] EventSize Size of event data.
+ @param[in] CfgDataBase Configuration data base address.
+ @param[in] EventSize Size of configuration data .
+ @retval EFI_NOT_FOUND Cannot locate protocol.
+ @retval EFI_OUT_OF_RESOURCES Allocate zero pool failure.
+ @return Status codes returned by
+ mTcg2Protocol->HashLogExtendEvent.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+MeasureQemuFwCfgAcpi(
+ IN CHAR8 *EventData,
+ IN UINT32 EventSize,
+ IN EFI_PHYSICAL_ADDRESS CfgDataBase,
+ IN UINTN CfgDataLength
+)
+{
+ EFI_TCG2_EVENT *Tcg2Event;
+ EFI_STATUS Status;
+
+ if (ProbeTdGuest () == FALSE) {
+ return EFI_SUCCESS;
+ }
+
+ if (mTdTcg2Protocol == NULL) {
+ Status = gBS->LocateProtocol (&gTdTcg2ProtocolGuid, NULL, (VOID **) &mTdTcg2Protocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // TdTcg2 protocol is not installed.
+ //
+ DEBUG ((EFI_D_ERROR, "MesureQemuFwCfgAcpi - TdTcg2 - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Tcg2Event = AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event));
+ if (Tcg2Event == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event);
+ Tcg2Event->Header.EventType = EV_PLATFORM_CONFIG_FLAGS;
+ Tcg2Event->Header.PCRIndex = 1;
+ Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);
+ Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
+ CopyMem (&Tcg2Event->Event[0], EventData, EventSize);
+
+ Status = mTdTcg2Protocol->HashLogExtendEvent (mTdTcg2Protocol,
+ 0,
+ CfgDataBase,
+ CfgDataLength,
+ Tcg2Event
+ );
+
+ FreePool (Tcg2Event);
+
+ DEBUG ((DEBUG_INFO, "MeasureQemuFwCfg %s, %r\n", EventData, Status));
+
+ return Status;
+}
+
/**
Compare a standalone key against a user structure containing an embedded key.
@@ -382,6 +451,16 @@ ProcessCmdAllocate (
QemuFwCfgSelectItem (FwCfgItem);
QemuFwCfgReadBytes (FwCfgSize, Blob->Base);
+
+ Status = MeasureQemuFwCfgAcpi ((CHAR8 *) Allocate->File,
+ sizeof(Allocate->File),
+ (EFI_PHYSICAL_ADDRESS) Blob->Base,
+ FwCfgSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Measure %s failure\n", Allocate->File));
+ }
+
ZeroMem (Blob->Base + Blob->Size, EFI_PAGES_TO_SIZE (NumPages) - Blob->Size);
DEBUG ((DEBUG_VERBOSE, "%a: File=\"%a\" Alignment=0x%x Zone=%d Size=0x%Lx "
@@ -913,9 +992,16 @@ Process2ndPassCmdAddPointer (
goto RollbackSeenPointer;
}
- Status = AcpiProtocol->InstallAcpiTable (AcpiProtocol,
+ if(ProbeTdGuest()) {
+ Status = QemuInstallAcpiTable(AcpiProtocol,
(VOID *)(UINTN)PointerValue, TableSize,
&InstalledKey[*NumInstalled]);
+ } else {
+ Status = AcpiProtocol->InstallAcpiTable (AcpiProtocol,
+ (VOID *)(UINTN)PointerValue, TableSize,
+ &InstalledKey[*NumInstalled]);
+ }
+
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: InstallAcpiTable(): %r\n", __FUNCTION__,
Status));
@@ -992,6 +1078,17 @@ InstallQemuFwCfgTables (
EnablePciDecoding (&OriginalPciAttributes, &OriginalPciAttributesCount);
QemuFwCfgSelectItem (FwCfgItem);
QemuFwCfgReadBytes (FwCfgSize, LoaderStart);
+
+ Status = MeasureQemuFwCfgAcpi (
+ "etc/table-loader",
+ sizeof ("etc/table-loader"),
+ (EFI_PHYSICAL_ADDRESS) LoaderStart,
+ FwCfgSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Measure etc/table-loader failure\n"));
+ }
+
RestorePciDecoding (OriginalPciAttributes, OriginalPciAttributesCount);
LoaderEnd = LoaderStart + FwCfgSize / sizeof *LoaderEntry;
diff --git a/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c b/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c
index 766ad1e59f47..0f9b78e1fdd1 100644
--- a/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c
+++ b/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
#include "Fvb.h"
#define EFI_AUTHENTICATED_VARIABLE_GUID \
@@ -596,6 +597,154 @@ ValidateFvHeader (
}
+/**
+ Check padding data all bit should be 1.
+
+ @param[in] Buffer - A pointer to buffer header
+ @param[in] BufferSize - Buffer size
+
+ @retval TRUE - The padding data is valid.
+ @retval TRUE - The padding data is invalid.
+
+**/
+BOOLEAN
+CheckPaddingData (
+ IN UINT8 *Buffer,
+ IN UINT32 BufferSize
+ )
+ {
+ UINT32 index;
+
+ for (index = 0; index < BufferSize; index++) {
+ if (Buffer[index] != 0xFF) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ }
+
+
+/**
+ Check the integrity of CFV data.
+
+ @param[in] TdxCfvBase - A pointer to CFV header
+ @param[in] TdxCfvSize - CFV data size
+
+ @retval TRUE - The CFV data is valid.
+ @retval FALSE - The CFV data is invalid.
+
+**/
+BOOLEAN
+ValidateTdxCfv (
+ IN UINT8 *TdxCfvBase,
+ IN UINT32 TdxCfvSize
+ )
+{
+ UINT16 Checksum;
+ UINTN VariableBase;
+ UINT32 VariableOffset;
+ UINT32 VariableOffsetBeforeAlign;
+ EFI_FIRMWARE_VOLUME_HEADER *CfvFvHeader;
+ VARIABLE_STORE_HEADER *CfvVariableStoreHeader;
+ AUTHENTICATED_VARIABLE_HEADER *VariableHeader;
+
+ static EFI_GUID FvHdrGUID = EFI_SYSTEM_NV_DATA_FV_GUID;
+ static EFI_GUID VarStoreHdrGUID = EFI_AUTHENTICATED_VARIABLE_GUID;
+
+ VariableOffset = 0;
+
+ if (TdxCfvBase == NULL) {
+ DEBUG ((DEBUG_ERROR, "TDX CFV: CFV pointer is NULL\n"));
+ return FALSE;
+ }
+
+ //
+ // Verify the header zerovetor, filesystemguid,
+ // revision, signature, attributes, fvlength, checksum
+ // HeaderLength cannot be an odd number
+ //
+ CfvFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) TdxCfvBase;
+
+ if ((!IsZeroBuffer (CfvFvHeader->ZeroVector, 16)) ||
+ (!CompareGuid (&FvHdrGUID, &CfvFvHeader->FileSystemGuid)) ||
+ (CfvFvHeader->Signature != EFI_FVH_SIGNATURE) ||
+ (CfvFvHeader->Attributes != 0x4feff) ||
+ (CfvFvHeader->HeaderLength != EMU_FV_HEADER_LENGTH) ||
+ (CfvFvHeader->Revision != EFI_FVH_REVISION)
+ ) {
+ DEBUG ((DEBUG_ERROR, "TDX CFV: Basic FV headers were invalid\n"));
+ return FALSE;
+ }
+
+ //
+ // Verify the header checksum
+ //
+ Checksum = CalculateSum16 ((VOID*) CfvFvHeader, CfvFvHeader->HeaderLength);
+
+ if (Checksum != 0) {
+ DEBUG ((DEBUG_ERROR, "TDX CFV: FV checksum was invalid\n"));
+ return FALSE;
+ }
+
+ //
+ // Verify the header signature, size, format, state
+ //
+ CfvVariableStoreHeader = (VARIABLE_STORE_HEADER *) (TdxCfvBase + CfvFvHeader->HeaderLength);
+ if ((!CompareGuid (&VarStoreHdrGUID, &CfvVariableStoreHeader->Signature)) ||
+ (CfvVariableStoreHeader->Format != VARIABLE_STORE_FORMATTED) ||
+ (CfvVariableStoreHeader->State != VARIABLE_STORE_HEALTHY)
+ ) {
+ DEBUG ((DEBUG_ERROR, "TDX CFV: Variable Store header was invalid\n"));
+ return FALSE;
+ }
+
+ //
+ // Verify the header startId, state
+ // Verify data to the end
+ //
+ VariableBase = (UINTN)TdxCfvBase + CfvFvHeader->HeaderLength + sizeof (VARIABLE_STORE_HEADER);
+ while (VariableOffset < (CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER))) {
+ VariableHeader = (AUTHENTICATED_VARIABLE_HEADER *) (VariableBase + VariableOffset);
+ if (VariableHeader->StartId != VARIABLE_DATA) {
+ if (!CheckPaddingData ((UINT8 *)VariableHeader, CfvVariableStoreHeader->Size - sizeof(VARIABLE_STORE_HEADER) - VariableOffset)) {
+ DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n"));
+ return FALSE;
+ }
+ VariableOffset = CfvVariableStoreHeader->Size - sizeof(VARIABLE_STORE_HEADER);
+ }
+ else {
+ if (!((VariableHeader->State == VAR_IN_DELETED_TRANSITION) ||
+ (VariableHeader->State == VAR_DELETED) ||
+ (VariableHeader->State == VAR_HEADER_VALID_ONLY) ||
+ (VariableHeader->State == VAR_ADDED))) {
+ DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n"));
+ return FALSE;
+ }
+
+ VariableOffset += sizeof (AUTHENTICATED_VARIABLE_HEADER) + VariableHeader->NameSize + VariableHeader->DataSize;
+ // Verify VariableOffset should be less than or equal CfvVariableStoreHeader->Size - sizeof(VARIABLE_STORE_HEADER)
+ if (VariableOffset > (CfvVariableStoreHeader->Size - sizeof(VARIABLE_STORE_HEADER))) {
+ DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n"));
+ return FALSE;
+ }
+
+ VariableOffsetBeforeAlign = VariableOffset;
+ // 4 byte align
+ VariableOffset = (VariableOffset + 3) & (UINTN)(~3);
+
+ if (!CheckPaddingData ((UINT8 *)(VariableBase + VariableOffsetBeforeAlign), VariableOffset - VariableOffsetBeforeAlign)) {
+ DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n"));
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+
+}
+
+
/**
Initializes the FV Header and Variable Store Header
to support variable operations.
@@ -718,6 +867,8 @@ FvbInitialize (
EFI_HANDLE Handle;
EFI_PHYSICAL_ADDRESS Address;
RETURN_STATUS PcdStatus;
+ UINT8 *CfvBase;
+ UINT32 CfvSize;
DEBUG ((DEBUG_INFO, "EMU Variable FVB Started\n"));
@@ -770,7 +921,21 @@ FvbInitialize (
mEmuVarsFvb.BufferPtr = Ptr;
//
- // Initialize the main FV header and variable store header
+ // Copy the content from Configuration FV in Td guest
+ //
+ if (ProbeTdGuest()) {
+ CfvBase = (UINT8*)(UINTN)PcdGet32(PcdCfvBase);
+ CfvSize = (UINT32)PcdGet32(PcdCfvRawDataSize);
+ DEBUG ((DEBUG_INFO, "Copy the content from Configuration FV. 0x%p : 0x%x\n", CfvBase, CfvSize));
+
+ if (ValidateTdxCfv(CfvBase, CfvSize)) {
+ CopyMem(Ptr, CfvBase, CfvSize);
+ Initialize = FALSE;
+ }
+ }
+
+ //
+ // Initialize the main FV header and variable store header.
//
if (Initialize) {
SetMem (Ptr, EMU_FVB_SIZE, ERASED_UINT8);
diff --git a/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf b/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
index 225ea27f5ffd..f6c4dcf4c5f4 100644
--- a/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
+++ b/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
@@ -44,6 +44,7 @@
UefiDriverEntryPoint
UefiLib
UefiRuntimeLib
+ TdxProbeLib
[Guids]
gEfiEventVirtualAddressChangeGuid # ALWAYS_CONSUMED Create Event: EVENT_GROUP_GUID
@@ -56,6 +57,8 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdCfvBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
diff --git a/OvmfPkg/Include/IndustryStandard/AcpiTdx.h b/OvmfPkg/Include/IndustryStandard/AcpiTdx.h
new file mode 100644
index 000000000000..16d96b83e20e
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/AcpiTdx.h
@@ -0,0 +1,30 @@
+/** @file
+ Processor or Compiler specific defines and types x64 (Intel 64, AMD64).
+
+ Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _ACPI_TDX_H_
+#define _ACPI_TDX_H_
+
+#define ACPI_MADT_MPWK_STRUCT_TYPE 0x10
+
+#pragma pack(1)
+
+typedef struct {
+ UINT8 Type;
+ UINT8 Length;
+ UINT16 MailBoxVersion;
+ UINT32 Reserved2;
+ UINT64 MailBoxAddress;
+} ACPI_MADT_MPWK_STRUCT;
+#pragma pack()
+#endif
diff --git a/OvmfPkg/Include/Library/MemEncryptLib.h b/OvmfPkg/Include/Library/MemEncryptLib.h
new file mode 100644
index 000000000000..c610748cb7b0
--- /dev/null
+++ b/OvmfPkg/Include/Library/MemEncryptLib.h
@@ -0,0 +1,20 @@
+/** @file
+
+ Define Memory Encrypted Virtualization base library helper function
+
+ Copyright (c) 2020, Intel Corporation. All rights reserved.
+ Copyright (c) 2017, AMD Incorporated. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _MEM_ENCRYPT_LIB_H_
+#define _MEM_ENCRYPT_LIB_H_
+
+#define MEM_ENCRYPT_NONE_ENABLED 0x00
+#define MEM_ENCRYPT_SEV_ENABLED 0x01
+#define MEM_ENCRYPT_SEVES_ENABLED 0x02
+#define MEM_ENCRYPT_TDX_ENABLED 0x04
+
+#endif // _MEM_ENCRYPT_LIB_H_
diff --git a/OvmfPkg/Include/Library/MemEncryptTdxLib.h b/OvmfPkg/Include/Library/MemEncryptTdxLib.h
new file mode 100644
index 000000000000..a93f23affc63
--- /dev/null
+++ b/OvmfPkg/Include/Library/MemEncryptTdxLib.h
@@ -0,0 +1,109 @@
+/** @file
+
+ Define Memory Encrypted Virtualization base library helper function
+
+ Copyright (c) 2020, Intel Corporation. All rights reserved.
+ Copyright (c) 2017, AMD Incorporated. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _MEM_ENCRYPT_TDX_LIB_H_
+#define _MEM_ENCRYPT_TDX_LIB_H_
+
+#include
+
+/**
+ Returns boolean to indicate whether to indicate which, if any, memory encryption is enabled
+
+ @param[in] Type Bitmask of encryption technologies to check is enabled
+
+ @retval TRUE The encryption type(s) are enabled
+ @retval FALSE The encryption type(s) are not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptTdxIsEnabled (
+ VOID
+ );
+
+/**
+ This function clears memory encryption bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+ @param[in] Flush Flush the caches before clearing the bit
+ (mostly TRUE except MMIO addresses)
+
+ @retval RETURN_SUCCESS The attributes were cleared for the
+ memory region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Clearing the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxClearPageEncMask (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages,
+ IN BOOLEAN Flush
+ );
+
+/**
+ This function sets memory encryption bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+ @param[in] Flush Flush the caches before setting the bit
+ (mostly TRUE except MMIO addresses)
+
+ @retval RETURN_SUCCESS The attributes were set for the memory
+ region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Setting the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxSetPageEncMask (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages,
+ IN BOOLEAN Flush
+ );
+
+
+/**
+ Locate the page range that covers the initial (pre-SMBASE-relocation) SMRAM
+ Save State Map.
+
+ @param[out] BaseAddress The base address of the lowest-address page that
+ covers the initial SMRAM Save State Map.
+
+ @param[out] NumberOfPages The number of pages in the page range that covers
+ the initial SMRAM Save State Map.
+
+ @retval RETURN_SUCCESS BaseAddress and NumberOfPages have been set on
+ output.
+
+ @retval RETURN_UNSUPPORTED SMM is unavailable.
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptLocateInitialSmramSaveStateMapPages (
+ OUT UINTN *BaseAddress,
+ OUT UINTN *NumberOfPages
+ );
+#endif // _MEM_ENCRYPT_TDX_LIB_H_
diff --git a/OvmfPkg/Include/Library/PrePiLibTdx.h b/OvmfPkg/Include/Library/PrePiLibTdx.h
new file mode 100644
index 000000000000..405ee4e5c628
--- /dev/null
+++ b/OvmfPkg/Include/Library/PrePiLibTdx.h
@@ -0,0 +1,241 @@
+/** @file
+ Library that helps implement monolithic PEI. (SEC goes to DXE)
+
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PRE_PI_LIB_TDX_H__
+#define __PRE_PI_LIB_TDX_H__
+
+/**
+ This service enables discovery of additional firmware volumes.
+
+ @param Instance This instance of the firmware volume to find. The value 0 is the
+ Boot Firmware Volume (BFV).
+ @param FwVolHeader Pointer to the firmware volume header of the volume to return.
+
+ @retval EFI_SUCCESS The volume was found.
+ @retval EFI_NOT_FOUND The volume was not found.
+ @retval EFI_INVALID_PARAMETER FwVolHeader is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsFindNextVolume (
+ IN UINTN Instance,
+ IN OUT EFI_PEI_FV_HANDLE *VolumeHandle
+ );
+
+
+/**
+ This service enables discovery of additional firmware files.
+
+ @param SearchType A filter to find files only of this type.
+ @param FwVolHeader Pointer to the firmware volume header of the volume to search.
+ This parameter must point to a valid FFS volume.
+ @param FileHeader Pointer to the current file from which to begin searching.
+
+ @retval EFI_SUCCESS The file was found.
+ @retval EFI_NOT_FOUND The file was not found.
+ @retval EFI_NOT_FOUND The header checksum was not zero.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsFindNextFile (
+ IN EFI_FV_FILETYPE SearchType,
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ );
+
+
+/**
+ This service enables discovery sections of a given type within a valid FFS file.
+
+ @param SearchType The value of the section type to find.
+ @param FfsFileHeader A pointer to the file header that contains the set of sections to
+ be searched.
+ @param SectionData A pointer to the discovered section, if successful.
+
+ @retval EFI_SUCCESS The section was found.
+ @retval EFI_NOT_FOUND The section was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsFindSectionData (
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData
+ );
+
+
+/**
+ Find a file in the volume by name
+
+ @param FileName A pointer to the name of the file to
+ find within the firmware volume.
+
+ @param VolumeHandle The firmware volume to search FileHandle
+ Upon exit, points to the found file's
+ handle or NULL if it could not be found.
+
+ @retval EFI_SUCCESS File was found.
+
+ @retval EFI_NOT_FOUND File was not found.
+
+ @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or
+ FileName was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsFindFileByName (
+ IN CONST EFI_GUID *FileName,
+ IN CONST EFI_PEI_FV_HANDLE VolumeHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ );
+
+
+/**
+ Get information about the file by name.
+
+ @param FileHandle Handle of the file.
+
+ @param FileInfo Upon exit, points to the file's
+ information.
+
+ @retval EFI_SUCCESS File information returned.
+
+ @retval EFI_INVALID_PARAMETER If FileHandle does not
+ represent a valid file.
+
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsGetFileInfo (
+ IN CONST EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO *FileInfo
+ );
+
+
+/**
+ Get Information about the volume by name
+
+ @param VolumeHandle Handle of the volume.
+
+ @param VolumeInfo Upon exit, points to the volume's
+ information.
+
+ @retval EFI_SUCCESS File information returned.
+
+ @retval EFI_INVALID_PARAMETER If FileHandle does not
+ represent a valid file.
+
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsGetVolumeInfo (
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ OUT EFI_FV_INFO *VolumeInfo
+ );
+
+
+
+/**
+ Get Fv image from the FV type file, then add FV & FV2 Hob.
+
+ @param FileHandle File handle of a Fv type file.
+
+ @retval EFI_NOT_FOUND FV image can't be found.
+ @retval EFI_SUCCESS Successfully to process it.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsProcessFvFile (
+ IN EFI_PEI_FILE_HANDLE FvFileHandle
+ );
+
+
+/**
+ Search through every FV until you find a file of type FileType
+
+ @param FileType File handle of a Fv type file.
+ @param Volumehandle On success Volume Handle of the match
+ @param FileHandle On success File Handle of the match
+
+ @retval EFI_NOT_FOUND FV image can't be found.
+ @retval EFI_SUCCESS Successfully found FileType
+
+**/
+EFI_STATUS
+EFIAPI
+FfsAnyFvFindFirstFile (
+ IN EFI_FV_FILETYPE FileType,
+ OUT EFI_PEI_FV_HANDLE *VolumeHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ );
+
+EFI_STATUS
+EFIAPI
+FfsAnyFvFindFileByName (
+ IN CONST EFI_GUID *Name,
+ OUT EFI_PEI_FV_HANDLE *VolumeHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ );
+
+
+/**
+ Get Fv image from the FV type file, then add FV & FV2 Hob.
+
+ @param FileHandle File handle of a Fv type file.
+
+
+ @retval EFI_NOT_FOUND FV image can't be found.
+ @retval EFI_SUCCESS Successfully to process it.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsProcessFvFile (
+ IN EFI_PEI_FILE_HANDLE FvFileHandle
+ );
+
+EFI_STATUS
+EFIAPI
+LoadPeCoffImage (
+ IN VOID *PeCoffImage,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
+ OUT UINT64 *ImageSize,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint
+ );
+
+EFI_STATUS
+EFIAPI
+LoadDxeCoreFromFfsFile (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINTN StackSize
+ );
+
+EFI_STATUS
+EFIAPI
+LoadDxeCoreFromFv (
+ IN UINTN *FvInstance, OPTIONAL
+ IN UINTN StackSize
+ );
+
+EFI_STATUS
+EFIAPI
+DecompressFirstFv (
+ VOID
+ );
+
+#endif
diff --git a/OvmfPkg/Include/Library/TdvfPlatformLib.h b/OvmfPkg/Include/Library/TdvfPlatformLib.h
new file mode 100644
index 000000000000..27bfb03ee2e8
--- /dev/null
+++ b/OvmfPkg/Include/Library/TdvfPlatformLib.h
@@ -0,0 +1,27 @@
+#ifndef __TDVF_PLATFORM_LIB_H__
+#define __TDVF_PLATFORM_LIB_H__
+
+#include
+#include
+#include
+#include
+#include
+
+#define EFI_RESOURCE_ATTRIBUTE_ENCRYPTED 0x04000000
+#pragma pack(1)
+typedef struct {
+ ///
+ EFI_HOB_GUID_TYPE GuidHeader;
+ UINT64 RelocatedMailBox;
+ UINT16 HostBridgePciDevId;
+ BOOLEAN SetNxForStack;
+ UINT8 SystemStates[6];
+} EFI_HOB_PLATFORM_INFO;
+#pragma pack()
+VOID
+EFIAPI
+TdvfPlatformInitialize (
+ IN OUT EFI_HOB_PLATFORM_INFO *
+ );
+
+#endif
diff --git a/OvmfPkg/Include/Library/TdxStartupLib.h b/OvmfPkg/Include/Library/TdxStartupLib.h
new file mode 100644
index 000000000000..1a53253cca27
--- /dev/null
+++ b/OvmfPkg/Include/Library/TdxStartupLib.h
@@ -0,0 +1,40 @@
+#ifndef __TDX_STARTUP_LIB_H__
+#define __TDX_STARTUP_LIB_H__
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#pragma pack(1)
+
+typedef struct {
+ UINT32 count;
+ TPMI_ALG_HASH hashAlg;
+ BYTE sha384[SHA384_DIGEST_SIZE];
+} TDX_DIGEST_VALUE;
+
+#pragma pack()
+
+
+typedef
+VOID
+(EFIAPI * fProcessLibraryConstructorList)(
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ );
+
+
+VOID
+EFIAPI
+TdxStartup(
+ IN VOID * Context,
+ IN VOID * VmmHobList,
+ IN UINTN Info,
+ IN fProcessLibraryConstructorList Function
+);
+
+#endif
diff --git a/OvmfPkg/Include/TdxCommondefs.inc b/OvmfPkg/Include/TdxCommondefs.inc
new file mode 100644
index 000000000000..673e5c867b4d
--- /dev/null
+++ b/OvmfPkg/Include/TdxCommondefs.inc
@@ -0,0 +1,114 @@
+;------------------------------------------------------------------------------
+; @file
+; TDX Common defitions used by the APs in mailbox
+;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+CommandOffset equ 00h
+ApicidOffset equ 04h
+WakeupVectorOffset equ 08h
+OSArgsOffset equ 10h
+FirmwareArgsOffset equ 800h
+WakeupArgsRelocatedMailBox equ 800h
+AcceptPageArgsPhysicalStart equ 800h
+AcceptPageArgsPhysicalEnd equ 808h
+AcceptPageArgsAcceptSize equ 810h
+;AcceptPageArgsTallies equ 818h
+AcceptPageArgsPageSize equ 818h
+CpuArrivalOffset equ 900h
+CpusExitingOffset equ 0a00h
+TalliesOffset equ 0a08h
+
+SIZE_4KB equ 1000h
+SIZE_2MB equ 200000h
+SIZE_1GB equ 40000000h
+
+MpProtectedModeWakeupCommandNoop equ 0
+MpProtectedModeWakeupCommandWakeup equ 1
+MpProtectedModeWakeupCommandSleep equ 2
+MpProtectedModeWakeupCommandAcceptPages equ 3
+
+MailboxApicIdInvalid equ 0xffffffff
+MailboxApicidBroadcast equ 0xfffffffe
+
+%macro simple_spinlock 3
+ mov edx, %1
+ mov eax, 0
+ mov ebx, 1
+%%testlock:
+ lock cmpxchg [edx], ebx
+ jnz %3
+ mov eax, 0
+ mov ebx, 1
+ lock cmpxchg [edx+4], ebx
+ jnz %2
+%%firstone:
+ pause
+%endmacro
+
+%macro simple_releaselock 3
+%2:
+ mov eax, 1
+ mov edx, %1
+ jmp %%testlock
+%3:
+ pause
+ mov eax, 0
+%%testlock:
+ mov ebx, 0
+ lock cmpxchg [edx], ebx
+ jnz %3
+%endmacro
+
+%define EFI_HOB_TYPE_HANDOFF 0x0001
+%define EFI_HOB_TYPE_MEMORY_ALLOCATION 0x0002
+%define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 0x0003
+%define EFI_HOB_TYPE_GUID_EXTENSION 0x0004
+%define EFI_HOB_TYPE_FV 0x0005
+%define EFI_HOB_TYPE_CPU 0x0006
+%define EFI_HOB_TYPE_MEMORY_POOL 0x0007
+%define EFI_HOB_TYPE_FV2 0x0009
+%define EFI_HOB_TYPE_LOAD_PEIM_UNUSED 0x000A
+%define EFI_HOB_TYPE_UEFI_CAPSULE 0x000B
+%define EFI_HOB_TYPE_FV3 0x000C
+%define EFI_HOB_TYPE_UNUSED 0xFFFE
+%define EFI_HOB_TYPE_END_OF_HOB_LIST 0xFFFF
+
+%define EFI_RESOURCE_SYSTEM_MEMORY 0x00000000
+%define EFI_RESOURCE_MEMORY_MAPPED_IO 0x00000001
+%define EFI_RESOURCE_IO 0x00000002
+%define EFI_RESOURCE_FIRMWARE_DEVICE 0x00000003
+%define EFI_RESOURCE_MEMORY_MAPPED_IO_PORT 0x00000004
+%define EFI_RESOURCE_MEMORY_RESERVED 0x00000005
+%define EFI_RESOURCE_IO_RESERVED 0x00000006
+%define EFI_RESOURCE_MAX_MEMORY_TYPE 0x00000007
+
+%define EFI_RESOURCE_ATTRIBUTE_PRESENT 0x00000001
+%define EFI_RESOURCE_ATTRIBUTE_INITIALIZED 0x00000002
+%define EFI_RESOURCE_ATTRIBUTE_TESTED 0x00000004
+%define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED 0x00000080
+
+%define EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE 0x00000400
+%define EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE 0x00000800
+%define EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE 0x00001000
+%define EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE 0x00002000
+
+
+%define EFI_IO_ATTR (EFI_RESOURCE_ATTRIBUTE_PRESENT + \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED + \
+ EFI_RESOURCE_ATTRIBUTE_TESTED + \
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE)
+
+%define EFI_LOW_MEM_ATTR (EFI_RESOURCE_ATTRIBUTE_PRESENT + \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED + \
+ EFI_RESOURCE_ATTRIBUTE_TESTED + \
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE + \
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE + \
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + \
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE)
+
+%define TDCALL_TDINFO 0x1
+%define TDCALL_TDACCEPTPAGE 0x6
diff --git a/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c b/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c
index 53c768167de9..c0f1cddefe6f 100644
--- a/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c
+++ b/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c
@@ -19,6 +19,7 @@
#include
#include
+#include
//
// The Legacy BIOS protocol has been located.
@@ -45,9 +46,15 @@ typedef struct {
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR AddressSpaceDesc;
EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;
} MMIO64_PREFERENCE;
+
+typedef struct {
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR AddressSpaceDesc;
+ EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;
+} OPTION_ROM_PREFERENCE;
+
#pragma pack ()
-STATIC CONST MMIO64_PREFERENCE mConfiguration = {
+STATIC CONST MMIO64_PREFERENCE mMmio6Configuration = {
//
// AddressSpaceDesc
//
@@ -85,6 +92,44 @@ STATIC CONST MMIO64_PREFERENCE mConfiguration = {
}
};
+STATIC CONST OPTION_ROM_PREFERENCE mOptionRomConfiguration = {
+ //
+ // AddressSpaceDesc
+ //
+ {
+ ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc
+ (UINT16)( // Len
+ sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -
+ OFFSET_OF (
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,
+ ResType
+ )
+ ),
+ ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType
+ 0, // GenFlag
+ BIT0, // Disable option roms SpecificFlag
+ 64, // AddrSpaceGranularity:
+ // aperture selection hint
+ // for BAR allocation
+ MAX_UINT64, // AddrRangeMin
+ MAX_UINT64, // AddrRangeMax:
+ // no special alignment
+ // for affected BARs
+ MAX_UINT64, // AddrTranslationOffset:
+ // hint covers all
+ // eligible BARs
+ 0 // AddrLen:
+ // use probed BAR size
+ },
+ //
+ // EndDesc
+ //
+ {
+ ACPI_END_TAG_DESCRIPTOR, // Desc
+ 0 // Checksum: to be ignored
+ }
+};
+
//
// The CheckDevice() member function has been called.
//
@@ -201,7 +246,20 @@ CheckDevice (
OUT VOID **Configuration
)
{
+ CONST VOID *ConfigurationPtr;
+ UINTN ConfigurationSize;
+ BOOLEAN TdGuest;
+
mCheckDeviceCalled = TRUE;
+ TdGuest = ProbeTdGuest();
+ if(TdGuest) {
+ ConfigurationPtr = &mOptionRomConfiguration;
+ ConfigurationSize = sizeof(mOptionRomConfiguration);
+ goto AllocateConfiguration;
+ } else {
+ ConfigurationPtr = &mMmio6Configuration;
+ ConfigurationSize = sizeof(mMmio6Configuration);
+ }
//
// Unlike the general description of this protocol member suggests, there is
@@ -231,11 +289,19 @@ CheckDevice (
// the edk2 PCI Bus UEFI_DRIVER actually handles error codes; see the
// UpdatePciInfo() function.
//
- *Configuration = AllocateCopyPool (sizeof mConfiguration, &mConfiguration);
+AllocateConfiguration:
+ *Configuration = AllocateCopyPool (ConfigurationSize, ConfigurationPtr);
if (*Configuration == NULL) {
+ if(TdGuest) {
DEBUG ((DEBUG_WARN,
- "%a: 64-bit MMIO BARs may be degraded for PCI 0x%04x:0x%04x (rev %d)\n",
- __FUNCTION__, (UINT32)VendorId, (UINT32)DeviceId, (UINT8)RevisionId));
+ "%a: Check device for Option ROM of PCI 0x%04x:0x%04x (rev %d) failed.\n\n",
+ __FUNCTION__, (UINT32)VendorId, (UINT32)DeviceId, (UINT8)RevisionId));
+ } else {
+ DEBUG ((DEBUG_WARN,
+ "%a: 64-bit MMIO BARs may be degraded for PCI 0x%04x:0x%04x (rev %d)\n",
+ __FUNCTION__, (UINT32)VendorId, (UINT32)DeviceId, (UINT8)RevisionId));
+ }
+
return EFI_OUT_OF_RESOURCES;
}
return EFI_SUCCESS;
@@ -265,6 +331,10 @@ DriverInitialize (
EFI_EVENT Event;
VOID *Registration;
+ if(ProbeTdGuest()) {
+ goto InstallProtocol;
+ }
+
//
// If the PCI Bus driver is not supposed to allocate resources, then it makes
// no sense to install a protocol that influences the resource allocation.
@@ -326,6 +396,7 @@ DriverInitialize (
Status = gBS->SignalEvent (Event);
ASSERT_EFI_ERROR (Status);
+InstallProtocol:
mIncompatiblePciDeviceSupport.CheckDevice = CheckDevice;
Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
&gEfiIncompatiblePciDeviceSupportProtocolGuid,
diff --git a/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf b/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
index f08b6f4bd4b4..971178804704 100644
--- a/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
+++ b/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
@@ -30,6 +30,7 @@
PcdLib
UefiBootServicesTableLib
UefiDriverEntryPoint
+ TdxProbeLib
[Protocols]
gEfiIncompatiblePciDeviceSupportProtocolGuid ## SOMETIMES_PRODUCES
diff --git a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c b/OvmfPkg/IoMmuDxe/IoMmu.c
similarity index 92%
rename from OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
rename to OvmfPkg/IoMmuDxe/IoMmu.c
index 49ffa2448811..cb6eb0855b8b 100644
--- a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
+++ b/OvmfPkg/IoMmuDxe/IoMmu.c
@@ -1,910 +1,930 @@
-/** @file
-
- The protocol provides support to allocate, free, map and umap a DMA buffer
- for bus master (e.g PciHostBridge). When SEV is enabled, the DMA operations
- must be performed on unencrypted buffer hence we use a bounce buffer to map
- the guest buffer into an unencrypted DMA buffer.
-
- Copyright (c) 2017, AMD Inc. All rights reserved.
- Copyright (c) 2017, Intel Corporation. All rights reserved.
-
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "AmdSevIoMmu.h"
-
-#define MAP_INFO_SIG SIGNATURE_64 ('M', 'A', 'P', '_', 'I', 'N', 'F', 'O')
-
-typedef struct {
- UINT64 Signature;
- LIST_ENTRY Link;
- EDKII_IOMMU_OPERATION Operation;
- UINTN NumberOfBytes;
- UINTN NumberOfPages;
- EFI_PHYSICAL_ADDRESS CryptedAddress;
- EFI_PHYSICAL_ADDRESS PlainTextAddress;
-} MAP_INFO;
-
-//
-// List of the MAP_INFO structures that have been set up by IoMmuMap() and not
-// yet torn down by IoMmuUnmap(). The list represents the full set of mappings
-// currently in effect.
-//
-STATIC LIST_ENTRY mMapInfos = INITIALIZE_LIST_HEAD_VARIABLE (mMapInfos);
-
-#define COMMON_BUFFER_SIG SIGNATURE_64 ('C', 'M', 'N', 'B', 'U', 'F', 'F', 'R')
-
-//
-// ASCII names for EDKII_IOMMU_OPERATION constants, for debug logging.
-//
-STATIC CONST CHAR8 * CONST
-mBusMasterOperationName[EdkiiIoMmuOperationMaximum] = {
- "Read",
- "Write",
- "CommonBuffer",
- "Read64",
- "Write64",
- "CommonBuffer64"
-};
-
-//
-// The following structure enables Map() and Unmap() to perform in-place
-// decryption and encryption, respectively, for BusMasterCommonBuffer[64]
-// operations, without dynamic memory allocation or release.
-//
-// Both COMMON_BUFFER_HEADER and COMMON_BUFFER_HEADER.StashBuffer are allocated
-// by AllocateBuffer() and released by FreeBuffer().
-//
-#pragma pack (1)
-typedef struct {
- UINT64 Signature;
-
- //
- // Always allocated from EfiBootServicesData type memory, and always
- // encrypted.
- //
- VOID *StashBuffer;
-
- //
- // Followed by the actual common buffer, starting at the next page.
- //
-} COMMON_BUFFER_HEADER;
-#pragma pack ()
-
-/**
- Provides the controller-specific addresses required to access system memory
- from a DMA bus master. On SEV guest, the DMA operations must be performed on
- shared buffer hence we allocate a bounce buffer to map the HostAddress to a
- DeviceAddress. The Encryption attribute is removed from the DeviceAddress
- buffer.
-
- @param This The protocol instance pointer.
- @param Operation Indicates if the bus master is going to read or
- write to system memory.
- @param HostAddress The system memory address to map to the PCI
- controller.
- @param NumberOfBytes On input the number of bytes to map. On output
- the number of bytes that were mapped.
- @param DeviceAddress The resulting map address for the bus master
- PCI controller to use to access the hosts
- HostAddress.
- @param Mapping A resulting value to pass to Unmap().
-
- @retval EFI_SUCCESS The range was mapped for the returned
- NumberOfBytes.
- @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common
- buffer.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
- lack of resources.
- @retval EFI_DEVICE_ERROR The system hardware could not map the requested
- address.
-
-**/
-EFI_STATUS
-EFIAPI
-IoMmuMap (
- IN EDKII_IOMMU_PROTOCOL *This,
- IN EDKII_IOMMU_OPERATION Operation,
- IN VOID *HostAddress,
- IN OUT UINTN *NumberOfBytes,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- )
-{
- EFI_STATUS Status;
- MAP_INFO *MapInfo;
- EFI_ALLOCATE_TYPE AllocateType;
- COMMON_BUFFER_HEADER *CommonBufferHeader;
- VOID *DecryptionSource;
-
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: Operation=%a Host=0x%p Bytes=0x%Lx\n",
- __FUNCTION__,
- ((Operation >= 0 &&
- Operation < ARRAY_SIZE (mBusMasterOperationName)) ?
- mBusMasterOperationName[Operation] :
- "Invalid"),
- HostAddress,
- (UINT64)((NumberOfBytes == NULL) ? 0 : *NumberOfBytes)
- ));
-
- if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL ||
- Mapping == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
- // called later.
- //
- MapInfo = AllocatePool (sizeof (MAP_INFO));
- if (MapInfo == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Failed;
- }
-
- //
- // Initialize the MAP_INFO structure, except the PlainTextAddress field
- //
- ZeroMem (&MapInfo->Link, sizeof MapInfo->Link);
- MapInfo->Signature = MAP_INFO_SIG;
- MapInfo->Operation = Operation;
- MapInfo->NumberOfBytes = *NumberOfBytes;
- MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);
- MapInfo->CryptedAddress = (UINTN)HostAddress;
-
- //
- // In the switch statement below, we point "MapInfo->PlainTextAddress" to the
- // plaintext buffer, according to Operation. We also set "DecryptionSource".
- //
- MapInfo->PlainTextAddress = MAX_ADDRESS;
- AllocateType = AllocateAnyPages;
- DecryptionSource = (VOID *)(UINTN)MapInfo->CryptedAddress;
- switch (Operation) {
- //
- // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer
- // is necessary regardless of whether the original (crypted) buffer crosses
- // the 4GB limit or not -- we have to allocate a separate plaintext buffer.
- // The only variable is whether the plaintext buffer should be under 4GB.
- //
- case EdkiiIoMmuOperationBusMasterRead:
- case EdkiiIoMmuOperationBusMasterWrite:
- MapInfo->PlainTextAddress = BASE_4GB - 1;
- AllocateType = AllocateMaxAddress;
- //
- // fall through
- //
- case EdkiiIoMmuOperationBusMasterRead64:
- case EdkiiIoMmuOperationBusMasterWrite64:
- //
- // Allocate the implicit plaintext bounce buffer.
- //
- Status = gBS->AllocatePages (
- AllocateType,
- EfiBootServicesData,
- MapInfo->NumberOfPages,
- &MapInfo->PlainTextAddress
- );
- if (EFI_ERROR (Status)) {
- goto FreeMapInfo;
- }
- break;
-
- //
- // For BusMasterCommonBuffer[64] operations, a to-be-plaintext buffer and a
- // stash buffer (for in-place decryption) have been allocated already, with
- // AllocateBuffer(). We only check whether the address of the to-be-plaintext
- // buffer is low enough for the requested operation.
- //
- case EdkiiIoMmuOperationBusMasterCommonBuffer:
- if ((MapInfo->CryptedAddress > BASE_4GB) ||
- (EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages) >
- BASE_4GB - MapInfo->CryptedAddress)) {
- //
- // CommonBuffer operations cannot be remapped. If the common buffer is
- // above 4GB, then it is not possible to generate a mapping, so return an
- // error.
- //
- Status = EFI_UNSUPPORTED;
- goto FreeMapInfo;
- }
- //
- // fall through
- //
- case EdkiiIoMmuOperationBusMasterCommonBuffer64:
- //
- // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer().
- //
- MapInfo->PlainTextAddress = MapInfo->CryptedAddress;
- //
- // Stash the crypted data.
- //
- CommonBufferHeader = (COMMON_BUFFER_HEADER *)(
- (UINTN)MapInfo->CryptedAddress - EFI_PAGE_SIZE
- );
- ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);
- CopyMem (
- CommonBufferHeader->StashBuffer,
- (VOID *)(UINTN)MapInfo->CryptedAddress,
- MapInfo->NumberOfBytes
- );
- //
- // Point "DecryptionSource" to the stash buffer so that we decrypt
- // it to the original location, after the switch statement.
- //
- DecryptionSource = CommonBufferHeader->StashBuffer;
- break;
-
- default:
- //
- // Operation is invalid
- //
- Status = EFI_INVALID_PARAMETER;
- goto FreeMapInfo;
- }
-
- //
- // Clear the memory encryption mask on the plaintext buffer.
- //
- Status = MemEncryptSevClearPageEncMask (
- 0,
- MapInfo->PlainTextAddress,
- MapInfo->NumberOfPages,
- TRUE
- );
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status)) {
- CpuDeadLoop ();
- }
-
- //
- // If this is a read operation from the Bus Master's point of view,
- // then copy the contents of the real buffer into the mapped buffer
- // so the Bus Master can read the contents of the real buffer.
- //
- // For BusMasterCommonBuffer[64] operations, the CopyMem() below will decrypt
- // the original data (from the stash buffer) back to the original location.
- //
- if (Operation == EdkiiIoMmuOperationBusMasterRead ||
- Operation == EdkiiIoMmuOperationBusMasterRead64 ||
- Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
- Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
- CopyMem (
- (VOID *) (UINTN) MapInfo->PlainTextAddress,
- DecryptionSource,
- MapInfo->NumberOfBytes
- );
- }
-
- //
- // Track all MAP_INFO structures.
- //
- InsertHeadList (&mMapInfos, &MapInfo->Link);
- //
- // Populate output parameters.
- //
- *DeviceAddress = MapInfo->PlainTextAddress;
- *Mapping = MapInfo;
-
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: Mapping=0x%p Device(PlainText)=0x%Lx Crypted=0x%Lx Pages=0x%Lx\n",
- __FUNCTION__,
- MapInfo,
- MapInfo->PlainTextAddress,
- MapInfo->CryptedAddress,
- (UINT64)MapInfo->NumberOfPages
- ));
-
- return EFI_SUCCESS;
-
-FreeMapInfo:
- FreePool (MapInfo);
-
-Failed:
- *NumberOfBytes = 0;
- return Status;
-}
-
-/**
- Completes the Map() operation and releases any corresponding resources.
-
- This is an internal worker function that only extends the Map() API with
- the MemoryMapLocked parameter.
-
- @param This The protocol instance pointer.
- @param Mapping The mapping value returned from Map().
- @param MemoryMapLocked The function is executing on the stack of
- gBS->ExitBootServices(); changes to the UEFI
- memory map are forbidden.
-
- @retval EFI_SUCCESS The range was unmapped.
- @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
- Map().
- @retval EFI_DEVICE_ERROR The data was not committed to the target system
- memory.
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-IoMmuUnmapWorker (
- IN EDKII_IOMMU_PROTOCOL *This,
- IN VOID *Mapping,
- IN BOOLEAN MemoryMapLocked
- )
-{
- MAP_INFO *MapInfo;
- EFI_STATUS Status;
- COMMON_BUFFER_HEADER *CommonBufferHeader;
- VOID *EncryptionTarget;
-
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: Mapping=0x%p MemoryMapLocked=%d\n",
- __FUNCTION__,
- Mapping,
- MemoryMapLocked
- ));
-
- if (Mapping == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- MapInfo = (MAP_INFO *)Mapping;
-
- //
- // set CommonBufferHeader to suppress incorrect compiler/analyzer warnings
- //
- CommonBufferHeader = NULL;
-
- //
- // For BusMasterWrite[64] operations and BusMasterCommonBuffer[64] operations
- // we have to encrypt the results, ultimately to the original place (i.e.,
- // "MapInfo->CryptedAddress").
- //
- // For BusMasterCommonBuffer[64] operations however, this encryption has to
- // land in-place, so divert the encryption to the stash buffer first.
- //
- EncryptionTarget = (VOID *)(UINTN)MapInfo->CryptedAddress;
-
- switch (MapInfo->Operation) {
- case EdkiiIoMmuOperationBusMasterCommonBuffer:
- case EdkiiIoMmuOperationBusMasterCommonBuffer64:
- ASSERT (MapInfo->PlainTextAddress == MapInfo->CryptedAddress);
-
- CommonBufferHeader = (COMMON_BUFFER_HEADER *)(
- (UINTN)MapInfo->PlainTextAddress - EFI_PAGE_SIZE
- );
- ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);
- EncryptionTarget = CommonBufferHeader->StashBuffer;
- //
- // fall through
- //
-
- case EdkiiIoMmuOperationBusMasterWrite:
- case EdkiiIoMmuOperationBusMasterWrite64:
- CopyMem (
- EncryptionTarget,
- (VOID *) (UINTN) MapInfo->PlainTextAddress,
- MapInfo->NumberOfBytes
- );
- break;
-
- default:
- //
- // nothing to encrypt after BusMasterRead[64] operations
- //
- break;
- }
-
- //
- // Restore the memory encryption mask on the area we used to hold the
- // plaintext.
- //
- Status = MemEncryptSevSetPageEncMask (
- 0,
- MapInfo->PlainTextAddress,
- MapInfo->NumberOfPages,
- TRUE
- );
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status)) {
- CpuDeadLoop ();
- }
-
- //
- // For BusMasterCommonBuffer[64] operations, copy the stashed data to the
- // original (now encrypted) location.
- //
- // For all other operations, fill the late bounce buffer (which existed as
- // plaintext at some point) with zeros, and then release it (unless the UEFI
- // memory map is locked).
- //
- if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
- MapInfo->Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
- CopyMem (
- (VOID *)(UINTN)MapInfo->CryptedAddress,
- CommonBufferHeader->StashBuffer,
- MapInfo->NumberOfBytes
- );
- } else {
- ZeroMem (
- (VOID *)(UINTN)MapInfo->PlainTextAddress,
- EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages)
- );
- if (!MemoryMapLocked) {
- gBS->FreePages (MapInfo->PlainTextAddress, MapInfo->NumberOfPages);
- }
- }
-
- //
- // Forget the MAP_INFO structure, then free it (unless the UEFI memory map is
- // locked).
- //
- RemoveEntryList (&MapInfo->Link);
- if (!MemoryMapLocked) {
- FreePool (MapInfo);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Completes the Map() operation and releases any corresponding resources.
-
- @param This The protocol instance pointer.
- @param Mapping The mapping value returned from Map().
-
- @retval EFI_SUCCESS The range was unmapped.
- @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
- Map().
- @retval EFI_DEVICE_ERROR The data was not committed to the target system
- memory.
-**/
-EFI_STATUS
-EFIAPI
-IoMmuUnmap (
- IN EDKII_IOMMU_PROTOCOL *This,
- IN VOID *Mapping
- )
-{
- return IoMmuUnmapWorker (
- This,
- Mapping,
- FALSE // MemoryMapLocked
- );
-}
-
-/**
- Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
- OperationBusMasterCommonBuffer64 mapping.
-
- @param This The protocol instance pointer.
- @param Type This parameter is not used and must be ignored.
- @param MemoryType The type of memory to allocate,
- EfiBootServicesData or EfiRuntimeServicesData.
- @param Pages The number of pages to allocate.
- @param HostAddress A pointer to store the base system memory
- address of the allocated range.
- @param Attributes The requested bit mask of attributes for the
- allocated range.
-
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal
- attribute bits are MEMORY_WRITE_COMBINE and
- MEMORY_CACHED.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-IoMmuAllocateBuffer (
- IN EDKII_IOMMU_PROTOCOL *This,
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN Pages,
- IN OUT VOID **HostAddress,
- IN UINT64 Attributes
- )
-{
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS PhysicalAddress;
- VOID *StashBuffer;
- UINTN CommonBufferPages;
- COMMON_BUFFER_HEADER *CommonBufferHeader;
-
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: MemoryType=%u Pages=0x%Lx Attributes=0x%Lx\n",
- __FUNCTION__,
- (UINT32)MemoryType,
- (UINT64)Pages,
- Attributes
- ));
-
- //
- // Validate Attributes
- //
- if ((Attributes & EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {
- return EFI_UNSUPPORTED;
- }
-
- //
- // Check for invalid inputs
- //
- if (HostAddress == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // The only valid memory types are EfiBootServicesData and
- // EfiRuntimeServicesData
- //
- if (MemoryType != EfiBootServicesData &&
- MemoryType != EfiRuntimeServicesData) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // We'll need a header page for the COMMON_BUFFER_HEADER structure.
- //
- if (Pages > MAX_UINTN - 1) {
- return EFI_OUT_OF_RESOURCES;
- }
- CommonBufferPages = Pages + 1;
-
- //
- // Allocate the stash in EfiBootServicesData type memory.
- //
- // Map() will temporarily save encrypted data in the stash for
- // BusMasterCommonBuffer[64] operations, so the data can be decrypted to the
- // original location.
- //
- // Unmap() will temporarily save plaintext data in the stash for
- // BusMasterCommonBuffer[64] operations, so the data can be encrypted to the
- // original location.
- //
- // StashBuffer always resides in encrypted memory.
- //
- StashBuffer = AllocatePages (Pages);
- if (StashBuffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- PhysicalAddress = (UINTN)-1;
- if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {
- //
- // Limit allocations to memory below 4GB
- //
- PhysicalAddress = SIZE_4GB - 1;
- }
- Status = gBS->AllocatePages (
- AllocateMaxAddress,
- MemoryType,
- CommonBufferPages,
- &PhysicalAddress
- );
- if (EFI_ERROR (Status)) {
- goto FreeStashBuffer;
- }
-
- CommonBufferHeader = (VOID *)(UINTN)PhysicalAddress;
- PhysicalAddress += EFI_PAGE_SIZE;
-
- CommonBufferHeader->Signature = COMMON_BUFFER_SIG;
- CommonBufferHeader->StashBuffer = StashBuffer;
-
- *HostAddress = (VOID *)(UINTN)PhysicalAddress;
-
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: Host=0x%Lx Stash=0x%p\n",
- __FUNCTION__,
- PhysicalAddress,
- StashBuffer
- ));
- return EFI_SUCCESS;
-
-FreeStashBuffer:
- FreePages (StashBuffer, Pages);
- return Status;
-}
-
-/**
- Frees memory that was allocated with AllocateBuffer().
-
- @param This The protocol instance pointer.
- @param Pages The number of pages to free.
- @param HostAddress The base system memory address of the allocated
- range.
-
- @retval EFI_SUCCESS The requested memory pages were freed.
- @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and
- Pages was not allocated with AllocateBuffer().
-
-**/
-EFI_STATUS
-EFIAPI
-IoMmuFreeBuffer (
- IN EDKII_IOMMU_PROTOCOL *This,
- IN UINTN Pages,
- IN VOID *HostAddress
- )
-{
- UINTN CommonBufferPages;
- COMMON_BUFFER_HEADER *CommonBufferHeader;
-
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: Host=0x%p Pages=0x%Lx\n",
- __FUNCTION__,
- HostAddress,
- (UINT64)Pages
- ));
-
- CommonBufferPages = Pages + 1;
- CommonBufferHeader = (COMMON_BUFFER_HEADER *)(
- (UINTN)HostAddress - EFI_PAGE_SIZE
- );
-
- //
- // Check the signature.
- //
- ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);
- if (CommonBufferHeader->Signature != COMMON_BUFFER_SIG) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Free the stash buffer. This buffer was always encrypted, so no need to
- // zero it.
- //
- FreePages (CommonBufferHeader->StashBuffer, Pages);
-
- //
- // Release the common buffer itself. Unmap() has re-encrypted it in-place, so
- // no need to zero it.
- //
- return gBS->FreePages ((UINTN)CommonBufferHeader, CommonBufferPages);
-}
-
-
-/**
- Set IOMMU attribute for a system memory.
-
- If the IOMMU protocol exists, the system memory cannot be used
- for DMA by default.
-
- When a device requests a DMA access for a system memory,
- the device driver need use SetAttribute() to update the IOMMU
- attribute to request DMA access (read and/or write).
-
- The DeviceHandle is used to identify which device submits the request.
- The IOMMU implementation need translate the device path to an IOMMU device
- ID, and set IOMMU hardware register accordingly.
- 1) DeviceHandle can be a standard PCI device.
- The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.
- The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.
- The memory for BusMasterCommonBuffer need set
- EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.
- After the memory is used, the memory need set 0 to keep it being
- protected.
- 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).
- The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or
- EDKII_IOMMU_ACCESS_WRITE.
-
- @param[in] This The protocol instance pointer.
- @param[in] DeviceHandle The device who initiates the DMA access
- request.
- @param[in] Mapping The mapping value returned from Map().
- @param[in] IoMmuAccess The IOMMU access.
-
- @retval EFI_SUCCESS The IoMmuAccess is set for the memory range
- specified by DeviceAddress and Length.
- @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.
- @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
- Map().
- @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination
- of access.
- @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.
- @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported
- by the IOMMU.
- @retval EFI_UNSUPPORTED The IOMMU does not support the memory range
- specified by Mapping.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
- modify the IOMMU access.
- @retval EFI_DEVICE_ERROR The IOMMU device reported an error while
- attempting the operation.
-
-**/
-EFI_STATUS
-EFIAPI
-IoMmuSetAttribute (
- IN EDKII_IOMMU_PROTOCOL *This,
- IN EFI_HANDLE DeviceHandle,
- IN VOID *Mapping,
- IN UINT64 IoMmuAccess
- )
-{
- return EFI_UNSUPPORTED;
-}
-
-EDKII_IOMMU_PROTOCOL mAmdSev = {
- EDKII_IOMMU_PROTOCOL_REVISION,
- IoMmuSetAttribute,
- IoMmuMap,
- IoMmuUnmap,
- IoMmuAllocateBuffer,
- IoMmuFreeBuffer,
-};
-
-/**
- Notification function that is queued when gBS->ExitBootServices() signals the
- EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals another
- event, received as Context, and returns.
-
- Signaling an event in this context is safe. The UEFI spec allows
- gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is not
- listed, hence memory is not allocated. The edk2 implementation also does not
- release memory (and we only have to care about the edk2 implementation
- because EDKII_IOMMU_PROTOCOL is edk2-specific anyway).
-
- @param[in] Event Event whose notification function is being invoked.
- Event is permitted to request the queueing of this
- function at TPL_CALLBACK or TPL_NOTIFY task
- priority level.
-
- @param[in] EventToSignal Identifies the EFI_EVENT to signal. EventToSignal
- is permitted to request the queueing of its
- notification function only at TPL_CALLBACK level.
-**/
-STATIC
-VOID
-EFIAPI
-AmdSevExitBoot (
- IN EFI_EVENT Event,
- IN VOID *EventToSignal
- )
-{
- //
- // (1) The NotifyFunctions of all the events in
- // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before
- // AmdSevExitBoot() is entered.
- //
- // (2) AmdSevExitBoot() is executing minimally at TPL_CALLBACK.
- //
- // (3) AmdSevExitBoot() has been queued in unspecified order relative to the
- // NotifyFunctions of all the other events in
- // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as
- // Event's.
- //
- // Consequences:
- //
- // - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions
- // queued at TPL_CALLBACK may be invoked after AmdSevExitBoot() returns.
- //
- // - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions
- // queued at TPL_NOTIFY may be invoked after AmdSevExitBoot() returns; plus
- // *all* NotifyFunctions queued at TPL_CALLBACK will be invoked strictly
- // after all NotifyFunctions queued at TPL_NOTIFY, including
- // AmdSevExitBoot(), have been invoked.
- //
- // - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we
- // queue EventToSignal's NotifyFunction after the NotifyFunctions of *all*
- // events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES.
- //
- DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__));
- gBS->SignalEvent (EventToSignal);
-}
-
-/**
- Notification function that is queued after the notification functions of all
- events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. The same memory
- map restrictions apply.
-
- This function unmaps all currently existing IOMMU mappings.
-
- @param[in] Event Event whose notification function is being invoked. Event
- is permitted to request the queueing of this function
- only at TPL_CALLBACK task priority level.
-
- @param[in] Context Ignored.
-**/
-STATIC
-VOID
-EFIAPI
-AmdSevUnmapAllMappings (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- LIST_ENTRY *Node;
- LIST_ENTRY *NextNode;
- MAP_INFO *MapInfo;
-
- DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__));
-
- //
- // All drivers that had set up IOMMU mappings have halted their respective
- // controllers by now; tear down the mappings.
- //
- for (Node = GetFirstNode (&mMapInfos); Node != &mMapInfos; Node = NextNode) {
- NextNode = GetNextNode (&mMapInfos, Node);
- MapInfo = CR (Node, MAP_INFO, Link, MAP_INFO_SIG);
- IoMmuUnmapWorker (
- &mAmdSev, // This
- MapInfo, // Mapping
- TRUE // MemoryMapLocked
- );
- }
-}
-
-/**
- Initialize Iommu Protocol.
-
-**/
-EFI_STATUS
-EFIAPI
-AmdSevInstallIoMmuProtocol (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_EVENT UnmapAllMappingsEvent;
- EFI_EVENT ExitBootEvent;
- EFI_HANDLE Handle;
-
- //
- // Create the "late" event whose notification function will tear down all
- // left-over IOMMU mappings.
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL, // Type
- TPL_CALLBACK, // NotifyTpl
- AmdSevUnmapAllMappings, // NotifyFunction
- NULL, // NotifyContext
- &UnmapAllMappingsEvent // Event
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Create the event whose notification function will be queued by
- // gBS->ExitBootServices() and will signal the event created above.
- //
- Status = gBS->CreateEvent (
- EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type
- TPL_CALLBACK, // NotifyTpl
- AmdSevExitBoot, // NotifyFunction
- UnmapAllMappingsEvent, // NotifyContext
- &ExitBootEvent // Event
- );
- if (EFI_ERROR (Status)) {
- goto CloseUnmapAllMappingsEvent;
- }
-
- Handle = NULL;
- Status = gBS->InstallMultipleProtocolInterfaces (
- &Handle,
- &gEdkiiIoMmuProtocolGuid, &mAmdSev,
- NULL
- );
- if (EFI_ERROR (Status)) {
- goto CloseExitBootEvent;
- }
-
- return EFI_SUCCESS;
-
-CloseExitBootEvent:
- gBS->CloseEvent (ExitBootEvent);
-
-CloseUnmapAllMappingsEvent:
- gBS->CloseEvent (UnmapAllMappingsEvent);
-
- return Status;
-}
+/** @file
+
+ The protocol provides support to allocate, free, map and umap a DMA buffer
+ for bus master (e.g PciHostBridge). When Memory Encryption is enabled, the DMA operations
+ must be performed on unencrypted buffer hence we use a bounce buffer to map
+ the guest buffer into an unencrypted DMA buffer.
+
+ Copyright (c) 2017, AMD Inc. All rights reserved.
+ Copyright (c) 2017, Intel Corporation. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "IoMmu.h"
+
+#define MAP_INFO_SIG SIGNATURE_64 ('M', 'A', 'P', '_', 'I', 'N', 'F', 'O')
+
+typedef struct {
+ UINT64 Signature;
+ LIST_ENTRY Link;
+ EDKII_IOMMU_OPERATION Operation;
+ UINTN NumberOfBytes;
+ UINTN NumberOfPages;
+ EFI_PHYSICAL_ADDRESS CryptedAddress;
+ EFI_PHYSICAL_ADDRESS PlainTextAddress;
+} MAP_INFO;
+
+UINTN mMemEncryptType;
+//
+// List of the MAP_INFO structures that have been set up by IoMmuMap() and not
+// yet torn down by IoMmuUnmap(). The list represents the full set of mappings
+// currently in effect.
+//
+STATIC LIST_ENTRY mMapInfos = INITIALIZE_LIST_HEAD_VARIABLE (mMapInfos);
+
+#define COMMON_BUFFER_SIG SIGNATURE_64 ('C', 'M', 'N', 'B', 'U', 'F', 'F', 'R')
+
+//
+// ASCII names for EDKII_IOMMU_OPERATION constants, for debug logging.
+//
+STATIC CONST CHAR8 * CONST
+mBusMasterOperationName[EdkiiIoMmuOperationMaximum] = {
+ "Read",
+ "Write",
+ "CommonBuffer",
+ "Read64",
+ "Write64",
+ "CommonBuffer64"
+};
+
+//
+// The following structure enables Map() and Unmap() to perform in-place
+// decryption and encryption, respectively, for BusMasterCommonBuffer[64]
+// operations, without dynamic memory allocation or release.
+//
+// Both COMMON_BUFFER_HEADER and COMMON_BUFFER_HEADER.StashBuffer are allocated
+// by AllocateBuffer() and released by FreeBuffer().
+//
+#pragma pack (1)
+typedef struct {
+ UINT64 Signature;
+
+ //
+ // Always allocated from EfiBootServicesData type memory, and always
+ // encrypted.
+ //
+ VOID *StashBuffer;
+
+ //
+ // Followed by the actual common buffer, starting at the next page.
+ //
+} COMMON_BUFFER_HEADER;
+#pragma pack ()
+
+/**
+ Provides the controller-specific addresses required to access system memory
+ from a DMA bus master. On an encrypted guest, the DMA operations must be performed on
+ shared buffer hence we allocate a bounce buffer to map the HostAddress to a
+ DeviceAddress. The Encryption attribute is removed from the DeviceAddress
+ buffer.
+
+ @param This The protocol instance pointer.
+ @param Operation Indicates if the bus master is going to read or
+ write to system memory.
+ @param HostAddress The system memory address to map to the PCI
+ controller.
+ @param NumberOfBytes On input the number of bytes to map. On output
+ the number of bytes that were mapped.
+ @param DeviceAddress The resulting map address for the bus master
+ PCI controller to use to access the hosts
+ HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned
+ NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common
+ buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested
+ address.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuMap (
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ MAP_INFO *MapInfo;
+ EFI_ALLOCATE_TYPE AllocateType;
+ COMMON_BUFFER_HEADER *CommonBufferHeader;
+ VOID *DecryptionSource;
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: Operation=%a Host=0x%p Bytes=0x%Lx\n",
+ __FUNCTION__,
+ ((Operation >= 0 &&
+ Operation < ARRAY_SIZE (mBusMasterOperationName)) ?
+ mBusMasterOperationName[Operation] :
+ "Invalid"),
+ HostAddress,
+ (UINT64)((NumberOfBytes == NULL) ? 0 : *NumberOfBytes)
+ ));
+
+ if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL ||
+ Mapping == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
+ // called later.
+ //
+ MapInfo = AllocatePool (sizeof (MAP_INFO));
+ if (MapInfo == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Failed;
+ }
+
+ //
+ // Initialize the MAP_INFO structure, except the PlainTextAddress field
+ //
+ ZeroMem (&MapInfo->Link, sizeof MapInfo->Link);
+ MapInfo->Signature = MAP_INFO_SIG;
+ MapInfo->Operation = Operation;
+ MapInfo->NumberOfBytes = *NumberOfBytes;
+ MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);
+ MapInfo->CryptedAddress = (UINTN)HostAddress;
+
+ //
+ // In the switch statement below, we point "MapInfo->PlainTextAddress" to the
+ // plaintext buffer, according to Operation. We also set "DecryptionSource".
+ //
+ MapInfo->PlainTextAddress = MAX_ADDRESS;
+ AllocateType = AllocateAnyPages;
+ DecryptionSource = (VOID *)(UINTN)MapInfo->CryptedAddress;
+ switch (Operation) {
+ //
+ // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer
+ // is necessary regardless of whether the original (crypted) buffer crosses
+ // the 4GB limit or not -- we have to allocate a separate plaintext buffer.
+ // The only variable is whether the plaintext buffer should be under 4GB.
+ //
+ case EdkiiIoMmuOperationBusMasterRead:
+ case EdkiiIoMmuOperationBusMasterWrite:
+ MapInfo->PlainTextAddress = BASE_4GB - 1;
+ AllocateType = AllocateMaxAddress;
+ //
+ // fall through
+ //
+ case EdkiiIoMmuOperationBusMasterRead64:
+ case EdkiiIoMmuOperationBusMasterWrite64:
+ //
+ // Allocate the implicit plaintext bounce buffer.
+ //
+ Status = gBS->AllocatePages (
+ AllocateType,
+ EfiBootServicesData,
+ MapInfo->NumberOfPages,
+ &MapInfo->PlainTextAddress
+ );
+ if (EFI_ERROR (Status)) {
+ goto FreeMapInfo;
+ }
+ break;
+
+ //
+ // For BusMasterCommonBuffer[64] operations, a to-be-plaintext buffer and a
+ // stash buffer (for in-place decryption) have been allocated already, with
+ // AllocateBuffer(). We only check whether the address of the to-be-plaintext
+ // buffer is low enough for the requested operation.
+ //
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:
+ if ((MapInfo->CryptedAddress > BASE_4GB) ||
+ (EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages) >
+ BASE_4GB - MapInfo->CryptedAddress)) {
+ //
+ // CommonBuffer operations cannot be remapped. If the common buffer is
+ // above 4GB, then it is not possible to generate a mapping, so return an
+ // error.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto FreeMapInfo;
+ }
+ //
+ // fall through
+ //
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+ //
+ // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer().
+ //
+ MapInfo->PlainTextAddress = MapInfo->CryptedAddress;
+ //
+ // Stash the crypted data.
+ //
+ CommonBufferHeader = (COMMON_BUFFER_HEADER *)(
+ (UINTN)MapInfo->CryptedAddress - EFI_PAGE_SIZE
+ );
+ ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);
+ CopyMem (
+ CommonBufferHeader->StashBuffer,
+ (VOID *)(UINTN)MapInfo->CryptedAddress,
+ MapInfo->NumberOfBytes
+ );
+ //
+ // Point "DecryptionSource" to the stash buffer so that we decrypt
+ // it to the original location, after the switch statement.
+ //
+ DecryptionSource = CommonBufferHeader->StashBuffer;
+ break;
+
+ default:
+ //
+ // Operation is invalid
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto FreeMapInfo;
+ }
+
+ //
+ // Clear the memory encryption mask on the plaintext buffer.
+ //
+ if (mMemEncryptType == MEM_ENCRYPT_SEV_ENABLED) {
+ Status = MemEncryptSevClearPageEncMask (
+ 0,
+ MapInfo->PlainTextAddress,
+ MapInfo->NumberOfPages,
+ TRUE
+ );
+ } else if (mMemEncryptType == MEM_ENCRYPT_TDX_ENABLED) {
+ Status = MemEncryptTdxClearPageEncMask (
+ 0,
+ MapInfo->PlainTextAddress,
+ MapInfo->NumberOfPages,
+ TRUE
+ );
+ }
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ CpuDeadLoop ();
+ }
+
+ //
+ // If this is a read operation from the Bus Master's point of view,
+ // then copy the contents of the real buffer into the mapped buffer
+ // so the Bus Master can read the contents of the real buffer.
+ //
+ // For BusMasterCommonBuffer[64] operations, the CopyMem() below will decrypt
+ // the original data (from the stash buffer) back to the original location.
+ //
+ if (Operation == EdkiiIoMmuOperationBusMasterRead ||
+ Operation == EdkiiIoMmuOperationBusMasterRead64 ||
+ Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
+ Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
+ CopyMem (
+ (VOID *) (UINTN) MapInfo->PlainTextAddress,
+ DecryptionSource,
+ MapInfo->NumberOfBytes
+ );
+ }
+
+ //
+ // Track all MAP_INFO structures.
+ //
+ InsertHeadList (&mMapInfos, &MapInfo->Link);
+ //
+ // Populate output parameters.
+ //
+ *DeviceAddress = MapInfo->PlainTextAddress;
+ *Mapping = MapInfo;
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: Mapping=0x%p Device(PlainText)=0x%Lx Crypted=0x%Lx Pages=0x%Lx\n",
+ __FUNCTION__,
+ MapInfo,
+ MapInfo->PlainTextAddress,
+ MapInfo->CryptedAddress,
+ (UINT64)MapInfo->NumberOfPages
+ ));
+
+ return EFI_SUCCESS;
+
+FreeMapInfo:
+ FreePool (MapInfo);
+
+Failed:
+ *NumberOfBytes = 0;
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ This is an internal worker function that only extends the Map() API with
+ the MemoryMapLocked parameter.
+
+ @param This The protocol instance pointer.
+ @param Mapping The mapping value returned from Map().
+ @param MemoryMapLocked The function is executing on the stack of
+ gBS->ExitBootServices(); changes to the UEFI
+ memory map are forbidden.
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
+ Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system
+ memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+IoMmuUnmapWorker (
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN VOID *Mapping,
+ IN BOOLEAN MemoryMapLocked
+ )
+{
+ MAP_INFO *MapInfo;
+ EFI_STATUS Status;
+ COMMON_BUFFER_HEADER *CommonBufferHeader;
+ VOID *EncryptionTarget;
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: Mapping=0x%p MemoryMapLocked=%d\n",
+ __FUNCTION__,
+ Mapping,
+ MemoryMapLocked
+ ));
+
+ if (Mapping == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MapInfo = (MAP_INFO *)Mapping;
+
+ //
+ // set CommonBufferHeader to suppress incorrect compiler/analyzer warnings
+ //
+ CommonBufferHeader = NULL;
+
+ //
+ // For BusMasterWrite[64] operations and BusMasterCommonBuffer[64] operations
+ // we have to encrypt the results, ultimately to the original place (i.e.,
+ // "MapInfo->CryptedAddress").
+ //
+ // For BusMasterCommonBuffer[64] operations however, this encryption has to
+ // land in-place, so divert the encryption to the stash buffer first.
+ //
+ EncryptionTarget = (VOID *)(UINTN)MapInfo->CryptedAddress;
+
+ switch (MapInfo->Operation) {
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+ ASSERT (MapInfo->PlainTextAddress == MapInfo->CryptedAddress);
+
+ CommonBufferHeader = (COMMON_BUFFER_HEADER *)(
+ (UINTN)MapInfo->PlainTextAddress - EFI_PAGE_SIZE
+ );
+ ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);
+ EncryptionTarget = CommonBufferHeader->StashBuffer;
+ //
+ // fall through
+ //
+
+ case EdkiiIoMmuOperationBusMasterWrite:
+ case EdkiiIoMmuOperationBusMasterWrite64:
+ CopyMem (
+ EncryptionTarget,
+ (VOID *) (UINTN) MapInfo->PlainTextAddress,
+ MapInfo->NumberOfBytes
+ );
+ break;
+
+ default:
+ //
+ // nothing to encrypt after BusMasterRead[64] operations
+ //
+ break;
+ }
+
+ //
+ // Restore the memory encryption mask on the area we used to hold the
+ // plaintext.
+ //
+ if (mMemEncryptType == MEM_ENCRYPT_SEV_ENABLED) {
+ Status = MemEncryptSevSetPageEncMask (
+ 0,
+ MapInfo->PlainTextAddress,
+ MapInfo->NumberOfPages,
+ TRUE
+ );
+ } else if (mMemEncryptType == MEM_ENCRYPT_TDX_ENABLED) {
+ Status = MemEncryptTdxSetPageEncMask (
+ 0,
+ MapInfo->PlainTextAddress,
+ MapInfo->NumberOfPages,
+ TRUE
+ );
+ }
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ CpuDeadLoop ();
+ }
+
+ //
+ // For BusMasterCommonBuffer[64] operations, copy the stashed data to the
+ // original (now encrypted) location.
+ //
+ // For all other operations, fill the late bounce buffer (which existed as
+ // plaintext at some point) with zeros, and then release it (unless the UEFI
+ // memory map is locked).
+ //
+ if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
+ MapInfo->Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
+ CopyMem (
+ (VOID *)(UINTN)MapInfo->CryptedAddress,
+ CommonBufferHeader->StashBuffer,
+ MapInfo->NumberOfBytes
+ );
+ } else {
+ ZeroMem (
+ (VOID *)(UINTN)MapInfo->PlainTextAddress,
+ EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages)
+ );
+ if (!MemoryMapLocked) {
+ gBS->FreePages (MapInfo->PlainTextAddress, MapInfo->NumberOfPages);
+ }
+ }
+
+ //
+ // Forget the MAP_INFO structure, then free it (unless the UEFI memory map is
+ // locked).
+ //
+ RemoveEntryList (&MapInfo->Link);
+ if (!MemoryMapLocked) {
+ FreePool (MapInfo);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This The protocol instance pointer.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
+ Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system
+ memory.
+**/
+EFI_STATUS
+EFIAPI
+IoMmuUnmap (
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ return IoMmuUnmapWorker (
+ This,
+ Mapping,
+ FALSE // MemoryMapLocked
+ );
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param This The protocol instance pointer.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate,
+ EfiBootServicesData or EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory
+ address of the allocated range.
+ @param Attributes The requested bit mask of attributes for the
+ allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal
+ attribute bits are MEMORY_WRITE_COMBINE and
+ MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuAllocateBuffer (
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ VOID *StashBuffer;
+ UINTN CommonBufferPages;
+ COMMON_BUFFER_HEADER *CommonBufferHeader;
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: MemoryType=%u Pages=0x%Lx Attributes=0x%Lx\n",
+ __FUNCTION__,
+ (UINT32)MemoryType,
+ (UINT64)Pages,
+ Attributes
+ ));
+
+ //
+ // Validate Attributes
+ //
+ if ((Attributes & EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check for invalid inputs
+ //
+ if (HostAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The only valid memory types are EfiBootServicesData and
+ // EfiRuntimeServicesData
+ //
+ if (MemoryType != EfiBootServicesData &&
+ MemoryType != EfiRuntimeServicesData) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // We'll need a header page for the COMMON_BUFFER_HEADER structure.
+ //
+ if (Pages > MAX_UINTN - 1) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CommonBufferPages = Pages + 1;
+
+ //
+ // Allocate the stash in EfiBootServicesData type memory.
+ //
+ // Map() will temporarily save encrypted data in the stash for
+ // BusMasterCommonBuffer[64] operations, so the data can be decrypted to the
+ // original location.
+ //
+ // Unmap() will temporarily save plaintext data in the stash for
+ // BusMasterCommonBuffer[64] operations, so the data can be encrypted to the
+ // original location.
+ //
+ // StashBuffer always resides in encrypted memory.
+ //
+ StashBuffer = AllocatePages (Pages);
+ if (StashBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PhysicalAddress = (UINTN)-1;
+ if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {
+ //
+ // Limit allocations to memory below 4GB
+ //
+ PhysicalAddress = SIZE_4GB - 1;
+ }
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ MemoryType,
+ CommonBufferPages,
+ &PhysicalAddress
+ );
+ if (EFI_ERROR (Status)) {
+ goto FreeStashBuffer;
+ }
+
+ CommonBufferHeader = (VOID *)(UINTN)PhysicalAddress;
+ PhysicalAddress += EFI_PAGE_SIZE;
+
+ CommonBufferHeader->Signature = COMMON_BUFFER_SIG;
+ CommonBufferHeader->StashBuffer = StashBuffer;
+
+ *HostAddress = (VOID *)(UINTN)PhysicalAddress;
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: Host=0x%Lx Stash=0x%p\n",
+ __FUNCTION__,
+ PhysicalAddress,
+ StashBuffer
+ ));
+ return EFI_SUCCESS;
+
+FreeStashBuffer:
+ FreePages (StashBuffer, Pages);
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param This The protocol instance pointer.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated
+ range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and
+ Pages was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuFreeBuffer (
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ )
+{
+ UINTN CommonBufferPages;
+ COMMON_BUFFER_HEADER *CommonBufferHeader;
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: Host=0x%p Pages=0x%Lx\n",
+ __FUNCTION__,
+ HostAddress,
+ (UINT64)Pages
+ ));
+
+ CommonBufferPages = Pages + 1;
+ CommonBufferHeader = (COMMON_BUFFER_HEADER *)(
+ (UINTN)HostAddress - EFI_PAGE_SIZE
+ );
+
+ //
+ // Check the signature.
+ //
+ ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);
+ if (CommonBufferHeader->Signature != COMMON_BUFFER_SIG) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Free the stash buffer. This buffer was always encrypted, so no need to
+ // zero it.
+ //
+ FreePages (CommonBufferHeader->StashBuffer, Pages);
+
+ //
+ // Release the common buffer itself. Unmap() has re-encrypted it in-place, so
+ // no need to zero it.
+ //
+ return gBS->FreePages ((UINTN)CommonBufferHeader, CommonBufferPages);
+}
+
+
+/**
+ Set IOMMU attribute for a system memory.
+
+ If the IOMMU protocol exists, the system memory cannot be used
+ for DMA by default.
+
+ When a device requests a DMA access for a system memory,
+ the device driver need use SetAttribute() to update the IOMMU
+ attribute to request DMA access (read and/or write).
+
+ The DeviceHandle is used to identify which device submits the request.
+ The IOMMU implementation need translate the device path to an IOMMU device
+ ID, and set IOMMU hardware register accordingly.
+ 1) DeviceHandle can be a standard PCI device.
+ The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.
+ The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.
+ The memory for BusMasterCommonBuffer need set
+ EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.
+ After the memory is used, the memory need set 0 to keep it being
+ protected.
+ 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).
+ The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or
+ EDKII_IOMMU_ACCESS_WRITE.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] DeviceHandle The device who initiates the DMA access
+ request.
+ @param[in] Mapping The mapping value returned from Map().
+ @param[in] IoMmuAccess The IOMMU access.
+
+ @retval EFI_SUCCESS The IoMmuAccess is set for the memory range
+ specified by DeviceAddress and Length.
+ @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
+ Map().
+ @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination
+ of access.
+ @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.
+ @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported
+ by the IOMMU.
+ @retval EFI_UNSUPPORTED The IOMMU does not support the memory range
+ specified by Mapping.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
+ modify the IOMMU access.
+ @retval EFI_DEVICE_ERROR The IOMMU device reported an error while
+ attempting the operation.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuSetAttribute (
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN EFI_HANDLE DeviceHandle,
+ IN VOID *Mapping,
+ IN UINT64 IoMmuAccess
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+EDKII_IOMMU_PROTOCOL mIoMmu = {
+ EDKII_IOMMU_PROTOCOL_REVISION,
+ IoMmuSetAttribute,
+ IoMmuMap,
+ IoMmuUnmap,
+ IoMmuAllocateBuffer,
+ IoMmuFreeBuffer,
+};
+
+/**
+ Notification function that is queued when gBS->ExitBootServices() signals the
+ EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals another
+ event, received as Context, and returns.
+
+ Signaling an event in this context is safe. The UEFI spec allows
+ gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is not
+ listed, hence memory is not allocated. The edk2 implementation also does not
+ release memory (and we only have to care about the edk2 implementation
+ because EDKII_IOMMU_PROTOCOL is edk2-specific anyway).
+
+ @param[in] Event Event whose notification function is being invoked.
+ Event is permitted to request the queueing of this
+ function at TPL_CALLBACK or TPL_NOTIFY task
+ priority level.
+
+ @param[in] EventToSignal Identifies the EFI_EVENT to signal. EventToSignal
+ is permitted to request the queueing of its
+ notification function only at TPL_CALLBACK level.
+**/
+STATIC
+VOID
+EFIAPI
+IoMmuExitBoot (
+ IN EFI_EVENT Event,
+ IN VOID *EventToSignal
+ )
+{
+ //
+ // (1) The NotifyFunctions of all the events in
+ // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before
+ // IoMmuExitBoot() is entered.
+ //
+ // (2) IoMmuExitBoot() is executing minimally at TPL_CALLBACK.
+ //
+ // (3) IoMmuExitBoot() has been queued in unspecified order relative to the
+ // NotifyFunctions of all the other events in
+ // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as
+ // Event's.
+ //
+ // Consequences:
+ //
+ // - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions
+ // queued at TPL_CALLBACK may be invoked after IoMmuExitBoot() returns.
+ //
+ // - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions
+ // queued at TPL_NOTIFY may be invoked after IoMmuExitBoot() returns; plus
+ // *all* NotifyFunctions queued at TPL_CALLBACK will be invoked strictly
+ // after all NotifyFunctions queued at TPL_NOTIFY, including
+ // IoMmuExitBoot(), have been invoked.
+ //
+ // - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we
+ // queue EventToSignal's NotifyFunction after the NotifyFunctions of *all*
+ // events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES.
+ //
+ DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__));
+ gBS->SignalEvent (EventToSignal);
+}
+
+/**
+ Notification function that is queued after the notification functions of all
+ events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. The same memory
+ map restrictions apply.
+
+ This function unmaps all currently existing IOMMU mappings.
+
+ @param[in] Event Event whose notification function is being invoked. Event
+ is permitted to request the queueing of this function
+ only at TPL_CALLBACK task priority level.
+
+ @param[in] Context Ignored.
+**/
+STATIC
+VOID
+EFIAPI
+IoMmuUnmapAllMappings (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ LIST_ENTRY *Node;
+ LIST_ENTRY *NextNode;
+ MAP_INFO *MapInfo;
+
+ DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__));
+
+ //
+ // All drivers that had set up IOMMU mappings have halted their respective
+ // controllers by now; tear down the mappings.
+ //
+ for (Node = GetFirstNode (&mMapInfos); Node != &mMapInfos; Node = NextNode) {
+ NextNode = GetNextNode (&mMapInfos, Node);
+ MapInfo = CR (Node, MAP_INFO, Link, MAP_INFO_SIG);
+ IoMmuUnmapWorker (
+ &mIoMmu, // This
+ MapInfo, // Mapping
+ TRUE // MemoryMapLocked
+ );
+ }
+}
+
+/**
+ Initialize Iommu Protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuInstallIoMmuProtocol (
+ UINTN MemEncryptType
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT UnmapAllMappingsEvent;
+ EFI_EVENT ExitBootEvent;
+ EFI_HANDLE Handle;
+
+ mMemEncryptType = MemEncryptType;
+ //
+ // Create the "late" event whose notification function will tear down all
+ // left-over IOMMU mappings.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL, // Type
+ TPL_CALLBACK, // NotifyTpl
+ IoMmuUnmapAllMappings, // NotifyFunction
+ NULL, // NotifyContext
+ &UnmapAllMappingsEvent // Event
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create the event whose notification function will be queued by
+ // gBS->ExitBootServices() and will signal the event created above.
+ //
+ Status = gBS->CreateEvent (
+ EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type
+ TPL_CALLBACK, // NotifyTpl
+ IoMmuExitBoot, // NotifyFunction
+ UnmapAllMappingsEvent, // NotifyContext
+ &ExitBootEvent // Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto CloseUnmapAllMappingsEvent;
+ }
+
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEdkiiIoMmuProtocolGuid, &mIoMmu,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto CloseExitBootEvent;
+ }
+
+ return EFI_SUCCESS;
+
+CloseExitBootEvent:
+ gBS->CloseEvent (ExitBootEvent);
+
+CloseUnmapAllMappingsEvent:
+ gBS->CloseEvent (UnmapAllMappingsEvent);
+
+ return Status;
+}
diff --git a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h b/OvmfPkg/IoMmuDxe/IoMmu.h
similarity index 78%
rename from OvmfPkg/IoMmuDxe/AmdSevIoMmu.h
rename to OvmfPkg/IoMmuDxe/IoMmu.h
index 8244f28b57fd..2ef3b756f792 100644
--- a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h
+++ b/OvmfPkg/IoMmuDxe/IoMmu.h
@@ -1,38 +1,40 @@
-/** @file
-
- The protocol provides support to allocate, free, map and umap a DMA buffer
- for bus master (e.g PciHostBridge). When SEV is enabled, the DMA operations
- must be performed on unencrypted buffer hence protocol clear the encryption
- bit from the DMA buffer.
-
- Copyright (c) 2017, Intel Corporation. All rights reserved.
- Copyright (c) 2017, AMD Inc. All rights reserved.
- (C) Copyright 2017 Hewlett Packard Enterprise Development LP
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _AMD_SEV_IOMMU_H_
-#define _AMD_SEV_IOMMU_H_
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-/**
- Install IOMMU protocol to provide the DMA support for PciHostBridge and
- MemEncryptSevLib.
-
-**/
-EFI_STATUS
-EFIAPI
-AmdSevInstallIoMmuProtocol (
- VOID
- );
-
-#endif
+/** @file
+
+ The protocol provides support to allocate, free, map and umap a DMA buffer
+ for bus master (e.g PciHostBridge). When memory encryption is enabled, the DMA operations
+ must be performed on unencrypted buffer hence protocol clear the encryption
+ bit from the DMA buffer.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2017, AMD Inc. All rights reserved.
+ (C) Copyright 2017 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _AMD_SEV_IOMMU_H_
+#define _AMD_SEV_IOMMU_H_
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/**
+ Install IOMMU protocol to provide the DMA support for PciHostBridge and
+ MemEncryptLib.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuInstallIoMmuProtocol (
+ UINTN MemEncryptType
+ );
+
+#endif
diff --git a/OvmfPkg/IoMmuDxe/IoMmuDxe.c b/OvmfPkg/IoMmuDxe/IoMmuDxe.c
index 13df8ba874c5..d511b2b82192 100644
--- a/OvmfPkg/IoMmuDxe/IoMmuDxe.c
+++ b/OvmfPkg/IoMmuDxe/IoMmuDxe.c
@@ -1,15 +1,16 @@
/** @file
IoMmuDxe driver installs EDKII_IOMMU_PROTOCOL to provide the support for DMA
- operations when SEV is enabled.
+ operations when memory encryption is enabled.
+ Copyright (c) 2020, Intel Corporation. All rights reserved.
Copyright (c) 2017, AMD Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
-#include "AmdSevIoMmu.h"
+#include "IoMmu.h"
EFI_STATUS
EFIAPI
@@ -20,13 +21,21 @@ IoMmuDxeEntryPoint (
{
EFI_STATUS Status;
EFI_HANDLE Handle;
+ UINTN Type;
//
- // When SEV is enabled, install IoMmu protocol otherwise install the
+ // When memory encryption is enabled, install IoMmu protocol otherwise install the
// placeholder protocol so that other dependent module can run.
//
+ Type = MEM_ENCRYPT_NONE_ENABLED;
if (MemEncryptSevIsEnabled ()) {
- Status = AmdSevInstallIoMmuProtocol ();
+ Type = MEM_ENCRYPT_SEV_ENABLED;
+ } else if (MemEncryptTdxIsEnabled ()) {
+ Type = MEM_ENCRYPT_TDX_ENABLED;
+ }
+
+ if (Type != MEM_ENCRYPT_NONE_ENABLED) {
+ Status = IoMmuInstallIoMmuProtocol (Type);
} else {
Handle = NULL;
diff --git a/OvmfPkg/IoMmuDxe/IoMmuDxe.inf b/OvmfPkg/IoMmuDxe/IoMmuDxe.inf
index 2ebd74e5558c..2aa8413cfe23 100644
--- a/OvmfPkg/IoMmuDxe/IoMmuDxe.inf
+++ b/OvmfPkg/IoMmuDxe/IoMmuDxe.inf
@@ -18,8 +18,8 @@
ENTRY_POINT = IoMmuDxeEntryPoint
[Sources]
- AmdSevIoMmu.c
- AmdSevIoMmu.h
+ IoMmu.c
+ IoMmu.h
IoMmuDxe.c
[Packages]
@@ -32,6 +32,7 @@
BaseMemoryLib
DebugLib
MemEncryptSevLib
+ MemEncryptTdxLib
MemoryAllocationLib
UefiBootServicesTableLib
UefiDriverEntryPoint
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
new file mode 100644
index 000000000000..41438394da0d
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
@@ -0,0 +1,46 @@
+## @file
+# Library for Memory Encryption
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.
+# Copyright (c) 2017 Advanced Micro Devices. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = MemEncryptTdxLibNull
+ FILE_GUID = 7E6651B2-B775-4593-A410-FC05B8C61993
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemEncryptTdxLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[Sources]
+ VirtualMemory.h
+ MemoryEncryption.c
+
+[LibraryClasses]
+ BaseLib
+ CacheMaintenanceLib
+ CpuLib
+ DebugLib
+ MemoryAllocationLib
+ PcdLib
+ TdxLib
+ TdxProbeLib
+
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
new file mode 100644
index 000000000000..e13670cfeae6
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
@@ -0,0 +1,36 @@
+## @file
+# Library for Memory Encryption
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.
+# Copyright (c) 2017 Advanced Micro Devices. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = MemEncryptTdxLib
+ FILE_GUID = 3C69C4CA-DE46-44D7-8AA5-6EE51A4E3EA7
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemEncryptTdxLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = X64 IA32
+#
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[Sources]
+ BaseMemoryEncryptionNull.c
+
+[LibraryClasses]
+ BaseLib
+
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
new file mode 100644
index 000000000000..689ae39da555
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
@@ -0,0 +1,123 @@
+/** @file
+
+ Virtual Memory Management Services to set or clear the memory encryption
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2017, AMD Incorporated. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+
+**/
+
+#include
+#include
+#include
+#include
+
+/**
+ Returns boolean to indicate whether to indicate which, if any, memory encryption is enabled
+
+ @param[in] Type Bitmask of encryption technologies to check is enabled
+
+ @retval TRUE The encryption type(s) are enabled
+ @retval FALSE The encryption type(s) are not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptTdxIsEnabled (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ This function clears memory encryption bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+ @param[in] Flush Flush the caches before clearing the bit
+ (mostly TRUE except MMIO addresses)
+
+ @retval RETURN_SUCCESS The attributes were cleared for the
+ memory region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Clearing the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxClearPageEncMask (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages,
+ IN BOOLEAN Flush
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This function sets memory encryption bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+ @param[in] Flush Flush the caches before setting the bit
+ (mostly TRUE except MMIO addresses)
+
+ @retval RETURN_SUCCESS The attributes were set for the memory
+ region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Setting the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxSetPageEncMask (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages,
+ IN BOOLEAN Flush
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Locate the page range that covers the initial (pre-SMBASE-relocation) SMRAM
+ Save State Map.
+
+ @param[out] BaseAddress The base address of the lowest-address page that
+ covers the initial SMRAM Save State Map.
+
+ @param[out] NumberOfPages The number of pages in the page range that covers
+ the initial SMRAM Save State Map.
+
+ @retval RETURN_SUCCESS BaseAddress and NumberOfPages have been set on
+ output.
+
+ @retval RETURN_UNSUPPORTED SMM is unavailable.
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptLocateInitialSmramSaveStateMapPages (
+ OUT UINTN *BaseAddress,
+ OUT UINTN *NumberOfPages
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c b/OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
new file mode 100644
index 000000000000..b71e1c6843c9
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
@@ -0,0 +1,949 @@
+/** @file
+
+ Virtual Memory Management Services to set or clear the memory encryption
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2017, AMD Incorporated. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "VirtualMemory.h"
+#include
+#include
+#include
+
+typedef enum {
+ SetSharedBit,
+ ClearSharedBit
+} TDX_PAGETABLE_MODE;
+
+STATIC PAGE_TABLE_POOL *mPageTablePool = NULL;
+
+/**
+ Returns boolean to indicate whether to indicate which, if any, memory encryption is enabled
+
+ @param[in] Type Bitmask of encryption technologies to check is enabled
+
+ @retval TRUE The encryption type(s) are enabled
+ @retval FALSE The encryption type(s) are not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptTdxIsEnabled (
+ VOID
+ )
+{
+ //
+ // If query any encrpytion type this library doesn't support, return FALSE
+ //
+ return ProbeTdGuest();
+}
+
+/**
+ Get the memory encryption mask
+
+ @param[out] EncryptionMask contains the pte mask.
+
+**/
+STATIC
+UINT64
+GetMemEncryptionAddressMask (
+ VOID
+ )
+{
+ return TdSharedPageMask();
+}
+
+/**
+ Initialize a buffer pool for page table use only.
+
+ To reduce the potential split operation on page table, the pages reserved for
+ page table should be allocated in the times of PAGE_TABLE_POOL_UNIT_PAGES and
+ at the boundary of PAGE_TABLE_POOL_ALIGNMENT. So the page pool is always
+ initialized with number of pages greater than or equal to the given
+ PoolPages.
+
+ Once the pages in the pool are used up, this method should be called again to
+ reserve at least another PAGE_TABLE_POOL_UNIT_PAGES. Usually this won't
+ happen often in practice.
+
+ @param[in] PoolPages The least page number of the pool to be created.
+
+ @retval TRUE The pool is initialized successfully.
+ @retval FALSE The memory is out of resource.
+**/
+STATIC
+BOOLEAN
+InitializePageTablePool (
+ IN UINTN PoolPages
+ )
+{
+ VOID *Buffer;
+
+ //
+ // Always reserve at least PAGE_TABLE_POOL_UNIT_PAGES, including one page for
+ // header.
+ //
+ PoolPages += 1; // Add one page for header.
+ PoolPages = ((PoolPages - 1) / PAGE_TABLE_POOL_UNIT_PAGES + 1) *
+ PAGE_TABLE_POOL_UNIT_PAGES;
+ Buffer = AllocateAlignedPages (PoolPages, PAGE_TABLE_POOL_ALIGNMENT);
+ if (Buffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Out of aligned pages\r\n"));
+ return FALSE;
+ }
+
+ //
+ // Link all pools into a list for easier track later.
+ //
+ if (mPageTablePool == NULL) {
+ mPageTablePool = Buffer;
+ mPageTablePool->NextPool = mPageTablePool;
+ } else {
+ ((PAGE_TABLE_POOL *)Buffer)->NextPool = mPageTablePool->NextPool;
+ mPageTablePool->NextPool = Buffer;
+ mPageTablePool = Buffer;
+ }
+
+ //
+ // Reserve one page for pool header.
+ //
+ mPageTablePool->FreePages = PoolPages - 1;
+ mPageTablePool->Offset = EFI_PAGES_TO_SIZE (1);
+
+ return TRUE;
+}
+
+/**
+ This API provides a way to allocate memory for page table.
+
+ This API can be called more than once to allocate memory for page tables.
+
+ Allocates the number of 4KB pages and returns a pointer to the allocated
+ buffer. The buffer returned is aligned on a 4KB boundary.
+
+ If Pages is 0, then NULL is returned.
+ If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+STATIC
+VOID *
+EFIAPI
+AllocatePageTableMemory (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ if (Pages == 0) {
+ return NULL;
+ }
+
+ //
+ // Renew the pool if necessary.
+ //
+ if (mPageTablePool == NULL ||
+ Pages > mPageTablePool->FreePages) {
+ if (!InitializePageTablePool (Pages)) {
+ return NULL;
+ }
+ }
+
+ Buffer = (UINT8 *)mPageTablePool + mPageTablePool->Offset;
+
+ mPageTablePool->Offset += EFI_PAGES_TO_SIZE (Pages);
+ mPageTablePool->FreePages -= Pages;
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a:%a: Buffer=0x%Lx Pages=%ld\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ Buffer,
+ Pages
+ ));
+
+ return Buffer;
+}
+
+
+/**
+ Split 2M page to 4K.
+
+ @param[in] PhysicalAddress Start physical address the 2M page
+ covered.
+ @param[in, out] PageEntry2M Pointer to 2M page entry.
+ @param[in] StackBase Stack base address.
+ @param[in] StackSize Stack size.
+
+**/
+STATIC
+VOID
+Split2MPageTo4K (
+ IN PHYSICAL_ADDRESS PhysicalAddress,
+ IN OUT UINT64 *PageEntry2M,
+ IN PHYSICAL_ADDRESS StackBase,
+ IN UINTN StackSize,
+ IN UINT64 AddressEncMask
+ )
+{
+ PHYSICAL_ADDRESS PhysicalAddress4K;
+ UINTN IndexOfPageTableEntries;
+ PAGE_TABLE_4K_ENTRY *PageTableEntry, *PageTableEntry1;
+
+ PageTableEntry = AllocatePageTableMemory(1);
+
+ PageTableEntry1 = PageTableEntry;
+
+ ASSERT (PageTableEntry != NULL);
+
+ PhysicalAddress4K = PhysicalAddress;
+ for (IndexOfPageTableEntries = 0;
+ IndexOfPageTableEntries < 512;
+ (IndexOfPageTableEntries++,
+ PageTableEntry++,
+ PhysicalAddress4K += SIZE_4KB)) {
+ //
+ // Fill in the Page Table entries
+ //
+ PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
+ PageTableEntry->Bits.ReadWrite = 1;
+ PageTableEntry->Bits.Present = 1;
+ if ((PhysicalAddress4K >= StackBase) &&
+ (PhysicalAddress4K < StackBase + StackSize)) {
+ //
+ // Set Nx bit for stack.
+ //
+ PageTableEntry->Bits.Nx = 1;
+ }
+ }
+
+ //
+ // Fill in 2M page entry.
+ //
+ *PageEntry2M = ((UINT64)(UINTN)PageTableEntry1 |
+ IA32_PG_P | IA32_PG_RW | AddressEncMask);
+}
+
+/**
+ Set one page of page table pool memory to be read-only.
+
+ @param[in] PageTableBase Base address of page table (CR3).
+ @param[in] Address Start address of a page to be set as read-only.
+ @param[in] Level4Paging Level 4 paging flag.
+
+**/
+STATIC
+VOID
+SetPageTablePoolReadOnly (
+ IN UINTN PageTableBase,
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN BOOLEAN Level4Paging
+ )
+{
+ UINTN Index;
+ UINTN EntryIndex;
+ UINT64 AddressEncMask;
+ UINT64 ActiveAddressEncMask;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ UINT64 *PageTable;
+ UINT64 *NewPageTable;
+ UINT64 PageAttr;
+ UINT64 LevelSize[5];
+ UINT64 LevelMask[5];
+ UINTN LevelShift[5];
+ UINTN Level;
+ UINT64 PoolUnitSize;
+
+ ASSERT (PageTableBase != 0);
+
+ //
+ // Since the page table is always from page table pool, which is always
+ // located at the boundary of PcdPageTablePoolAlignment, we just need to
+ // set the whole pool unit to be read-only.
+ //
+ Address = Address & PAGE_TABLE_POOL_ALIGN_MASK;
+
+ LevelShift[1] = PAGING_L1_ADDRESS_SHIFT;
+ LevelShift[2] = PAGING_L2_ADDRESS_SHIFT;
+ LevelShift[3] = PAGING_L3_ADDRESS_SHIFT;
+ LevelShift[4] = PAGING_L4_ADDRESS_SHIFT;
+
+ LevelMask[1] = PAGING_4K_ADDRESS_MASK_64;
+ LevelMask[2] = PAGING_2M_ADDRESS_MASK_64;
+ LevelMask[3] = PAGING_1G_ADDRESS_MASK_64;
+ LevelMask[4] = PAGING_1G_ADDRESS_MASK_64;
+
+ LevelSize[1] = SIZE_4KB;
+ LevelSize[2] = SIZE_2MB;
+ LevelSize[3] = SIZE_1GB;
+ LevelSize[4] = SIZE_512GB;
+
+ AddressEncMask = GetMemEncryptionAddressMask() &
+ PAGING_1G_ADDRESS_MASK_64;
+ PageTable = (UINT64 *)(UINTN)PageTableBase;
+ PoolUnitSize = PAGE_TABLE_POOL_UNIT_SIZE;
+
+ for (Level = (Level4Paging) ? 4 : 3; Level > 0; --Level) {
+ Index = ((UINTN)RShiftU64 (Address, LevelShift[Level]));
+ Index &= PAGING_PAE_INDEX_MASK;
+
+ PageAttr = PageTable[Index];
+ ActiveAddressEncMask = GetMemEncryptionAddressMask() & PageAttr;
+
+ if ((PageAttr & IA32_PG_PS) == 0) {
+ //
+ // Go to next level of table.
+ //
+ PageTable = (UINT64 *)(UINTN)(PageAttr & ~AddressEncMask &
+ PAGING_4K_ADDRESS_MASK_64);
+ continue;
+ }
+
+ if (PoolUnitSize >= LevelSize[Level]) {
+ //
+ // Clear R/W bit if current page granularity is not larger than pool unit
+ // size.
+ //
+ if ((PageAttr & IA32_PG_RW) != 0) {
+ while (PoolUnitSize > 0) {
+ //
+ // PAGE_TABLE_POOL_UNIT_SIZE and PAGE_TABLE_POOL_ALIGNMENT are fit in
+ // one page (2MB). Then we don't need to update attributes for pages
+ // crossing page directory. ASSERT below is for that purpose.
+ //
+ ASSERT (Index < EFI_PAGE_SIZE/sizeof (UINT64));
+
+ PageTable[Index] &= ~(UINT64)IA32_PG_RW;
+ PoolUnitSize -= LevelSize[Level];
+
+ ++Index;
+ }
+ }
+
+ break;
+
+ } else {
+ //
+ // The smaller granularity of page must be needed.
+ //
+ ASSERT (Level > 1);
+
+ NewPageTable = AllocatePageTableMemory (1);
+ ASSERT (NewPageTable != NULL);
+
+ PhysicalAddress = PageAttr & LevelMask[Level];
+ for (EntryIndex = 0;
+ EntryIndex < EFI_PAGE_SIZE/sizeof (UINT64);
+ ++EntryIndex) {
+ NewPageTable[EntryIndex] = PhysicalAddress | ActiveAddressEncMask |
+ IA32_PG_P | IA32_PG_RW;
+ if (Level > 2) {
+ NewPageTable[EntryIndex] |= IA32_PG_PS;
+ }
+ PhysicalAddress += LevelSize[Level - 1];
+ }
+
+ PageTable[Index] = (UINT64)(UINTN)NewPageTable | ActiveAddressEncMask |
+ IA32_PG_P | IA32_PG_RW;
+ PageTable = NewPageTable;
+ }
+ }
+}
+
+/**
+ Prevent the memory pages used for page table from been overwritten.
+
+ @param[in] PageTableBase Base address of page table (CR3).
+ @param[in] Level4Paging Level 4 paging flag.
+
+**/
+STATIC
+VOID
+EnablePageTableProtection (
+ IN UINTN PageTableBase,
+ IN BOOLEAN Level4Paging
+ )
+{
+ PAGE_TABLE_POOL *HeadPool;
+ PAGE_TABLE_POOL *Pool;
+ UINT64 PoolSize;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ if (mPageTablePool == NULL) {
+ return;
+ }
+
+ //
+ // SetPageTablePoolReadOnly might update mPageTablePool. It's safer to
+ // remember original one in advance.
+ //
+ HeadPool = mPageTablePool;
+ Pool = HeadPool;
+ do {
+ Address = (EFI_PHYSICAL_ADDRESS)(UINTN)Pool;
+ PoolSize = Pool->Offset + EFI_PAGES_TO_SIZE (Pool->FreePages);
+
+ //
+ // The size of one pool must be multiple of PAGE_TABLE_POOL_UNIT_SIZE,
+ // which is one of page size of the processor (2MB by default). Let's apply
+ // the protection to them one by one.
+ //
+ while (PoolSize > 0) {
+ SetPageTablePoolReadOnly(PageTableBase, Address, Level4Paging);
+ Address += PAGE_TABLE_POOL_UNIT_SIZE;
+ PoolSize -= PAGE_TABLE_POOL_UNIT_SIZE;
+ }
+
+ Pool = Pool->NextPool;
+ } while (Pool != HeadPool);
+
+}
+
+
+/**
+ Split 1G page to 2M.
+
+ @param[in] PhysicalAddress Start physical address the 1G page
+ covered.
+ @param[in, out] PageEntry1G Pointer to 1G page entry.
+ @param[in] StackBase Stack base address.
+ @param[in] StackSize Stack size.
+
+**/
+STATIC
+VOID
+Split1GPageTo2M (
+ IN PHYSICAL_ADDRESS PhysicalAddress,
+ IN OUT UINT64 *PageEntry1G,
+ IN PHYSICAL_ADDRESS StackBase,
+ IN UINTN StackSize
+ )
+{
+ PHYSICAL_ADDRESS PhysicalAddress2M;
+ UINTN IndexOfPageDirectoryEntries;
+ PAGE_TABLE_ENTRY *PageDirectoryEntry;
+ UINT64 AddressEncMask;
+ UINT64 ActiveAddressEncMask;
+
+ PageDirectoryEntry = AllocatePageTableMemory(1);
+
+ AddressEncMask = GetMemEncryptionAddressMask ();
+ ASSERT (PageDirectoryEntry != NULL);
+
+ ActiveAddressEncMask = *PageEntry1G & AddressEncMask;
+ //
+ // Fill in 1G page entry.
+ //
+ *PageEntry1G = ((UINT64)(UINTN)PageDirectoryEntry |
+ IA32_PG_P | IA32_PG_RW | ActiveAddressEncMask);
+
+ PhysicalAddress2M = PhysicalAddress;
+ for (IndexOfPageDirectoryEntries = 0;
+ IndexOfPageDirectoryEntries < 512;
+ (IndexOfPageDirectoryEntries++,
+ PageDirectoryEntry++,
+ PhysicalAddress2M += SIZE_2MB)) {
+ if ((PhysicalAddress2M < StackBase + StackSize) &&
+ ((PhysicalAddress2M + SIZE_2MB) > StackBase)) {
+ //
+ // Need to split this 2M page that covers stack range.
+ //
+ Split2MPageTo4K (
+ PhysicalAddress2M,
+ (UINT64 *)PageDirectoryEntry,
+ StackBase,
+ StackSize,
+ ActiveAddressEncMask
+ );
+ } else {
+ //
+ // Fill in the Page Directory entries
+ //
+ PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress2M | ActiveAddressEncMask;
+ PageDirectoryEntry->Bits.ReadWrite = 1;
+ PageDirectoryEntry->Bits.Present = 1;
+ PageDirectoryEntry->Bits.MustBe1 = 1;
+ }
+ }
+}
+
+
+/**
+ Set or Clear the memory encryption bit
+
+ @param[in] PagetablePoint Page table entry pointer (PTE).
+ @param[in] Mode Set or Clear encryption bit
+
+**/
+STATIC VOID
+SetOrClearSharedBit(
+ IN OUT UINT64* PageTablePointer,
+ IN TDX_PAGETABLE_MODE Mode,
+ IN PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT64 Length
+ )
+{
+ UINT64 AddressEncMask;
+ UINT64 Status;
+
+ AddressEncMask = GetMemEncryptionAddressMask ();
+
+ //
+ // Set or clear page table entry. Also, set shared bit in physical address, before calling MapGPA
+ //
+ if (Mode == SetSharedBit) {
+ *PageTablePointer |= AddressEncMask;
+ PhysicalAddress |= AddressEncMask;
+ } else {
+ *PageTablePointer &= ~AddressEncMask;
+ PhysicalAddress &= ~AddressEncMask;
+ }
+
+ Status = TdVmCall(TDVMCALL_MAPGPA, PhysicalAddress, Length, 0, 0, NULL);
+
+ //
+ // If changing shared to private, must accept-page again
+ //
+ if (Mode == ClearSharedBit) {
+ TdAcceptPages(PhysicalAddress, Length / EFI_PAGE_SIZE, EFI_PAGE_SIZE);
+ }
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a:%a: pte=0x%Lx AddressEncMask=0x%Lx Mode=0x%x MapGPA Status=0x%x\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ *PageTablePointer,
+ AddressEncMask,
+ Mode, Status));
+}
+
+/**
+ Check the WP status in CR0 register. This bit is used to lock or unlock write
+ access to pages marked as read-only.
+
+ @retval TRUE Write protection is enabled.
+ @retval FALSE Write protection is disabled.
+**/
+STATIC
+BOOLEAN
+IsReadOnlyPageWriteProtected (
+ VOID
+ )
+{
+ return ((AsmReadCr0 () & BIT16) != 0);
+}
+
+
+/**
+ Disable Write Protect on pages marked as read-only.
+**/
+STATIC
+VOID
+DisableReadOnlyPageWriteProtect (
+ VOID
+ )
+{
+ AsmWriteCr0 (AsmReadCr0() & ~BIT16);
+}
+
+/**
+ Enable Write Protect on pages marked as read-only.
+**/
+VOID
+EnableReadOnlyPageWriteProtect (
+ VOID
+ )
+{
+ AsmWriteCr0 (AsmReadCr0() | BIT16);
+}
+
+/**
+ This function either sets or clears memory encryption for the memory
+ region specified by PhysicalAddress and Length from the current page table
+ context.
+
+ The function iterates through the PhysicalAddress one page at a time, and set
+ or clears the memory encryption in the page table. If it encounters
+ that a given physical address range is part of large page then it attempts to
+ change the attribute at one go (based on size), otherwise it splits the
+ large pages into smaller (e.g 2M page into 4K pages) and then try to set or
+ clear the encryption bit on the smallest page size.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] PhysicalAddress The physical address that is the start
+ address of a memory region.
+ @param[in] Length The length of memory region
+ @param[in] Mode Set or Clear mode
+ @param[in] CacheFlush Flush the caches before applying the
+ encryption mask
+
+ @retval RETURN_SUCCESS The attributes were cleared for the
+ memory region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Setting the memory encyrption attribute
+ is not supported
+**/
+
+STATIC
+RETURN_STATUS
+EFIAPI
+SetMemorySharedOrPrivate (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINTN Length,
+ IN TDX_PAGETABLE_MODE Mode,
+ IN BOOLEAN CacheFlush
+ )
+{
+
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageUpperDirectoryPointerEntry;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
+ PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;
+ PAGE_TABLE_ENTRY *PageDirectory2MEntry;
+ PAGE_TABLE_4K_ENTRY *PageTableEntry;
+ UINT64 PgTableMask;
+ UINT64 AddressEncMask;
+ UINT64 ActiveEncMask;
+ BOOLEAN IsWpEnabled;
+ RETURN_STATUS Status;
+ IA32_CR4 Cr4;
+ BOOLEAN Page5LevelSupport;
+
+ //
+ // Set PageMapLevel4Entry to suppress incorrect compiler/analyzer warnings.
+ //
+ PageMapLevel4Entry = NULL;
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx Mode=%a CacheFlush=%u\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ Cr3BaseAddress,
+ PhysicalAddress,
+ (UINT64)Length,
+ (Mode == SetSharedBit) ? "Shared" : "Private",
+ (UINT32)CacheFlush
+ ));
+
+ //
+ // Check if we have a valid memory encryption mask
+ //
+ AddressEncMask = GetMemEncryptionAddressMask ();
+
+ PgTableMask = AddressEncMask | EFI_PAGE_MASK;
+
+ if (Length == 0) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // We are going to change the memory encryption attribute from C=0 -> C=1 or
+ // vice versa Flush the caches to ensure that data is written into memory
+ // with correct C-bit
+ //
+ if (CacheFlush) {
+ WriteBackInvalidateDataCacheRange((VOID*) (UINTN)PhysicalAddress, Length);
+ }
+
+ //
+ // Make sure that the page table is changeable.
+ //
+ IsWpEnabled = IsReadOnlyPageWriteProtected ();
+ if (IsWpEnabled) {
+ DisableReadOnlyPageWriteProtect ();
+ }
+
+ //
+ // If Cr3BaseAddress is not specified then read the current CR3
+ //
+ if (Cr3BaseAddress == 0) {
+ Cr3BaseAddress = AsmReadCr3();
+ }
+ //
+ // CPU will already have LA57 enabled so just check CR4
+ //
+ Cr4.UintN = AsmReadCr4 ();
+
+ Page5LevelSupport = (Cr4.Bits.LA57 ? TRUE : FALSE);
+ //
+ // If 5-level pages, adjust Cr3BaseAddress to point to first 4-level page directory,
+ // we will only have 1
+ //
+ if (Page5LevelSupport) {
+ Cr3BaseAddress = *(UINT64 *)Cr3BaseAddress & ~PgTableMask;
+ }
+
+ Status = EFI_SUCCESS;
+
+ while (Length)
+ {
+ PageMapLevel4Entry = (VOID*) (Cr3BaseAddress & ~PgTableMask);
+ PageMapLevel4Entry += PML4_OFFSET(PhysicalAddress);
+ if (!PageMapLevel4Entry->Bits.Present) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a:%a: bad PML4 for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+ Status = RETURN_NO_MAPPING;
+ goto Done;
+ }
+
+ PageDirectory1GEntry = (VOID *)(
+ (PageMapLevel4Entry->Bits.PageTableBaseAddress <<
+ 12) & ~PgTableMask
+ );
+ PageDirectory1GEntry += PDP_OFFSET(PhysicalAddress);
+ if (!PageDirectory1GEntry->Bits.Present) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a:%a: bad PDPE for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+ Status = RETURN_NO_MAPPING;
+ goto Done;
+ }
+
+ //
+ // If the MustBe1 bit is not 1, it's not actually a 1GB entry
+ //
+ if (PageDirectory1GEntry->Bits.MustBe1) {
+ //
+ // Valid 1GB page
+ // If we have at least 1GB to go, we can just update this entry
+ //
+ if (!(PhysicalAddress & (BIT30 - 1)) && Length >= BIT30) {
+ SetOrClearSharedBit(&PageDirectory1GEntry->Uint64, Mode, PhysicalAddress, BIT30);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a:%a: updated 1GB entry for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+ PhysicalAddress += BIT30;
+ Length -= BIT30;
+ } else {
+ //
+ // We must split the page
+ //
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a:%a: splitting 1GB page for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+ Split1GPageTo2M (
+ (UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress << 30,
+ (UINT64 *)PageDirectory1GEntry,
+ 0,
+ 0
+ );
+ continue;
+ }
+ } else {
+ //
+ // Actually a PDP
+ //
+ PageUpperDirectoryPointerEntry =
+ (PAGE_MAP_AND_DIRECTORY_POINTER *)PageDirectory1GEntry;
+ PageDirectory2MEntry =
+ (VOID *)(
+ (PageUpperDirectoryPointerEntry->Bits.PageTableBaseAddress <<
+ 12) & ~PgTableMask
+ );
+ PageDirectory2MEntry += PDE_OFFSET(PhysicalAddress);
+ if (!PageDirectory2MEntry->Bits.Present) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a:%a: bad PDE for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+ Status = RETURN_NO_MAPPING;
+ goto Done;
+ }
+ //
+ // If the MustBe1 bit is not a 1, it's not a 2MB entry
+ //
+ if (PageDirectory2MEntry->Bits.MustBe1) {
+ //
+ // Valid 2MB page
+ // If we have at least 2MB left to go, we can just update this entry
+ //
+ if (!(PhysicalAddress & (BIT21-1)) && Length >= BIT21) {
+ SetOrClearSharedBit (&PageDirectory2MEntry->Uint64, Mode, PhysicalAddress, BIT21);
+ PhysicalAddress += BIT21;
+ Length -= BIT21;
+ } else {
+ //
+ // We must split up this page into 4K pages
+ //
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a:%a: splitting 2MB page for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+
+ ActiveEncMask = PageDirectory2MEntry->Uint64 & AddressEncMask;
+
+ Split2MPageTo4K (
+ (UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress << 21,
+ (UINT64 *)PageDirectory2MEntry,
+ 0,
+ 0,
+ ActiveEncMask
+ );
+ continue;
+ }
+ } else {
+ PageDirectoryPointerEntry =
+ (PAGE_MAP_AND_DIRECTORY_POINTER *)PageDirectory2MEntry;
+ PageTableEntry =
+ (VOID *)(
+ (PageDirectoryPointerEntry->Bits.PageTableBaseAddress <<
+ 12) & ~PgTableMask
+ );
+ PageTableEntry += PTE_OFFSET(PhysicalAddress);
+ if (!PageTableEntry->Bits.Present) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a:%a: bad PTE for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+ Status = RETURN_NO_MAPPING;
+ goto Done;
+ }
+ SetOrClearSharedBit (&PageTableEntry->Uint64, Mode, PhysicalAddress, EFI_PAGE_SIZE);
+ PhysicalAddress += EFI_PAGE_SIZE;
+ Length -= EFI_PAGE_SIZE;
+ }
+ }
+ }
+
+ //
+ // Protect the page table by marking the memory used for page table to be
+ // read-only.
+ //
+ if (IsWpEnabled) {
+ EnablePageTableProtection ((UINTN)PageMapLevel4Entry, TRUE);
+ }
+
+ //
+ // Flush TLB
+ //
+ CpuFlushTlb();
+
+Done:
+ //
+ // Restore page table write protection, if any.
+ //
+ if (IsWpEnabled) {
+ EnableReadOnlyPageWriteProtect ();
+ }
+
+ return Status;
+}
+
+/**
+ This function clears memory encryption bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+ @param[in] Flush Flush the caches before clearing the bit
+ (mostly TRUE except MMIO addresses)
+
+ @retval RETURN_SUCCESS The attributes were cleared for the
+ memory region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Clearing the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxClearPageEncMask (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages,
+ IN BOOLEAN Flush
+ )
+{
+ return SetMemorySharedOrPrivate (
+ Cr3BaseAddress,
+ BaseAddress,
+ EFI_PAGES_TO_SIZE (NumPages),
+ SetSharedBit,
+ Flush
+ );
+}
+
+/**
+ This function sets memory encryption bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+ @param[in] Flush Flush the caches before setting the bit
+ (mostly TRUE except MMIO addresses)
+ @retval RETURN_SUCCESS The attributes were set for the memory
+ region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Setting the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxSetPageEncMask (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages,
+ IN BOOLEAN Flush
+ )
+{
+ return SetMemorySharedOrPrivate (
+ Cr3BaseAddress,
+ BaseAddress,
+ EFI_PAGES_TO_SIZE (NumPages),
+ ClearSharedBit,
+ Flush
+ );
+}
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h b/OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h
new file mode 100644
index 000000000000..eca4fe77987d
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h
@@ -0,0 +1,181 @@
+/** @file
+
+ Virtual Memory Management Services to set or clear the memory encryption bit
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+ Copyright (c) 2017, AMD Incorporated. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
+
+**/
+
+#ifndef __VIRTUAL_MEMORY__
+#define __VIRTUAL_MEMORY__
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define SYS_CODE64_SEL 0x38
+
+#pragma pack(1)
+
+//
+// Page-Map Level-4 Offset (PML4) and
+// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
+//
+
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory,
+ // 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching,
+ // 1 = Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed,
+ // 1 = Accessed (set by CPU)
+ UINT64 Reserved:1; // Reserved
+ UINT64 MustBeZero:2; // Must Be Zero
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PageTableBaseAddress:40; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // No Execute bit
+ } Bits;
+ UINT64 Uint64;
+} PAGE_MAP_AND_DIRECTORY_POINTER;
+
+//
+// Page Table Entry 4KB
+//
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory,
+ // 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching,
+ // 1 = Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed,
+ // 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by
+ // processor on access to page
+ UINT64 PAT:1; //
+ UINT64 Global:1; // 0 = Not global page, 1 = global page
+ // TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PageTableBaseAddress:40; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code,
+ // 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_4K_ENTRY;
+
+//
+// Page Table Entry 2MB
+//
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory,
+ // 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching,
+ // 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed,
+ // 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by
+ // processor on access to page
+ UINT64 MustBe1:1; // Must be 1
+ UINT64 Global:1; // 0 = Not global page, 1 = global page
+ // TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PAT:1; //
+ UINT64 MustBeZero:8; // Must be zero;
+ UINT64 PageTableBaseAddress:31; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code,
+ // 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_ENTRY;
+
+//
+// Page Table Entry 1GB
+//
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory,
+ // 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching,
+ // 1 = Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed,
+ // 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by
+ // processor on access to page
+ UINT64 MustBe1:1; // Must be 1
+ UINT64 Global:1; // 0 = Not global page, 1 = global page
+ // TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PAT:1; //
+ UINT64 MustBeZero:17; // Must be zero;
+ UINT64 PageTableBaseAddress:22; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code,
+ // 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_1G_ENTRY;
+
+#pragma pack()
+
+#define IA32_PG_P BIT0
+#define IA32_PG_RW BIT1
+#define IA32_PG_PS BIT7
+
+#define PAGING_PAE_INDEX_MASK 0x1FF
+
+#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
+#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
+
+#define PAGING_L1_ADDRESS_SHIFT 12
+#define PAGING_L2_ADDRESS_SHIFT 21
+#define PAGING_L3_ADDRESS_SHIFT 30
+#define PAGING_L4_ADDRESS_SHIFT 39
+
+#define PAGING_PML4E_NUMBER 4
+
+#define PAGETABLE_ENTRY_MASK ((1UL << 9) - 1)
+#define PML4_OFFSET(x) ( (x >> 39) & PAGETABLE_ENTRY_MASK)
+#define PDP_OFFSET(x) ( (x >> 30) & PAGETABLE_ENTRY_MASK)
+#define PDE_OFFSET(x) ( (x >> 21) & PAGETABLE_ENTRY_MASK)
+#define PTE_OFFSET(x) ( (x >> 12) & PAGETABLE_ENTRY_MASK)
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
+
+#define PAGE_TABLE_POOL_ALIGNMENT BASE_2MB
+#define PAGE_TABLE_POOL_UNIT_SIZE SIZE_2MB
+#define PAGE_TABLE_POOL_UNIT_PAGES \
+ EFI_SIZE_TO_PAGES (PAGE_TABLE_POOL_UNIT_SIZE)
+#define PAGE_TABLE_POOL_ALIGN_MASK \
+ (~(EFI_PHYSICAL_ADDRESS)(PAGE_TABLE_POOL_ALIGNMENT - 1))
+
+typedef struct {
+ VOID *NextPool;
+ UINTN Offset;
+ UINTN FreePages;
+} PAGE_TABLE_POOL;
+
+#endif
diff --git a/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouter.c b/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouter.c
new file mode 100644
index 000000000000..0cf2ae73eaad
--- /dev/null
+++ b/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouter.c
@@ -0,0 +1,240 @@
+/** @file
+ This library is BaseCrypto router.
+
+Copyright (c) 2013 - 2021, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "HashLibBaseCryptoRouterCommon.h"
+
+#define TDX_HASH_COUNT 1
+HASH_INTERFACE mHashInterface[TDX_HASH_COUNT] = {{{0}, NULL, NULL, NULL}};
+
+UINTN mHashInterfaceCount = 0;
+HASH_HANDLE mHashCtx[TDX_HASH_COUNT] = {0};
+
+/**
+ Start hash sequence.
+
+ @param HashHandle Hash handle.
+
+ @retval EFI_SUCCESS Hash sequence start and HandleHandle returned.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to start hash.
+**/
+EFI_STATUS
+EFIAPI
+HashStart (
+ OUT HASH_HANDLE *HashHandle
+ )
+{
+ HASH_HANDLE *HashCtx;
+
+ if (mHashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HashCtx = mHashCtx;
+ mHashInterface[0].HashInit (&HashCtx[0]);
+
+ *HashHandle = (HASH_HANDLE)HashCtx;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update hash sequence data.
+
+ @param HashHandle Hash handle.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+
+ @retval EFI_SUCCESS Hash sequence updated.
+**/
+EFI_STATUS
+EFIAPI
+HashUpdate (
+ IN HASH_HANDLE HashHandle,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen
+ )
+{
+ HASH_HANDLE *HashCtx;
+
+ if (mHashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HashCtx = (HASH_HANDLE *)HashHandle;
+ mHashInterface[0].HashUpdate (HashCtx[0], DataToHash, DataToHashLen);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ MRTD => PCR[0]
+ RTMR[0] => PCR[1,7]
+ RTMR[1] => PCR[2,3,4,5,6]
+ RTMR[2] => PCR[8~15]
+ RTMR[3] => NA
+
+**/
+UINT8 GetMappedRtmrIndex(UINT32 PCRIndex)
+{
+ UINT8 RtmrIndex;
+
+ ASSERT (PCRIndex <= 16 && PCRIndex >= 0);
+ RtmrIndex = 0;
+ if (PCRIndex == 1 || PCRIndex == 7) {
+ RtmrIndex = 0;
+ } else if (PCRIndex >= 2 && PCRIndex <= 6) {
+ RtmrIndex = 1;
+ } else if (PCRIndex >= 8 && PCRIndex <= 15) {
+ RtmrIndex = 2;
+ }
+
+ return RtmrIndex;
+}
+
+/**
+ Hash sequence complete and extend to PCR.
+
+ @param HashHandle Hash handle.
+ @param PcrIndex PCR to be extended.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash sequence complete and DigestList is returned.
+**/
+EFI_STATUS
+EFIAPI
+HashCompleteAndExtend (
+ IN HASH_HANDLE HashHandle,
+ IN TPMI_DH_PCR PcrIndex,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen,
+ OUT TPML_DIGEST_VALUES *DigestList
+ )
+{
+ TPML_DIGEST_VALUES Digest;
+ HASH_HANDLE *HashCtx;
+ EFI_STATUS Status;
+
+ if (mHashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HashCtx = (HASH_HANDLE *)HashHandle;
+ ZeroMem (DigestList, sizeof(*DigestList));
+
+ mHashInterface[0].HashUpdate (HashCtx[0], DataToHash, DataToHashLen);
+ mHashInterface[0].HashFinal (HashCtx[0], &Digest);
+ Tpm2SetHashToDigestList (DigestList, &Digest);
+
+ ASSERT(DigestList->count == 1 && DigestList->digests[0].hashAlg == TPM_ALG_SHA384);
+
+ Status = TdExtendRtmr (
+ (UINT32*)DigestList->digests[0].digest.sha384,
+ SHA384_DIGEST_SIZE,
+ GetMappedRtmrIndex(PcrIndex)
+ );
+ return Status;
+}
+
+/**
+ Hash data and extend to PCR.
+
+ @param PcrIndex PCR to be extended.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash data and DigestList is returned.
+**/
+EFI_STATUS
+EFIAPI
+HashAndExtend (
+ IN TPMI_DH_PCR PcrIndex,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen,
+ OUT TPML_DIGEST_VALUES *DigestList
+ )
+{
+ HASH_HANDLE HashHandle;
+ EFI_STATUS Status;
+
+ if (mHashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HashStart (&HashHandle);
+ HashUpdate (HashHandle, DataToHash, DataToHashLen);
+ Status = HashCompleteAndExtend (HashHandle, PcrIndex, NULL, 0, DigestList);
+
+ DEBUG((DEBUG_INFO, "Td: HashAndExtend: %d, %p, 0x%x, %r\n",
+ PcrIndex, DataToHash, DataToHashLen, Status));
+
+ return Status;
+}
+
+/**
+ This service register Hash.
+
+ @param HashInterface Hash interface
+
+ @retval EFI_SUCCESS This hash interface is registered successfully.
+ @retval EFI_UNSUPPORTED System does not support register this interface.
+ @retval EFI_ALREADY_STARTED System already register this interface.
+**/
+EFI_STATUS
+EFIAPI
+RegisterHashInterfaceLib (
+ IN HASH_INTERFACE *HashInterface
+ )
+{
+ UINTN Index;
+ UINT32 HashMask;
+
+ //
+ // Check allow
+ //
+ HashMask = Tpm2GetHashMaskFromAlgo (&HashInterface->HashGuid);
+ ASSERT (HashMask == HASH_ALG_SHA384);
+
+ if (HashMask != HASH_ALG_SHA384) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUG((DEBUG_INFO, "TD: Hash is registered. mask = 0x%x, guid = %g\n", HashMask, HashInterface->HashGuid));
+
+ if (mHashInterfaceCount >= sizeof(mHashInterface)/sizeof(mHashInterface[0])) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Check duplication
+ //
+ for (Index = 0; Index < mHashInterfaceCount; Index++) {
+ if (CompareGuid (&mHashInterface[Index].HashGuid, &HashInterface->HashGuid)) {
+ DEBUG ((DEBUG_ERROR, "Hash Interface (%g) has been registered\n", &HashInterface->HashGuid));
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ CopyMem (&mHashInterface[mHashInterfaceCount], HashInterface, sizeof(*HashInterface));
+ mHashInterfaceCount ++;
+
+ return EFI_SUCCESS;
+}
+
diff --git a/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouter.inf b/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouter.inf
new file mode 100644
index 000000000000..d8124b214b2b
--- /dev/null
+++ b/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouter.inf
@@ -0,0 +1,45 @@
+## @file
+# Provides hash service by registered hash handler in Td guest
+#
+# This library is BaseCrypto router. It will redirect hash request to each individual
+# hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to
+# mask some hash engines.
+#
+# Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HashLibBaseCryptoRouter
+ MODULE_UNI_FILE = HashLibBaseCryptoRouter.uni
+ FILE_GUID = 77F6EA3E-1ABA-4467-A447-926E8CEB2D13
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = HashLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ HashLibBaseCryptoRouterCommon.h
+ HashLibBaseCryptoRouterCommon.c
+ HashLibBaseCryptoRouter.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ PcdLib
+ TdxProbeLib
+ TdxLib
+
diff --git a/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouter.uni b/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouter.uni
new file mode 100644
index 000000000000..29fdd4255ca6
--- /dev/null
+++ b/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouter.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Provides hash service by registered hash handler
+//
+// This library is BaseCrypto router. It will redirect hash request to each individual
+// hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to
+// mask some hash engines.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides hash service by registered hash handler"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is BaseCrypto router. It will redirect hash request to each individual hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to mask some hash engines."
+
diff --git a/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouterCommon.c b/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouterCommon.c
new file mode 100644
index 000000000000..6a58697d977a
--- /dev/null
+++ b/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouterCommon.c
@@ -0,0 +1,67 @@
+/** @file
+ This is BaseCrypto router support function.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+typedef struct {
+ EFI_GUID Guid;
+ UINT32 Mask;
+} TPM2_HASH_MASK;
+
+TPM2_HASH_MASK mTpm2HashMask[] = {
+ {HASH_ALGORITHM_SHA384_GUID, HASH_ALG_SHA384},
+};
+
+/**
+ The function get hash mask info from algorithm.
+
+ @param HashGuid Hash Guid
+
+ @return HashMask
+**/
+UINT32
+EFIAPI
+Tpm2GetHashMaskFromAlgo (
+ IN EFI_GUID *HashGuid
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < sizeof(mTpm2HashMask)/sizeof(mTpm2HashMask[0]); Index++) {
+ if (CompareGuid (HashGuid, &mTpm2HashMask[Index].Guid)) {
+ return mTpm2HashMask[Index].Mask;
+ }
+ }
+ return 0;
+}
+
+/**
+ The function set digest to digest list.
+
+ @param DigestList digest list
+ @param Digest digest data
+**/
+VOID
+EFIAPI
+Tpm2SetHashToDigestList (
+ IN OUT TPML_DIGEST_VALUES *DigestList,
+ IN TPML_DIGEST_VALUES *Digest
+ )
+{
+ CopyMem (
+ &DigestList->digests[DigestList->count],
+ &Digest->digests[0],
+ sizeof(Digest->digests[0])
+ );
+ DigestList->count ++;
+}
diff --git a/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouterCommon.h b/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouterCommon.h
new file mode 100644
index 000000000000..6af53aa206a7
--- /dev/null
+++ b/OvmfPkg/Library/HashLibBaseCryptoRouterTdx/HashLibBaseCryptoRouterCommon.h
@@ -0,0 +1,38 @@
+/** @file
+ This is BaseCrypto router support function definition.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _HASH_LIB_BASE_CRYPTO_ROUTER_COMMON_H_
+#define _HASH_LIB_BASE_CRYPTO_ROUTER_COMMON_H_
+
+/**
+ The function get hash mask info from algorithm.
+
+ @param HashGuid Hash Guid
+
+ @return HashMask
+**/
+UINT32
+EFIAPI
+Tpm2GetHashMaskFromAlgo (
+ IN EFI_GUID *HashGuid
+ );
+
+/**
+ The function set digest to digest list.
+
+ @param DigestList digest list
+ @param Digest digest data
+**/
+VOID
+EFIAPI
+Tpm2SetHashToDigestList (
+ IN OUT TPML_DIGEST_VALUES *DigestList,
+ IN TPML_DIGEST_VALUES *Digest
+ );
+
+#endif
diff --git a/OvmfPkg/Library/PrePiLibTdx/FwVol.c b/OvmfPkg/Library/PrePiLibTdx/FwVol.c
new file mode 100644
index 000000000000..474d48306464
--- /dev/null
+++ b/OvmfPkg/Library/PrePiLibTdx/FwVol.c
@@ -0,0 +1,978 @@
+/** @file
+ Implementation of the 6 PEI Ffs (FV) APIs in library form.
+
+ This code only knows about a FV if it has a EFI_HOB_TYPE_FV entry in the HOB list
+
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+#include
+
+#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
+ (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))
+
+#define MAX_FV_IMAGES 8
+/**
+ Returns the highest bit set of the State field
+
+ @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY
+ in the Attributes field.
+ @param FfsHeader Pointer to FFS File Header
+
+
+ @retval the highest bit in the State field
+
+**/
+STATIC
+EFI_FFS_FILE_STATE
+GetFileState(
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ EFI_FFS_FILE_STATE HighestBit;
+
+ FileState = FfsHeader->State;
+
+ if (ErasePolarity != 0) {
+ FileState = (EFI_FFS_FILE_STATE)~FileState;
+ }
+
+ HighestBit = 0x80;
+ while (HighestBit != 0 && (HighestBit & FileState) == 0) {
+ HighestBit >>= 1;
+ }
+
+ return HighestBit;
+}
+
+
+/**
+ Calculates the checksum of the header of a file.
+ The header is a zero byte checksum, so zero means header is good
+
+ @param FfsHeader Pointer to FFS File Header
+
+ @retval Checksum of the header
+
+**/
+STATIC
+UINT8
+CalculateHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FileHeader
+ )
+{
+ UINT8 *Ptr;
+ UINTN Index;
+ UINT8 Sum;
+
+ Sum = 0;
+ Ptr = (UINT8 *)FileHeader;
+
+ for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER) - 3; Index += 4) {
+ Sum = (UINT8)(Sum + Ptr[Index]);
+ Sum = (UINT8)(Sum + Ptr[Index+1]);
+ Sum = (UINT8)(Sum + Ptr[Index+2]);
+ Sum = (UINT8)(Sum + Ptr[Index+3]);
+ }
+
+ for (; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) {
+ Sum = (UINT8)(Sum + Ptr[Index]);
+ }
+
+ //
+ // State field (since this indicates the different state of file).
+ //
+ Sum = (UINT8)(Sum - FileHeader->State);
+ //
+ // Checksum field of the file is not part of the header checksum.
+ //
+ Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File);
+
+ return Sum;
+}
+
+
+/**
+ Given a FileHandle return the VolumeHandle
+
+ @param FileHandle File handle to look up
+ @param VolumeHandle Match for FileHandle
+
+ @retval TRUE VolumeHandle is valid
+
+**/
+STATIC
+BOOLEAN
+EFIAPI
+FileHandleToVolume (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_PEI_FV_HANDLE *VolumeHandle
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_PEI_HOB_POINTERS Hob;
+
+ Hob.Raw = GetHobList ();
+ if (Hob.Raw == NULL) {
+ return FALSE;
+ }
+
+ do {
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);
+ if (Hob.Raw != NULL) {
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(Hob.FirmwareVolume->BaseAddress);
+ if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) && \
+ ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) {
+ *VolumeHandle = (EFI_PEI_FV_HANDLE)FwVolHeader;
+ return TRUE;
+ }
+
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));
+ }
+ } while (Hob.Raw != NULL);
+
+ return FALSE;
+}
+
+
+
+/**
+ Given the input file pointer, search for the next matching file in the
+ FFS volume as defined by SearchType. The search starts from FileHeader inside
+ the Firmware Volume defined by FwVolHeader.
+
+ @param FileHandle File handle to look up
+ @param VolumeHandle Match for FileHandle
+
+
+**/
+EFI_STATUS
+FindFileEx (
+ IN CONST EFI_PEI_FV_HANDLE FvHandle,
+ IN CONST EFI_GUID *FileName, OPTIONAL
+ IN EFI_FV_FILETYPE SearchType,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FFS_FILE_HEADER **FileHeader;
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;
+ UINT32 FileLength;
+ UINT32 FileOccupiedSize;
+ UINT32 FileOffset;
+ UINT64 FvLength;
+ UINT8 ErasePolarity;
+ UINT8 FileState;
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvHandle;
+ FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle;
+
+ FvLength = FwVolHeader->FvLength;
+ if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ ErasePolarity = 1;
+ } else {
+ ErasePolarity = 0;
+ }
+
+ //
+ // If FileHeader is not specified (NULL) or FileName is not NULL,
+ // start with the first file in the firmware volume. Otherwise,
+ // start from the FileHeader.
+ //
+ if ((*FileHeader == NULL) || (FileName != NULL)) {
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength);
+ if (FwVolHeader->ExtHeaderOffset != 0) {
+ FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)FwVolHeader) + FwVolHeader->ExtHeaderOffset);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FwVolExHeaderInfo) + FwVolExHeaderInfo->ExtHeaderSize);
+ }
+ } else {
+ //
+ // Length is 24 bits wide so mask upper 8 bits
+ // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.
+ //
+ FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF;
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize);
+ }
+
+ // FFS files begin with a header that is aligned on an 8-byte boundary
+ FfsFileHeader = ALIGN_POINTER (FfsFileHeader, 8);
+
+ FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);
+ ASSERT (FileOffset <= 0xFFFFFFFF);
+
+ while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
+ //
+ // Get FileState which is the highest bit of the State
+ //
+ FileState = GetFileState (ErasePolarity, FfsFileHeader);
+
+ switch (FileState) {
+
+ case EFI_FILE_HEADER_INVALID:
+ FileOffset += sizeof(EFI_FFS_FILE_HEADER);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER));
+ break;
+
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ if (CalculateHeaderChecksum (FfsFileHeader) != 0) {
+ ASSERT (FALSE);
+ *FileHeader = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
+ FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
+
+ if (FileName != NULL) {
+ if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) {
+ *FileHeader = FfsFileHeader;
+ return EFI_SUCCESS;
+ }
+ } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) &&
+ (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) {
+ *FileHeader = FfsFileHeader;
+ return EFI_SUCCESS;
+ }
+
+ FileOffset += FileOccupiedSize;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
+ break;
+
+ case EFI_FILE_DELETED:
+ FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
+ FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
+ FileOffset += FileOccupiedSize;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
+ break;
+
+ default:
+ *FileHeader = NULL;
+ return EFI_NOT_FOUND;
+ }
+ }
+
+
+ *FileHeader = NULL;
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Go through the file to search SectionType section,
+ when meeting an encapsuled section.
+
+ @param SectionType - Filter to find only section of this type.
+ @param Section - From where to search.
+ @param SectionSize - The file size to search.
+ @param OutputBuffer - Pointer to the section to search.
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+FfsProcessSection (
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_COMMON_SECTION_HEADER *Section,
+ IN UINTN SectionSize,
+ IN OUT UINT32 *SectionDatas,
+ IN OUT UINT32 *SectionCnt
+ )
+{
+ EFI_STATUS Status;
+ UINT32 SectionLength;
+ UINT32 ParsedLength;
+ EFI_COMPRESSION_SECTION *CompressionSection;
+ EFI_COMPRESSION_SECTION2 *CompressionSection2;
+ UINT32 DstBufferSize;
+ VOID *ScratchBuffer;
+ UINT32 ScratchBufferSize;
+ VOID *DstBuffer;
+ CHAR8 *CompressedData;
+ UINT32 CompressedDataLength;
+ UINT16 SectionAttribute;
+ UINT32 AuthenticationStatus;
+ UINT32 Cnt;
+ UINT32 MaxCnt;
+
+ Cnt = 0;
+ MaxCnt = *SectionCnt;
+ ParsedLength = 0;
+ Status = EFI_NOT_FOUND;
+
+ while (ParsedLength < SectionSize && Cnt < MaxCnt) {
+ if (IS_SECTION2 (Section)) {
+ ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
+ }
+
+ if (Section->Type == SectionType) {
+
+ if (IS_SECTION2 (Section)) {
+ *(SectionDatas + Cnt++) = (UINT32)(UINTN)(VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2));
+ } else {
+ *(SectionDatas + Cnt++) = (UINT32)(UINTN)(VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER));
+ }
+ DEBUG((DEBUG_INFO, "Find Section with type(0x%x) size(0x%x)\n", SectionType, *(UINT32*)(Section->Size) & 0x00ffffff));
+
+ } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) {
+
+ if (Section->Type == EFI_SECTION_COMPRESSION) {
+ if (IS_SECTION2 (Section)) {
+ CompressionSection2 = (EFI_COMPRESSION_SECTION2 *) Section;
+ SectionLength = SECTION2_SIZE (Section);
+
+ if (CompressionSection2->CompressionType != EFI_STANDARD_COMPRESSION) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION2 *) Section + 1);
+ CompressedDataLength = (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION2);
+ } else {
+ CompressionSection = (EFI_COMPRESSION_SECTION *) Section;
+ SectionLength = SECTION_SIZE (Section);
+
+ if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1);
+ CompressedDataLength = (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION);
+ }
+
+ Status = UefiDecompressGetInfo (
+ CompressedData,
+ CompressedDataLength,
+ &DstBufferSize,
+ &ScratchBufferSize
+ );
+ } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {
+ Status = ExtractGuidedSectionGetInfo (
+ Section,
+ &DstBufferSize,
+ &ScratchBufferSize,
+ &SectionAttribute
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // GetInfo failed
+ //
+ DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Allocate scratch buffer
+ //
+ ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
+ if (ScratchBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Allocate destination buffer, extra one page for adjustment
+ //
+ DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);
+ if (DstBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header
+ // to make section data at page alignment.
+ //
+ if (IS_SECTION2 (Section))
+ DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER2);
+ else
+ DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
+ //
+ // Call decompress function
+ //
+ if (Section->Type == EFI_SECTION_COMPRESSION) {
+ if (IS_SECTION2 (Section)) {
+ CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION2 *) Section + 1);
+ }
+ else {
+ CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1);
+ }
+
+ Status = UefiDecompress (
+ CompressedData,
+ DstBuffer,
+ ScratchBuffer
+ );
+ } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {
+ Status = ExtractGuidedSectionDecode (
+ Section,
+ &DstBuffer,
+ ScratchBuffer,
+ &AuthenticationStatus
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Decompress failed
+ //
+ DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status));
+ return EFI_NOT_FOUND;
+ } else {
+ DEBUG((DEBUG_INFO, "Decompress success\n"));
+ return FfsProcessSection (
+ SectionType,
+ DstBuffer,
+ DstBufferSize,
+ SectionDatas,
+ SectionCnt
+ );
+ }
+ }
+
+ if (IS_SECTION2 (Section)) {
+ SectionLength = SECTION2_SIZE (Section);
+ } else {
+ SectionLength = SECTION_SIZE (Section);
+ }
+ //
+ // SectionLength is adjusted it is 4 byte aligned.
+ // Go to the next section
+ //
+ SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
+ ASSERT (SectionLength != 0);
+ ParsedLength += SectionLength;
+ Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
+ }
+
+ *SectionCnt = Cnt;
+
+ return Cnt == 0 ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+
+
+/**
+ This service enables discovery sections of a given type within a valid FFS file.
+
+ @param SearchType The value of the section type to find.
+ @param FfsFileHeader A pointer to the file header that contains the set of sections to
+ be searched.
+ @param SectionData A pointer to the discovered section, if successful.
+
+ @retval EFI_SUCCESS The section was found.
+ @retval EFI_NOT_FOUND The section was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsFindSectionData (
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData
+ )
+{
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ UINT32 FileSize;
+ EFI_COMMON_SECTION_HEADER *Section;
+ EFI_STATUS Status;
+ UINT32 SectionDatas[1];
+ UINT32 MaxSectionCnt;
+
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
+ MaxSectionCnt = 1;
+
+ //
+ // Size is 24 bits wide so mask upper 8 bits.
+ // Does not include FfsFileHeader header size
+ // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
+ //
+ Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);
+ FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
+ FileSize -= sizeof (EFI_FFS_FILE_HEADER);
+
+ Status = FfsProcessSection (
+ SectionType,
+ Section,
+ FileSize,
+ SectionDatas,
+ &MaxSectionCnt
+ );
+
+ if(Status == EFI_SUCCESS){
+ ASSERT(MaxSectionCnt == 1);
+ *SectionData = (VOID *)(UINTN)SectionDatas[0];
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FfsFindSectionDataEx (
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT UINT32 *SectionDatas,
+ OUT UINT32 *SectionCnt
+ )
+{
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ UINT32 FileSize;
+ EFI_COMMON_SECTION_HEADER *Section;
+
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
+
+ //
+ // Size is 24 bits wide so mask upper 8 bits.
+ // Does not include FfsFileHeader header size
+ // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
+ //
+ Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);
+ FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
+ FileSize -= sizeof (EFI_FFS_FILE_HEADER);
+
+ return FfsProcessSection (
+ SectionType,
+ Section,
+ FileSize,
+ SectionDatas,
+ SectionCnt
+ );
+}
+
+
+/**
+ This service enables discovery of additional firmware files.
+
+ @param SearchType A filter to find files only of this type.
+ @param FwVolHeader Pointer to the firmware volume header of the volume to search.
+ This parameter must point to a valid FFS volume.
+ @param FileHeader Pointer to the current file from which to begin searching.
+
+ @retval EFI_SUCCESS The file was found.
+ @retval EFI_NOT_FOUND The file was not found.
+ @retval EFI_NOT_FOUND The header checksum was not zero.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsFindNextFile (
+ IN UINT8 SearchType,
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle);
+}
+
+
+/**
+ This service enables discovery of additional firmware volumes.
+
+ @param Instance This instance of the firmware volume to find. The value 0 is the
+ Boot Firmware Volume (BFV).
+ @param FwVolHeader Pointer to the firmware volume header of the volume to return.
+
+ @retval EFI_SUCCESS The volume was found.
+ @retval EFI_NOT_FOUND The volume was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsFindNextVolume (
+ IN UINTN Instance,
+ IN OUT EFI_PEI_FV_HANDLE *VolumeHandle
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+
+
+ Hob.Raw = GetHobList ();
+ if (Hob.Raw == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ do {
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);
+ if (Hob.Raw != NULL) {
+ if (Instance-- == 0) {
+ *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress);
+ return EFI_SUCCESS;
+ }
+
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));
+ }
+ } while (Hob.Raw != NULL);
+
+ return EFI_NOT_FOUND;
+
+}
+
+
+/**
+ Find a file in the volume by name
+
+ @param FileName A pointer to the name of the file to
+ find within the firmware volume.
+
+ @param VolumeHandle The firmware volume to search FileHandle
+ Upon exit, points to the found file's
+ handle or NULL if it could not be found.
+
+ @retval EFI_SUCCESS File was found.
+
+ @retval EFI_NOT_FOUND File was not found.
+
+ @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or
+ FileName was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsFindFileByName (
+ IN CONST EFI_GUID *FileName,
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ EFI_STATUS Status;
+ if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle);
+ if (Status == EFI_NOT_FOUND) {
+ *FileHandle = NULL;
+ }
+ return Status;
+}
+
+
+
+
+/**
+ Get information about the file by name.
+
+ @param FileHandle Handle of the file.
+
+ @param FileInfo Upon exit, points to the file's
+ information.
+
+ @retval EFI_SUCCESS File information returned.
+
+ @retval EFI_INVALID_PARAMETER If FileHandle does not
+ represent a valid file.
+
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsGetFileInfo (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO *FileInfo
+ )
+{
+ UINT8 FileState;
+ UINT8 ErasePolarity;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+
+ if ((FileHandle == NULL) || (FileInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VolumeHandle = 0;
+ //
+ // Retrieve the FirmwareVolume which the file resides in.
+ //
+ if (!FileHandleToVolume(FileHandle, &VolumeHandle)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER*)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ ErasePolarity = 1;
+ } else {
+ ErasePolarity = 0;
+ }
+
+ //
+ // Get FileState which is the highest bit of the State
+ //
+ FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle);
+
+ switch (FileState) {
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
+ CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID));
+ FileInfo->FileType = FileHeader->Type;
+ FileInfo->FileAttributes = FileHeader->Attributes;
+ FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);
+ FileInfo->Buffer = (FileHeader + 1);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get Information about the volume by name
+
+ @param VolumeHandle Handle of the volume.
+
+ @param VolumeInfo Upon exit, points to the volume's
+ information.
+
+ @retval EFI_SUCCESS File information returned.
+
+ @retval EFI_INVALID_PARAMETER If FileHandle does not
+ represent a valid file.
+
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsGetVolumeInfo (
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ OUT EFI_FV_INFO *VolumeInfo
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;
+
+ if (VolumeInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // VolumeHandle may not align at 8 byte,
+ // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.
+ // So, Copy FvHeader into the local FvHeader structure.
+ //
+ CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+ //
+ // Check Fv Image Signature
+ //
+ if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ VolumeInfo->FvAttributes = FwVolHeader.Attributes;
+ VolumeInfo->FvStart = (VOID *) VolumeHandle;
+ VolumeInfo->FvSize = FwVolHeader.FvLength;
+ CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID));
+
+ if (FwVolHeader.ExtHeaderOffset != 0) {
+ FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset);
+ CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID));
+ }
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Search through every FV until you find a file of type FileType
+
+ @param FileType File handle of a Fv type file.
+ @param Volumehandle On success Volume Handle of the match
+ @param FileHandle On success File Handle of the match
+
+ @retval EFI_NOT_FOUND FV image can't be found.
+ @retval EFI_SUCCESS Successfully found FileType
+
+**/
+EFI_STATUS
+EFIAPI
+FfsAnyFvFindFirstFile (
+ IN EFI_FV_FILETYPE FileType,
+ OUT EFI_PEI_FV_HANDLE *VolumeHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN Instance;
+
+ //
+ // Search every FV for the DXE Core
+ //
+ Instance = 0;
+ *FileHandle = NULL;
+
+ while (1)
+ {
+ Status = FfsFindNextVolume (Instance++, VolumeHandle);
+ if (EFI_ERROR (Status))
+ {
+ break;
+ }
+
+ Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle);
+ if (!EFI_ERROR (Status))
+ {
+ break;
+ }
+ }
+
+ DEBUG((DEBUG_INFO, "FfsAnyFvFindFirstFile with FileType = 0x%x (DXE_CORE == 0x05). %r\n", FileType, Status));
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FfsAnyFvFindFileByName (
+ IN CONST EFI_GUID *Name,
+ OUT EFI_PEI_FV_HANDLE *VolumeHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN Instance;
+
+ //
+ // Search every FV for the DXE Core
+ //
+ Instance = 0;
+ *FileHandle = NULL;
+
+ while (1)
+ {
+ Status = FfsFindNextVolume (Instance++, VolumeHandle);
+ if (EFI_ERROR (Status))
+ {
+ break;
+ }
+
+ Status = FfsFindFileByName (Name, *VolumeHandle, FileHandle);
+ if (!EFI_ERROR (Status))
+ {
+ break;
+ }
+ }
+
+ DEBUG((DEBUG_INFO, "FfsAnyFvFindFileByName with name = %g, %r\n", Name, Status));
+
+ return Status;
+}
+
+
+/**
+ Get Fv image from the FV type file, then add FV & FV2 Hob.
+
+ @param FileHandle File handle of a Fv type file.
+
+
+ @retval EFI_NOT_FOUND FV image can't be found.
+ @retval EFI_SUCCESS Successfully to process it.
+
+**/
+EFI_STATUS
+EFIAPI
+FfsProcessFvFile (
+ IN EFI_PEI_FILE_HANDLE FvFileHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_FV_INFO FvImageInfo;
+ UINT32 FvAlignment;
+ VOID *FvBuffer;
+ EFI_PEI_HOB_POINTERS HobFv2;
+ UINT32 FvImagesCnt;
+ UINT32 FvImageHandles[MAX_FV_IMAGES];
+ UINT32 Index;
+
+ //
+ // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
+ // been extracted.
+ //
+ HobFv2.Raw = GetHobList ();
+ while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
+
+ if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) {
+ //
+ // this FILE has been dispatched, it will not be dispatched again.
+ //
+ return EFI_SUCCESS;
+ }
+ HobFv2.Raw = GET_NEXT_HOB (HobFv2);
+ }
+
+ //
+ // Find FvImage in FvFile
+ // In FvFile there may be multi FvImages
+ //
+ FvImagesCnt = MAX_FV_IMAGES;
+ Status = FfsFindSectionDataEx (EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
+ FvFileHandle,
+ FvImageHandles,
+ &FvImagesCnt);
+ if (EFI_ERROR (Status)) {
+ ASSERT(FALSE);
+ return Status;
+ }
+
+ DEBUG((DEBUG_INFO, "Collect FvImageInfo\n"));
+ for(Index=0; Index < FvImagesCnt; Index++){
+
+ //
+ // Collect FvImage Info.
+ //
+
+ ZeroMem (&FvImageInfo, sizeof (FvImageInfo));
+ Status = FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE)((UINTN)FvImageHandles[Index]), &FvImageInfo);
+ ASSERT_EFI_ERROR(Status);
+ DEBUG((DEBUG_INFO, " Fv Name=%g, Format=%g, Size=0x%x\n", FvImageInfo.FvName, FvImageInfo.FvFormat, FvImageInfo.FvSize));
+
+ //
+ // FvAlignment must be more than 8 bytes required by FvHeader structure.
+ //
+ FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);
+ if (FvAlignment < 8) {
+ FvAlignment = 8;
+ }
+
+ //
+ // Check FvImage
+ //
+ if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) {
+ FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment);
+ if (FvBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize);
+ //
+ // Update FvImageInfo after reload FvImage to new aligned memory
+ //
+ FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo);
+ }
+
+
+ //
+ // Inform HOB consumer phase, i.e. DXE core, the existence of this FV
+ //
+ BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, FvImageInfo.FvSize);
+
+ //
+ // Makes the encapsulated volume show up in DXE phase to skip processing of
+ // encapsulated file again.
+ //
+ BuildFv2Hob (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart,
+ FvImageInfo.FvSize,
+ &FvImageInfo.FvName,
+ &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name)
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
diff --git a/OvmfPkg/Library/PrePiLibTdx/PrePi.h b/OvmfPkg/Library/PrePiLibTdx/PrePi.h
new file mode 100644
index 000000000000..340daef6ed09
--- /dev/null
+++ b/OvmfPkg/Library/PrePiLibTdx/PrePi.h
@@ -0,0 +1,29 @@
+/** @file
+ Library that helps implement monolithic PEI (i.e. PEI part of SEC)
+
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PI_PEI_H_
+#define _PI_PEI_H_
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#endif
diff --git a/OvmfPkg/Library/PrePiLibTdx/PrePiLib.c b/OvmfPkg/Library/PrePiLibTdx/PrePiLib.c
new file mode 100644
index 000000000000..1ff83b28d1c4
--- /dev/null
+++ b/OvmfPkg/Library/PrePiLibTdx/PrePiLib.c
@@ -0,0 +1,251 @@
+/** @file
+
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+
+//
+// Hack to work in NT32
+//
+EFI_STATUS
+
+EFIAPI
+
+SecWinNtPeiLoadFile (
+ IN VOID *Pe32Data,
+ IN EFI_PHYSICAL_ADDRESS *ImageAddress,
+ IN UINT64 *ImageSize,
+ IN EFI_PHYSICAL_ADDRESS *EntryPoint
+ );
+
+STATIC
+VOID*
+EFIAPI
+AllocateCodePages (
+ IN UINTN Pages
+ )
+{
+ VOID *Alloc;
+ EFI_PEI_HOB_POINTERS Hob;
+
+ Alloc = AllocatePages (Pages);
+ if (Alloc == NULL) {
+ return NULL;
+ }
+
+ // find the HOB we just created, and change the type to EfiBootServicesCode
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ if (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress == (UINTN)Alloc) {
+ Hob.MemoryAllocation->AllocDescriptor.MemoryType = EfiBootServicesCode;
+ return Alloc;
+ }
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (Hob));
+ }
+
+ ASSERT (FALSE);
+
+ FreePages (Alloc, Pages);
+ return NULL;
+}
+
+
+EFI_STATUS
+EFIAPI
+LoadPeCoffImage (
+ IN VOID *PeCoffImage,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
+ OUT UINT64 *ImageSize,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint
+ )
+{
+ RETURN_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ VOID *Buffer;
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+
+ ImageContext.Handle = PeCoffImage;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ ASSERT_EFI_ERROR (Status);
+
+
+ //
+ // Allocate Memory for the image
+ //
+ Buffer = AllocateCodePages (EFI_SIZE_TO_PAGES((UINT32)ImageContext.ImageSize));
+ ASSERT (Buffer != 0);
+
+
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ ASSERT_EFI_ERROR (Status);
+
+
+ *ImageAddress = ImageContext.ImageAddress;
+ *ImageSize = ImageContext.ImageSize;
+ *EntryPoint = ImageContext.EntryPoint;
+
+ //
+ // Flush not needed for all architectures. We could have a processor specific
+ // function in this library that does the no-op if needed.
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)*ImageAddress, (UINTN)*ImageSize);
+
+ return Status;
+}
+
+
+
+typedef
+VOID
+(EFIAPI *DXE_CORE_ENTRY_POINT) (
+ IN VOID *HobStart
+ );
+
+EFI_STATUS
+EFIAPI
+LoadDxeCoreFromFfsFile (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINTN StackSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *PeCoffImage;
+ EFI_PHYSICAL_ADDRESS ImageAddress;
+ UINT64 ImageSize;
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+ VOID *BaseOfStack;
+ VOID *TopOfStack;
+ VOID *Hob;
+ EFI_FV_FILE_INFO FvFileInfo;
+
+ Status = FfsFindSectionData (EFI_SECTION_PE32, FileHandle, &PeCoffImage);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+
+ Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint);
+// For NT32 Debug Status = SecWinNtPeiLoadFile (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Extract the DxeCore GUID file name.
+ //
+ Status = FfsGetFileInfo (FileHandle, &FvFileInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ BuildModuleHob (&FvFileInfo.FileName, (EFI_PHYSICAL_ADDRESS)(UINTN)ImageAddress, EFI_SIZE_TO_PAGES ((UINT32) ImageSize) * EFI_PAGE_SIZE, EntryPoint);
+
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading DxeCore at 0x%10p EntryPoint=0x%10p\n", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)EntryPoint));
+
+ Hob = GetHobList ();
+ if (StackSize == 0) {
+ // User the current stack
+
+ ((DXE_CORE_ENTRY_POINT)(UINTN)EntryPoint) (Hob);
+ } else {
+
+ //
+ // Allocate 128KB for the Stack
+ //
+ BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (StackSize));
+ ASSERT (BaseOfStack != NULL);
+
+ //
+ // Compute the top of the stack we were allocated. Pre-allocate a UINTN
+ // for safety.
+ //
+ TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (StackSize) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
+ TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
+
+ //
+ // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
+ //
+ UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, StackSize);
+
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)EntryPoint,
+ Hob,
+ NULL,
+ TopOfStack
+ );
+
+ }
+
+ // Should never get here as DXE Core does not return
+ DEBUG ((EFI_D_ERROR, "DxeCore returned\n"));
+ ASSERT (FALSE);
+
+ return EFI_DEVICE_ERROR;
+}
+
+
+
+EFI_STATUS
+EFIAPI
+LoadDxeCoreFromFv (
+ IN UINTN *FvInstance, OPTIONAL
+ IN UINTN StackSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_PEI_FILE_HANDLE FileHandle = NULL;
+
+ if (FvInstance != NULL) {
+ //
+ // Caller passed in a specific FV to try, so only try that one
+ //
+ Status = FfsFindNextVolume (*FvInstance, &VolumeHandle);
+ if (!EFI_ERROR (Status)) {
+ Status = FfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE, VolumeHandle, &FileHandle);
+ }
+ } else {
+ Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, &FileHandle);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ return LoadDxeCoreFromFfsFile (FileHandle, StackSize);
+ }
+
+ return Status;
+}
+
+
+EFI_STATUS
+EFIAPI
+DecompressFirstFv (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_PEI_FILE_HANDLE FileHandle;
+
+ Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, &VolumeHandle, &FileHandle);
+ if (!EFI_ERROR (Status)) {
+ Status = FfsProcessFvFile (FileHandle);
+ }
+
+ return Status;
+}
+
+
diff --git a/OvmfPkg/Library/PrePiLibTdx/PrePiLibTdx.inf b/OvmfPkg/Library/PrePiLibTdx/PrePiLibTdx.inf
new file mode 100644
index 000000000000..09cdef3a31b8
--- /dev/null
+++ b/OvmfPkg/Library/PrePiLibTdx/PrePiLibTdx.inf
@@ -0,0 +1,51 @@
+#/** @file
+# Component description file for TDX Pre PI Library
+#
+# LIbrary helps you build a platform that skips PEI and loads DXE Core
+# directly. Helps building HOBs, reading data from the FV, and doing
+# decompression.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2008, Apple Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PrePiLibTdx
+ FILE_GUID = 1F3A3278-82EB-4C0D-86F1-5BCDA5846CB2
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PrePiLib
+
+
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources.common]
+ PrePi.h
+ FwVol.c
+ PrePiLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ UefiDecompressLib
+ PeCoffLib
+ CacheMaintenanceLib
+ PrintLib
+ SerialPortLib
+ TimerLib
+ PerformanceLib
+ HobLib
+ ExtractGuidedSectionLib
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
index 0182c9235cac..9f8ae1227b16 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include "QemuFwCfgLibInternal.h"
@@ -85,7 +86,7 @@ QemuFwCfgInitialize (
DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
}
- if (mQemuFwCfgDmaSupported && MemEncryptSevIsEnabled ()) {
+ if (mQemuFwCfgDmaSupported && (MemEncryptSevIsEnabled () || (MemEncryptTdxIsEnabled ()))) {
EFI_STATUS Status;
//
@@ -96,7 +97,7 @@ QemuFwCfgInitialize (
(VOID **)&mIoMmuProtocol);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR,
- "QemuFwCfgSevDma %a:%a Failed to locate IOMMU protocol.\n",
+ "QemuFwCfgDma %a:%a Failed to locate IOMMU protocol.\n",
gEfiCallerBaseName, __FUNCTION__));
ASSERT (FALSE);
CpuDeadLoop ();
@@ -371,10 +372,10 @@ InternalQemuFwCfgDmaBytes (
DataBuffer = Buffer;
//
- // When SEV is enabled, map Buffer to DMA address before issuing the DMA
+ // When memory encryption is enabled, map Buffer to DMA address before issuing the DMA
// request
//
- if (MemEncryptSevIsEnabled ()) {
+ if (MemEncryptSevIsEnabled() || MemEncryptTdxIsEnabled ()) {
VOID *AccessBuffer;
EFI_PHYSICAL_ADDRESS DataBufferAddress;
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf
index 48899ff1236a..b89a12ca31cb 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf
@@ -42,6 +42,7 @@
DebugLib
IoLib
MemoryAllocationLib
+ MemEncryptTdxLib
MemEncryptSevLib
[Protocols]
diff --git a/OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf b/OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
index 10f41d64c6a1..da342286db27 100644
--- a/OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+++ b/OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
@@ -36,6 +36,7 @@
MemoryAllocationLib
QemuFwCfgLib
UefiBootServicesTableLib
+ TdxProbeLib
[Protocols]
gEfiS3SaveStateProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf b/OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
index 8268828a7615..0b2643091050 100644
--- a/OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
+++ b/OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
@@ -37,3 +37,4 @@
[LibraryClasses]
DebugLib
QemuFwCfgLib
+ TdxProbeLib
diff --git a/OvmfPkg/Library/QemuFwCfgS3Lib/QemuFwCfgS3PeiDxe.c b/OvmfPkg/Library/QemuFwCfgS3Lib/QemuFwCfgS3PeiDxe.c
index 5557c70aa3ad..4fca19edf0b4 100644
--- a/OvmfPkg/Library/QemuFwCfgS3Lib/QemuFwCfgS3PeiDxe.c
+++ b/OvmfPkg/Library/QemuFwCfgS3Lib/QemuFwCfgS3PeiDxe.c
@@ -9,6 +9,7 @@
#include
#include
+#include
/**
Determine if S3 support is explicitly enabled.
@@ -27,16 +28,23 @@ QemuFwCfgS3Enabled (
VOID
)
{
- RETURN_STATUS Status;
- FIRMWARE_CONFIG_ITEM FwCfgItem;
- UINTN FwCfgSize;
- UINT8 SystemStates[6];
+ RETURN_STATUS Status;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ UINT8 SystemStates[6];
- Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize);
- if (Status != RETURN_SUCCESS || FwCfgSize != sizeof SystemStates) {
+ if (ProbeTdGuest()) {
+
return FALSE;
+
+ } else {
+
+ Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize);
+ if (Status != RETURN_SUCCESS || FwCfgSize != sizeof SystemStates) {
+ return FALSE;
+ }
+ QemuFwCfgSelectItem (FwCfgItem);
+ QemuFwCfgReadBytes (sizeof SystemStates, SystemStates);
+ return (BOOLEAN) (SystemStates[3] & BIT7);
}
- QemuFwCfgSelectItem (FwCfgItem);
- QemuFwCfgReadBytes (sizeof SystemStates, SystemStates);
- return (BOOLEAN) (SystemStates[3] & BIT7);
}
diff --git a/OvmfPkg/Library/TdvfPlatformLibQemu/Platform.c b/OvmfPkg/Library/TdvfPlatformLibQemu/Platform.c
new file mode 100644
index 000000000000..1c9aa92f9319
--- /dev/null
+++ b/OvmfPkg/Library/TdvfPlatformLibQemu/Platform.c
@@ -0,0 +1,270 @@
+/**@file
+ Platform PEI driver
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+ Copyright (c) 2011, Andrei Warkentin
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include
+
+//
+// The Library classes this module consumes
+//
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+
+//
+// Host Bridge DID Address
+//
+#define HOSTBRIDGE_DID \
+ PCI_LIB_ADDRESS (0, 0, 0, PCI_DEVICE_ID_OFFSET)
+
+//
+// Values we program into the PM base address registers
+//
+#define PIIX4_PMBA_VALUE 0xB000
+#define ICH9_PMBASE_VALUE 0x0600
+
+EFI_STATUS
+GetNamedFwCfgBoolean (
+ IN CHAR8 *FwCfgFileName,
+ OUT BOOLEAN *Setting
+ )
+{
+ EFI_STATUS Status;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ UINT8 Value[3];
+
+ Status = QemuFwCfgFindFile (FwCfgFileName, &FwCfgItem, &FwCfgSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (FwCfgSize > sizeof Value) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ QemuFwCfgSelectItem (FwCfgItem);
+ QemuFwCfgReadBytes (FwCfgSize, Value);
+
+ if ((FwCfgSize == 1) ||
+ (FwCfgSize == 2 && Value[1] == '\n') ||
+ (FwCfgSize == 3 && Value[1] == '\r' && Value[2] == '\n')) {
+ switch (Value[0]) {
+ case '0':
+ case 'n':
+ case 'N':
+ *Setting = FALSE;
+ return EFI_SUCCESS;
+
+ case '1':
+ case 'y':
+ case 'Y':
+ *Setting = TRUE;
+ return EFI_SUCCESS;
+
+ default:
+ break;
+ }
+ }
+ return EFI_PROTOCOL_ERROR;
+}
+
+VOID
+PciExBarInitialization (
+ VOID
+ )
+{
+ union {
+ UINT64 Uint64;
+ UINT32 Uint32[2];
+ } PciExBarBase;
+
+ //
+ // We only support the 256MB size for the MMCONFIG area:
+ // 256 buses * 32 devices * 8 functions * 4096 bytes config space.
+ //
+ // The masks used below enforce the Q35 requirements that the MMCONFIG area
+ // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.
+ //
+ // Note that (b) also ensures that the minimum address width we have
+ // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice
+ // for DXE's page tables to cover the MMCONFIG area.
+ //
+ PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);
+ ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);
+ ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);
+
+ //
+ // Clear the PCIEXBAREN bit first, before programming the high register.
+ //
+ PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);
+
+ //
+ // Program the high register. Then program the low register, setting the
+ // MMCONFIG area size and enabling decoding at once.
+ //
+ PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);
+ PciWrite32 (
+ DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),
+ PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN
+ );
+}
+
+VOID
+MiscInitialization (
+ EFI_HOB_PLATFORM_INFO *PlatformInfoHob
+ )
+{
+ RETURN_STATUS Status;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ UINTN PmCmd;
+ UINTN Pmba;
+ UINT32 PmbaAndVal;
+ UINT32 PmbaOrVal;
+ UINTN AcpiCtlReg;
+ UINT8 AcpiEnBit;
+ //
+ // Disable A20 Mask
+ //
+ IoOr8 (0x92, BIT1);
+
+ //
+ // Determine platform type and save Host Bridge DID to PCD
+ //
+ switch (PlatformInfoHob->HostBridgePciDevId) {
+ case INTEL_82441_DEVICE_ID:
+ PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
+ Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
+ PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;
+ PmbaOrVal = PIIX4_PMBA_VALUE;
+ AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
+ AcpiEnBit = PIIX4_PMREGMISC_PMIOSE;
+ break;
+ case INTEL_Q35_MCH_DEVICE_ID:
+ PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);
+ Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
+ PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;
+ PmbaOrVal = ICH9_PMBASE_VALUE;
+ AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
+ AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN;
+ break;
+ default:
+ DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
+ __FUNCTION__, PlatformInfoHob->HostBridgePciDevId));
+ ASSERT (FALSE);
+ return;
+ }
+ //
+ // If the appropriate IOspace enable bit is set, assume the ACPI PMBA
+ // has been configured and skip the setup here.
+ // This matches the logic in AcpiTimerLibConstructor ().
+ //
+ if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
+ //
+ // The PEI phase should be exited with fully accessibe ACPI PM IO space:
+ // 1. set PMBA
+ //
+ PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
+
+ //
+ // 2. set PCICMD/IOSE
+ //
+ PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
+
+ //
+ // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
+ //
+ PciOr8 (AcpiCtlReg, AcpiEnBit);
+ }
+
+ if (PlatformInfoHob->HostBridgePciDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ //
+ // Set Root Complex Register Block BAR
+ //
+ PciWrite32 (
+ POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
+ ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
+ );
+
+ //
+ // Set PCI Express Register Range Base Address
+ //
+ PciExBarInitialization ();
+ }
+
+ //
+ // check for overrides
+ //
+ Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize);
+ if (Status != RETURN_SUCCESS || FwCfgSize != sizeof PlatformInfoHob->SystemStates) {
+ DEBUG ((DEBUG_INFO, "ACPI using S3/S4 defaults\n"));
+ return;
+ }
+ QemuFwCfgSelectItem (FwCfgItem);
+ QemuFwCfgReadBytes (sizeof PlatformInfoHob->SystemStates, PlatformInfoHob->SystemStates);
+}
+
+/**
+ Perform Platform initialization.
+**/
+VOID
+EFIAPI
+TdvfPlatformInitialize (
+ EFI_HOB_PLATFORM_INFO *PlatformInfoHob
+)
+{
+ DEBUG ((DEBUG_INFO, "Qemu Platform Loaded\n"));
+
+ PlatformInfoHob->HostBridgePciDevId = PciRead16 (HOSTBRIDGE_DID);
+
+ if (PlatformInfoHob->HostBridgePciDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_IO,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
+ 0x6000,
+ 0xa000
+ );
+ } else {
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_IO,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
+ 0xc000,
+ 0x4000
+ );
+ }
+
+ MiscInitialization (PlatformInfoHob);
+
+ GetNamedFwCfgBoolean ("opt/ovmf/PcdSetNxForStack", &PlatformInfoHob->SetNxForStack);
+}
diff --git a/OvmfPkg/Library/TdvfPlatformLibQemu/TdvfPlatformLibQemuSec.inf b/OvmfPkg/Library/TdvfPlatformLibQemu/TdvfPlatformLibQemuSec.inf
new file mode 100644
index 000000000000..dd60d4d79da2
--- /dev/null
+++ b/OvmfPkg/Library/TdvfPlatformLibQemu/TdvfPlatformLibQemuSec.inf
@@ -0,0 +1,49 @@
+## @file
+#
+# Tdvf Platform Lib for the QEMU VMM
+#
+# Copyright (C) 2013, Red Hat, Inc.
+# Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.
+# Copyright (c) 2017, AMD Incorporated. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TdvfPlatformLibQemuSec
+ FILE_GUID = 44cabe70-fcfb-11ea-8b6e-0800200c9a66
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TdvfPlatformLib|SEC
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ Platform.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[Guids]
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ IoLib
+ PcdLib
+ HobLib
+ PciLib
+ QemuFwCfgLib
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/OvmfPkg/Library/TdxProbeLib/TdxProbeLib.c b/OvmfPkg/Library/TdxProbeLib/TdxProbeLib.c
new file mode 100644
index 000000000000..6f4220607a48
--- /dev/null
+++ b/OvmfPkg/Library/TdxProbeLib/TdxProbeLib.c
@@ -0,0 +1,40 @@
+/** @file
+ instance of TdxProbeLib in OvmfPkg.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include
+#include
+
+BOOLEAN mTdGuest = FALSE;
+BOOLEAN mTdGuestProbed = FALSE;
+
+#define TDX_WORK_AREA_OFFSET 0x10
+
+/**
+ Probe whether it is TD guest or Non-TD guest.
+
+ @return TRUE TD guest
+ @return FALSE Non-TD guest
+**/
+BOOLEAN
+EFIAPI
+ProbeTdGuest (
+ VOID)
+{
+ UINT8 * TdxWorkArea;
+
+ if (mTdGuestProbed) {
+ return mTdGuest;
+ }
+
+ TdxWorkArea = (UINT8 *)((UINTN)(FixedPcdGet32 (PcdTdMailboxBase) + TDX_WORK_AREA_OFFSET));
+ mTdGuest = *TdxWorkArea != 0;
+ mTdGuestProbed = TRUE;
+
+ return mTdGuest;
+}
diff --git a/OvmfPkg/Library/TdxProbeLib/TdxProbeLib.inf b/OvmfPkg/Library/TdxProbeLib/TdxProbeLib.inf
new file mode 100644
index 000000000000..7e36735bfeff
--- /dev/null
+++ b/OvmfPkg/Library/TdxProbeLib/TdxProbeLib.inf
@@ -0,0 +1,31 @@
+## @file
+# Tdx Probe library instance in OvmfPkg
+#
+# Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TdxProbeLib
+ FILE_GUID = 26BF0B58-6E9D-4375-A363-52FD83FB82CE
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TdxProbeLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = X64 IA32
+#
+
+[Sources]
+ TdxProbeLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdMailboxBase
diff --git a/OvmfPkg/Library/TdxStartupLib/DxeLoad.c b/OvmfPkg/Library/TdxStartupLib/DxeLoad.c
new file mode 100644
index 000000000000..a3734964fad3
--- /dev/null
+++ b/OvmfPkg/Library/TdxStartupLib/DxeLoad.c
@@ -0,0 +1,325 @@
+/** @file
+ Responsibility of this file is to load the DXE Core from a Firmware Volume.
+
+Copyright (c) 2016 HP Development Company, L.P.
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "TdxStartupInternal.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "X64/PageTables.h"
+#include
+
+#define PCD_PEIM_GUID { \
+ 0x9b3ada4f, 0xae56, 0x4c24, {0x8d, 0xea, 0xf0, 0x3b, 0x75, 0x58, 0xae, 0x50} \
+ }
+
+EFI_GUID mPcdPeimGuid = PCD_PEIM_GUID;
+
+#define STACK_SIZE 0x20000
+
+EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
+ { EfiACPIMemoryNVS, 0x004 },
+ { EfiACPIReclaimMemory, 0x008 },
+ { EfiReservedMemoryType, 0x004 },
+ { EfiRuntimeServicesData, 0x024 },
+ { EfiRuntimeServicesCode, 0x030 },
+ { EfiBootServicesCode, 0x180 },
+ { EfiBootServicesData, 0xF00 },
+ { EfiMaxMemoryType, 0x000 }
+};
+
+
+/**
+ Transfers control to DxeCore.
+
+ This function performs a CPU architecture specific operations to execute
+ the entry point of DxeCore
+
+ @param DxeCoreEntryPoint The entry point of DxeCore.
+
+**/
+VOID
+HandOffToDxeCore (
+ IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint
+ )
+{
+ VOID *BaseOfStack;
+ VOID *TopOfStack;
+ UINTN PageTables;
+
+ //
+ // Clear page 0 and mark it as allocated if NULL pointer detection is enabled.
+ //
+ if (IsNullDetectionEnabled ()) {
+ ClearFirst4KPage (GetHobList ());
+ BuildMemoryAllocationHob (0, EFI_PAGES_TO_SIZE (1), EfiBootServicesData);
+ }
+
+
+ //
+ // Allocate 128KB for the Stack
+ //
+ BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE));
+ ASSERT (BaseOfStack != NULL);
+
+ //
+ // Compute the top of the stack we were allocated. Pre-allocate a UINTN
+ // for safety.
+ //
+ TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
+ TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
+
+ DEBUG((DEBUG_INFO, "BaseOfStack=0x%x, TopOfStack=0x%x\n", BaseOfStack, TopOfStack));
+
+ PageTables = 0;
+ if (FeaturePcdGet (PcdDxeIplBuildPageTables)) {
+ //
+ // Create page table and save PageMapLevel4 to CR3
+ //
+ PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack,
+ STACK_SIZE);
+ } else {
+ //
+ // Set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE
+ // for the DxeIpl and the DxeCore are both X64.
+ //
+ ASSERT (FixedPcdGetBool (PcdTdxSetNxForStack) == FALSE);
+ ASSERT (FixedPcdGetBool (PcdCpuStackGuard) == FALSE);
+ }
+
+ if (FeaturePcdGet (PcdDxeIplBuildPageTables)) {
+ AsmWriteCr3 (PageTables);
+ }
+
+ //
+ // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
+ //
+ UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, STACK_SIZE);
+
+ DEBUG ((DEBUG_INFO, "SwitchStack then Jump to DxeCore\n"));
+ //
+ // Transfer the control to the entry point of DxeCore.
+ //
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
+ GetHobList(),
+ NULL,
+ TopOfStack
+ );
+}
+
+EFI_STATUS
+FindPcdPeim (
+ IN INTN FvInstance,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+
+ ASSERT (FileHandle != NULL);
+ ASSERT (FvInstance != -1);
+ *FileHandle = NULL;
+
+ //
+ // Caller passed in a specific FV to try, so only try that one
+ //
+ Status = FfsFindNextVolume (FvInstance, &VolumeHandle);
+ if (!EFI_ERROR (Status)) {
+ Status = FfsFindNextFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, VolumeHandle, FileHandle);
+
+ if (*FileHandle) {
+ // Assume the FV that contains multiple compressed FVs.
+ // So decompress the compressed FVs
+ Status = FfsProcessFvFile (*FileHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = FfsAnyFvFindFileByName (&mPcdPeimGuid, &VolumeHandle, FileHandle);
+ }
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+InitPeimPcd (
+ IN INTN FvInstance)
+{
+ EFI_STATUS Status;
+ PEI_PCD_DATABASE *Database;
+ PEI_PCD_DATABASE *PeiPcdDbBinary;
+ EFI_PEI_FILE_HANDLE FileHandle;
+
+ //
+ // Find the PcdPeim and initialize the Pcd Database
+ //
+ Status = FindPcdPeim (FvInstance, &FileHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = FfsFindSectionData (EFI_SECTION_RAW, FileHandle, (VOID**)(UINTN)&PeiPcdDbBinary);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Database = BuildGuidHob (&gPcdDataBaseHobGuid, PeiPcdDbBinary->Length + PeiPcdDbBinary->UninitDataBaseSize);
+
+ ZeroMem (Database, PeiPcdDbBinary->Length + PeiPcdDbBinary->UninitDataBaseSize);
+
+ //
+ // PeiPcdDbBinary is smaller than Database
+ //
+ CopyMem (Database, PeiPcdDbBinary, PeiPcdDbBinary->Length);
+
+ return Status;
+}
+
+
+/**
+ Searches DxeCore in all firmware Volumes and loads the first
+ instance that contains DxeCore.
+
+ @return FileHandle of DxeCore to load DxeCore.
+
+**/
+EFI_STATUS
+FindDxeCore (
+ IN INTN FvInstance,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+
+ ASSERT (FileHandle != NULL);
+ *FileHandle = NULL;
+
+ if (FvInstance != -1) {
+ //
+ // Caller passed in a specific FV to try, so only try that one
+ //
+ Status = FfsFindNextVolume (FvInstance, &VolumeHandle);
+ if (!EFI_ERROR (Status)) {
+ Status = FfsFindNextFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, VolumeHandle, FileHandle);
+
+ if (*FileHandle) {
+ // Assume the FV that contains multiple compressed FVs.
+ // So decompress the compressed FVs
+ Status = FfsProcessFvFile (*FileHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, FileHandle);
+ }
+ }
+ } else {
+ // Assume the FV that contains the SEC (our code) also contains a compressed FV.
+ Status = DecompressFirstFv ();
+ ASSERT_EFI_ERROR (Status);
+ Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, FileHandle);
+ }
+
+ return Status;
+}
+
+/**
+ This function finds DXE Core in the firmware volume and transfer the control to
+ DXE core.
+
+ @return EFI_SUCCESS DXE core was successfully loaded.
+ @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeLoadCore (
+ IN INTN FvInstance
+ )
+{
+ EFI_STATUS Status;
+ EFI_FV_FILE_INFO DxeCoreFileInfo;
+ EFI_PHYSICAL_ADDRESS DxeCoreAddress;
+ UINT64 DxeCoreSize;
+ EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ VOID *PeCoffImage;
+
+
+ //
+ // Create Memory Type Information HOB
+ //
+ BuildGuidDataHob (
+ &gEfiMemoryTypeInformationGuid,
+ mDefaultMemoryTypeInformation,
+ sizeof (mDefaultMemoryTypeInformation)
+ );
+
+ //
+ // Look in all the FVs present and find the DXE Core FileHandle
+ //
+ Status = FindDxeCore (FvInstance, &FileHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Load the DXE Core from a Firmware Volume.
+ //
+ Status = FfsFindSectionData (EFI_SECTION_PE32, FileHandle, &PeCoffImage);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = LoadPeCoffImage (PeCoffImage, &DxeCoreAddress, &DxeCoreSize, &DxeCoreEntryPoint);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Extract the DxeCore GUID file name.
+ //
+ Status = FfsGetFileInfo (FileHandle, &DxeCoreFileInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Add HOB for the DXE Core
+ //
+ BuildModuleHob (
+ &DxeCoreFileInfo.FileName,
+ DxeCoreAddress,
+ ALIGN_VALUE (DxeCoreSize, EFI_PAGE_SIZE),
+ DxeCoreEntryPoint
+ );
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading DXE CORE at 0x%11p EntryPoint=0x%11p\n",
+ (VOID *)(UINTN)DxeCoreAddress, FUNCTION_ENTRY_POINT (DxeCoreEntryPoint)));
+
+ //
+ // Initialize PeimPcd database
+ //
+ Status = InitPeimPcd (FvInstance);
+ ASSERT_EFI_ERROR (Status);
+
+ // Transfer control to the DXE Core
+ // The hand off state is simply a pointer to the HOB list
+ //
+ HandOffToDxeCore (DxeCoreEntryPoint);
+
+ //
+ // If we get here, then the DXE Core returned. This is an error
+ // DxeCore should not return.
+ //
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+
+ return EFI_OUT_OF_RESOURCES;
+}
+
+
diff --git a/OvmfPkg/Library/TdxStartupLib/Hob.c b/OvmfPkg/Library/TdxStartupLib/Hob.c
new file mode 100644
index 000000000000..321e4aeb4935
--- /dev/null
+++ b/OvmfPkg/Library/TdxStartupLib/Hob.c
@@ -0,0 +1,451 @@
+/** @file
+ Main SEC phase code. Handles initial TDX Hob List Processing
+
+ Copyright (c) 2008, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "TdxStartupInternal.h"
+
+VOID
+EFIAPI
+DEBUG_HOBLIST (
+ IN CONST VOID *HobStart
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ Hob.Raw = (UINT8 *) HobStart;
+ //
+ // Parse the HOB list until end of list or matching type is found.
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ DEBUG ((DEBUG_INFO, "HOB(%p) : %x %x\n", Hob, Hob.Header->HobType, Hob.Header->HobLength));
+ switch (Hob.Header->HobType) {
+ case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
+ DEBUG ((DEBUG_INFO, "\t: %x %x %llx %llx\n",
+ Hob.ResourceDescriptor->ResourceType,
+ Hob.ResourceDescriptor->ResourceAttribute,
+ Hob.ResourceDescriptor->PhysicalStart,
+ Hob.ResourceDescriptor->ResourceLength));
+
+ break;
+ case EFI_HOB_TYPE_MEMORY_ALLOCATION:
+ DEBUG ((DEBUG_INFO, "\t: %llx %llx %x\n",
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,
+ Hob.MemoryAllocation->AllocDescriptor.MemoryLength,
+ Hob.MemoryAllocation->AllocDescriptor.MemoryType));
+ break;
+ default:
+ break;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+}
+
+/**
+ 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 TD
+
+ Firmware must parse list, and accept the pages of memory before their can be
+ use by the guest.
+
+ In addition, the hob list will be measured so it cannot be modified.
+ After accepting the pages, the firmware will use the largest memory resource
+ region as it's initial memory pool. It will initialize a new hoblist there, and the pre-DXE
+ memory allocation will use that for allocations.
+
+ Also, it will location the highest memory region < 4GIG. It will use this to allocate
+ ACPI NVS memory for mailbox and spinloop for AP use. The APs will be relocated there
+ until the guest OS wakes them up.
+
+ @param[in] VmmHobList The Hoblist pass the firmware
+
+**/
+VOID
+EFIAPI
+ProcessHobList (
+ IN CONST VOID *VmmHobList
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PHYSICAL_ADDRESS PhysicalEnd;
+ EFI_PHYSICAL_ADDRESS PhysicalStart;
+ UINT64 Length;
+ EFI_HOB_RESOURCE_DESCRIPTOR *LowMemoryResource = NULL;
+
+ 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));
+
+ //
+ // FixMe:
+ // We only accept the ResourceType (EFI_RESOURCE_UNACCEPTED_MEMORY)
+ // But this ResourceType is still in upstream.
+ // So now we accept the ResourceType (EFI_RESOURCE_SYSTEM_MEMORY) without
+ // EFI_RESOURCE_ATTRIBUTE_ENCRYPTED.
+ // After EFI_RESOURCE_UNACCEPTED_MEMORY is in EDK2, then we switch to it.
+ //
+ 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;
+
+ if (PhysicalEnd <= BASE_4GB) {
+ if ((LowMemoryResource == NULL) || (Hob.ResourceDescriptor->ResourceLength > LowMemoryResource->ResourceLength)) {
+ LowMemoryResource = Hob.ResourceDescriptor;
+ }
+ }
+
+ MpAcceptMemoryResourceRange (
+ Hob.ResourceDescriptor->PhysicalStart,
+ PhysicalEnd);
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+ ASSERT (LowMemoryResource != NULL);
+
+ PhysicalStart = LowMemoryResource->PhysicalStart;
+ Length = LowMemoryResource->ResourceLength;
+
+ //
+ // HobLib doesn't like HobStart at address 0 so adjust is needed
+ //
+ if (PhysicalStart == 0) {
+ PhysicalStart += EFI_PAGE_SIZE;
+ Length -= EFI_PAGE_SIZE;
+ }
+
+
+ HobConstructor (
+ (VOID *) PhysicalStart,
+ Length,
+ (VOID *) PhysicalStart,
+ (VOID *) (PhysicalStart + Length)
+ );
+
+ PrePeiSetHobList ((VOID *)(UINT64)PhysicalStart);
+}
+
+/**
+ Transfer the incoming HobList for the TD to the final HobList for Dxe
+
+ @param[in] VmmHobList The Hoblist pass the firmware
+
+**/
+VOID
+EFIAPI
+TransferHobList (
+ IN CONST VOID *VmmHobList
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute;
+ EFI_PHYSICAL_ADDRESS PhysicalEnd;
+
+ Hob.Raw = (UINT8 *) VmmHobList;
+ while (!END_OF_HOB_LIST (Hob)) {
+ switch (Hob.Header->HobType) {
+ case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
+ ResourceAttribute = Hob.ResourceDescriptor->ResourceAttribute;
+ PhysicalEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
+
+ //
+ // We mark each resource that we issue AcceptPage to with EFI_RESOURCE_SYSTEM_MEMORY
+ //
+ if ((Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
+ (PhysicalEnd <= BASE_4GB)) {
+ ResourceAttribute |= EFI_RESOURCE_ATTRIBUTE_ENCRYPTED;
+ }
+ BuildResourceDescriptorHob (
+ Hob.ResourceDescriptor->ResourceType,
+ ResourceAttribute,
+ Hob.ResourceDescriptor->PhysicalStart,
+ Hob.ResourceDescriptor->ResourceLength);
+ break;
+ case EFI_HOB_TYPE_MEMORY_ALLOCATION:
+ BuildMemoryAllocationHob (
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,
+ Hob.MemoryAllocation->AllocDescriptor.MemoryLength,
+ Hob.MemoryAllocation->AllocDescriptor.MemoryType);
+ break;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+ DEBUG_HOBLIST (GetHobList ());
+}
+
+/**
+ Create a log event for the Hoblist passed from the VMM.
+
+ This function will create a unique GUID hob entry will be
+ found from the TCG driver building the event log.
+ This module will generate the measurement with the data in
+ this hob, and log the event.
+
+ @param[in] VmmHobList The Hoblist pass the firmware
+
+**/
+VOID
+EFIAPI
+LogHobList (
+ IN CONST VOID *VmmHobList
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ TDX_HANDOFF_TABLE_POINTERS2 HandoffTables;
+ EFI_STATUS Status;
+
+ Hob.Raw = (UINT8 *) VmmHobList;
+
+ //
+ // Parse the HOB list until end of list.
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+ //
+ // Init the log event for HOB measurement
+ //
+
+ HandoffTables.TableDescriptionSize = sizeof (HandoffTables.TableDescription);
+ CopyMem (HandoffTables.TableDescription, HANDOFF_TABLE_DESC, sizeof (HandoffTables.TableDescription));
+ HandoffTables.NumberOfTables = 1;
+ CopyGuid (&(HandoffTables.TableEntry[0].VendorGuid), &gUefiOvmfPkgTokenSpaceGuid);
+ HandoffTables.TableEntry[0].VendorTable = (VOID *) VmmHobList;
+
+ Status = CreateTdxExtendEvent (
+ 1, // PCRIndex
+ EV_EFI_HANDOFF_TABLES2, // EventType
+ (VOID *)&HandoffTables, // EventData
+ sizeof (HandoffTables), // EventSize
+ (UINT8*) (UINTN) VmmHobList, // HashData
+ (UINTN) ((UINT8 *)Hob.Raw - (UINT8 *)VmmHobList) // HashDataLen
+ );
+
+ ASSERT_EFI_ERROR (Status);
+}
diff --git a/OvmfPkg/Library/TdxStartupLib/Mp.c b/OvmfPkg/Library/TdxStartupLib/Mp.c
new file mode 100644
index 000000000000..01ede34bb4ac
--- /dev/null
+++ b/OvmfPkg/Library/TdxStartupLib/Mp.c
@@ -0,0 +1,299 @@
+/** @file
+ Main SEC MP code.
+
+ Copyright (c) 2008, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "TdxStartupInternal.h"
+
+#define ALIGNED_2MB_MASK 0x1fffff
+
+/**
+ This function will be called by BSP to wakeup APs the are spinning on mailbox
+ in protected mode
+
+ @param[in] Command Command to send APs
+ @param[in] WakeupVector If used, address for APs to start executing
+ @param[in] WakeArgsX Args to pass to APs for excuting commands
+**/
+VOID
+EFIAPI
+MpSendWakeupCommand(
+ IN UINT16 Command,
+ IN UINT64 WakeupVector,
+ IN UINT64 WakeupArgs1,
+ IN UINT64 WakeupArgs2,
+ IN UINT64 WakeupArgs3,
+ IN UINT64 WakeupArgs4
+)
+{
+ volatile MP_WAKEUP_MAILBOX *MailBox;
+
+ MailBox = (volatile MP_WAKEUP_MAILBOX *)GetMailBox();
+ MailBox->ApicId = MP_CPU_PROTECTED_MODE_MAILBOX_APICID_INVALID;
+ MailBox->WakeUpVector = 0;
+ MailBox->Command = MpProtectedModeWakeupCommandNoop;
+ MailBox->ApicId = MP_CPU_PROTECTED_MODE_MAILBOX_APICID_BROADCAST;
+ MailBox->WakeUpVector = WakeupVector;
+ MailBox->WakeUpArgs1 = WakeupArgs1;
+ MailBox->WakeUpArgs2 = WakeupArgs2;
+ MailBox->WakeUpArgs3 = WakeupArgs3;
+ MailBox->WakeUpArgs4 = WakeupArgs4;
+ AsmCpuid (0x01, NULL, NULL, NULL, NULL);
+ MailBox->Command = Command;
+ AsmCpuid (0x01, NULL, NULL, NULL, NULL);
+ return;
+}
+
+VOID
+EFIAPI
+MpSerializeStart (
+ VOID
+ )
+{
+ volatile MP_WAKEUP_MAILBOX *MailBox;
+ UINT32 NumOfCpus;
+
+ NumOfCpus = GetNumCpus();
+ MailBox = (volatile MP_WAKEUP_MAILBOX *)GetMailBox();
+
+ DEBUG((DEBUG_VERBOSE, "Waiting for APs to arriving. NumOfCpus=%d, MailBox=%p\n", NumOfCpus, MailBox));
+ while (MailBox->NumCpusArriving != ( NumOfCpus -1 )) {
+ CpuPause();
+ }
+ DEBUG((DEBUG_VERBOSE, "Releasing APs\n"));
+ MailBox->NumCpusExiting = NumOfCpus;
+ InterlockedIncrement ((UINT32 *) &MailBox->NumCpusArriving);
+}
+
+VOID
+EFIAPI
+MpSerializeEnd (
+ VOID
+ )
+{
+ volatile MP_WAKEUP_MAILBOX *MailBox;
+
+ MailBox = (volatile MP_WAKEUP_MAILBOX *)GetMailBox();
+ DEBUG((DEBUG_VERBOSE, "Waiting for APs to finish\n"));
+ while (MailBox->NumCpusExiting != 1 ) {
+ CpuPause();
+ }
+ DEBUG((DEBUG_VERBOSE, "Restarting APs\n"));
+ MailBox->Command = MpProtectedModeWakeupCommandNoop;
+ MailBox->NumCpusArriving = 0;
+ InterlockedDecrement ((UINT32 *) &MailBox->NumCpusExiting);
+}
+
+EFI_STATUS
+EFIAPI
+BspAcceptMemoryResourceRange (
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINT64 Length,
+ IN UINT64 AcceptChunkSize,
+ IN UINT64 AcceptPageSize
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Pages;
+ UINT64 Stride;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ volatile MP_WAKEUP_MAILBOX *MailBox;
+
+ Status = EFI_SUCCESS;
+ PhysicalAddress = StartAddress;
+ Stride = GetNumCpus() * AcceptChunkSize;
+ MailBox = (volatile MP_WAKEUP_MAILBOX *)GetMailBox();
+
+ while (!EFI_ERROR(Status) && PhysicalAddress < StartAddress + Length) {
+ //
+ // Decrease size of near end of resource if needed.
+ //
+ Pages = RShiftU64(MIN(AcceptChunkSize, Length), EFI_PAGE_SHIFT);
+
+ MailBox->Tallies[0] += (UINT32)Pages;
+
+ Status = TdAcceptPages (PhysicalAddress, Pages, AcceptPageSize);
+ //
+ // Bump address to next chunk this cpu is responisble for
+ //
+ PhysicalAddress += Stride;
+ }
+
+ return Status;
+}
+
+/**
+ This function will be called to accept pages. BSP and APs are invokded
+ to do the task together.
+
+ 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
+ |---------------|
+
+ part 1) will be accepted in 4k and by BSP.
+ Part 2) will be accepted in 2M and by BSP/AP.
+ Part 3) will be accepted in 4k and by BSP.
+
+ @param[in] PhysicalAddress Start physical adress
+ @param[in] PhysicalEnd End physical address
+**/
+VOID
+EFIAPI
+MpAcceptMemoryResourceRange (
+ IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
+ IN EFI_PHYSICAL_ADDRESS PhysicalEnd
+ )
+{
+ EFI_STATUS Status;
+ UINT64 AcceptChunkSize;
+ UINT64 AcceptPageSize;
+ UINT64 StartAddress1;
+ UINT64 StartAddress2;
+ UINT64 StartAddress3;
+ UINT64 TotalLength;
+ UINT64 Length1;
+ UINT64 Length2;
+ UINT64 Length3;
+ volatile MP_WAKEUP_MAILBOX *MailBox;
+
+ MailBox = (volatile MP_WAKEUP_MAILBOX *)GetMailBox ();
+ AcceptChunkSize = FixedPcdGet64 (PcdTdxAcceptChunkSize);
+ AcceptPageSize = FixedPcdGet64 (PcdTdxAcceptPageSize);
+ TotalLength = PhysicalEnd - PhysicalAddress;
+ StartAddress1 = 0;
+ StartAddress2 = 0;
+ StartAddress3 = 0;
+ Length1 = 0;
+ Length2 = 0;
+ Length3 = 0;
+
+ if (AcceptPageSize == SIZE_4KB || TotalLength <= SIZE_2MB) {
+ //
+ // if total length is less than 2M, then we accept pages in 4k
+ //
+ StartAddress1 = 0;
+ Length1 = 0;
+ StartAddress2 = PhysicalAddress;
+ Length2 = PhysicalEnd - PhysicalAddress;
+ StartAddress3 = 0;
+ Length3 = 0;
+ } 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
+ //
+ StartAddress1 = 0;
+ Length1 = 0;
+ StartAddress2 = PhysicalAddress;
+ Length2 = TotalLength & 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) & ALIGNED_2MB_MASK;
+ StartAddress3 = StartAddress2 + Length2;
+ Length3 = TotalLength - Length1 - Length2;
+ 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));
+
+ MpSerializeStart();
+
+ if (Length2 > 0) {
+ MpSendWakeupCommand (
+ MpProtectedModeWakeupCommandAcceptPages,
+ 0,
+ StartAddress2,
+ StartAddress2 + Length2,
+ AcceptChunkSize,
+ AcceptPageSize);
+
+ Status = BspAcceptMemoryResourceRange (
+ StartAddress2,
+ Length2,
+ AcceptChunkSize,
+ AcceptPageSize);
+ ASSERT (!EFI_ERROR (Status));
+ }
+
+ if (Length1 > 0) {
+ Status = BspAcceptMemoryResourceRange (
+ StartAddress1,
+ Length1,
+ AcceptChunkSize,
+ SIZE_4KB);
+ ASSERT (!EFI_ERROR (Status));
+ }
+
+ if (Length3 > 0) {
+ Status = BspAcceptMemoryResourceRange (
+ StartAddress3,
+ Length3,
+ AcceptChunkSize,
+ SIZE_4KB);
+ ASSERT (!EFI_ERROR (Status));
+ }
+
+ MpSerializeEnd();
+
+ DEBUG((DEBUG_INFO, "Tallies %x %x %x %x %x %x %x %x\n",
+ MailBox->Tallies[0],
+ MailBox->Tallies[1],
+ MailBox->Tallies[2],
+ MailBox->Tallies[3],
+ MailBox->Tallies[4],
+ MailBox->Tallies[5],
+ MailBox->Tallies[6],
+ MailBox->Tallies[7]));
+
+}
diff --git a/OvmfPkg/Library/TdxStartupLib/Tcg.c b/OvmfPkg/Library/TdxStartupLib/Tcg.c
new file mode 100644
index 000000000000..7b0b145da0b4
--- /dev/null
+++ b/OvmfPkg/Library/TdxStartupLib/Tcg.c
@@ -0,0 +1,259 @@
+/** @file
+ Initialize TPM2 device and measure FVs before handing off control to DXE.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2017, Microsoft Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "TdxStartupInternal.h"
+
+#pragma pack (1)
+
+#define FV_HANDOFF_TABLE_DESC "Fv(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)"
+typedef struct {
+ UINT8 BlobDescriptionSize;
+ UINT8 BlobDescription[sizeof(FV_HANDOFF_TABLE_DESC)];
+ EFI_PHYSICAL_ADDRESS BlobBase;
+ UINT64 BlobLength;
+} FV_HANDOFF_TABLE_POINTERS2;
+
+#pragma pack ()
+
+extern UINT32 GetMappedRtmrIndex(UINT32 PCRIndex);
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in] DigestList A list of digest.
+ @param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
+ @param[in] NewEventData Pointer to the new event data.
+
+ @retval EFI_SUCCESS The new event log entry was added.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+**/
+EFI_STATUS
+CreateTdxExtendEvent (
+ IN TCG_PCRINDEX PCRIndex,
+ IN TCG_EVENTTYPE EventType,
+ IN UINT8 *EventData,
+ IN UINTN EventSize,
+ IN UINT8 *HashData,
+ IN UINTN HashDataLen
+ )
+{
+ EFI_STATUS Status;
+ UINT32 RtmrIndex;
+ VOID *EventHobData;
+ TCG_PCR_EVENT2 *TcgPcrEvent2;
+ UINT8 *DigestBuffer;
+ TDX_DIGEST_VALUE *TdxDigest;
+ TPML_DIGEST_VALUES DigestList;
+ UINT8 *Ptr;
+
+
+ DEBUG ((EFI_D_INFO, "Creating TdTcg2PcrEvent PCR %d EventType 0x%x\n", PCRIndex, EventType));
+
+ RtmrIndex = GetMappedRtmrIndex (PCRIndex);
+ Status = HashAndExtend (RtmrIndex,
+ (VOID*)HashData,
+ HashDataLen,
+ &DigestList);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Failed to HashAndExtend. %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Use TDX_DIGEST_VALUE in the GUID HOB DataLength calculation
+ // to reserve enough buffer to hold TPML_DIGEST_VALUES compact binary
+ // which is limited to a SHA384 digest list
+ //
+ EventHobData = BuildGuidHob (
+ &gTcgEvent2EntryHobGuid,
+ sizeof(TcgPcrEvent2->PCRIndex) + sizeof(TcgPcrEvent2->EventType) +
+ sizeof(TDX_DIGEST_VALUE) +
+ sizeof(TcgPcrEvent2->EventSize) + EventSize);
+
+ if (EventHobData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG ((EFI_D_INFO, " Tcg2PcrEvent - data %p\n", EventHobData));
+
+ Ptr = (UINT8*)EventHobData;
+ //
+ // Initialize PcrEvent data now
+ //
+ CopyMem(Ptr, &PCRIndex, sizeof(TCG_PCRINDEX));
+ Ptr += sizeof(TCG_PCRINDEX);
+ CopyMem(Ptr, &EventType, sizeof(TCG_EVENTTYPE));
+ Ptr += sizeof(TCG_EVENTTYPE);
+
+ DigestBuffer = Ptr;
+ DEBUG ((EFI_D_INFO, " Tcg2PcrEvent - digest %p\n", DigestBuffer));
+
+ TdxDigest = (TDX_DIGEST_VALUE *)DigestBuffer;
+ TdxDigest->count = 1;
+ TdxDigest->hashAlg = TPM_ALG_SHA384;
+ CopyMem (TdxDigest->sha384,
+ DigestList.digests[0].digest.sha384,
+ SHA384_DIGEST_SIZE);
+
+ Ptr += sizeof(TDX_DIGEST_VALUE);
+ DEBUG ((EFI_D_INFO, " Tcg2PcrEvent - eventdata %p\n", DigestBuffer));
+
+ CopyMem (Ptr, &EventSize, sizeof(UINT32));
+ Ptr += sizeof(UINT32);
+ CopyMem (Ptr, EventData, EventSize);
+ Ptr += EventSize;
+
+ Status = EFI_SUCCESS;
+ return Status;
+}
+
+
+/**
+ Get the FvName from the FV header.
+
+ Causion: The FV is untrusted input.
+
+ @param[in] FvBase Base address of FV image.
+ @param[in] FvLength Length of FV image.
+
+ @return FvName pointer
+ @retval NULL FvName is NOT found
+**/
+VOID *
+GetFvName (
+ IN EFI_PHYSICAL_ADDRESS FvBase,
+ IN UINT64 FvLength
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+
+ if (FvBase >= MAX_ADDRESS) {
+ return NULL;
+ }
+ if (FvLength >= MAX_ADDRESS - FvBase) {
+ return NULL;
+ }
+ if (FvLength < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) {
+ return NULL;
+ }
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase;
+ if (FvHeader->ExtHeaderOffset < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) {
+ return NULL;
+ }
+ if (FvHeader->ExtHeaderOffset + sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER) > FvLength) {
+ return NULL;
+ }
+ FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(UINTN)(FvBase + FvHeader->ExtHeaderOffset);
+
+ return &FvExtHeader->FvName;
+}
+
+/**
+ Measure FV image.
+ Add it into the measured FV list after the FV is measured successfully.
+
+ @param[in] FvBase Base address of FV image.
+ @param[in] FvLength Length of FV image.
+ @param[in] PcrIndex Index of PCR
+
+ @retval EFI_SUCCESS Fv image is measured successfully
+ or it has been already measured.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+TdxMeasureFvImage (
+ IN EFI_PHYSICAL_ADDRESS FvBase,
+ IN UINT64 FvLength,
+ IN UINT8 PcrIndex
+ )
+{
+ EFI_STATUS Status;
+ FV_HANDOFF_TABLE_POINTERS2 FvBlob2;
+ VOID *FvName;
+
+ //
+ // Init the log event for FV measurement
+ //
+ FvBlob2.BlobDescriptionSize = sizeof(FvBlob2.BlobDescription);
+ CopyMem (FvBlob2.BlobDescription, FV_HANDOFF_TABLE_DESC, sizeof(FvBlob2.BlobDescription));
+ FvName = GetFvName (FvBase, FvLength);
+ if (FvName != NULL) {
+ AsciiSPrint ((CHAR8 *)FvBlob2.BlobDescription, sizeof(FvBlob2.BlobDescription), "Fv(%g)", FvName);
+ }
+ FvBlob2.BlobBase = FvBase;
+ FvBlob2.BlobLength = FvLength;
+
+ //
+ // Hash the FV, extend digest to the TPM and log TCG event
+ //
+ Status = CreateTdxExtendEvent (
+ PcrIndex, // PCRIndex
+ EV_EFI_PLATFORM_FIRMWARE_BLOB2, // EventType
+ (VOID *)&FvBlob2, // EventData
+ sizeof (FvBlob2), // EventSize
+ (UINT8*) (UINTN) FvBase, // HashData
+ (UINTN) FvLength // HashDataLen
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "The FV which failed to be measured starts at: 0x%x\n", FvBase));
+ return Status;
+ }
+ return Status;
+}
+
+EFI_STATUS
+MeasureQemuCfgSystemSts (
+ IN TCG_PCRINDEX PCRIndex,
+ IN UINT8 *HashData,
+ IN UINTN HashDataLength
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *Item = "etc/system-states";
+
+ Status = CreateTdxExtendEvent (
+ PCRIndex, // PCRIndex
+ EV_PLATFORM_CONFIG_FLAGS, // EventType
+ (UINT8*)Item, // EventData
+ AsciiStrLen(Item), // EventSize
+ HashData, // HashData
+ HashDataLength // HashDataLen
+ );
+
+ return Status;
+}
+
diff --git a/OvmfPkg/Library/TdxStartupLib/TdxStartup.c b/OvmfPkg/Library/TdxStartupLib/TdxStartup.c
new file mode 100644
index 000000000000..e548ec425406
--- /dev/null
+++ b/OvmfPkg/Library/TdxStartupLib/TdxStartup.c
@@ -0,0 +1,260 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "TdxStartupInternal.h"
+
+volatile VOID *mMailBox = NULL;
+UINT32 mNumOfCpus = 0;
+
+#define GET_GPAW_INIT_STATE(INFO) ((UINT8) ((INFO) & 0x3f))
+
+volatile VOID *
+EFIAPI
+GetMailBox (
+ VOID
+ )
+{
+ return mMailBox;
+}
+
+UINT32
+EFIAPI
+GetNumCpus (
+ VOID
+ )
+{
+ return mNumOfCpus;
+}
+
+/**
+ Validates the configuration volume, measures it, and created a FV Hob
+
+ @param[in] VolumeAddress The base of the where the CFV must reside
+
+ @retval None
+**/
+VOID
+EFIAPI
+MeasureConfigurationVolume (
+ IN UINT64 VolumeAddress
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *Fv;
+ UINT16 Expected;
+ UINT16 Checksum;
+ UINT32 CfvSize;
+
+ ASSERT (VolumeAddress);
+ ASSERT (((UINTN) VolumeAddress & EFI_PAGE_MASK) == 0);
+
+ Fv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)VolumeAddress;
+ ASSERT (Fv->Signature == EFI_FVH_SIGNATURE );
+
+ //
+ // Validate Volume Checksum
+ //
+ Checksum = CalculateSum16 ((UINT16 *) Fv, Fv->HeaderLength);
+
+ Expected = (UINT16) (((UINTN) Fv->Checksum + 0x10000 - Checksum) & 0xffff);
+
+ DEBUG ((EFI_D_INFO, "FV@%p Checksum is 0x%x, expected 0x%x\n",
+ Fv, Fv->Checksum, Expected));
+
+ ASSERT (Fv->Checksum == Expected);
+
+ //
+ // Add FvHob for the Volume
+ //
+ BuildFvHob ((UINTN)Fv, Fv->FvLength);
+
+ //
+ // The configuration volume needs to be measured
+ //
+ CfvSize = PcdGet32 (PcdCfvRawDataSize);
+ TdxMeasureFvImage ((UINTN)Fv, CfvSize, 1);
+}
+
+VOID
+EFIAPI
+TdxStartup(
+ IN VOID * Context,
+ IN VOID * VmmHobList,
+ IN UINTN Info,
+ IN fProcessLibraryConstructorList Function
+ )
+{
+ EFI_SEC_PEI_HAND_OFF *SecCoreData;
+ EFI_FIRMWARE_VOLUME_HEADER *BootFv;
+ EFI_STATUS Status;
+ EFI_HOB_PLATFORM_INFO PlatformInfoHob;
+ VOID *Address;
+ VOID *ApLoopFunc = NULL;
+ UINT32 RelocationPages;
+ MP_RELOCATION_MAP RelocationMap;
+ MP_WAKEUP_MAILBOX *RelocatedMailBox;
+ UINT32 DxeCodeBase;
+ UINT32 DxeCodeSize;
+ TD_RETURN_DATA TdReturnData;
+ UINT8 *PlatformInfoPtr;
+
+ Status = EFI_SUCCESS;
+ BootFv = NULL;
+ SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context;
+
+ Status = TdCall (TDCALL_TDINFO, 0,0,0, &TdReturnData);
+ ASSERT (Status == EFI_SUCCESS);
+ mNumOfCpus = TdReturnData.TdInfo.NumVcpus;
+ mMailBox = (VOID *)(UINTN)PcdGet32 (PcdTdMailboxBase);
+
+ DEBUG ((EFI_D_INFO,
+ "Tdx started with(Hob: 0x%x, Info: 0x%x, Cpus: %d, MailBox: 0x%x)\n",
+ (UINT32)(UINTN)VmmHobList,
+ (UINT32)(UINTN)Info,
+ mNumOfCpus,
+ (UINT32)(UINTN)mMailBox
+ ));
+
+ ZeroMem (&PlatformInfoHob, sizeof (PlatformInfoHob));
+
+ //
+ // Validate HobList
+ //
+ if (ValidateHobList (VmmHobList) == FALSE) {
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+ }
+
+ //
+ // Process Hoblist for the TD
+ //
+ ProcessHobList (VmmHobList);
+
+ //
+ // ProcessLibaryConstructorList
+ //
+ Function (NULL, NULL);
+
+ //
+ // Tranfer the Hoblist to the final Hoblist for DXe
+ //
+ TransferHobList (VmmHobList);
+
+ //
+ // Initialize Platform
+ //
+ TdvfPlatformInitialize (&PlatformInfoHob);
+
+ //
+ // Get information needed to setup aps running in their
+ // run loop in allocated acpi reserved memory
+ // Add another page for mailbox
+ //
+ AsmGetRelocationMap (&RelocationMap);
+ RelocationPages = EFI_SIZE_TO_PAGES ((UINT32)RelocationMap.RelocateApLoopFuncSize) + 1;
+
+ Address = AllocatePagesWithMemoryType (EfiACPIMemoryNVS, RelocationPages);
+ ApLoopFunc = (VOID *) ((UINTN) Address + EFI_PAGE_SIZE);
+
+ CopyMem (
+ ApLoopFunc,
+ RelocationMap.RelocateApLoopFuncAddress,
+ RelocationMap.RelocateApLoopFuncSize
+ );
+
+ DEBUG ((DEBUG_INFO, "Ap Relocation: mailbox %p, loop %p\n",
+ Address, ApLoopFunc));
+
+ //
+ // Initialize mailbox
+ //
+ RelocatedMailBox = (MP_WAKEUP_MAILBOX *)Address;
+ RelocatedMailBox->Command = MpProtectedModeWakeupCommandNoop;
+ RelocatedMailBox->ApicId = MP_CPU_PROTECTED_MODE_MAILBOX_APICID_INVALID;
+ RelocatedMailBox->WakeUpVector = 0;
+
+ PlatformInfoHob.RelocatedMailBox = (UINT64)RelocatedMailBox;
+
+ //
+ // Create and event log entry so VMM Hoblist can be measured
+ //
+ LogHobList (VmmHobList);
+
+ //
+ // Wakup APs and have been move to the finalized run loop
+ // They will spin until guest OS wakes them
+ //
+ MpSerializeStart ();
+
+ MpSendWakeupCommand (
+ MpProtectedModeWakeupCommandWakeup,
+ (UINT64)ApLoopFunc,
+ (UINT64)RelocatedMailBox,
+ 0,
+ 0,
+ 0);
+
+ //
+ // TDVF must not use any CpuHob from input HobList.
+ // It must create its own using GPWA from VMM and 0 for SizeOfIoSpace
+ //
+ BuildCpuHob (GET_GPAW_INIT_STATE(Info), 16);
+
+ //
+ // SecFV
+ //
+ BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
+ BuildFvHob ((UINTN)BootFv, BootFv->FvLength);
+
+ //
+ // DxeFV
+ //
+ DxeCodeBase = PcdGet32 (PcdBfvBase);
+ DxeCodeSize = PcdGet32 (PcdBfvRawDataSize) - (UINT32)BootFv->FvLength;
+ BuildFvHob (DxeCodeBase, DxeCodeSize);
+
+ DEBUG ((DEBUG_INFO, "SecFv : %p, 0x%x\n", BootFv, BootFv->FvLength));
+ DEBUG ((DEBUG_INFO, "DxeFv : %x, 0x%x\n", DxeCodeBase, DxeCodeSize));
+
+ MeasureConfigurationVolume ((UINT64)(UINTN)PcdGet32 (PcdCfvBase));
+
+ PlatformInfoPtr = (UINT8*)BuildGuidDataHob (&gUefiOvmfPkgTdxPlatformGuid, &PlatformInfoHob, sizeof (EFI_HOB_PLATFORM_INFO));
+ MeasureQemuCfgSystemSts (1, PlatformInfoPtr + sizeof(EFI_HOB_PLATFORM_INFO) - 6, 6);
+
+ BuildStackHob ((UINTN)SecCoreData->StackBase, SecCoreData->StackSize <<=1 );
+
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
+ (UINT64)SecCoreData->TemporaryRamBase,
+ (UINT64)SecCoreData->TemporaryRamSize);
+
+ BuildMemoryAllocationHob (
+ FixedPcdGet32 (PcdTdMailboxBase),
+ EFI_PAGE_SIZE,
+ EfiACPIMemoryNVS
+ );
+
+ //
+ // Load the DXE Core and transfer control to it
+ //
+ Status = DxeLoadCore (1);
+
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+
+}
+
diff --git a/OvmfPkg/Library/TdxStartupLib/TdxStartupInternal.h b/OvmfPkg/Library/TdxStartupLib/TdxStartupInternal.h
new file mode 100644
index 000000000000..9e2db4e0f3d3
--- /dev/null
+++ b/OvmfPkg/Library/TdxStartupLib/TdxStartupInternal.h
@@ -0,0 +1,191 @@
+#ifndef _TDX_STARTUP_INTERNAL_LIB__H_
+#define _TDX_STARTUP_INTERNAL_LIB__H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MP_CPU_PROTECTED_MODE_MAILBOX_APICID_INVALID 0xFFFFFFFF
+#define MP_CPU_PROTECTED_MODE_MAILBOX_APICID_BROADCAST 0xFFFFFFFE
+
+ typedef enum {
+ MpProtectedModeWakeupCommandNoop = 0,
+ MpProtectedModeWakeupCommandWakeup = 1,
+ MpProtectedModeWakeupCommandSleep = 2,
+ MpProtectedModeWakeupCommandAcceptPages = 3,
+ } MP_CPU_PROTECTED_MODE_WAKEUP_CMD;
+
+#pragma pack (1)
+
+ //
+ // Describes the CPU MAILBOX control structure use to
+ // wakeup cpus spinning in long mode
+ //
+ typedef struct {
+ UINT16 Command;
+ UINT16 Resv;
+ UINT32 ApicId;
+ UINT64 WakeUpVector;
+ UINT8 ResvForOs[2032];
+ //
+ // Arguments available for wakeup code
+ //
+ UINT64 WakeUpArgs1;
+ UINT64 WakeUpArgs2;
+ UINT64 WakeUpArgs3;
+ UINT64 WakeUpArgs4;
+ UINT8 Pad1[0xe0];
+ UINT64 NumCpusArriving;
+ UINT8 Pad2[0xf8];
+ UINT64 NumCpusExiting;
+ UINT32 Tallies[256];
+ UINT8 Pad3[0x1f8];
+ } MP_WAKEUP_MAILBOX;
+
+ //
+ // AP relocation code information including code address and size,
+ // this structure will be shared be C code and assembly code.
+ // It is natural aligned by design.
+ //
+ typedef struct {
+ UINT8 *RelocateApLoopFuncAddress;
+ UINTN RelocateApLoopFuncSize;
+ } MP_RELOCATION_MAP;
+
+#define HANDOFF_TABLE_DESC "TdxTable"
+typedef struct {
+ UINT8 TableDescriptionSize;
+ UINT8 TableDescription[sizeof (HANDOFF_TABLE_DESC)];
+ UINT64 NumberOfTables;
+ EFI_CONFIGURATION_TABLE TableEntry[1];
+} TDX_HANDOFF_TABLE_POINTERS2;
+#pragma pack()
+
+#define LOOPIT(X) do { \
+ volatile int foo = (X); \
+ while (foo) ; \
+} while(0)
+
+
+volatile VOID *
+EFIAPI
+GetMailBox(
+ VOID
+ );
+
+UINT32
+EFIAPI
+GetNumCpus(
+ VOID
+ );
+
+EFI_STATUS
+EFIAPI
+DxeLoadCore (
+ IN INTN FvInstance
+ );
+
+EFI_STATUS
+EFIAPI
+InitPcdPeim (
+ IN INTN FvInstance
+ );
+
+VOID
+EFIAPI
+MpSendWakeupCommand(
+ IN UINT16 Command,
+ IN UINT64 WakeupVector,
+ IN UINT64 WakeupArgs1,
+ IN UINT64 WakeupArgs2,
+ IN UINT64 WakeupArgs3,
+ IN UINT64 WakeupArgs4
+);
+
+VOID
+EFIAPI
+MpSerializeStart (
+ VOID
+ );
+
+VOID
+EFIAPI
+MpSerializeEnd (
+ VOID
+ );
+
+VOID
+EFIAPI
+MpAcceptMemoryResourceRange (
+ IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
+ IN EFI_PHYSICAL_ADDRESS PhysicalEnd
+ );
+
+/**
+ 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
+ );
+
+
+VOID
+EFIAPI
+ProcessHobList (
+ IN CONST VOID *HobStart
+ );
+
+VOID
+EFIAPI
+TransferHobList (
+ IN CONST VOID *HobStart
+ );
+
+VOID
+EFIAPI
+LogHobList (
+ IN CONST VOID *HobStart
+ );
+
+EFI_STATUS
+TdxMeasureFvImage (
+ IN EFI_PHYSICAL_ADDRESS FvBase,
+ IN UINT64 FvLength,
+ IN UINT8 PcrIndex
+ );
+
+EFI_STATUS
+CreateTdxExtendEvent (
+ IN TCG_PCRINDEX PCRIndex,
+ IN TCG_EVENTTYPE EventType,
+ IN UINT8 *EventData,
+ IN UINTN EventSize,
+ IN UINT8 *HashData,
+ IN UINTN HashDataLen
+ );
+
+EFI_STATUS
+MeasureQemuCfgSystemSts (
+ IN TCG_PCRINDEX PCRIndex,
+ IN UINT8 *HashData,
+ IN UINTN HashDataLength
+ );
+
+VOID
+EFIAPI
+AsmGetRelocationMap (
+ OUT MP_RELOCATION_MAP *AddressMap
+ );
+
+#endif
diff --git a/OvmfPkg/Library/TdxStartupLib/TdxStartupLib.inf b/OvmfPkg/Library/TdxStartupLib/TdxStartupLib.inf
new file mode 100644
index 000000000000..02eb185ee3b5
--- /dev/null
+++ b/OvmfPkg/Library/TdxStartupLib/TdxStartupLib.inf
@@ -0,0 +1,100 @@
+#/** @file
+# Component description file for TDX Pre PI Library
+#
+# LIbrary helps you build a platform that skips PEI and loads DXE Core
+# directly. Helps building HOBs, reading data from the FV, and doing
+# decompression.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2008, Apple Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TdxStartupLib
+ FILE_GUID = 8FA74135-F841-40A4-86C8-69C923D2E85F
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TdxStartupLib|SEC
+
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ TdxStartup.c
+ Hob.c
+ Mp.c
+ DxeLoad.c
+ Tcg.c
+
+[Sources.X64]
+ X64/ApRunLoop.nasm
+ X64/VirtualMemory.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+ OvmfPkg/OvmfPkg.dec
+ CryptoPkg/CryptoPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ PcdLib
+ UefiCpuLib
+ DebugAgentLib
+ IoLib
+ LocalApicLib
+ CpuExceptionHandlerLib
+ SynchronizationLib
+ HobLib
+ TdxLib
+ MemoryAllocationLib
+ TdvfPlatformLib
+ PrePiLib
+ HashLib
+
+[Guids]
+ gEfiHobMemoryAllocModuleGuid
+ gEfiHobMemoryAllocStackGuid
+ gUefiOvmfPkgTdxPlatformGuid
+ gEfiMemoryTypeInformationGuid
+ gTcgEvent2EntryHobGuid
+ gPcdDataBaseHobGuid
+
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdMailboxBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdMailboxSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdHobBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdHobSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdCfvBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataOffset
+ gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdBfvBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataOffset
+ gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdUseTdxEmulation
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptChunkSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdxSetNxForStack
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdxPteMemoryEncryptionAddressOrMask
+
+ //
+ // TODO check these PCDs' impact on Ovmf
+ //
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplBuildPageTables ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
diff --git a/OvmfPkg/Library/TdxStartupLib/TdxStartupLibNull.inf b/OvmfPkg/Library/TdxStartupLib/TdxStartupLibNull.inf
new file mode 100644
index 000000000000..23600658f135
--- /dev/null
+++ b/OvmfPkg/Library/TdxStartupLib/TdxStartupLibNull.inf
@@ -0,0 +1,40 @@
+#/** @file
+# Component description file for TDX Pre PI Library
+#
+# LIbrary helps you build a platform that skips PEI and loads DXE Core
+# directly. Helps building HOBs, reading data from the FV, and doing
+# decompression.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2008, Apple Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TdxStartupLibNull
+ FILE_GUID = 79DD2160-D5E0-48CD-AA87-479EACEE8393
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TdxStartupLib|SEC
+
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ TdxStartupNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+
+[Pcd]
diff --git a/OvmfPkg/Library/TdxStartupLib/TdxStartupNull.c b/OvmfPkg/Library/TdxStartupLib/TdxStartupNull.c
new file mode 100644
index 000000000000..18b4e9ecdca0
--- /dev/null
+++ b/OvmfPkg/Library/TdxStartupLib/TdxStartupNull.c
@@ -0,0 +1,17 @@
+#include
+#include
+#include
+
+VOID
+EFIAPI
+TdxStartup(
+ IN VOID * Context,
+ IN VOID * VmmHobList,
+ IN UINTN Info,
+ IN fProcessLibraryConstructorList Function
+ )
+{
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+}
+
diff --git a/OvmfPkg/Library/TdxStartupLib/X64/ApRunLoop.nasm b/OvmfPkg/Library/TdxStartupLib/X64/ApRunLoop.nasm
new file mode 100644
index 000000000000..9cc5b7b340fa
--- /dev/null
+++ b/OvmfPkg/Library/TdxStartupLib/X64/ApRunLoop.nasm
@@ -0,0 +1,88 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; ApRunLoop.nasm
+;
+; Abstract:
+;
+; This is the assembly code for run loop for APs in the guest TD
+;
+;-------------------------------------------------------------------------------
+
+%include "TdxCommondefs.inc"
+
+DEFAULT REL
+
+SECTION .text
+
+BITS 64
+
+%macro tdcall 0
+%if (FixedPcdGet32 (PcdUseTdxEmulation) != 0)
+ vmcall
+%else
+ db 0x66, 0x0f, 0x01, 0xcc
+%endif
+%endmacro
+
+;
+; Relocated Ap Mailbox loop
+;
+; @param[in] RBX: Relocated mailbox address
+; @param[in] RBP: vCpuId
+;
+; @return None This routine does not return
+;
+global ASM_PFX(AsmRelocateApMailBoxLoop)
+ASM_PFX(AsmRelocateApMailBoxLoop):
+AsmRelocateApMailBoxLoopStart:
+
+ ;
+ ; TdCall[TDINFO] to get the vCpuId
+ ;
+ ;mov rax, 1
+ ;tdcall
+ ;
+ ; R8 [31:0] NUM_VCPUS
+ ; [63:32] MAX_VCPUS
+ ; R9 [31:0] VCPU_INDEX
+ ;
+
+ mov r8, rbp
+MailBoxLoop:
+ ; Spin until command set
+ cmp dword [rbx + CommandOffset], MpProtectedModeWakeupCommandNoop
+ je MailBoxLoop
+ ; Determine if this is a broadcast or directly for my apic-id, if not, ignore
+ cmp dword [rbx + ApicidOffset], MailboxApicidBroadcast
+ je MailBoxProcessCommand
+ cmp dword [rbx + ApicidOffset], r8d
+ jne MailBoxLoop
+MailBoxProcessCommand:
+ cmp dword [rbx + CommandOffset], MpProtectedModeWakeupCommandWakeup
+ je MailBoxWakeUp
+ cmp dword [rbx + CommandOffset], MpProtectedModeWakeupCommandSleep
+ je MailBoxSleep
+ ; Don't support this command, so ignore
+ jmp MailBoxLoop
+MailBoxWakeUp:
+ mov rax, [rbx + WakeupVectorOffset]
+ jmp rax
+MailBoxSleep:
+ jmp $
+BITS 64
+AsmRelocateApMailBoxLoopEnd:
+
+;-------------------------------------------------------------------------------------
+; AsmGetRelocationMap (&RelocationMap);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmGetRelocationMap)
+ASM_PFX(AsmGetRelocationMap):
+ lea rax, [ASM_PFX(AsmRelocateApMailBoxLoopStart)]
+ mov qword [rcx], rax
+ mov qword [rcx + 8h], AsmRelocateApMailBoxLoopEnd - AsmRelocateApMailBoxLoopStart
+ ret
+
diff --git a/OvmfPkg/Library/TdxStartupLib/X64/PageTables.h b/OvmfPkg/Library/TdxStartupLib/X64/PageTables.h
new file mode 100644
index 000000000000..f1d1005c9a6b
--- /dev/null
+++ b/OvmfPkg/Library/TdxStartupLib/X64/PageTables.h
@@ -0,0 +1,208 @@
+/** @file
+ x64 Long Mode Virtual Memory Management Definitions
+
+ References:
+ 1) IA-32 Intel(R) Architecture Software Developer's Manual Volume 1:Basic Architecture, Intel
+ 2) IA-32 Intel(R) Architecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel
+ 3) IA-32 Intel(R) Architecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel
+ 4) AMD64 Architecture Programmer's Manual Volume 2: System Programming
+
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
+Copyright (c) 2017, AMD Incorporated. All rights reserved.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _PAGE_TABLES_H_
+#define _PAGE_TABLES_H_
+
+
+#define SYS_CODE64_SEL 0x38
+
+
+#pragma pack(1)
+
+typedef union {
+ struct {
+ UINT32 LimitLow : 16;
+ UINT32 BaseLow : 16;
+ UINT32 BaseMid : 8;
+ UINT32 Type : 4;
+ UINT32 System : 1;
+ UINT32 Dpl : 2;
+ UINT32 Present : 1;
+ UINT32 LimitHigh : 4;
+ UINT32 Software : 1;
+ UINT32 Reserved : 1;
+ UINT32 DefaultSize : 1;
+ UINT32 Granularity : 1;
+ UINT32 BaseHigh : 8;
+ } Bits;
+ UINT64 Uint64;
+} IA32_GDT;
+
+typedef struct {
+ IA32_IDT_GATE_DESCRIPTOR Ia32IdtEntry;
+ UINT32 Offset32To63;
+ UINT32 Reserved;
+} X64_IDT_GATE_DESCRIPTOR;
+
+//
+// Page-Map Level-4 Offset (PML4) and
+// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
+//
+
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Reserved:1; // Reserved
+ UINT64 MustBeZero:2; // Must Be Zero
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PageTableBaseAddress:40; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // No Execute bit
+ } Bits;
+ UINT64 Uint64;
+} PAGE_MAP_AND_DIRECTORY_POINTER;
+
+//
+// Page Table Entry 4KB
+//
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
+ UINT64 PAT:1; //
+ UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PageTableBaseAddress:40; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_4K_ENTRY;
+
+//
+// Page Table Entry 2MB
+//
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
+ UINT64 MustBe1:1; // Must be 1
+ UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PAT:1; //
+ UINT64 MustBeZero:8; // Must be zero;
+ UINT64 PageTableBaseAddress:31; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_ENTRY;
+
+//
+// Page Table Entry 1GB
+//
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
+ UINT64 MustBe1:1; // Must be 1
+ UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PAT:1; //
+ UINT64 MustBeZero:17; // Must be zero;
+ UINT64 PageTableBaseAddress:22; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_1G_ENTRY;
+
+#pragma pack()
+
+#define CR0_WP BIT16
+
+#define IA32_PG_P BIT0
+#define IA32_PG_RW BIT1
+#define IA32_PG_PS BIT7
+
+#define PAGING_PAE_INDEX_MASK 0x1FF
+
+#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
+#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
+
+#define PAGING_L1_ADDRESS_SHIFT 12
+#define PAGING_L2_ADDRESS_SHIFT 21
+#define PAGING_L3_ADDRESS_SHIFT 30
+#define PAGING_L4_ADDRESS_SHIFT 39
+
+#define PAGING_PML4E_NUMBER 4
+
+#define PAGE_TABLE_POOL_ALIGNMENT BASE_2MB
+#define PAGE_TABLE_POOL_UNIT_SIZE SIZE_2MB
+#define PAGE_TABLE_POOL_UNIT_PAGES EFI_SIZE_TO_PAGES (PAGE_TABLE_POOL_UNIT_SIZE)
+#define PAGE_TABLE_POOL_ALIGN_MASK \
+ (~(EFI_PHYSICAL_ADDRESS)(PAGE_TABLE_POOL_ALIGNMENT - 1))
+
+typedef struct {
+ VOID *NextPool;
+ UINTN Offset;
+ UINTN FreePages;
+} PAGE_TABLE_POOL;
+
+UINTN
+CreateIdentityMappingPageTables (
+ IN EFI_PHYSICAL_ADDRESS StackBase,
+ IN UINTN StackSize
+ );
+
+/**
+ Clear legacy memory located at the first 4K-page.
+
+ This function traverses the whole HOB list to check if memory from 0 to 4095
+ exists and has not been allocated, and then clear it if so.
+
+ @param HobStart The start of HobList passed to DxeCore.
+
+**/
+VOID
+ClearFirst4KPage (
+ IN VOID *HobStart
+ );
+
+/**
+ Return configure status of NULL pointer detection feature.
+
+ @return TRUE NULL pointer detection feature is enabled
+ @return FALSE NULL pointer detection feature is disabled
+**/
+BOOLEAN
+IsNullDetectionEnabled (
+ VOID
+ );
+
+
+#endif
diff --git a/OvmfPkg/Library/TdxStartupLib/X64/VirtualMemory.c b/OvmfPkg/Library/TdxStartupLib/X64/VirtualMemory.c
new file mode 100644
index 000000000000..ebdaa85b7c23
--- /dev/null
+++ b/OvmfPkg/Library/TdxStartupLib/X64/VirtualMemory.c
@@ -0,0 +1,896 @@
+/** @file
+ x64-specifc functionality for Page Table Setup.
+
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+
+#include
+#include
+#include
+#include
+#include